浏览代码

初始化蓝牙

yuhao 2 年之前
父节点
当前提交
f57b65700f
共有 100 个文件被更改,包括 13958 次插入0 次删除
  1. 20 0
      .hbuilderx/launch.json
  2. 32 0
      App.vue
  3. 21 0
      index.html
  4. 69 0
      main.js
  5. 102 0
      manifest.json
  6. 99 0
      node_modules/@escook/request-miniprogram/README.md
  7. 73 0
      node_modules/@escook/request-miniprogram/miniprogram_dist/index.js
  8. 53 0
      node_modules/@escook/request-miniprogram/package.json
  9. 7 0
      node_modules/crypto/README.md
  10. 45 0
      node_modules/crypto/package.json
  11. 16 0
      package-lock.json
  12. 47 0
      pages.json
  13. 578 0
      pages/edit/edit.vue
  14. 396 0
      pages/home/home.vue
  15. 20 0
      static/customicons.css
  16. 二进制
      static/customicons.ttf
  17. 二进制
      static/logo.png
  18. 二进制
      static/uni.png
  19. 5 0
      uni.scss
  20. 31 0
      uni_modules/uni-badge/changelog.md
  21. 268 0
      uni_modules/uni-badge/components/uni-badge/uni-badge.vue
  22. 85 0
      uni_modules/uni-badge/package.json
  23. 10 0
      uni_modules/uni-badge/readme.md
  24. 6 0
      uni_modules/uni-breadcrumb/changelog.md
  25. 121 0
      uni_modules/uni-breadcrumb/components/uni-breadcrumb-item/uni-breadcrumb-item.vue
  26. 41 0
      uni_modules/uni-breadcrumb/components/uni-breadcrumb/uni-breadcrumb.vue
  27. 88 0
      uni_modules/uni-breadcrumb/package.json
  28. 66 0
      uni_modules/uni-breadcrumb/readme.md
  29. 20 0
      uni_modules/uni-calendar/changelog.md
  30. 546 0
      uni_modules/uni-calendar/components/uni-calendar/calendar.js
  31. 12 0
      uni_modules/uni-calendar/components/uni-calendar/i18n/en.json
  32. 8 0
      uni_modules/uni-calendar/components/uni-calendar/i18n/index.js
  33. 12 0
      uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hans.json
  34. 12 0
      uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json
  35. 188 0
      uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue
  36. 562 0
      uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue
  37. 350 0
      uni_modules/uni-calendar/components/uni-calendar/util.js
  38. 85 0
      uni_modules/uni-calendar/package.json
  39. 103 0
      uni_modules/uni-calendar/readme.md
  40. 26 0
      uni_modules/uni-card/changelog.md
  41. 270 0
      uni_modules/uni-card/components/uni-card/uni-card.vue
  42. 90 0
      uni_modules/uni-card/package.json
  43. 12 0
      uni_modules/uni-card/readme.md
  44. 36 0
      uni_modules/uni-collapse/changelog.md
  45. 402 0
      uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue
  46. 147 0
      uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue
  47. 89 0
      uni_modules/uni-collapse/package.json
  48. 12 0
      uni_modules/uni-collapse/readme.md
  49. 15 0
      uni_modules/uni-combox/changelog.md
  50. 275 0
      uni_modules/uni-combox/components/uni-combox/uni-combox.vue
  51. 90 0
      uni_modules/uni-combox/package.json
  52. 11 0
      uni_modules/uni-combox/readme.md
  53. 24 0
      uni_modules/uni-countdown/changelog.md
  54. 6 0
      uni_modules/uni-countdown/components/uni-countdown/i18n/en.json
  55. 8 0
      uni_modules/uni-countdown/components/uni-countdown/i18n/index.js
  56. 6 0
      uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hans.json
  57. 6 0
      uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hant.json
  58. 271 0
      uni_modules/uni-countdown/components/uni-countdown/uni-countdown.vue
  59. 86 0
      uni_modules/uni-countdown/package.json
  60. 10 0
      uni_modules/uni-countdown/readme.md
  61. 45 0
      uni_modules/uni-data-checkbox/changelog.md
  62. 821 0
      uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue
  63. 84 0
      uni_modules/uni-data-checkbox/package.json
  64. 18 0
      uni_modules/uni-data-checkbox/readme.md
  65. 66 0
      uni_modules/uni-data-picker/changelog.md
  66. 45 0
      uni_modules/uni-data-picker/components/uni-data-picker/keypress.js
  67. 547 0
      uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue
  68. 622 0
      uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js
  69. 321 0
      uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue
  70. 90 0
      uni_modules/uni-data-picker/package.json
  71. 22 0
      uni_modules/uni-data-picker/readme.md
  72. 22 0
      uni_modules/uni-data-select/changelog.md
  73. 440 0
      uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue
  74. 85 0
      uni_modules/uni-data-select/package.json
  75. 8 0
      uni_modules/uni-data-select/readme.md
  76. 10 0
      uni_modules/uni-dateformat/changelog.md
  77. 200 0
      uni_modules/uni-dateformat/components/uni-dateformat/date-format.js
  78. 88 0
      uni_modules/uni-dateformat/components/uni-dateformat/uni-dateformat.vue
  79. 88 0
      uni_modules/uni-dateformat/package.json
  80. 11 0
      uni_modules/uni-dateformat/readme.md
  81. 103 0
      uni_modules/uni-datetime-picker/changelog.md
  82. 187 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue
  83. 924 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue
  84. 22 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json
  85. 8 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js
  86. 22 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json
  87. 22 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json
  88. 45 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/keypress.js
  89. 946 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue
  90. 1015 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue
  91. 410 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js
  92. 87 0
      uni_modules/uni-datetime-picker/package.json
  93. 21 0
      uni_modules/uni-datetime-picker/readme.md
  94. 13 0
      uni_modules/uni-drawer/changelog.md
  95. 45 0
      uni_modules/uni-drawer/components/uni-drawer/keypress.js
  96. 183 0
      uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue
  97. 87 0
      uni_modules/uni-drawer/package.json
  98. 10 0
      uni_modules/uni-drawer/readme.md
  99. 86 0
      uni_modules/uni-easyinput/changelog.md
  100. 0 0
      uni_modules/uni-easyinput/components/uni-easyinput/common.js

+ 20 - 0
.hbuilderx/launch.json

@@ -0,0 +1,20 @@
1
+{
2
+    // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
3
+    // launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
4
+    "version" : "0.0",
5
+    "configurations" : [
6
+        {
7
+            "app-plus" : {
8
+                "launchtype" : "local"
9
+            },
10
+            "default" : {
11
+                "launchtype" : "local"
12
+            },
13
+            "type" : "uniCloud"
14
+        },
15
+        {
16
+            "playground" : "standard",
17
+            "type" : "uni-app:app-android"
18
+        }
19
+    ]
20
+}

+ 32 - 0
App.vue

@@ -0,0 +1,32 @@
1
+<script>
2
+	export default {
3
+		onLaunch: function() {
4
+			console.warn('当前组件仅支持 uni_modules 目录结构 ,请升级 HBuilderX 到 3.1.0 版本以上!')
5
+			console.log('App Launch')
6
+		},
7
+		onShow: function() {
8
+			console.log('App Show')
9
+		},
10
+		onHide: function() {
11
+			console.log('App Hide')
12
+		}
13
+	}
14
+</script>
15
+
16
+<style lang="scss">
17
+	/*每个页面公共css */
18
+	@import '@/uni_modules/uni-scss/index.scss';
19
+	/* #ifndef APP-NVUE */
20
+	@import '@/static/customicons.css';
21
+	// 设置整个项目的背景色
22
+	page {
23
+		background-color: #f5f5f5;
24
+	}
25
+
26
+	/* #endif */
27
+	.example-info {
28
+		font-size: 14px;
29
+		color: #333;
30
+		padding: 10px;
31
+	}
32
+</style>

+ 21 - 0
index.html

@@ -0,0 +1,21 @@
1
+<!DOCTYPE html>
2
+<html lang="en">
3
+  <head>
4
+    <meta charset="UTF-8" />
5
+    <script>
6
+      var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
7
+        CSS.supports('top: constant(a)'))
8
+      document.write(
9
+        '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
10
+        (coverSupport ? ', viewport-fit=cover' : '') + '" />')
11
+    </script>
12
+	<script type="text/javascript" src="https://ydcommon.51yund.com/test_web_hd/vendor/vconsole.min.js"></script>
13
+    <title></title>
14
+    <!--preload-links-->
15
+    <!--app-context-->
16
+  </head>
17
+  <body>
18
+    <div id="app"><!--app-html--></div>
19
+    <script type="module" src="/main.js"></script>
20
+  </body>
21
+</html>

+ 69 - 0
main.js

@@ -0,0 +1,69 @@
1
+// #ifndef VUE3
2
+import Vue from 'vue'
3
+import App from './App'
4
+
5
+// 导入网络请求的包
6
+import {
7
+	$http
8
+} from '@escook/request-miniprogram'
9
+import {
10
+	formatDate,
11
+	sortASCII
12
+} from '@/utils.js'
13
+import crypto from 'crypto'
14
+Vue.config.productionTip = false
15
+
16
+App.mpType = 'app'
17
+uni.$http = $http
18
+// 请求的根路径
19
+$http.baseUrl = 'https://api.ijolijoli.com/'
20
+
21
+// 请求拦截器
22
+$http.beforeRequest = function(options) {
23
+	// 当前发送请求时间
24
+	let req_time = formatDate(new Date(), 'YYYYMMDDhhmmss')
25
+	let app_id = '10020'
26
+	let key = 'c2c1d3893504d063d7b30c0fc553c1b2'
27
+	options.data.app_id=app_id
28
+	options.data.req_time = req_time
29
+	// 参数排序
30
+	let sortObj = sortASCII(options.data, true)
31
+	sortObj.key = key
32
+	// 拼接参数
33
+	let mdd = []
34
+	let fnAdd = function(key, value) {
35
+		return key + '=' + value
36
+	}
37
+	for (var k in sortObj) {
38
+		mdd.push(fnAdd(k, sortObj[k]))
39
+	}
40
+	// 转成md5加密
41
+	mdd=mdd.join('&')
42
+	const md5 = crypto.createHash('md5')
43
+	md5.update(mdd)
44
+	const sign = md5.digest('hex')
45
+	options.data.sign = sign
46
+}
47
+// 响应拦截器
48
+$http.afterRequest = function() {}
49
+const app = new Vue({
50
+	...App
51
+})
52
+app.$mount()
53
+// #endif
54
+
55
+// #ifdef VUE3
56
+import {
57
+	createSSRApp
58
+} from 'vue'
59
+import App from './App.vue'
60
+import {
61
+	log
62
+} from 'console'
63
+export function createApp() {
64
+	const app = createSSRApp(App)
65
+	return {
66
+		app
67
+	}
68
+}
69
+// #endif

+ 102 - 0
manifest.json

@@ -0,0 +1,102 @@
1
+{
2
+    "name" : "JOLIJOLI设备端",
3
+    "appid" : "__UNI__9FA9CB3",
4
+    "description" : "",
5
+    "versionName" : "1.0.0",
6
+    "versionCode" : "100",
7
+    "transformPx" : false,
8
+    "app-plus" : {
9
+        /* 5+App特有相关 */
10
+        "usingComponents" : true,
11
+        "nvueCompiler" : "uni-app",
12
+        "nvueStyleCompiler" : "uni-app",
13
+        "splashscreen" : {
14
+            "alwaysShowBeforeRender" : true,
15
+            "waiting" : true,
16
+            "autoclose" : true,
17
+            "delay" : 0
18
+        },
19
+        "modules" : {
20
+            "Bluetooth" : {},
21
+            "Geolocation" : {},
22
+            "Maps" : {}
23
+        },
24
+        /* 模块配置 */
25
+        "distribute" : {
26
+            /* 应用发布信息 */
27
+            "android" : {
28
+                /* android打包配置 */
29
+                "permissions" : [
30
+                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
31
+                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
32
+                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
33
+                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
34
+                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
35
+                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
36
+                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
37
+                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
38
+                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
39
+                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
40
+                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
41
+                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
42
+                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
43
+                    "<uses-feature android:name=\"android.hardware.camera\"/>",
44
+                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
45
+                ]
46
+            },
47
+            "ios" : {
48
+                "dSYMs" : false
49
+            },
50
+            /* ios打包配置 */
51
+            "sdkConfigs" : {
52
+                "geolocation" : {},
53
+                "maps" : {},
54
+                "ad" : {}
55
+            },
56
+            "icons" : {
57
+                "android" : {
58
+                    "hdpi" : "unpackage/res/icons/72x72.png",
59
+                    "xhdpi" : "unpackage/res/icons/96x96.png",
60
+                    "xxhdpi" : "unpackage/res/icons/144x144.png",
61
+                    "xxxhdpi" : "unpackage/res/icons/192x192.png"
62
+                },
63
+                "ios" : {
64
+                    "appstore" : "unpackage/res/icons/1024x1024.png",
65
+                    "ipad" : {
66
+                        "app" : "unpackage/res/icons/76x76.png",
67
+                        "app@2x" : "unpackage/res/icons/152x152.png",
68
+                        "notification" : "unpackage/res/icons/20x20.png",
69
+                        "notification@2x" : "unpackage/res/icons/40x40.png",
70
+                        "proapp@2x" : "unpackage/res/icons/167x167.png",
71
+                        "settings" : "unpackage/res/icons/29x29.png",
72
+                        "settings@2x" : "unpackage/res/icons/58x58.png",
73
+                        "spotlight" : "unpackage/res/icons/40x40.png",
74
+                        "spotlight@2x" : "unpackage/res/icons/80x80.png"
75
+                    },
76
+                    "iphone" : {
77
+                        "app@2x" : "unpackage/res/icons/120x120.png",
78
+                        "app@3x" : "unpackage/res/icons/180x180.png",
79
+                        "notification@2x" : "unpackage/res/icons/40x40.png",
80
+                        "notification@3x" : "unpackage/res/icons/60x60.png",
81
+                        "settings@2x" : "unpackage/res/icons/58x58.png",
82
+                        "settings@3x" : "unpackage/res/icons/87x87.png",
83
+                        "spotlight@2x" : "unpackage/res/icons/80x80.png",
84
+                        "spotlight@3x" : "unpackage/res/icons/120x120.png"
85
+                    }
86
+                }
87
+            }
88
+        }
89
+    },
90
+    /* SDK配置 */
91
+    "quickapp" : {},
92
+    /* 快应用特有相关 */
93
+    "mp-weixin" : {
94
+        /* 小程序特有相关 */
95
+        "appid" : "",
96
+        "setting" : {
97
+            "urlCheck" : false
98
+        },
99
+        "usingComponents" : true
100
+    },
101
+    "vueVersion" : "2"
102
+}

+ 99 - 0
node_modules/@escook/request-miniprogram/README.md

@@ -0,0 +1,99 @@
1
+## 安装
2
+
3
+```bash
4
+npm install @escook/request-miniprogram
5
+```
6
+
7
+## 导入
8
+
9
+```js
10
+// 按需导入 $http 对象
11
+import { $http } from '@escook/request-miniprogram'
12
+
13
+// 将按需导入的 $http 挂载到 wx 顶级对象之上,方便全局调用
14
+wx.$http = $http
15
+
16
+// 在 uni-app 项目中,可以把 $http 挂载到 uni 顶级对象之上,方便全局调用
17
+uni.$http = $http
18
+```
19
+
20
+## 使用
21
+
22
+### 支持的请求方法
23
+
24
+```js
25
+// 发起 GET 请求,data 是可选的参数对象
26
+$http.get(url, data?)
27
+
28
+// 发起 POST 请求,data 是可选的参数对象
29
+$http.post(url, data?)
30
+
31
+// 发起 PUT 请求,data 是可选的参数对象
32
+$http.put(url, data?)
33
+
34
+// 发起 DELETE 请求,data 是可选的参数对象
35
+$http.delete(url, data?)
36
+```
37
+
38
+### 配置请求根路径
39
+
40
+```js
41
+$http.baseUrl = 'https://www.example.com'
42
+```
43
+
44
+### 请求拦截器
45
+
46
+```js
47
+// 请求开始之前做一些事情
48
+$http.beforeRequest = function (options) {
49
+  // do somethimg...
50
+}
51
+```
52
+
53
+例 1,展示 loading 效果:
54
+
55
+```js
56
+// 请求开始之前做一些事情
57
+$http.beforeRequest = function (options) {
58
+  wx.showLoading({
59
+    title: '数据加载中...',
60
+  })
61
+}
62
+```
63
+
64
+例 2,自定义 header 请求头:
65
+
66
+```js
67
+// 请求开始之前做一些事情
68
+$http.beforeRequest = function (options) {
69
+  if (options.url.indexOf('/home/catitems') !== -1) {
70
+    options.header = {
71
+      'X-Test': 'AAA',
72
+    }
73
+  }
74
+}
75
+```
76
+
77
+### 响应拦截器
78
+
79
+```js
80
+// 请求完成之后做一些事情
81
+$http.afterRequest = function () {
82
+  // do something...
83
+}
84
+```
85
+
86
+例如,隐藏 loading 效果:
87
+
88
+```js
89
+// 请求完成之后做一些事情
90
+$http.afterRequest = function () {
91
+  wx.hideLoading()
92
+}
93
+```
94
+
95
+## 开源协议
96
+
97
+![MIT](https://img.shields.io/badge/License-MIT-blue)
98
+
99
+**enjoy!**

+ 73 - 0
node_modules/@escook/request-miniprogram/miniprogram_dist/index.js

@@ -0,0 +1,73 @@
1
+class Request {
2
+  constructor(options = {}) {
3
+    // 请求的根路径
4
+    this.baseUrl = options.baseUrl || ''
5
+    // 请求的 url 地址
6
+    this.url = options.url || ''
7
+    // 请求方式
8
+    this.method = 'GET'
9
+    // 请求的参数对象
10
+    this.data = null
11
+    // header 请求头
12
+    this.header = options.header || {}
13
+    this.beforeRequest = null
14
+    this.afterRequest = null
15
+  }
16
+
17
+  get(url, data = {}) {
18
+    this.method = 'GET'
19
+    this.url = this.baseUrl + url
20
+    this.data = data
21
+    return this._()
22
+  }
23
+
24
+  post(url, data = {}) {
25
+    this.method = 'POST'
26
+    this.url = this.baseUrl + url
27
+    this.data = data
28
+    return this._()
29
+  }
30
+
31
+  put(url, data = {}) {
32
+    this.method = 'PUT'
33
+    this.url = this.baseUrl + url
34
+    this.data = data
35
+    return this._()
36
+  }
37
+
38
+  delete(url, data = {}) {
39
+    this.method = 'DELETE'
40
+    this.url = this.baseUrl + url
41
+    this.data = data
42
+    return this._()
43
+  }
44
+
45
+  _() {
46
+    // 清空 header 对象
47
+    this.header = {}
48
+    // 请求之前做一些事
49
+    this.beforeRequest && typeof this.beforeRequest === 'function' && this.beforeRequest(this)
50
+    // 发起请求
51
+    return new Promise((resolve, reject) => {
52
+      let weixin = wx
53
+      // 适配 uniapp
54
+      if ('undefined' !== typeof uni) {
55
+        weixin = uni
56
+      }
57
+      weixin.request({
58
+        url: this.url,
59
+        method: this.method,
60
+        data: this.data,
61
+        header: this.header,
62
+        success: (res) => { resolve(res) },
63
+        fail: (err) => { reject(err) },
64
+        complete: (res) => {
65
+          // 请求完成以后做一些事情
66
+          this.afterRequest && typeof this.afterRequest === 'function' && this.afterRequest(res)
67
+        }
68
+      })
69
+    })
70
+  }
71
+}
72
+
73
+export const $http = new Request()

+ 53 - 0
node_modules/@escook/request-miniprogram/package.json

@@ -0,0 +1,53 @@
1
+{
2
+  "_from": "@escook/request-miniprogram",
3
+  "_id": "@escook/request-miniprogram@0.2.1",
4
+  "_inBundle": false,
5
+  "_integrity": "sha512-ueWV5YsaEm/ycQZuEjMiA88GFMhfBQSjy9GrP9omy4xAQajkGTbYIlnhzsDfWzRPmRC1fKmAiKMrCVcgS+SHcQ==",
6
+  "_location": "/@escook/request-miniprogram",
7
+  "_phantomChildren": {},
8
+  "_requested": {
9
+    "type": "tag",
10
+    "registry": true,
11
+    "raw": "@escook/request-miniprogram",
12
+    "name": "@escook/request-miniprogram",
13
+    "escapedName": "@escook%2frequest-miniprogram",
14
+    "scope": "@escook",
15
+    "rawSpec": "",
16
+    "saveSpec": null,
17
+    "fetchSpec": "latest"
18
+  },
19
+  "_requiredBy": [
20
+    "#USER",
21
+    "/"
22
+  ],
23
+  "_resolved": "https://registry.npmmirror.com/@escook/request-miniprogram/-/request-miniprogram-0.2.1.tgz",
24
+  "_shasum": "c3b13249f5a94601f2949f4d68245df9a5683819",
25
+  "_spec": "@escook/request-miniprogram",
26
+  "_where": "D:\\资料\\蓝牙\\蓝牙",
27
+  "author": {
28
+    "name": "LiuLongBin"
29
+  },
30
+  "bugs": {
31
+    "url": "https://github.com/liulongbin1314/request-miniprogram/issues"
32
+  },
33
+  "bundleDependencies": false,
34
+  "deprecated": false,
35
+  "description": "基于 Promise 的小程序网路请求库",
36
+  "homepage": "https://github.com/liulongbin1314/request-miniprogram#readme",
37
+  "keywords": [
38
+    "request",
39
+    "miniprogram",
40
+    "wx",
41
+    "weixin"
42
+  ],
43
+  "license": "MIT",
44
+  "main": "miniprogram_dist/index.js",
45
+  "miniprogram": "miniprogram_dist",
46
+  "name": "@escook/request-miniprogram",
47
+  "repository": {
48
+    "type": "git",
49
+    "url": "git+ssh://git@github.com/liulongbin1314/request-miniprogram.git"
50
+  },
51
+  "scripts": {},
52
+  "version": "0.2.1"
53
+}

+ 7 - 0
node_modules/crypto/README.md

@@ -0,0 +1,7 @@
1
+# Deprecated Package
2
+
3
+This package is no longer supported and has been deprecated. To avoid malicious use, npm is hanging on to the package name.
4
+
5
+It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in.
6
+
7
+Please contact support@npmjs.com if you have questions about this package.

+ 45 - 0
node_modules/crypto/package.json

@@ -0,0 +1,45 @@
1
+{
2
+  "_from": "crypto",
3
+  "_id": "crypto@1.0.1",
4
+  "_inBundle": false,
5
+  "_integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==",
6
+  "_location": "/crypto",
7
+  "_phantomChildren": {},
8
+  "_requested": {
9
+    "type": "tag",
10
+    "registry": true,
11
+    "raw": "crypto",
12
+    "name": "crypto",
13
+    "escapedName": "crypto",
14
+    "rawSpec": "",
15
+    "saveSpec": null,
16
+    "fetchSpec": "latest"
17
+  },
18
+  "_requiredBy": [
19
+    "#USER",
20
+    "/"
21
+  ],
22
+  "_resolved": "https://registry.npmmirror.com/crypto/-/crypto-1.0.1.tgz",
23
+  "_shasum": "2af1b7cad8175d24c8a1b0778255794a21803037",
24
+  "_spec": "crypto",
25
+  "_where": "D:\\资料\\蓝牙\\蓝牙",
26
+  "author": "",
27
+  "bugs": {
28
+    "url": "https://github.com/npm/deprecate-holder/issues"
29
+  },
30
+  "bundleDependencies": false,
31
+  "deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in.",
32
+  "description": "This package is no longer supported and has been deprecated. To avoid malicious use, npm is hanging on to the package name.",
33
+  "homepage": "https://github.com/npm/deprecate-holder#readme",
34
+  "license": "ISC",
35
+  "main": "index.js",
36
+  "name": "crypto",
37
+  "repository": {
38
+    "type": "git",
39
+    "url": "git+https://github.com/npm/deprecate-holder.git"
40
+  },
41
+  "scripts": {
42
+    "test": "echo \"Error: no test specified\" && exit 1"
43
+  },
44
+  "version": "1.0.1"
45
+}

+ 16 - 0
package-lock.json

@@ -0,0 +1,16 @@
1
+{
2
+  "requires": true,
3
+  "lockfileVersion": 1,
4
+  "dependencies": {
5
+    "@escook/request-miniprogram": {
6
+      "version": "0.2.1",
7
+      "resolved": "https://registry.npmmirror.com/@escook/request-miniprogram/-/request-miniprogram-0.2.1.tgz",
8
+      "integrity": "sha512-ueWV5YsaEm/ycQZuEjMiA88GFMhfBQSjy9GrP9omy4xAQajkGTbYIlnhzsDfWzRPmRC1fKmAiKMrCVcgS+SHcQ=="
9
+    },
10
+    "crypto": {
11
+      "version": "1.0.1",
12
+      "resolved": "https://registry.npmmirror.com/crypto/-/crypto-1.0.1.tgz",
13
+      "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig=="
14
+    }
15
+  }
16
+}

+ 47 - 0
pages.json

@@ -0,0 +1,47 @@
1
+{
2
+	"pages": [
3
+		{
4
+		        "path" : "pages/home/home",
5
+		        "style" :                                                                                    
6
+		        {
7
+		            "navigationBarTitleText": "",
8
+		            "enablePullDownRefresh": false
9
+		        }
10
+		        
11
+		    },
12
+        {
13
+            "path" : "pages/edit/edit",
14
+            "style" :                                                                                    
15
+            {
16
+                "navigationBarTitleText": "",
17
+                "enablePullDownRefresh": false,
18
+				"app-plus": {
19
+					"titleNView": {
20
+						"autoBackButton": false
21
+					}
22
+				}
23
+            }
24
+            
25
+        }
26
+    ],
27
+	"globalStyle": {
28
+		"navigationBarTextStyle": "black",
29
+		"navigationBarTitleText": "uni-app",
30
+		"navigationBarBackgroundColor": "#F8F8F8",
31
+		"backgroundColor": "#F8F8F8",
32
+		"app-plus": {
33
+			"background": "#efeff4"
34
+		},
35
+		"pageOrientation": "landscape"
36
+	},
37
+	"condition" : { //模式配置,仅开发期间生效
38
+		"current": 0, //当前激活的模式(list 的索引项)
39
+		"list": [
40
+			{
41
+				"name": "", //模式名称
42
+				"path": "", //启动页面,必选
43
+				"query": "" //启动参数,在页面的onLoad函数里面得到
44
+			}
45
+		]
46
+	}
47
+}

+ 578 - 0
pages/edit/edit.vue

@@ -0,0 +1,578 @@
1
+<template>
2
+	<view>
3
+		<view class="top">
4
+			<span class='title'>编辑蓝牙设备</span><span class='id'>设备id</span><span>{{deviceId}}</span><span
5
+				class='startTime'>开始时间</span><span>{{startTime}}</span><span class='totalTime'
6
+				style='font-weight: 700;'>总时长</span><span style='font-weight: 700;'>{{time}}</span>
7
+		</view>
8
+		<view class="type">
9
+			<view class="facilityType">
10
+				<p>设备类型</p>
11
+				<view class="buttonOP" v-if="typeList">
12
+						<view class="item" @click="selectOne('type_sn',index,item)" :class="{selectType:index==selectTypeIndex}" v-for="(item,index) in typeList" :key="index">
13
+							<img :src="item.cover_url" alt="">
14
+							<span>{{item.name}}</span>
15
+						</view>
16
+				</view>
17
+			</view>
18
+			<view class="facilityType">
19
+				<p>探头</p>
20
+				<view class="buttonOP" v-if="typeList!=''">
21
+						<view class="item" @click="selectOne('detectors',index,item)" :class="{selectType:index==selectDetectorsIndexA}" v-for="(item,index) in typeList[selectTypeIndex].detectors"
22
+						:key="index">
23
+							<img :src="item.cover_url" alt="">
24
+							<span>{{item.detector_name}}</span>
25
+						</view>
26
+				</view>
27
+			</view>
28
+			<!-- mode中的模式 -->
29
+			<view class="pattern">
30
+			<view class="facilityType"
31
+				v-if="typeList!=''&&typeList[selectTypeIndex].detectors[selectDetectorsIndex].config.mode&&typeList[selectTypeIndex].detectors[selectDetectorsIndex].config.mode.list">
32
+				<p>模式</p>
33
+				<view class="buttonOP">
34
+					<button @click="selectOne('mode',index,item)" :class="{selectType:index==selectModeIndexA}"
35
+						v-for="(item,index) in typeList[selectTypeIndex].detectors[selectDetectorsIndex].config.mode.list">{{item.name}}</button>
36
+				</view>
37
+			</view>
38
+			<!-- power中的模式 -->
39
+			<view class="facilityType"
40
+				v-else-if="typeList!=''&&typeList[selectTypeIndex].detectors[selectDetectorsIndex].config.power.list">
41
+				<p>模式</p>
42
+				<view class="buttonOP">
43
+					<button @click="selectOne('mode',index,item)" :class="{selectType:index==selectModeIndexA}"
44
+						v-for="(item,index) in typeList[selectTypeIndex].detectors[selectDetectorsIndex].config.power.list">{{item.name}}</button>
45
+					<button style="margin-left: 100px; background-color: #374b5f;" @click="pqCLick">点击排气</button>
46
+				</view>
47
+			</view>
48
+			<view class="facilityType" v-else>
49
+				<p>强度</p>
50
+				<view class="buttonOPO">
51
+					<button @click="reduce">减少</button>
52
+					<view class="strength">
53
+						{{modeClass}}
54
+					</view><button @click="add">增加</button>
55
+				</view>
56
+			</view>
57
+			{{CODE}}
58
+			</view>
59
+		</view>
60
+		<view class="bottomBox">
61
+			<view class="back">
62
+				<button @click="back">返回蓝牙匹配</button>
63
+			</view>
64
+			<view class="bottomBox-right">
65
+				<button @click="operate('open')" class="open">开始</button>
66
+				<button @click="operate('pause')" class="pause">暂停</button>
67
+				<button @click="operate('finish')" class="finish">结束</button>
68
+			</view>
69
+		</view>
70
+	</view>
71
+</template>
72
+
73
+<script>
74
+	import {
75
+		formatDate
76
+	} from '../../utils.js'
77
+	export default {
78
+		data() {
79
+			return {
80
+				deviceId: '', //蓝牙设备ID
81
+				serviceId: '', //服务UUID
82
+				characteristicId: '', //特征值
83
+				typeList: [], //设备数据列表
84
+				selectTypeIndex: 0, //选择中设备类型index
85
+				selectDetectorsIndex: 0, //探头index
86
+				selectDetectorsIndexA: 99, //探头index
87
+				selectModeIndex: 0, //模式index
88
+				selectModeIndexA: 99, //模式index
89
+				TYPE_SN: 'ZK', //设备名称
90
+				CODE: 'AABB12343838373244363235444138020301010101', //设备码
91
+				PQCODE: "AABB12343838373244363235444138010101010101", //开始排气
92
+				PQCLOSECODE: "AABB12343838373244363235444138010201010101", //关闭排气
93
+				modeClass: 0, //强度等级
94
+				minClass: '', //最小强度等级
95
+				maxClass: '', //小大强度等级
96
+				incrementClass: '', //强度增幅
97
+				START: '01', //开始
98
+				PAUSE: '00', //暂停
99
+				equipmentNum: '', //设备编号
100
+				modeNum: '01', //模式编号
101
+				CODE: '',
102
+				startTime: "", //开始时间
103
+				time: '00:00:00', //初始展示时间
104
+				timer: '', 
105
+				istimer: false, //是否暂停
106
+				hour: 0, //计时(时)
107
+				minutes: 0, //计时(分)
108
+				seconds: 0, //计时(秒)
109
+			};
110
+		},
111
+		onLoad(options) {
112
+			console.log(options, 333333);
113
+			this.deviceId = options.deviceId
114
+			this.serviceId = options.serviceId
115
+			this.characteristicId = options.characteristicId
116
+			let typeList = uni.getStorageSync('typeList')
117
+			if(!typeList){
118
+				// 获取设备列表
119
+				this.getTypeList()
120
+			}else{
121
+				this.typeList = typeList
122
+			}
123
+		},
124
+		methods: {
125
+			// -----------蓝牙报错提示
126
+			blueError(code) {
127
+				switch (code) {
128
+					case 10000:
129
+						// uni.openBluetoothAdapter({
130
+						// 	success(res) {
131
+						// 		uni.showToast({
132
+						// 			title: '初始化成功,请重新启动',
133
+						// 			duration: 2500,
134
+						// 			icon: 'none'
135
+						// 		})
136
+						// 	},
137
+						// 	fail(err) {
138
+						// 		uni.hideLoading()
139
+						// 		console.log('初始化蓝牙失败')
140
+						// 	}
141
+						// })
142
+						this.errorToast('未初始化蓝牙适配器,请返回重新连接')
143
+						break
144
+					case 10001:
145
+						this.errorToast('当前蓝牙适配器不可用')
146
+						break
147
+					case 10002:
148
+						this.errorToast('没有找到指定设备')
149
+						break
150
+					case 10003:
151
+						this.errorToast('连接失败')
152
+						break
153
+					case 10004:
154
+						this.errorToast('没有找到指定服务,请返回重新连接')
155
+						break
156
+					case 10005:
157
+						this.errorToast('没有找到指定特征值')
158
+						break
159
+					case 10006:
160
+						this.errorToast('当前连接已断开')
161
+						break
162
+					case 10007:
163
+						this.errorToast('当前特征值不支持此操作')
164
+						break
165
+					case 10008:
166
+						this.errorToast('其余所有系统上报的异常')
167
+						break
168
+					case 10009:
169
+						this.errorToast('Android 系统特有,系统版本低于 4.3 不支持 BLE')
170
+						break
171
+					case 100010:
172
+						this.errorToast('已连接')
173
+						break
174
+					case 100011:
175
+						this.errorToast('配对设备需要配对码')
176
+						break
177
+					case 100012:
178
+						this.errorToast('连接超时')
179
+						break
180
+					case 100013:
181
+						this.errorToast('连接 deviceld 为空或者是格式不正确')
182
+						break
183
+				}
184
+			},
185
+			// -----------统一错误封装
186
+			errorToast(err) {
187
+				uni.showToast({
188
+					title: `${err}`,
189
+					icon: 'none',
190
+					duration: 2500
191
+				})
192
+			},
193
+			// -----------------返回蓝牙匹配
194
+			back() {
195
+				uni.navigateBack()
196
+			},
197
+			// ------------------获取设备数据列表
198
+			async getTypeList() {
199
+				const {
200
+					data: res
201
+				} = await uni.$http.post('v2/api-device/device/type_list')
202
+				console.log(JSON.parse(JSON.stringify(res.data.list)), '获取的数据返回');
203
+				// 筛选出无创水光
204
+				for (let key in res.data.list) {
205
+					if (res.data.list[key].id != 1&&res.data.list[key].id != 15) {
206
+						this.typeList.push(res.data.list[key])   
207
+					}
208
+				}
209
+				// this.typeList = res.data.list
210
+				uni.setStorageSync('typeList', this.typeList)
211
+				// console.log(JSON.parse(JSON.stringify(this.typeList[0].detectors[1])), 333333);
212
+				// console.log(JSON.parse(JSON.stringify(this.typeList)), 333333);
213
+			},
214
+			// ------------------选择设备配置
215
+			selectOne(type, index, item) {
216
+				switch (type) {
217
+					case 'type_sn':
218
+						this.selectTypeIndex = index
219
+						this.selectDetectorsIndex = 0
220
+						this.selectModeIndex = 0
221
+						this.selectDetectorsIndexA = 99
222
+						this.selectModeIndexA = 99
223
+						this.equipmentNum = '' //重置探头
224
+						this.modeNum = '' //重置模式或强度
225
+						console.log(item)
226
+						//赋值哪个厂家的设备
227
+						if (item.type_sn.includes('ZK')) {
228
+							this.TYPE_SN = 'ZK'
229
+						} else {
230
+							this.TYPE_SN = 'LD'
231
+						}
232
+						break
233
+					case 'detectors':
234
+						this.selectDetectorsIndex = index
235
+						this.selectDetectorsIndexA = index
236
+						this.selectModeIndexA = 99
237
+						this.equipmentNum = Number(item.detector_sn).toString(16) < 10 ? '0' + Number(item.detector_sn)
238
+							.toString(16) : Number(item.detector_sn).toString(16) //设备探头编号(16进制)
239
+						console.log(this.equipmentNum)
240
+						console.log(JSON.parse(JSON.stringify(this.typeList[this.selectTypeIndex].detectors[this
241
+							.selectDetectorsIndex])))
242
+						this.minClass = this.typeList[this.selectTypeIndex].detectors[this.selectDetectorsIndex].config
243
+							.power.min //最小值
244
+						this.maxClass = this.typeList[this.selectTypeIndex].detectors[this.selectDetectorsIndex].config
245
+							.power.max //最大值
246
+						this.incrementClass = this.typeList[this.selectTypeIndex].detectors[this.selectDetectorsIndex]
247
+							.config.power.increment //增幅
248
+						this.modeClass = this.typeList[this.selectTypeIndex].detectors[this.selectDetectorsIndex].config
249
+							.power.default //默认值
250
+						break
251
+					case 'mode':
252
+						this.selectModeIndex = index
253
+						this.selectModeIndexA = index
254
+						this.modeNum = Number(item.value).toString(16) < 10 ? '0' + Number(item.value).toString(16) :
255
+							Number(item.value).toString(16)
256
+						console.log(this.modeNum)
257
+						break
258
+				}
259
+			},
260
+			// -----------------开始计时
261
+			begin() {
262
+				if (!this.istimer) {
263
+					this.timer = setInterval(this.startTimer, 1000);
264
+					this.istimer = true
265
+				}
266
+			},
267
+			//------------暂停计时
268
+			pauseTime() {
269
+				if (this.timer) {
270
+					clearInterval(this.timer);
271
+					this.istimer = false
272
+				}
273
+			},
274
+			// -------------结束计时
275
+			finishTime() {
276
+				if (this.timer) {
277
+					clearInterval(this.timer);
278
+					this.istimer = false
279
+					this.time = '00:00:00'
280
+					this.startTime = ''
281
+					this.seconds = 0
282
+					this.minutes = 0
283
+					this.hour = 0
284
+				}
285
+			},
286
+			// -----------------计时器
287
+			startTimer() {
288
+				this.seconds += 1;
289
+				if (this.seconds >= 60) {
290
+					this.seconds = 0;
291
+					this.minutes = Number(this.minutes) + 1;
292
+				}
293
+				if (this.minutes >= 60) {
294
+					this.minutes = 0;
295
+					this.hour = Number(this.hour) + 1;
296
+				}
297
+				this.time = (this.hour < 10 ? '0' + this.hour : this.hour) + ':' + (this.minutes < 10 ? '0' + this
298
+					.minutes :
299
+					this.minutes) + ':' + (this.seconds < 10 ? '0' + this.seconds : this.seconds);
300
+			},
301
+			// ----------------------操作设备开启暂停结束
302
+			operate(type) {
303
+				// 强度编号
304
+				let	modeNum = Number(this.modeClass).toString(16) < 10 ? '0' + Number(this.modeClass).toString(16) :
305
+						Number(this.modeClass).toString(16)
306
+				// 设备模式编号
307
+				if (this.typeList[this.selectTypeIndex].detectors[this.selectDetectorsIndex].config.mode?.list||this.typeList[this.selectTypeIndex].detectors[this.selectDetectorsIndex].config.power?.list) {
308
+					modeNum = this.modeNum
309
+				}
310
+				console.log(modeNum);
311
+				// 蓝牙指令操作码
312
+				let code =
313
+					`AABB12343838373244363235444138${this.equipmentNum}03${type=='open'?this.START:this.PAUSE}${modeNum}0101`
314
+				// 判断是否是(中科)厂家的设备
315
+				if (this.TYPE_SN == 'ZK') {
316
+					code = `a9800100${this.equipmentNum}${modeNum}0101${type=='open'?this.START:this.PAUSE}3cc3`
317
+				}
318
+				if (!this.equipmentNum) {
319
+					uni.showToast({
320
+						title: '请选择探头',
321
+						icon: "none"
322
+					})
323
+					return
324
+				}
325
+				if (this.typeList[this.selectTypeIndex].detectors[this.selectDetectorsIndex].config.mode?.list||this.typeList[this.selectTypeIndex].detectors[this.selectDetectorsIndex].config.power?.list) {
326
+					if(this.selectModeIndexA==99){						
327
+					uni.showToast({
328
+						title: '请选择模式',
329
+						icon: "none"
330
+					})
331
+					return
332
+					}
333
+				}
334
+				// 操作 开始 暂停 结束
335
+				if (type == 'open') {
336
+					this.send(code, '启动成功')
337
+				} else if (type == 'pause') {
338
+					this.send(code, '暂停成功')
339
+				} else {
340
+					this.send(code, '结束操作')
341
+				}
342
+			},
343
+			// --------------减少强度
344
+			reduce() {
345
+				this.modeClass = this.modeClass - this.incrementClass
346
+				if (this.modeClass <= this.minClass) {
347
+					this.modeClass = this.minClass
348
+					return
349
+				}
350
+			},
351
+			//---------------增加强度
352
+			add() {
353
+				this.modeClass = Number(this.modeClass) + Number(this.incrementClass)
354
+				if (this.modeClass >= this.maxClass) {
355
+					this.modeClass = this.maxClass
356
+					return
357
+				}
358
+			},
359
+			// --------------排气
360
+			pqCLick() {
361
+				// 判断是否是排气指令(16)进制
362
+				this.send(this.PQCODE, '启动成功')
363
+			},
364
+			// -------------------发送数据
365
+			send(newMsg, title = '执行成功') {
366
+				console.log(newMsg);
367
+				this.CODE = newMsg
368
+				wx.showLoading({
369
+					title: '正在启动',
370
+					mask: true
371
+				})
372
+				// 向蓝牙设备发送一个0x00的16进制数据
373
+				let that = this
374
+				let buffer = new ArrayBuffer(Math.ceil(newMsg.length / 2))
375
+				let dataView = new DataView(buffer)
376
+				var index = 0
377
+				for (var i = 0; i < newMsg.length; i++) {
378
+					if (i % 2 < 1) {
379
+						dataView.setUint8(index, '0x' + newMsg.substr(i, 2))
380
+						index++
381
+					}
382
+				}
383
+				console.log(that.deviceId, that.serviceId, that.characteristicId);
384
+				// return
385
+				uni.writeBLECharacteristicValue({
386
+					deviceId: that.deviceId, // 设备ID
387
+					serviceId: that.serviceId, // 服务UUID
388
+					characteristicId: that.characteristicId, // 特征值
389
+					value: buffer,
390
+					success(res) {
391
+						if (newMsg != that.PQCODE || newMsg != that.PQCLOSECODE) {
392
+							uni.hideLoading()
393
+							uni.showToast({
394
+								title,
395
+								icon: 'none',
396
+							})
397
+						}
398
+						// ------排气指令
399
+						if (newMsg == that.PQCODE) {
400
+							uni.showLoading({
401
+								title: '正在排气',
402
+								mask: true
403
+							})
404
+							setTimeout(() => {
405
+								console.log(1);
406
+								that.send(that.PQCLOSECODE, '排气完成')
407
+							}, 2000)
408
+						}
409
+						// ------排气指令
410
+						if (newMsg == that.PQCLOSECODE) {
411
+							uni.hideLoading()
412
+							uni.showToast({
413
+								title: '排气完成',
414
+								icon: 'success'
415
+							})
416
+						}
417
+						// 开始计时
418
+						if (title == '启动成功') {
419
+							that.begin()
420
+							if (this.startTime == '') {
421
+								this.startTime = formatDate(new Date(), 'YYYY/MM/DD/hh/mm/ss')
422
+							}
423
+						} else if (title == '暂停成功' || title == '排气完成') {
424
+							that.pauseTime()
425
+						} else {
426
+							that.finishTime()
427
+						}
428
+						console.log(res,'发送数据成功')
429
+					},
430
+					fail(err) {
431
+						uni.hideLoading()
432
+						that.blueError(err.errCode)
433
+						console.error(err)
434
+					}
435
+				})
436
+			},
437
+		}
438
+	}
439
+</script>
440
+
441
+<style lang="less" scoped>
442
+	.top {
443
+		padding-left: 30px;
444
+
445
+		span {
446
+			font-size: 16px;
447
+		}
448
+
449
+		.title {
450
+			font-weight: 700;
451
+			margin-right: 40px;
452
+		}
453
+
454
+		.id {
455
+			margin-right: 20px;
456
+		}
457
+
458
+		.startTime {
459
+			margin: 0 20px;
460
+		}
461
+
462
+		.totalTime {
463
+			margin: 0 20px;
464
+		}
465
+	}
466
+
467
+	.type {
468
+		margin-left: 100px;
469
+		margin-top: 40px;
470
+		width: 85%;
471
+		.pattern{
472
+			display: flex;
473
+			overflow-x: scroll;
474
+			.facilityType{
475
+				margin-right: 80px;
476
+			}
477
+		}
478
+		.buttonOP {
479
+			display: flex;
480
+			.item{
481
+				padding-right: 20px;
482
+				padding-left:6px;
483
+				height: 100px;
484
+				background-color: #b8b8b8;
485
+				margin-right: 20px;
486
+				border-radius: 24px;
487
+				overflow: hidden;
488
+				display: flex;
489
+				justify-content: center;
490
+				align-items: center;
491
+				img{
492
+					width: 90px;
493
+					height: 90px;
494
+					border-radius: 24px;
495
+					margin-right: 20px;
496
+				}
497
+			}
498
+			button {
499
+				flex-shrink: 0;
500
+				margin: 0;
501
+				background-color: #b8b8b8;
502
+				color: #fff;
503
+				margin-right: 50px;
504
+			}
505
+
506
+			.selectType {
507
+				background-color: #1e98d7;
508
+			}
509
+			
510
+		}
511
+
512
+		.buttonOPO {
513
+			display: flex;
514
+			align-items: center;
515
+
516
+			button {
517
+				flex-shrink: 0;
518
+				margin: 0;
519
+				background-color: #f8c126;
520
+				color: #fff;
521
+			}
522
+
523
+			.strength {
524
+				width: 200px;
525
+				background-color: #b8b8b8;
526
+				padding: 14px;
527
+				text-align: center;
528
+				border-radius: 12px;
529
+				margin: 0 4px;
530
+			}
531
+		}
532
+
533
+		.facilityType {
534
+			p {
535
+				font-size: 18px;
536
+				margin-bottom: 30px;
537
+				margin-top: 30px;
538
+			}
539
+		}
540
+	}
541
+
542
+	.bottomBox {
543
+		width: 90%;
544
+		display: flex;
545
+		margin-top: 100px;
546
+		margin-left: 30px;
547
+		justify-content: space-between;
548
+
549
+		.back {
550
+			button {
551
+				background-color: #1e98d7;
552
+				color: #fff;
553
+			}
554
+		}
555
+
556
+		.bottomBox-right {
557
+			display: flex;
558
+
559
+			button {
560
+				margin-right: 20px;
561
+				width: 120px;
562
+				color: #fff;
563
+			}
564
+
565
+			.open {
566
+				background-color: #03bf16;
567
+			}
568
+
569
+			.pause {
570
+				background-color: #1e98d7;
571
+			}
572
+
573
+			.finish {
574
+				background-color: #d9001b;
575
+			}
576
+		}
577
+	}
578
+</style>

+ 396 - 0
pages/home/home.vue

@@ -0,0 +1,396 @@
1
+<template>
2
+	<view>
3
+		<h2 class='hTitle'>匹配蓝牙设备</h2>
4
+		<view class="bottomBox">
5
+			<button @click="refreshBlue" class="refreshBlueTooth">刷新蓝牙设备</button>
6
+			<view class="equipmentTitle">
7
+				设备名称
8
+			</view>
9
+			<!-- 连接蓝牙列表 -->
10
+			<view class="blueListBox">
11
+				<scroll-view scroll-y class="box">
12
+					<view class="item" v-for="item in blueDeviceList" @click="connect(item)">
13
+						<view>
14
+							<text>id: {{ item.deviceId }}</text>
15
+						</view>
16
+						<view>
17
+							<text>name: {{ item.name }}</text>
18
+						</view>
19
+					</view>
20
+				</scroll-view>
21
+			</view>
22
+			<view class="equipmentTitle">
23
+				已配对的设备
24
+			</view>
25
+			<view class="alreadyBlue">
26
+				{{deviceId}}
27
+			</view>
28
+			<view class="bottom-btn">
29
+				<button :loading='characteristicId==""' @click="confirmEdit" class="refreshBlueToothNot"
30
+					:class="{refreshBlueTooth:characteristicId?true:false}">{{characteristicId?'确定编辑设备':'获取服务中'}}</button>
31
+			</view>
32
+		</view>
33
+	</view>
34
+</template>
35
+
36
+<script>
37
+	export default {
38
+		data() {
39
+			return {
40
+				blueDeviceList: [], //蓝牙设备
41
+				deviceId: '', //蓝牙设备ID
42
+				serviceId: '', //服务UUID
43
+				characteristicId: '', //特征值
44
+			};
45
+		},
46
+		created() {
47
+			// 初始化蓝牙
48
+			this.openBlue()
49
+			// 获取蓝牙监听
50
+			this.stateChange()
51
+		},
52
+		methods: {
53
+			// 蓝牙报错提示
54
+			blueError(code) {
55
+				switch (code) {
56
+					case 10000:
57
+						this.errorToast('未初始化蓝牙适配器')
58
+						break
59
+					case 10001:
60
+						this.errorToast('当前蓝牙适配器不可用')
61
+						break
62
+					case 10002:
63
+						this.errorToast('没有找到指定设备')
64
+						break
65
+					case 10003:
66
+						this.errorToast('连接失败')
67
+						break
68
+					case 10004:
69
+						this.errorToast('没有找到指定服务')
70
+						break
71
+					case 10005:
72
+						this.errorToast('没有找到指定特征值')
73
+						break
74
+					case 10006:
75
+						this.errorToast('当前连接已断开')
76
+						break
77
+					case 10007:
78
+						this.errorToast('当前特征值不支持此操作')
79
+						break
80
+					case 10008:
81
+						this.errorToast('其余所有系统上报的异常')
82
+						break
83
+					case 10009:
84
+						this.errorToast('Android 系统特有,系统版本低于 4.3 不支持 BLE')
85
+						break
86
+					case 100010:
87
+						this.errorToast('已连接')
88
+						break
89
+					case 100011:
90
+						this.errorToast('配对设备需要配对码')
91
+						break
92
+					case 100012:
93
+						this.errorToast('连接超时')
94
+						break
95
+					case 100013:
96
+						this.errorToast('连接 deviceld 为空或者是格式不正确')
97
+						break
98
+				}
99
+			},
100
+			// 统一错误封装
101
+			errorToast(err) {
102
+				uni.showToast({
103
+					title: `${err}`,
104
+					icon: 'none',
105
+					duration: 2500
106
+				})
107
+			},
108
+			// 刷新蓝牙设备列表
109
+			refreshBlue() {
110
+				uni.showLoading({
111
+					title: '正在刷新',
112
+					mask: true
113
+				})
114
+				this.discovery('refresh')
115
+			},
116
+			// 确定编辑
117
+			confirmEdit() {
118
+				if (!this.characteristicId) {
119
+					return
120
+				}
121
+				uni.navigateTo({
122
+					url: `/pages/edit/edit?deviceId=${this.deviceId}&serviceId=${this.serviceId}&characteristicId=${this.characteristicId}`
123
+				})
124
+			},
125
+			// 初始化蓝牙
126
+			openBlue() {
127
+				let that = this
128
+				uni.showLoading({
129
+					title: '初始化中',
130
+					mask: true
131
+				})
132
+				uni.openBluetoothAdapter({
133
+					success(res) {
134
+						uni.hideLoading()
135
+						uni.showToast({
136
+							title: '初始化成功',
137
+							duration: 2500
138
+						})
139
+						that.discovery()
140
+					},
141
+					fail(err) {
142
+						uni.hideLoading()
143
+						that.blueError(err.errCode)
144
+						console.log('初始化蓝牙失败')
145
+						console.error(err)
146
+					}
147
+				})
148
+			},
149
+			// 搜索蓝牙设备
150
+			discovery(msg) {
151
+				let that = this
152
+				that.blueDeviceList = []
153
+				uni.startBluetoothDevicesDiscovery({
154
+					success(res) {
155
+						if (msg = 'refresh') {
156
+							uni.hideLoading()
157
+						}
158
+						// 开启监听回调
159
+						uni.onBluetoothDeviceFound((res) => {
160
+							if (res.devices[0].name) {
161
+								that.found(res)
162
+							}
163
+						})
164
+					},
165
+					fail(err) {
166
+						console.log('搜索失败')
167
+						console.error(err)
168
+					}
169
+				})
170
+			},
171
+			// 找到新设备就触发该方法
172
+			found(res) {
173
+				if (res.devices[0].name.includes('BT24')) {
174
+					this.blueDeviceList.push(res.devices[0])
175
+				}
176
+				// 检查本地是否有id
177
+				let deviceId = uni.getStorageSync('deviceId')
178
+				if(deviceId){
179
+					// 重置deviceId
180
+					this.deviceId = ''
181
+					let data = {
182
+						deviceId
183
+					}
184
+					this.connect(data)   
185
+				}
186
+			},
187
+			//监听蓝牙状态
188
+			stateChange() {
189
+				uni.onBLEConnectionStateChange(function(res) {
190
+					// 该方法回调中可以用于处理连接意外断开等异常情况
191
+					console.log(`device ${res.deviceId} state has changed, connected: ${res.connected}`,
192
+						'监听到蓝牙设备变化')
193
+					if (!res.connected) {
194
+						console.log(111111, '断开重连操作');
195
+						let data = {
196
+							deviceId: this.deviceId
197
+						}
198
+						// 重置deviceId
199
+						this.deviceId = ''
200
+						this.connect(data)
201
+					}
202
+				})
203
+			},
204
+			// 断开蓝牙设备
205
+			closeBLEConnection(deviceId) {
206
+				console.log(deviceId, '断开蓝牙设备ID');
207
+				uni.closeBLEConnection({
208
+					deviceId,
209
+					success(res) {
210
+						console.log('断开蓝牙成功', res)
211
+					},
212
+					fail(err) {
213
+						console.log('断开蓝牙失败', err);
214
+					}
215
+				})
216
+			},
217
+			// 连接设备
218
+			connect(data) {
219
+				// 判断是否是连接当前的蓝牙
220
+				if (data.deviceId == this.deviceId) {
221
+					uni.showToast({
222
+						title: '您已经连接该蓝牙',
223
+						duration: 2500,
224
+						icon: 'none'
225
+					})
226
+					return
227
+				} else if (this.deviceId) {
228
+					this.closeBLEConnection(this.deviceId)
229
+				}
230
+				wx.showLoading({
231
+					title: '正在连接',
232
+					mask: true
233
+				})
234
+				let that = this
235
+				that.deviceId = data.deviceId
236
+				uni.createBLEConnection({
237
+					deviceId: that.deviceId,
238
+					timeout: 30000,
239
+					success(res) {
240
+						wx.hideLoading()
241
+						uni.showToast({
242
+							title: '连接成功',
243
+							duration: 2500
244
+						})
245
+						console.log('连接成功');
246
+						// 把deviceId保存到本地
247
+						uni.setStorageSync('deviceId', that.deviceId);
248
+						// 停止搜索
249
+						that.stopDiscovery()
250
+						//获取蓝牙服务
251
+						setTimeout(() => {
252
+							//需要延迟获取
253
+							that.getLyService(that.deviceId)
254
+						}, 1000)
255
+					},
256
+					fail(err) {
257
+						wx.hideLoading()
258
+						switch (err.errMsg) {
259
+							default:
260
+								that.blueError(err.errCode)
261
+						}
262
+						console.log('连接失败')
263
+						console.error(err)
264
+					}
265
+				})
266
+			},
267
+			// 停止搜索
268
+			stopDiscovery() {
269
+				uni.stopBluetoothDevicesDiscovery({
270
+					success(res) {
271
+						console.log('停止成功')
272
+						console.log(res)
273
+					},
274
+					fail(err) {
275
+						console.log('停止失败')
276
+						console.error(err)
277
+					}
278
+				})
279
+			},
280
+			//获取蓝牙可用服务
281
+			getLyService(deviceId) {
282
+				uni.getBLEDeviceServices({
283
+					deviceId: deviceId,
284
+					success: async (res) => {
285
+						console.log('蓝牙服务', JSON.stringify(res))
286
+						if (res.services.length < 1) {
287
+							setTimeout(() => {
288
+								this.getLyService(deviceId)
289
+							}, 1000)
290
+							return;
291
+						}
292
+						for (var i = 0; i < res.services.length; i++) {
293
+							//获取蓝牙特征值
294
+							var characteristic = await this.getLyCharacteristic(deviceId, res.services[i].uuid)
295
+							if (!characteristic) continue;
296
+							this.serviceId = res.services[i].uuid
297
+							this.characteristicId = characteristic
298
+							console.log('ok:', this.serviceId + ',' + this.characteristicId)
299
+							this.notifyLy();
300
+							break;
301
+						}
302
+					},
303
+					fail: (err) => {
304
+						console.error(JSON.stringify(err))
305
+					}
306
+				})
307
+			},
308
+			//获取蓝牙可用特征值
309
+			getLyCharacteristic(deviceId, serviceId) {
310
+				return new Promise((resolve, reject) => {
311
+					uni.getBLEDeviceCharacteristics({
312
+						deviceId: deviceId,
313
+						serviceId: serviceId,
314
+						success: (res) => {
315
+							var result = '';
316
+							for (var i = 0; i < res.characteristics.length; i++) {
317
+								var properties = res.characteristics[i].properties;
318
+								if (properties.read && properties.write && properties.notify) {
319
+									console.log('可用特征值', JSON.stringify(res.characteristics[i].uuid))
320
+									result = res.characteristics[i].uuid;
321
+									break;
322
+								}
323
+							}
324
+							resolve(result)
325
+						},
326
+						fail: (err) => {
327
+							console.log('特征值', JSON.stringify(err))
328
+							reject('')
329
+						}
330
+					})
331
+				})
332
+			},
333
+		}
334
+	}
335
+</script>
336
+
337
+<style lang="less" scoped>
338
+	.hTitle {
339
+		margin-left: 10px;
340
+	}
341
+
342
+	.bottomBox {
343
+		margin-left: 40px;
344
+		margin-top: 50px;
345
+
346
+		// 蓝牙按钮
347
+		.refreshBlueTooth {
348
+			width: 140px;
349
+			background-color: #1e98d7;
350
+			color: #fff;
351
+			margin: 0;
352
+		}
353
+
354
+		.refreshBlueToothNot {
355
+			width: 140px;
356
+			margin: 0;
357
+		}
358
+
359
+		.equipmentTitle {
360
+			font-size: 18px;
361
+			margin-top: 20px;
362
+		}
363
+
364
+		.blueListBox {
365
+			margin-top: 20px;
366
+			width: 90%;
367
+			height: 300px;
368
+			border: 1px solid #1e98d7;
369
+			border-radius: 12px;
370
+			padding: 8px;
371
+			background-color: #eee;
372
+
373
+			.box {
374
+				margin-bottom: 20px;
375
+				height: 100%;
376
+				width: 100%;
377
+			}
378
+
379
+			.item:nth-child(2n) {
380
+				background-color: aqua;
381
+			}
382
+		}
383
+
384
+		.alreadyBlue {
385
+			margin-top: 16px;
386
+			font-size: 16px;
387
+		}
388
+
389
+		.bottom-btn {
390
+			width: 90%;
391
+			margin-top: 20px;
392
+			display: flex;
393
+			justify-content: flex-end;
394
+		}
395
+	}
396
+</style>

+ 20 - 0
static/customicons.css

@@ -0,0 +1,20 @@
1
+@font-face {
2
+  font-family: "customicons"; /* Project id 2878519 */
3
+  src:url('/static/customicons.ttf') format('truetype');
4
+}
5
+
6
+.customicons {
7
+  font-family: "customicons" !important;
8
+}
9
+
10
+.youxi:before {
11
+  content: "\e60e";
12
+}
13
+
14
+.wenjian:before {
15
+  content: "\e60f";
16
+}
17
+
18
+.zhuanfa:before {
19
+  content: "\e610";
20
+}

二进制
static/customicons.ttf


二进制
static/logo.png


二进制
static/uni.png


+ 5 - 0
uni.scss

@@ -0,0 +1,5 @@
1
+@import '@/uni_modules/uni-scss/variables.scss';
2
+*{
3
+	margin: 0;
4
+	padding: 0;
5
+}

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

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

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

@@ -0,0 +1,268 @@
1
+<template>
2
+	<view class="uni-badge--x">
3
+		<slot />
4
+		<text v-if="text" :class="classNames" :style="[positionStyle, customStyle, dotStyle]"
5
+			class="uni-badge" @click="onClick()">{{displayValue}}</text>
6
+	</view>
7
+</template>
8
+
9
+<script>
10
+	/**
11
+	 * Badge 数字角标
12
+	 * @description 数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景
13
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=21
14
+	 * @property {String} text 角标内容
15
+	 * @property {String} size = [normal|small] 角标内容
16
+	 * @property {String} type = [info|primary|success|warning|error] 颜色类型
17
+	 * 	@value info 灰色
18
+	 * 	@value primary 蓝色
19
+	 * 	@value success 绿色
20
+	 * 	@value warning 黄色
21
+	 * 	@value error 红色
22
+	 * @property {String} inverted = [true|false] 是否无需背景颜色
23
+	 * @property {Number} maxNum 展示封顶的数字值,超过 99 显示 99+
24
+	 * @property {String} absolute = [rightTop|rightBottom|leftBottom|leftTop] 开启绝对定位, 角标将定位到其包裹的标签的四角上		
25
+	 * 	@value rightTop 右上
26
+	 * 	@value rightBottom 右下
27
+	 * 	@value leftTop 左上
28
+	 * 	@value leftBottom 左下
29
+	 * @property {Array[number]} offset	距定位角中心点的偏移量,只有存在 absolute 属性时有效,例如:[-10, -10] 表示向外偏移 10px,[10, 10] 表示向 absolute 指定的内偏移 10px
30
+	 * @property {String} isDot = [true|false] 是否显示为一个小点
31
+	 * @event {Function} click 点击 Badge 触发事件
32
+	 * @example <uni-badge text="1"></uni-badge>
33
+	 */
34
+
35
+	export default {
36
+		name: 'UniBadge',
37
+		emits: ['click'],
38
+		props: {
39
+			type: {
40
+				type: String,
41
+				default: 'error'
42
+			},
43
+			inverted: {
44
+				type: Boolean,
45
+				default: false
46
+			},
47
+			isDot: {
48
+				type: Boolean,
49
+				default: false
50
+			},
51
+			maxNum: {
52
+				type: Number,
53
+				default: 99
54
+			},
55
+			absolute: {
56
+				type: String,
57
+				default: ''
58
+			},
59
+			offset: {
60
+				type: Array,
61
+				default () {
62
+					return [0, 0]
63
+				}
64
+			},
65
+			text: {
66
+				type: [String, Number],
67
+				default: ''
68
+			},
69
+			size: {
70
+				type: String,
71
+				default: 'small'
72
+			},
73
+			customStyle: {
74
+				type: Object,
75
+				default () {
76
+					return {}
77
+				}
78
+			}
79
+		},
80
+		data() {
81
+			return {};
82
+		},
83
+		computed: {
84
+			width() {
85
+				return String(this.text).length * 8 + 12
86
+			},
87
+			classNames() {
88
+				const {
89
+					inverted,
90
+					type,
91
+					size,
92
+					absolute
93
+				} = this
94
+				return [
95
+					inverted ? 'uni-badge--' + type + '-inverted' : '',
96
+					'uni-badge--' + type,
97
+					'uni-badge--' + size,
98
+					absolute ? 'uni-badge--absolute' : ''
99
+				].join(' ')
100
+			},
101
+			positionStyle() {
102
+				if (!this.absolute) return {}
103
+				let w = this.width / 2,
104
+					h = 10
105
+				if (this.isDot) {
106
+					w = 5
107
+					h = 5
108
+				}
109
+				const x = `${- w  + this.offset[0]}px`
110
+				const y = `${- h + this.offset[1]}px`
111
+
112
+				const whiteList = {
113
+					rightTop: {
114
+						right: x,
115
+						top: y
116
+					},
117
+					rightBottom: {
118
+						right: x,
119
+						bottom: y
120
+					},
121
+					leftBottom: {
122
+						left: x,
123
+						bottom: y
124
+					},
125
+					leftTop: {
126
+						left: x,
127
+						top: y
128
+					}
129
+				}
130
+				const match = whiteList[this.absolute]
131
+				return match ? match : whiteList['rightTop']
132
+			},
133
+			dotStyle() {
134
+				if (!this.isDot) return {}
135
+				return {
136
+					width: '10px',
137
+					minWidth: '0',
138
+					height: '10px',
139
+					padding: '0',
140
+					borderRadius: '10px'
141
+				}
142
+			},
143
+			displayValue() {
144
+				const {
145
+					isDot,
146
+					text,
147
+					maxNum
148
+				} = this
149
+				return isDot ? '' : (Number(text) > maxNum ? `${maxNum}+` : text)
150
+			}
151
+		},
152
+		methods: {
153
+			onClick() {
154
+				this.$emit('click');
155
+			}
156
+		}
157
+	};
158
+</script>
159
+
160
+<style lang="scss" >
161
+	$uni-primary: #2979ff !default;
162
+	$uni-success: #4cd964 !default;
163
+	$uni-warning: #f0ad4e !default;
164
+	$uni-error: #dd524d !default;
165
+	$uni-info: #909399 !default;
166
+
167
+
168
+	$bage-size: 12px;
169
+	$bage-small: scale(0.8);
170
+
171
+	.uni-badge--x {
172
+		/* #ifdef APP-NVUE */
173
+		// align-self: flex-start;
174
+		/* #endif */
175
+		/* #ifndef APP-NVUE */
176
+		display: inline-block;
177
+		/* #endif */
178
+		position: relative;
179
+	}
180
+
181
+	.uni-badge--absolute {
182
+		position: absolute;
183
+	}
184
+
185
+	.uni-badge--small {
186
+		transform: $bage-small;
187
+		transform-origin: center center;
188
+	}
189
+
190
+	.uni-badge {
191
+		/* #ifndef APP-NVUE */
192
+		display: flex;
193
+		overflow: hidden;
194
+		box-sizing: border-box;
195
+		/* #endif */
196
+		justify-content: center;
197
+		flex-direction: row;
198
+		height: 20px;
199
+		min-width: 20px;
200
+		padding: 0 4px;
201
+		line-height: 18px;
202
+		color: #fff;
203
+		border-radius: 100px;
204
+		background-color: $uni-info;
205
+		background-color: transparent;
206
+		border: 1px solid #fff;
207
+		text-align: center;
208
+		font-family: 'Helvetica Neue', Helvetica, sans-serif;
209
+		font-feature-settings: "tnum";
210
+		font-size: $bage-size;
211
+		/* #ifdef H5 */
212
+		z-index: 999;
213
+		cursor: pointer;
214
+		/* #endif */
215
+
216
+		&--info {
217
+			color: #fff;
218
+			background-color: $uni-info;
219
+		}
220
+
221
+		&--primary {
222
+			background-color: $uni-primary;
223
+		}
224
+
225
+		&--success {
226
+			background-color: $uni-success;
227
+		}
228
+
229
+		&--warning {
230
+			background-color: $uni-warning;
231
+		}
232
+
233
+		&--error {
234
+			background-color: $uni-error;
235
+		}
236
+
237
+		&--inverted {
238
+			padding: 0 5px 0 0;
239
+			color: $uni-info;
240
+		}
241
+
242
+		&--info-inverted {
243
+			color: $uni-info;
244
+			background-color: transparent;
245
+		}
246
+
247
+		&--primary-inverted {
248
+			color: $uni-primary;
249
+			background-color: transparent;
250
+		}
251
+
252
+		&--success-inverted {
253
+			color: $uni-success;
254
+			background-color: transparent;
255
+		}
256
+
257
+		&--warning-inverted {
258
+			color: $uni-warning;
259
+			background-color: transparent;
260
+		}
261
+
262
+		&--error-inverted {
263
+			color: $uni-error;
264
+			background-color: transparent;
265
+		}
266
+
267
+	}
268
+</style>

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

@@ -0,0 +1,85 @@
1
+{
2
+  "id": "uni-badge",
3
+  "displayName": "uni-badge 数字角标",
4
+  "version": "1.2.1",
5
+  "description": "数字角标(徽章)组件,在元素周围展示消息提醒,一般用于列表、九宫格、按钮等地方。",
6
+  "keywords": [
7
+    "",
8
+    "badge",
9
+    "uni-ui",
10
+    "uniui",
11
+    "数字角标",
12
+    "徽章"
13
+],
14
+  "repository": "https://github.com/dcloudio/uni-ui",
15
+  "engines": {
16
+    "HBuilderX": ""
17
+  },
18
+  "directories": {
19
+    "example": "../../temps/example_temps"
20
+  },
21
+"dcloudext": {
22
+    "sale": {
23
+      "regular": {
24
+        "price": "0.00"
25
+      },
26
+      "sourcecode": {
27
+        "price": "0.00"
28
+      }
29
+    },
30
+    "contact": {
31
+      "qq": ""
32
+    },
33
+    "declaration": {
34
+      "ads": "无",
35
+      "data": "无",
36
+      "permissions": "无"
37
+    },
38
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
39
+    "type": "component-vue"
40
+  },
41
+  "uni_modules": {
42
+    "dependencies": ["uni-scss"],
43
+    "encrypt": [],
44
+    "platforms": {
45
+      "cloud": {
46
+        "tcb": "y",
47
+        "aliyun": "y"
48
+      },
49
+      "client": {
50
+        "App": {
51
+          "app-vue": "y",
52
+          "app-nvue": "y"
53
+        },
54
+        "H5-mobile": {
55
+          "Safari": "y",
56
+          "Android Browser": "y",
57
+          "微信浏览器(Android)": "y",
58
+          "QQ浏览器(Android)": "y"
59
+        },
60
+        "H5-pc": {
61
+          "Chrome": "y",
62
+          "IE": "y",
63
+          "Edge": "y",
64
+          "Firefox": "y",
65
+          "Safari": "y"
66
+        },
67
+        "小程序": {
68
+          "微信": "y",
69
+          "阿里": "y",
70
+          "百度": "y",
71
+          "字节跳动": "y",
72
+          "QQ": "y"
73
+        },
74
+        "快应用": {
75
+          "华为": "y",
76
+          "联盟": "y"
77
+        },
78
+        "Vue": {
79
+            "vue2": "y",
80
+            "vue3": "y"
81
+        }
82
+      }
83
+    }
84
+  }
85
+}

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

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

+ 6 - 0
uni_modules/uni-breadcrumb/changelog.md

@@ -0,0 +1,6 @@
1
+## 0.1.2(2022-06-08)
2
+- 修复 微信小程序 separator 不显示问题
3
+## 0.1.1(2022-06-02)
4
+- 新增 支持 uni.scss 修改颜色
5
+## 0.1.0(2022-04-21)
6
+- 初始化

+ 121 - 0
uni_modules/uni-breadcrumb/components/uni-breadcrumb-item/uni-breadcrumb-item.vue

@@ -0,0 +1,121 @@
1
+<template>
2
+	<view class="uni-breadcrumb-item">
3
+		<view :class="{
4
+			'uni-breadcrumb-item--slot': true,
5
+			'uni-breadcrumb-item--slot-link': to && currentPage !== to
6
+			}" @click="navTo">
7
+			<slot />
8
+		</view>
9
+		<i v-if="separatorClass" class="uni-breadcrumb-item--separator" :class="separatorClass" />
10
+		<text v-else class="uni-breadcrumb-item--separator">{{ separator }}</text>
11
+	</view>
12
+</template>
13
+<script>
14
+	/**
15
+	 * BreadcrumbItem 面包屑导航子组件
16
+	 * @property {String/Object} to 路由跳转页面路径/对象
17
+	 * @property {Boolean} replace 在使用 to 进行路由跳转时,启用 replace 将不会向 history 添加新记录(仅 h5 支持)
18
+	 */
19
+	export default {
20
+		data() {
21
+			return {
22
+				currentPage: ""
23
+			}
24
+		},
25
+		options: {
26
+			virtualHost: true
27
+		},
28
+		props: {
29
+			to: {
30
+				type: String,
31
+				default: ''
32
+			},
33
+			replace:{
34
+				type: Boolean,
35
+				default: false
36
+			}
37
+		},
38
+		inject: {
39
+			uniBreadcrumb: {
40
+				from: "uniBreadcrumb",
41
+				default: null
42
+			}
43
+		},
44
+		created(){
45
+			const pages = getCurrentPages()
46
+			const page = pages[pages.length-1]
47
+
48
+			if(page){
49
+				this.currentPage = `/${page.route}`
50
+			}
51
+		},
52
+		computed: {
53
+			separator() {
54
+				return this.uniBreadcrumb.separator
55
+			},
56
+			separatorClass() {
57
+				return this.uniBreadcrumb.separatorClass
58
+			}
59
+		},
60
+		methods: {
61
+			navTo() {
62
+				const { to } = this
63
+
64
+				if (!to || this.currentPage === to){
65
+					return
66
+				}
67
+
68
+				if(this.replace){
69
+					uni.redirectTo({
70
+						url:to
71
+					})
72
+				}else{
73
+					uni.navigateTo({
74
+						url:to
75
+					})
76
+				}
77
+			}
78
+		}
79
+	}
80
+</script>
81
+<style lang="scss">
82
+	$uni-primary: #2979ff !default;
83
+	$uni-base-color: #6a6a6a !default;
84
+	$uni-main-color: #3a3a3a !default;
85
+	.uni-breadcrumb-item {
86
+		display: flex;
87
+		align-items: center;
88
+		white-space: nowrap;
89
+		font-size: 14px;
90
+
91
+		&--slot {
92
+			color: $uni-base-color;
93
+			padding: 0 10px;
94
+
95
+			&-link {
96
+				color: $uni-main-color;
97
+				font-weight: bold;
98
+				/* #ifndef APP-NVUE */
99
+				cursor: pointer;
100
+				/* #endif */
101
+
102
+				&:hover {
103
+					color: $uni-primary;
104
+				}
105
+			}
106
+		}
107
+
108
+		&--separator {
109
+			font-size: 12px;
110
+			color: $uni-base-color;
111
+		}
112
+
113
+		&:first-child &--slot {
114
+			padding-left: 0;
115
+		}
116
+		
117
+		&:last-child &--separator {
118
+			display: none;
119
+		}
120
+	}
121
+</style>

+ 41 - 0
uni_modules/uni-breadcrumb/components/uni-breadcrumb/uni-breadcrumb.vue

@@ -0,0 +1,41 @@
1
+<template>
2
+	<view class="uni-breadcrumb">
3
+		<slot />
4
+	</view>
5
+</template>
6
+<script>
7
+	/**
8
+	 * Breadcrumb 面包屑导航父组件
9
+	 * @description 显示当前页面的路径,快速返回之前的任意页面
10
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
11
+	 * @property {String} separator 分隔符,默认为斜杠'/'
12
+	 * @property {String} separatorClass 图标分隔符 class
13
+	 */
14
+	export default {
15
+		options: {
16
+			virtualHost: true
17
+		},
18
+		props: {
19
+			separator: {
20
+				type: String,
21
+				default: '/'
22
+			},
23
+			separatorClass: {
24
+				type: String,
25
+				default: ''
26
+			}
27
+		},
28
+
29
+		provide() {
30
+			return {
31
+				uniBreadcrumb: this
32
+			}
33
+		}
34
+
35
+	}
36
+</script>
37
+<style lang="scss">
38
+	.uni-breadcrumb {
39
+		display: flex;
40
+	}
41
+</style>

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

@@ -0,0 +1,88 @@
1
+{
2
+  "id": "uni-breadcrumb",
3
+  "displayName": "uni-breadcrumb 面包屑",
4
+  "version": "0.1.2",
5
+  "description": "Breadcrumb  面包屑",
6
+  "keywords": [
7
+    "uni-breadcrumb",
8
+    "breadcrumb",
9
+    "uni-ui",
10
+    "面包屑导航",
11
+    "面包屑"
12
+],
13
+  "repository": "",
14
+  "engines": {
15
+    "HBuilderX": "^3.1.0"
16
+  },
17
+  "directories": {
18
+    "example": "../../temps/example_temps"
19
+  },
20
+  "dcloudext": {
21
+    "category": [
22
+        "前端组件",
23
+        "通用组件"
24
+    ],
25
+    "sale": {
26
+      "regular": {
27
+        "price": "0.00"
28
+      },
29
+      "sourcecode": {
30
+        "price": "0.00"
31
+      }
32
+    },
33
+    "contact": {
34
+      "qq": ""
35
+    },
36
+    "declaration": {
37
+      "ads": "无",
38
+      "data": "无",
39
+      "permissions": "无"
40
+    },
41
+    "npmurl": ""
42
+  },
43
+  "uni_modules": {
44
+    "dependencies": [],
45
+    "encrypt": [],
46
+    "platforms": {
47
+      "cloud": {
48
+        "tcb": "y",
49
+        "aliyun": "y"
50
+      },
51
+      "client": {
52
+        "Vue": {
53
+          "vue2": "y",
54
+          "vue3": "y"
55
+        },
56
+        "App": {
57
+          "app-vue": "y",
58
+          "app-nvue": "n"
59
+        },
60
+        "H5-mobile": {
61
+          "Safari": "y",
62
+          "Android Browser": "y",
63
+          "微信浏览器(Android)": "y",
64
+          "QQ浏览器(Android)": "y"
65
+        },
66
+        "H5-pc": {
67
+          "Chrome": "y",
68
+          "IE": "y",
69
+          "Edge": "y",
70
+          "Firefox": "y",
71
+          "Safari": "y"
72
+        },
73
+        "小程序": {
74
+          "微信": "y",
75
+          "阿里": "u",
76
+          "百度": "u",
77
+          "字节跳动": "u",
78
+        "QQ": "u",
79
+        "京东": "u"
80
+        },
81
+        "快应用": {
82
+          "华为": "u",
83
+          "联盟": "u"
84
+        }
85
+      }
86
+    }
87
+  }
88
+}

+ 66 - 0
uni_modules/uni-breadcrumb/readme.md

@@ -0,0 +1,66 @@
1
+
2
+## breadcrumb 面包屑导航
3
+> **组件名:uni-breadcrumb**
4
+> 代码块: `ubreadcrumb`
5
+
6
+显示当前页面的路径,快速返回之前的任意页面。
7
+
8
+### 安装方式
9
+
10
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
11
+
12
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
13
+
14
+### 基本用法
15
+
16
+在 ``template`` 中使用组件
17
+
18
+```html
19
+<uni-breadcrumb separator="/">
20
+	<uni-breadcrumb-item v-for="(route,index) in routes" :key="index" :to="route.to">{{route.name}}</uni-breadcrumb-item>
21
+</uni-breadcrumb>
22
+```
23
+
24
+```js
25
+export default {
26
+		name: "uni-stat-breadcrumb",
27
+		data() {
28
+			return {
29
+				routes: [{
30
+					to: '/A',
31
+					name: 'A页面'
32
+				}, {
33
+					to: '/B',
34
+					name: 'B页面'
35
+				}, {
36
+					to: '/C',
37
+					name: 'C页面'
38
+				}]
39
+			};
40
+		}
41
+	}
42
+```
43
+
44
+
45
+## API
46
+
47
+### Breadcrumb Props
48
+
49
+|属性名			|类型	|默认值	|说明				|
50
+|:-:			|:-:	|:-:	|:-:				|
51
+|separator		|String	|斜杠'/' |分隔符				|
52
+|separatorClass	|String	|		|图标分隔符 class	    |
53
+
54
+### Breadcrumb Item Props
55
+
56
+|属性名	|类型			|默认值	|说明																			|
57
+|:-:	|:-:			|:-:	|:-:																			|
58
+|to		|String     	|		|路由跳转页面路径           														|
59
+|replace|Boolean		|		|在使用 to 进行路由跳转时,启用 replace 将不会向 history 添加新记录(仅 h5 支持)         |
60
+
61
+
62
+
63
+
64
+## 组件示例
65
+
66
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/breadcrumb/breadcrumb](https://hellouniapp.dcloud.net.cn/pages/extUI/breadcrumb/breadcrumb)

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

@@ -0,0 +1,20 @@
1
+## 1.4.7(2022-09-16)
2
+- 可以使用 uni-scss 控制主题色
3
+## 1.4.6(2022-09-08)
4
+- fix: 表头年月切换,导致改变当前日期为选择月1号,且未触发change事件
5
+## 1.4.5(2022-02-25)
6
+- 修复 条件编译 nvue 不支持的 css 样式
7
+## 1.4.4(2022-02-25)
8
+- 修复 条件编译 nvue 不支持的 css 样式
9
+## 1.4.3(2021-09-22)
10
+- 修复 startDate、 endDate 属性失效的 bug
11
+## 1.4.2(2021-08-24)
12
+- 新增 支持国际化
13
+## 1.4.1(2021-08-05)
14
+- 修复 弹出层被 tabbar 遮盖 bug
15
+## 1.4.0(2021-07-30)
16
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
17
+## 1.3.16(2021-05-12)
18
+- 新增 组件示例地址
19
+## 1.3.15(2021-02-04)
20
+- 调整为uni_modules目录规范 

+ 546 - 0
uni_modules/uni-calendar/components/uni-calendar/calendar.js

@@ -0,0 +1,546 @@
1
+/**
2
+* @1900-2100区间内的公历、农历互转
3
+* @charset UTF-8
4
+* @github  https://github.com/jjonline/calendar.js
5
+* @Author  Jea杨(JJonline@JJonline.Cn)
6
+* @Time    2014-7-21
7
+* @Time    2016-8-13 Fixed 2033hex、Attribution Annals
8
+* @Time    2016-9-25 Fixed lunar LeapMonth Param Bug
9
+* @Time    2017-7-24 Fixed use getTerm Func Param Error.use solar year,NOT lunar year
10
+* @Version 1.0.3
11
+* @公历转农历:calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0]
12
+* @农历转公历:calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0]
13
+*/
14
+/* eslint-disable */
15
+var calendar = {
16
+
17
+  /**
18
+      * 农历1900-2100的润大小信息表
19
+      * @Array Of Property
20
+      * @return Hex
21
+      */
22
+  lunarInfo: [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900-1909
23
+    0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919
24
+    0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929
25
+    0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939
26
+    0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949
27
+    0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959
28
+    0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969
29
+    0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, // 1970-1979
30
+    0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989
31
+    0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999
32
+    0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009
33
+    0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019
34
+    0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029
35
+    0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039
36
+    0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049
37
+    /** Add By JJonline@JJonline.Cn**/
38
+    0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059
39
+    0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069
40
+    0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079
41
+    0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089
42
+    0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099
43
+    0x0d520], // 2100
44
+
45
+  /**
46
+      * 公历每个月份的天数普通表
47
+      * @Array Of Property
48
+      * @return Number
49
+      */
50
+  solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
51
+
52
+  /**
53
+      * 天干地支之天干速查表
54
+      * @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
55
+      * @return Cn string
56
+      */
57
+  Gan: ['\u7532', '\u4e59', '\u4e19', '\u4e01', '\u620a', '\u5df1', '\u5e9a', '\u8f9b', '\u58ec', '\u7678'],
58
+
59
+  /**
60
+      * 天干地支之地支速查表
61
+      * @Array Of Property
62
+      * @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
63
+      * @return Cn string
64
+      */
65
+  Zhi: ['\u5b50', '\u4e11', '\u5bc5', '\u536f', '\u8fb0', '\u5df3', '\u5348', '\u672a', '\u7533', '\u9149', '\u620c', '\u4ea5'],
66
+
67
+  /**
68
+      * 天干地支之地支速查表<=>生肖
69
+      * @Array Of Property
70
+      * @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"]
71
+      * @return Cn string
72
+      */
73
+  Animals: ['\u9f20', '\u725b', '\u864e', '\u5154', '\u9f99', '\u86c7', '\u9a6c', '\u7f8a', '\u7334', '\u9e21', '\u72d7', '\u732a'],
74
+
75
+  /**
76
+      * 24节气速查表
77
+      * @Array Of Property
78
+      * @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"]
79
+      * @return Cn string
80
+      */
81
+  solarTerm: ['\u5c0f\u5bd2', '\u5927\u5bd2', '\u7acb\u6625', '\u96e8\u6c34', '\u60ca\u86f0', '\u6625\u5206', '\u6e05\u660e', '\u8c37\u96e8', '\u7acb\u590f', '\u5c0f\u6ee1', '\u8292\u79cd', '\u590f\u81f3', '\u5c0f\u6691', '\u5927\u6691', '\u7acb\u79cb', '\u5904\u6691', '\u767d\u9732', '\u79cb\u5206', '\u5bd2\u9732', '\u971c\u964d', '\u7acb\u51ac', '\u5c0f\u96ea', '\u5927\u96ea', '\u51ac\u81f3'],
82
+
83
+  /**
84
+      * 1900-2100各年的24节气日期速查表
85
+      * @Array Of Property
86
+      * @return 0x string For splice
87
+      */
88
+  sTermInfo: ['9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f',
89
+    '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
90
+    '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa',
91
+    '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f',
92
+    'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f',
93
+    '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa',
94
+    '97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2',
95
+    '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f',
96
+    '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e',
97
+    '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
98
+    '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722',
99
+    '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f',
100
+    '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
101
+    '97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
102
+    '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722',
103
+    '9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f',
104
+    '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
105
+    '97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
106
+    '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722',
107
+    '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
108
+    '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
109
+    '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
110
+    '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722',
111
+    '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
112
+    '97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
113
+    '97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
114
+    '9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722',
115
+    '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
116
+    '97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
117
+    '9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
118
+    '7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
119
+    '7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
120
+    '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
121
+    '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
122
+    '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
123
+    '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
124
+    '97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
125
+    '9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
126
+    '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721',
127
+    '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2',
128
+    '977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
129
+    '7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
130
+    '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd',
131
+    '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
132
+    '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
133
+    '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
134
+    '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd',
135
+    '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
136
+    '977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
137
+    '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721',
138
+    '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5',
139
+    '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722',
140
+    '7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
141
+    '7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
142
+    '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35',
143
+    '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
144
+    '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721',
145
+    '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd',
146
+    '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35',
147
+    '7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
148
+    '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721',
149
+    '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5',
150
+    '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35',
151
+    '665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
152
+    '7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
153
+    '7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35',
154
+    '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722'],
155
+
156
+  /**
157
+      * 数字转中文速查表
158
+      * @Array Of Property
159
+      * @trans ['日','一','二','三','四','五','六','七','八','九','十']
160
+      * @return Cn string
161
+      */
162
+  nStr1: ['\u65e5', '\u4e00', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341'],
163
+
164
+  /**
165
+      * 日期转农历称呼速查表
166
+      * @Array Of Property
167
+      * @trans ['初','十','廿','卅']
168
+      * @return Cn string
169
+      */
170
+  nStr2: ['\u521d', '\u5341', '\u5eff', '\u5345'],
171
+
172
+  /**
173
+      * 月份转农历称呼速查表
174
+      * @Array Of Property
175
+      * @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊']
176
+      * @return Cn string
177
+      */
178
+  nStr3: ['\u6b63', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341', '\u51ac', '\u814a'],
179
+
180
+  /**
181
+      * 返回农历y年一整年的总天数
182
+      * @param lunar Year
183
+      * @return Number
184
+      * @eg:var count = calendar.lYearDays(1987) ;//count=387
185
+      */
186
+  lYearDays: function (y) {
187
+    var i; var sum = 348
188
+    for (i = 0x8000; i > 0x8; i >>= 1) { sum += (this.lunarInfo[y - 1900] & i) ? 1 : 0 }
189
+    return (sum + this.leapDays(y))
190
+  },
191
+
192
+  /**
193
+      * 返回农历y年闰月是哪个月;若y年没有闰月 则返回0
194
+      * @param lunar Year
195
+      * @return Number (0-12)
196
+      * @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6
197
+      */
198
+  leapMonth: function (y) { // 闰字编码 \u95f0
199
+    return (this.lunarInfo[y - 1900] & 0xf)
200
+  },
201
+
202
+  /**
203
+      * 返回农历y年闰月的天数 若该年没有闰月则返回0
204
+      * @param lunar Year
205
+      * @return Number (0、29、30)
206
+      * @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29
207
+      */
208
+  leapDays: function (y) {
209
+    if (this.leapMonth(y)) {
210
+      return ((this.lunarInfo[y - 1900] & 0x10000) ? 30 : 29)
211
+    }
212
+    return (0)
213
+  },
214
+
215
+  /**
216
+      * 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法
217
+      * @param lunar Year
218
+      * @return Number (-1、29、30)
219
+      * @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29
220
+      */
221
+  monthDays: function (y, m) {
222
+    if (m > 12 || m < 1) { return -1 }// 月份参数从1至12,参数错误返回-1
223
+    return ((this.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29)
224
+  },
225
+
226
+  /**
227
+      * 返回公历(!)y年m月的天数
228
+      * @param solar Year
229
+      * @return Number (-1、28、29、30、31)
230
+      * @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30
231
+      */
232
+  solarDays: function (y, m) {
233
+    if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
234
+    var ms = m - 1
235
+    if (ms == 1) { // 2月份的闰平规律测算后确认返回28或29
236
+      return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28)
237
+    } else {
238
+      return (this.solarMonth[ms])
239
+    }
240
+  },
241
+
242
+  /**
243
+     * 农历年份转换为干支纪年
244
+     * @param  lYear 农历年的年份数
245
+     * @return Cn string
246
+     */
247
+  toGanZhiYear: function (lYear) {
248
+    var ganKey = (lYear - 3) % 10
249
+    var zhiKey = (lYear - 3) % 12
250
+    if (ganKey == 0) ganKey = 10// 如果余数为0则为最后一个天干
251
+    if (zhiKey == 0) zhiKey = 12// 如果余数为0则为最后一个地支
252
+    return this.Gan[ganKey - 1] + this.Zhi[zhiKey - 1]
253
+  },
254
+
255
+  /**
256
+     * 公历月、日判断所属星座
257
+     * @param  cMonth [description]
258
+     * @param  cDay [description]
259
+     * @return Cn string
260
+     */
261
+  toAstro: function (cMonth, cDay) {
262
+    var s = '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf'
263
+    var arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]
264
+    return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7'// 座
265
+  },
266
+
267
+  /**
268
+      * 传入offset偏移量返回干支
269
+      * @param offset 相对甲子的偏移量
270
+      * @return Cn string
271
+      */
272
+  toGanZhi: function (offset) {
273
+    return this.Gan[offset % 10] + this.Zhi[offset % 12]
274
+  },
275
+
276
+  /**
277
+      * 传入公历(!)y年获得该年第n个节气的公历日期
278
+      * @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起
279
+      * @return day Number
280
+      * @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春
281
+      */
282
+  getTerm: function (y, n) {
283
+    if (y < 1900 || y > 2100) { return -1 }
284
+    if (n < 1 || n > 24) { return -1 }
285
+    var _table = this.sTermInfo[y - 1900]
286
+    var _info = [
287
+      parseInt('0x' + _table.substr(0, 5)).toString(),
288
+      parseInt('0x' + _table.substr(5, 5)).toString(),
289
+      parseInt('0x' + _table.substr(10, 5)).toString(),
290
+      parseInt('0x' + _table.substr(15, 5)).toString(),
291
+      parseInt('0x' + _table.substr(20, 5)).toString(),
292
+      parseInt('0x' + _table.substr(25, 5)).toString()
293
+    ]
294
+    var _calday = [
295
+      _info[0].substr(0, 1),
296
+      _info[0].substr(1, 2),
297
+      _info[0].substr(3, 1),
298
+      _info[0].substr(4, 2),
299
+
300
+      _info[1].substr(0, 1),
301
+      _info[1].substr(1, 2),
302
+      _info[1].substr(3, 1),
303
+      _info[1].substr(4, 2),
304
+
305
+      _info[2].substr(0, 1),
306
+      _info[2].substr(1, 2),
307
+      _info[2].substr(3, 1),
308
+      _info[2].substr(4, 2),
309
+
310
+      _info[3].substr(0, 1),
311
+      _info[3].substr(1, 2),
312
+      _info[3].substr(3, 1),
313
+      _info[3].substr(4, 2),
314
+
315
+      _info[4].substr(0, 1),
316
+      _info[4].substr(1, 2),
317
+      _info[4].substr(3, 1),
318
+      _info[4].substr(4, 2),
319
+
320
+      _info[5].substr(0, 1),
321
+      _info[5].substr(1, 2),
322
+      _info[5].substr(3, 1),
323
+      _info[5].substr(4, 2)
324
+    ]
325
+    return parseInt(_calday[n - 1])
326
+  },
327
+
328
+  /**
329
+      * 传入农历数字月份返回汉语通俗表示法
330
+      * @param lunar month
331
+      * @return Cn string
332
+      * @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月'
333
+      */
334
+  toChinaMonth: function (m) { // 月 => \u6708
335
+    if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
336
+    var s = this.nStr3[m - 1]
337
+    s += '\u6708'// 加上月字
338
+    return s
339
+  },
340
+
341
+  /**
342
+      * 传入农历日期数字返回汉字表示法
343
+      * @param lunar day
344
+      * @return Cn string
345
+      * @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一'
346
+      */
347
+  toChinaDay: function (d) { // 日 => \u65e5
348
+    var s
349
+    switch (d) {
350
+      case 10:
351
+        s = '\u521d\u5341'; break
352
+      case 20:
353
+        s = '\u4e8c\u5341'; break
354
+        break
355
+      case 30:
356
+        s = '\u4e09\u5341'; break
357
+        break
358
+      default :
359
+        s = this.nStr2[Math.floor(d / 10)]
360
+        s += this.nStr1[d % 10]
361
+    }
362
+    return (s)
363
+  },
364
+
365
+  /**
366
+      * 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春”
367
+      * @param y year
368
+      * @return Cn string
369
+      * @eg:var animal = calendar.getAnimal(1987) ;//animal='兔'
370
+      */
371
+  getAnimal: function (y) {
372
+    return this.Animals[(y - 4) % 12]
373
+  },
374
+
375
+  /**
376
+      * 传入阳历年月日获得详细的公历、农历object信息 <=>JSON
377
+      * @param y  solar year
378
+      * @param m  solar month
379
+      * @param d  solar day
380
+      * @return JSON object
381
+      * @eg:console.log(calendar.solar2lunar(1987,11,01));
382
+      */
383
+  solar2lunar: function (y, m, d) { // 参数区间1900.1.31~2100.12.31
384
+    // 年份限定、上限
385
+    if (y < 1900 || y > 2100) {
386
+      return -1// undefined转换为数字变为NaN
387
+    }
388
+    // 公历传参最下限
389
+    if (y == 1900 && m == 1 && d < 31) {
390
+      return -1
391
+    }
392
+    // 未传参  获得当天
393
+    if (!y) {
394
+      var objDate = new Date()
395
+    } else {
396
+      var objDate = new Date(y, parseInt(m) - 1, d)
397
+    }
398
+    var i; var leap = 0; var temp = 0
399
+    // 修正ymd参数
400
+    var y = objDate.getFullYear()
401
+    var m = objDate.getMonth() + 1
402
+    var d = objDate.getDate()
403
+    var offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, 31)) / 86400000
404
+    for (i = 1900; i < 2101 && offset > 0; i++) {
405
+      temp = this.lYearDays(i)
406
+      offset -= temp
407
+    }
408
+    if (offset < 0) {
409
+      offset += temp; i--
410
+    }
411
+
412
+    // 是否今天
413
+    var isTodayObj = new Date()
414
+    var isToday = false
415
+    if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) {
416
+      isToday = true
417
+    }
418
+    // 星期几
419
+    var nWeek = objDate.getDay()
420
+    var cWeek = this.nStr1[nWeek]
421
+    // 数字表示周几顺应天朝周一开始的惯例
422
+    if (nWeek == 0) {
423
+      nWeek = 7
424
+    }
425
+    // 农历年
426
+    var year = i
427
+    var leap = this.leapMonth(i) // 闰哪个月
428
+    var isLeap = false
429
+
430
+    // 效验闰月
431
+    for (i = 1; i < 13 && offset > 0; i++) {
432
+      // 闰月
433
+      if (leap > 0 && i == (leap + 1) && isLeap == false) {
434
+        --i
435
+        isLeap = true; temp = this.leapDays(year) // 计算农历闰月天数
436
+      } else {
437
+        temp = this.monthDays(year, i)// 计算农历普通月天数
438
+      }
439
+      // 解除闰月
440
+      if (isLeap == true && i == (leap + 1)) { isLeap = false }
441
+      offset -= temp
442
+    }
443
+    // 闰月导致数组下标重叠取反
444
+    if (offset == 0 && leap > 0 && i == leap + 1) {
445
+      if (isLeap) {
446
+        isLeap = false
447
+      } else {
448
+        isLeap = true; --i
449
+      }
450
+    }
451
+    if (offset < 0) {
452
+      offset += temp; --i
453
+    }
454
+    // 农历月
455
+    var month = i
456
+    // 农历日
457
+    var day = offset + 1
458
+    // 天干地支处理
459
+    var sm = m - 1
460
+    var gzY = this.toGanZhiYear(year)
461
+
462
+    // 当月的两个节气
463
+    // bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year`
464
+    var firstNode = this.getTerm(y, (m * 2 - 1))// 返回当月「节」为几日开始
465
+    var secondNode = this.getTerm(y, (m * 2))// 返回当月「节」为几日开始
466
+
467
+    // 依据12节气修正干支月
468
+    var gzM = this.toGanZhi((y - 1900) * 12 + m + 11)
469
+    if (d >= firstNode) {
470
+      gzM = this.toGanZhi((y - 1900) * 12 + m + 12)
471
+    }
472
+
473
+    // 传入的日期的节气与否
474
+    var isTerm = false
475
+    var Term = null
476
+    if (firstNode == d) {
477
+      isTerm = true
478
+      Term = this.solarTerm[m * 2 - 2]
479
+    }
480
+    if (secondNode == d) {
481
+      isTerm = true
482
+      Term = this.solarTerm[m * 2 - 1]
483
+    }
484
+    // 日柱 当月一日与 1900/1/1 相差天数
485
+    var dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10
486
+    var gzD = this.toGanZhi(dayCyclical + d - 1)
487
+    // 该日期所属的星座
488
+    var astro = this.toAstro(m, d)
489
+
490
+    return { 'lYear': year, 'lMonth': month, 'lDay': day, 'Animal': this.getAnimal(year), 'IMonthCn': (isLeap ? '\u95f0' : '') + this.toChinaMonth(month), 'IDayCn': this.toChinaDay(day), 'cYear': y, 'cMonth': m, 'cDay': d, 'gzYear': gzY, 'gzMonth': gzM, 'gzDay': gzD, 'isToday': isToday, 'isLeap': isLeap, 'nWeek': nWeek, 'ncWeek': '\u661f\u671f' + cWeek, 'isTerm': isTerm, 'Term': Term, 'astro': astro }
491
+  },
492
+
493
+  /**
494
+      * 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON
495
+      * @param y  lunar year
496
+      * @param m  lunar month
497
+      * @param d  lunar day
498
+      * @param isLeapMonth  lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可]
499
+      * @return JSON object
500
+      * @eg:console.log(calendar.lunar2solar(1987,9,10));
501
+      */
502
+  lunar2solar: function (y, m, d, isLeapMonth) { // 参数区间1900.1.31~2100.12.1
503
+    var isLeapMonth = !!isLeapMonth
504
+    var leapOffset = 0
505
+    var leapMonth = this.leapMonth(y)
506
+    var leapDay = this.leapDays(y)
507
+    if (isLeapMonth && (leapMonth != m)) { return -1 }// 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同
508
+    if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) { return -1 }// 超出了最大极限值
509
+    var day = this.monthDays(y, m)
510
+    var _day = day
511
+    // bugFix 2016-9-25
512
+    // if month is leap, _day use leapDays method
513
+    if (isLeapMonth) {
514
+      _day = this.leapDays(y, m)
515
+    }
516
+    if (y < 1900 || y > 2100 || d > _day) { return -1 }// 参数合法性效验
517
+
518
+    // 计算农历的时间差
519
+    var offset = 0
520
+    for (var i = 1900; i < y; i++) {
521
+      offset += this.lYearDays(i)
522
+    }
523
+    var leap = 0; var isAdd = false
524
+    for (var i = 1; i < m; i++) {
525
+      leap = this.leapMonth(y)
526
+      if (!isAdd) { // 处理闰月
527
+        if (leap <= i && leap > 0) {
528
+          offset += this.leapDays(y); isAdd = true
529
+        }
530
+      }
531
+      offset += this.monthDays(y, i)
532
+    }
533
+    // 转换闰月农历 需补充该年闰月的前一个月的时差
534
+    if (isLeapMonth) { offset += day }
535
+    // 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点)
536
+    var stmap = Date.UTC(1900, 1, 30, 0, 0, 0)
537
+    var calObj = new Date((offset + d - 31) * 86400000 + stmap)
538
+    var cY = calObj.getUTCFullYear()
539
+    var cM = calObj.getUTCMonth() + 1
540
+    var cD = calObj.getUTCDate()
541
+
542
+    return this.solar2lunar(cY, cM, cD)
543
+  }
544
+}
545
+
546
+export default calendar

+ 12 - 0
uni_modules/uni-calendar/components/uni-calendar/i18n/en.json

@@ -0,0 +1,12 @@
1
+{
2
+	"uni-calender.ok": "ok",
3
+	"uni-calender.cancel": "cancel",
4
+	"uni-calender.today": "today",
5
+	"uni-calender.MON": "MON",
6
+	"uni-calender.TUE": "TUE",
7
+	"uni-calender.WED": "WED",
8
+	"uni-calender.THU": "THU",
9
+	"uni-calender.FRI": "FRI",
10
+	"uni-calender.SAT": "SAT",
11
+	"uni-calender.SUN": "SUN"
12
+}

+ 8 - 0
uni_modules/uni-calendar/components/uni-calendar/i18n/index.js

@@ -0,0 +1,8 @@
1
+import en from './en.json'
2
+import zhHans from './zh-Hans.json'
3
+import zhHant from './zh-Hant.json'
4
+export default {
5
+	en,
6
+	'zh-Hans': zhHans,
7
+	'zh-Hant': zhHant
8
+}

+ 12 - 0
uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hans.json

@@ -0,0 +1,12 @@
1
+{
2
+	"uni-calender.ok": "确定",
3
+	"uni-calender.cancel": "取消",
4
+	"uni-calender.today": "今日",
5
+	"uni-calender.SUN": "日",
6
+	"uni-calender.MON": "一",
7
+	"uni-calender.TUE": "二",
8
+	"uni-calender.WED": "三",
9
+	"uni-calender.THU": "四",
10
+	"uni-calender.FRI": "五",
11
+	"uni-calender.SAT": "六"
12
+}

+ 12 - 0
uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json

@@ -0,0 +1,12 @@
1
+{
2
+	"uni-calender.ok": "確定",
3
+	"uni-calender.cancel": "取消",
4
+	"uni-calender.today": "今日",
5
+	"uni-calender.SUN": "日",
6
+	"uni-calender.MON": "一",
7
+	"uni-calender.TUE": "二",
8
+	"uni-calender.WED": "三",
9
+	"uni-calender.THU": "四",
10
+	"uni-calender.FRI": "五",
11
+	"uni-calender.SAT": "六"
12
+}

+ 188 - 0
uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue

@@ -0,0 +1,188 @@
1
+<template>
2
+	<view class="uni-calendar-item__weeks-box" :class="{
3
+		'uni-calendar-item--disable':weeks.disable,
4
+		'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
5
+		'uni-calendar-item--checked':(calendar.fullDate === weeks.fullDate && !weeks.isDay) ,
6
+		'uni-calendar-item--before-checked':weeks.beforeMultiple,
7
+		'uni-calendar-item--multiple': weeks.multiple,
8
+		'uni-calendar-item--after-checked':weeks.afterMultiple,
9
+		}"
10
+	 @click="choiceDate(weeks)">
11
+		<view class="uni-calendar-item__weeks-box-item">
12
+			<text v-if="selected&&weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text>
13
+			<text class="uni-calendar-item__weeks-box-text" :class="{
14
+				'uni-calendar-item--isDay-text': weeks.isDay,
15
+				'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
16
+				'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
17
+				'uni-calendar-item--before-checked':weeks.beforeMultiple,
18
+				'uni-calendar-item--multiple': weeks.multiple,
19
+				'uni-calendar-item--after-checked':weeks.afterMultiple,
20
+				'uni-calendar-item--disable':weeks.disable,
21
+				}">{{weeks.date}}</text>
22
+			<text v-if="!lunar&&!weeks.extraInfo && weeks.isDay" class="uni-calendar-item__weeks-lunar-text" :class="{
23
+				'uni-calendar-item--isDay-text':weeks.isDay,
24
+				'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
25
+				'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
26
+				'uni-calendar-item--before-checked':weeks.beforeMultiple,
27
+				'uni-calendar-item--multiple': weeks.multiple,
28
+				'uni-calendar-item--after-checked':weeks.afterMultiple,
29
+				}">{{todayText}}</text>
30
+			<text v-if="lunar&&!weeks.extraInfo" class="uni-calendar-item__weeks-lunar-text" :class="{
31
+				'uni-calendar-item--isDay-text':weeks.isDay,
32
+				'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
33
+				'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
34
+				'uni-calendar-item--before-checked':weeks.beforeMultiple,
35
+				'uni-calendar-item--multiple': weeks.multiple,
36
+				'uni-calendar-item--after-checked':weeks.afterMultiple,
37
+				'uni-calendar-item--disable':weeks.disable,
38
+				}">{{weeks.isDay ? todayText : (weeks.lunar.IDayCn === '初一'?weeks.lunar.IMonthCn:weeks.lunar.IDayCn)}}</text>
39
+			<text v-if="weeks.extraInfo&&weeks.extraInfo.info" class="uni-calendar-item__weeks-lunar-text" :class="{
40
+				'uni-calendar-item--extra':weeks.extraInfo.info,
41
+				'uni-calendar-item--isDay-text':weeks.isDay,
42
+				'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
43
+				'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
44
+				'uni-calendar-item--before-checked':weeks.beforeMultiple,
45
+				'uni-calendar-item--multiple': weeks.multiple,
46
+				'uni-calendar-item--after-checked':weeks.afterMultiple,
47
+				'uni-calendar-item--disable':weeks.disable,
48
+				}">{{weeks.extraInfo.info}}</text>
49
+		</view>
50
+	</view>
51
+</template>
52
+
53
+<script>
54
+	import {
55
+	initVueI18n
56
+	} from '@dcloudio/uni-i18n'
57
+	import messages from './i18n/index.js'
58
+	const {	t	} = initVueI18n(messages)
59
+	export default {
60
+		emits:['change'],
61
+		props: {
62
+			weeks: {
63
+				type: Object,
64
+				default () {
65
+					return {}
66
+				}
67
+			},
68
+			calendar: {
69
+				type: Object,
70
+				default: () => {
71
+					return {}
72
+				}
73
+			},
74
+			selected: {
75
+				type: Array,
76
+				default: () => {
77
+					return []
78
+				}
79
+			},
80
+			lunar: {
81
+				type: Boolean,
82
+				default: false
83
+			}
84
+		},
85
+		computed: {
86
+			todayText() {
87
+				return t("uni-calender.today")
88
+			},
89
+		},
90
+		methods: {
91
+			choiceDate(weeks) {
92
+				this.$emit('change', weeks)
93
+			}
94
+		}
95
+	}
96
+</script>
97
+
98
+<style lang="scss" scoped>
99
+	$uni-font-size-base:14px;
100
+	$uni-text-color:#333;
101
+	$uni-font-size-sm:12px;
102
+	$uni-color-error: #e43d33;
103
+	$uni-opacity-disabled: 0.3;
104
+	$uni-text-color-disable:#c0c0c0;
105
+	$uni-primary: #2979ff !default;
106
+	.uni-calendar-item__weeks-box {
107
+		flex: 1;
108
+		/* #ifndef APP-NVUE */
109
+		display: flex;
110
+		/* #endif */
111
+		flex-direction: column;
112
+		justify-content: center;
113
+		align-items: center;
114
+	}
115
+
116
+	.uni-calendar-item__weeks-box-text {
117
+		font-size: $uni-font-size-base;
118
+		color: $uni-text-color;
119
+	}
120
+
121
+	.uni-calendar-item__weeks-lunar-text {
122
+		font-size: $uni-font-size-sm;
123
+		color: $uni-text-color;
124
+	}
125
+
126
+	.uni-calendar-item__weeks-box-item {
127
+		position: relative;
128
+		/* #ifndef APP-NVUE */
129
+		display: flex;
130
+		/* #endif */
131
+		flex-direction: column;
132
+		justify-content: center;
133
+		align-items: center;
134
+		width: 100rpx;
135
+		height: 100rpx;
136
+	}
137
+
138
+	.uni-calendar-item__weeks-box-circle {
139
+		position: absolute;
140
+		top: 5px;
141
+		right: 5px;
142
+		width: 8px;
143
+		height: 8px;
144
+		border-radius: 8px;
145
+		background-color: $uni-color-error;
146
+
147
+	}
148
+
149
+	.uni-calendar-item--disable {
150
+		background-color: rgba(249, 249, 249, $uni-opacity-disabled);
151
+		color: $uni-text-color-disable;
152
+	}
153
+
154
+	.uni-calendar-item--isDay-text {
155
+		color: $uni-primary;
156
+	}
157
+
158
+	.uni-calendar-item--isDay {
159
+		background-color: $uni-primary;
160
+		opacity: 0.8;
161
+		color: #fff;
162
+	}
163
+
164
+	.uni-calendar-item--extra {
165
+		color: $uni-color-error;
166
+		opacity: 0.8;
167
+	}
168
+
169
+	.uni-calendar-item--checked {
170
+		background-color: $uni-primary;
171
+		color: #fff;
172
+		opacity: 0.8;
173
+	}
174
+
175
+	.uni-calendar-item--multiple {
176
+		background-color: $uni-primary;
177
+		color: #fff;
178
+		opacity: 0.8;
179
+	}
180
+	.uni-calendar-item--before-checked {
181
+		background-color: #ff5a5f;
182
+		color: #fff;
183
+	}
184
+	.uni-calendar-item--after-checked {
185
+		background-color: #ff5a5f;
186
+		color: #fff;
187
+	}
188
+</style>

+ 562 - 0
uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue

@@ -0,0 +1,562 @@
1
+<template>
2
+	<view class="uni-calendar">
3
+		<view v-if="!insert&&show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}" @click="clean"></view>
4
+		<view v-if="insert || show" class="uni-calendar__content" :class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow}">
5
+			<view v-if="!insert" class="uni-calendar__header uni-calendar--fixed-top">
6
+				<view class="uni-calendar__header-btn-box" @click="close">
7
+					<text class="uni-calendar__header-text uni-calendar--fixed-width">{{cancelText}}</text>
8
+				</view>
9
+				<view class="uni-calendar__header-btn-box" @click="confirm">
10
+					<text class="uni-calendar__header-text uni-calendar--fixed-width">{{okText}}</text>
11
+				</view>
12
+			</view>
13
+			<view class="uni-calendar__header">
14
+				<view class="uni-calendar__header-btn-box" @click.stop="pre">
15
+					<view class="uni-calendar__header-btn uni-calendar--left"></view>
16
+				</view>
17
+				<picker mode="date" :value="date" fields="month" @change="bindDateChange">
18
+					<text class="uni-calendar__header-text">{{ (nowDate.year||'') +' / '+( nowDate.month||'')}}</text>
19
+				</picker>
20
+				<view class="uni-calendar__header-btn-box" @click.stop="next">
21
+					<view class="uni-calendar__header-btn uni-calendar--right"></view>
22
+				</view>
23
+				<text class="uni-calendar__backtoday" @click="backtoday">{{todayText}}</text>
24
+
25
+			</view>
26
+			<view class="uni-calendar__box">
27
+				<view v-if="showMonth" class="uni-calendar__box-bg">
28
+					<text class="uni-calendar__box-bg-text">{{nowDate.month}}</text>
29
+				</view>
30
+				<view class="uni-calendar__weeks">
31
+					<view class="uni-calendar__weeks-day">
32
+						<text class="uni-calendar__weeks-day-text">{{SUNText}}</text>
33
+					</view>
34
+					<view class="uni-calendar__weeks-day">
35
+						<text class="uni-calendar__weeks-day-text">{{monText}}</text>
36
+					</view>
37
+					<view class="uni-calendar__weeks-day">
38
+						<text class="uni-calendar__weeks-day-text">{{TUEText}}</text>
39
+					</view>
40
+					<view class="uni-calendar__weeks-day">
41
+						<text class="uni-calendar__weeks-day-text">{{WEDText}}</text>
42
+					</view>
43
+					<view class="uni-calendar__weeks-day">
44
+						<text class="uni-calendar__weeks-day-text">{{THUText}}</text>
45
+					</view>
46
+					<view class="uni-calendar__weeks-day">
47
+						<text class="uni-calendar__weeks-day-text">{{FRIText}}</text>
48
+					</view>
49
+					<view class="uni-calendar__weeks-day">
50
+						<text class="uni-calendar__weeks-day-text">{{SATText}}</text>
51
+					</view>
52
+				</view>
53
+				<view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
54
+					<view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
55
+						<calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar" :selected="selected" :lunar="lunar" @change="choiceDate"></calendar-item>
56
+					</view>
57
+				</view>
58
+			</view>
59
+		</view>
60
+	</view>
61
+</template>
62
+
63
+<script>
64
+	import Calendar from './util.js';
65
+	import calendarItem from './uni-calendar-item.vue'
66
+	import {
67
+	initVueI18n
68
+	} from '@dcloudio/uni-i18n'
69
+	import messages from './i18n/index.js'
70
+	const {	t	} = initVueI18n(messages)
71
+	/**
72
+	 * Calendar 日历
73
+	 * @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等
74
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=56
75
+	 * @property {String} date 自定义当前时间,默认为今天
76
+	 * @property {Boolean} lunar 显示农历
77
+	 * @property {String} startDate 日期选择范围-开始日期
78
+	 * @property {String} endDate 日期选择范围-结束日期
79
+	 * @property {Boolean} range 范围选择
80
+	 * @property {Boolean} insert = [true|false] 插入模式,默认为false
81
+	 * 	@value true 弹窗模式
82
+	 * 	@value false 插入模式
83
+	 * @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容
84
+	 * @property {Array} selected 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]
85
+	 * @property {Boolean} showMonth 是否选择月份为背景
86
+	 * @event {Function} change 日期改变,`insert :ture` 时生效
87
+	 * @event {Function} confirm 确认选择`insert :false` 时生效
88
+	 * @event {Function} monthSwitch 切换月份时触发
89
+	 * @example <uni-calendar :insert="true":lunar="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
90
+	 */
91
+	export default {
92
+		components: {
93
+			calendarItem
94
+		},
95
+		emits:['close','confirm','change','monthSwitch'],
96
+		props: {
97
+			date: {
98
+				type: String,
99
+				default: ''
100
+			},
101
+			selected: {
102
+				type: Array,
103
+				default () {
104
+					return []
105
+				}
106
+			},
107
+			lunar: {
108
+				type: Boolean,
109
+				default: false
110
+			},
111
+			startDate: {
112
+				type: String,
113
+				default: ''
114
+			},
115
+			endDate: {
116
+				type: String,
117
+				default: ''
118
+			},
119
+			range: {
120
+				type: Boolean,
121
+				default: false
122
+			},
123
+			insert: {
124
+				type: Boolean,
125
+				default: true
126
+			},
127
+			showMonth: {
128
+				type: Boolean,
129
+				default: true
130
+			},
131
+			clearDate: {
132
+				type: Boolean,
133
+				default: true
134
+			}
135
+		},
136
+		data() {
137
+			return {
138
+				show: false,
139
+				weeks: [],
140
+				calendar: {},
141
+				nowDate: '',
142
+				aniMaskShow: false
143
+			}
144
+		},
145
+		computed:{
146
+			/**
147
+			 * for i18n
148
+			 */
149
+
150
+			okText() {
151
+				return t("uni-calender.ok")
152
+			},
153
+			cancelText() {
154
+				return t("uni-calender.cancel")
155
+			},
156
+			todayText() {
157
+				return t("uni-calender.today")
158
+			},
159
+			monText() {
160
+				return t("uni-calender.MON")
161
+			},
162
+			TUEText() {
163
+				return t("uni-calender.TUE")
164
+			},
165
+			WEDText() {
166
+				return t("uni-calender.WED")
167
+			},
168
+			THUText() {
169
+				return t("uni-calender.THU")
170
+			},
171
+			FRIText() {
172
+				return t("uni-calender.FRI")
173
+			},
174
+			SATText() {
175
+				return t("uni-calender.SAT")
176
+			},
177
+			SUNText() {
178
+				return t("uni-calender.SUN")
179
+			},
180
+		},
181
+		watch: {
182
+			date(newVal) {
183
+				// this.cale.setDate(newVal)
184
+				this.init(newVal)
185
+			},
186
+			startDate(val){
187
+				this.cale.resetSatrtDate(val)
188
+				this.cale.setDate(this.nowDate.fullDate)
189
+				this.weeks = this.cale.weeks
190
+			},
191
+			endDate(val){
192
+				this.cale.resetEndDate(val)
193
+				this.cale.setDate(this.nowDate.fullDate)
194
+				this.weeks = this.cale.weeks
195
+			},
196
+			selected(newVal) {
197
+				this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
198
+				this.weeks = this.cale.weeks
199
+			}
200
+		},
201
+		created() {
202
+			// 获取日历方法实例
203
+			this.cale = new Calendar({
204
+				// date: new Date(),
205
+				selected: this.selected,
206
+				startDate: this.startDate,
207
+				endDate: this.endDate,
208
+				range: this.range,
209
+			})
210
+			// 选中某一天
211
+			// this.cale.setDate(this.date)
212
+			this.init(this.date)
213
+			// this.setDay
214
+		},
215
+		methods: {
216
+			// 取消穿透
217
+			clean() {},
218
+			bindDateChange(e) {
219
+				const value = e.detail.value + '-1'
220
+				console.log(this.cale.getDate(value));
221
+				this.setDate(value)
222
+			},
223
+			/**
224
+			 * 初始化日期显示
225
+			 * @param {Object} date
226
+			 */
227
+			init(date) {
228
+				this.cale.setDate(date)
229
+				this.weeks = this.cale.weeks
230
+				this.nowDate = this.calendar = this.cale.getInfo(date)
231
+			},
232
+			/**
233
+			 * 打开日历弹窗
234
+			 */
235
+			open() {
236
+				// 弹窗模式并且清理数据
237
+				if (this.clearDate && !this.insert) {
238
+					this.cale.cleanMultipleStatus()
239
+					// this.cale.setDate(this.date)
240
+					this.init(this.date)
241
+				}
242
+				this.show = true
243
+				this.$nextTick(() => {
244
+					setTimeout(() => {
245
+						this.aniMaskShow = true
246
+					}, 50)
247
+				})
248
+			},
249
+			/**
250
+			 * 关闭日历弹窗
251
+			 */
252
+			close() {
253
+				this.aniMaskShow = false
254
+				this.$nextTick(() => {
255
+					setTimeout(() => {
256
+						this.show = false
257
+						this.$emit('close')
258
+					}, 300)
259
+				})
260
+			},
261
+			/**
262
+			 * 确认按钮
263
+			 */
264
+			confirm() {
265
+				this.setEmit('confirm')
266
+				this.close()
267
+			},
268
+			/**
269
+			 * 变化触发
270
+			 */
271
+			change() {
272
+				if (!this.insert) return
273
+				this.setEmit('change')
274
+			},
275
+			/**
276
+			 * 选择月份触发
277
+			 */
278
+			monthSwitch() {
279
+				let {
280
+					year,
281
+					month
282
+				} = this.nowDate
283
+				this.$emit('monthSwitch', {
284
+					year,
285
+					month: Number(month)
286
+				})
287
+			},
288
+			/**
289
+			 * 派发事件
290
+			 * @param {Object} name
291
+			 */
292
+			setEmit(name) {
293
+				let {
294
+					year,
295
+					month,
296
+					date,
297
+					fullDate,
298
+					lunar,
299
+					extraInfo
300
+				} = this.calendar
301
+				this.$emit(name, {
302
+					range: this.cale.multipleStatus,
303
+					year,
304
+					month,
305
+					date,
306
+					fulldate: fullDate,
307
+					lunar,
308
+					extraInfo: extraInfo || {}
309
+				})
310
+			},
311
+			/**
312
+			 * 选择天触发
313
+			 * @param {Object} weeks
314
+			 */
315
+			choiceDate(weeks) {
316
+				if (weeks.disable) return
317
+				this.calendar = weeks
318
+				// 设置多选
319
+				this.cale.setMultiple(this.calendar.fullDate)
320
+				this.weeks = this.cale.weeks
321
+				this.change()
322
+			},
323
+			/**
324
+			 * 回到今天
325
+			 */
326
+			backtoday() {
327
+				console.log(this.cale.getDate(new Date()).fullDate);
328
+				let date = this.cale.getDate(new Date()).fullDate
329
+				// this.cale.setDate(date)
330
+				this.init(date)
331
+				this.change()
332
+			},
333
+			/**
334
+			 * 上个月
335
+			 */
336
+			pre() {
337
+				const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate
338
+				this.setDate(preDate)
339
+				this.monthSwitch()
340
+
341
+			},
342
+			/**
343
+			 * 下个月
344
+			 */
345
+			next() {
346
+				const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate
347
+				this.setDate(nextDate)
348
+				this.monthSwitch()
349
+			},
350
+			/**
351
+			 * 设置日期
352
+			 * @param {Object} date
353
+			 */
354
+			setDate(date) {
355
+				this.cale.setDate(date)
356
+				this.weeks = this.cale.weeks
357
+				this.nowDate = this.cale.getInfo(date)
358
+			}
359
+		}
360
+	}
361
+</script>
362
+
363
+<style lang="scss" scoped>
364
+	$uni-bg-color-mask: rgba($color: #000000, $alpha: 0.4);
365
+	$uni-border-color: #EDEDED;
366
+	$uni-text-color: #333;
367
+	$uni-bg-color-hover:#f1f1f1;
368
+	$uni-font-size-base:14px;
369
+	$uni-text-color-placeholder: #808080;
370
+	$uni-color-subtitle: #555555;
371
+	$uni-text-color-grey:#999;
372
+	.uni-calendar {
373
+		/* #ifndef APP-NVUE */
374
+		display: flex;
375
+		/* #endif */
376
+		flex-direction: column;
377
+	}
378
+
379
+	.uni-calendar__mask {
380
+		position: fixed;
381
+		bottom: 0;
382
+		top: 0;
383
+		left: 0;
384
+		right: 0;
385
+		background-color: $uni-bg-color-mask;
386
+		transition-property: opacity;
387
+		transition-duration: 0.3s;
388
+		opacity: 0;
389
+		/* #ifndef APP-NVUE */
390
+		z-index: 99;
391
+		/* #endif */
392
+	}
393
+
394
+	.uni-calendar--mask-show {
395
+		opacity: 1
396
+	}
397
+
398
+	.uni-calendar--fixed {
399
+		position: fixed;
400
+		/* #ifdef APP-NVUE */
401
+		bottom: 0;
402
+		/* #endif */
403
+		left: 0;
404
+		right: 0;
405
+		transition-property: transform;
406
+		transition-duration: 0.3s;
407
+		transform: translateY(460px);
408
+		/* #ifndef APP-NVUE */
409
+		bottom: calc(var(--window-bottom));
410
+		z-index: 99;
411
+		/* #endif */
412
+	}
413
+
414
+	.uni-calendar--ani-show {
415
+		transform: translateY(0);
416
+	}
417
+
418
+	.uni-calendar__content {
419
+		background-color: #fff;
420
+	}
421
+
422
+	.uni-calendar__header {
423
+		position: relative;
424
+		/* #ifndef APP-NVUE */
425
+		display: flex;
426
+		/* #endif */
427
+		flex-direction: row;
428
+		justify-content: center;
429
+		align-items: center;
430
+		height: 50px;
431
+		border-bottom-color: $uni-border-color;
432
+		border-bottom-style: solid;
433
+		border-bottom-width: 1px;
434
+	}
435
+
436
+	.uni-calendar--fixed-top {
437
+		/* #ifndef APP-NVUE */
438
+		display: flex;
439
+		/* #endif */
440
+		flex-direction: row;
441
+		justify-content: space-between;
442
+		border-top-color: $uni-border-color;
443
+		border-top-style: solid;
444
+		border-top-width: 1px;
445
+	}
446
+
447
+	.uni-calendar--fixed-width {
448
+		width: 50px;
449
+		// padding: 0 15px;
450
+	}
451
+
452
+	.uni-calendar__backtoday {
453
+		position: absolute;
454
+		right: 0;
455
+		top: 25rpx;
456
+		padding: 0 5px;
457
+		padding-left: 10px;
458
+		height: 25px;
459
+		line-height: 25px;
460
+		font-size: 12px;
461
+		border-top-left-radius: 25px;
462
+		border-bottom-left-radius: 25px;
463
+		color: $uni-text-color;
464
+		background-color: $uni-bg-color-hover;
465
+	}
466
+
467
+	.uni-calendar__header-text {
468
+		text-align: center;
469
+		width: 100px;
470
+		font-size: $uni-font-size-base;
471
+		color: $uni-text-color;
472
+	}
473
+
474
+	.uni-calendar__header-btn-box {
475
+		/* #ifndef APP-NVUE */
476
+		display: flex;
477
+		/* #endif */
478
+		flex-direction: row;
479
+		align-items: center;
480
+		justify-content: center;
481
+		width: 50px;
482
+		height: 50px;
483
+	}
484
+
485
+	.uni-calendar__header-btn {
486
+		width: 10px;
487
+		height: 10px;
488
+		border-left-color: $uni-text-color-placeholder;
489
+		border-left-style: solid;
490
+		border-left-width: 2px;
491
+		border-top-color: $uni-color-subtitle;
492
+		border-top-style: solid;
493
+		border-top-width: 2px;
494
+	}
495
+
496
+	.uni-calendar--left {
497
+		transform: rotate(-45deg);
498
+	}
499
+
500
+	.uni-calendar--right {
501
+		transform: rotate(135deg);
502
+	}
503
+
504
+
505
+	.uni-calendar__weeks {
506
+		position: relative;
507
+		/* #ifndef APP-NVUE */
508
+		display: flex;
509
+		/* #endif */
510
+		flex-direction: row;
511
+	}
512
+
513
+	.uni-calendar__weeks-item {
514
+		flex: 1;
515
+	}
516
+
517
+	.uni-calendar__weeks-day {
518
+		flex: 1;
519
+		/* #ifndef APP-NVUE */
520
+		display: flex;
521
+		/* #endif */
522
+		flex-direction: column;
523
+		justify-content: center;
524
+		align-items: center;
525
+		height: 45px;
526
+		border-bottom-color: #F5F5F5;
527
+		border-bottom-style: solid;
528
+		border-bottom-width: 1px;
529
+	}
530
+
531
+	.uni-calendar__weeks-day-text {
532
+		font-size: 14px;
533
+	}
534
+
535
+	.uni-calendar__box {
536
+		position: relative;
537
+	}
538
+
539
+	.uni-calendar__box-bg {
540
+		/* #ifndef APP-NVUE */
541
+		display: flex;
542
+		/* #endif */
543
+		justify-content: center;
544
+		align-items: center;
545
+		position: absolute;
546
+		top: 0;
547
+		left: 0;
548
+		right: 0;
549
+		bottom: 0;
550
+	}
551
+
552
+	.uni-calendar__box-bg-text {
553
+		font-size: 200px;
554
+		font-weight: bold;
555
+		color: $uni-text-color-grey;
556
+		opacity: 0.1;
557
+		text-align: center;
558
+		/* #ifndef APP-NVUE */
559
+		line-height: 1;
560
+		/* #endif */
561
+	}
562
+</style>

+ 350 - 0
uni_modules/uni-calendar/components/uni-calendar/util.js

@@ -0,0 +1,350 @@
1
+import CALENDAR from './calendar.js'
2
+
3
+class Calendar {
4
+	constructor({
5
+		date,
6
+		selected,
7
+		startDate,
8
+		endDate,
9
+		range
10
+	} = {}) {
11
+		// 当前日期
12
+		this.date = this.getDate(new Date()) // 当前初入日期
13
+		// 打点信息
14
+		this.selected = selected || [];
15
+		// 范围开始
16
+		this.startDate = startDate
17
+		// 范围结束
18
+		this.endDate = endDate
19
+		this.range = range
20
+		// 多选状态
21
+		this.cleanMultipleStatus()
22
+		// 每周日期
23
+		this.weeks = {}
24
+		// this._getWeek(this.date.fullDate)
25
+	}
26
+	/**
27
+	 * 设置日期
28
+	 * @param {Object} date
29
+	 */
30
+	setDate(date) {
31
+		this.selectDate = this.getDate(date)
32
+		this._getWeek(this.selectDate.fullDate)
33
+	}
34
+
35
+	/**
36
+	 * 清理多选状态
37
+	 */
38
+	cleanMultipleStatus() {
39
+		this.multipleStatus = {
40
+			before: '',
41
+			after: '',
42
+			data: []
43
+		}
44
+	}
45
+
46
+	/**
47
+	 * 重置开始日期
48
+	 */
49
+	resetSatrtDate(startDate) {
50
+		// 范围开始
51
+		this.startDate = startDate
52
+
53
+	}
54
+
55
+	/**
56
+	 * 重置结束日期
57
+	 */
58
+	resetEndDate(endDate) {
59
+		// 范围结束
60
+		this.endDate = endDate
61
+	}
62
+
63
+	/**
64
+	 * 获取任意时间
65
+	 */
66
+	getDate(date, AddDayCount = 0, str = 'day') {
67
+		if (!date) {
68
+			date = new Date()
69
+		}
70
+		if (typeof date !== 'object') {
71
+			date = date.replace(/-/g, '/')
72
+		}
73
+		const dd = new Date(date)
74
+		switch (str) {
75
+			case 'day':
76
+				dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
77
+				break
78
+			case 'month':
79
+				if (dd.getDate() === 31) {
80
+					dd.setDate(dd.getDate() + AddDayCount)
81
+				} else {
82
+					dd.setMonth(dd.getMonth() + AddDayCount) // 获取AddDayCount天后的日期
83
+				}
84
+				break
85
+			case 'year':
86
+				dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
87
+				break
88
+		}
89
+		const y = dd.getFullYear()
90
+		const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
91
+		const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
92
+		return {
93
+			fullDate: y + '-' + m + '-' + d,
94
+			year: y,
95
+			month: m,
96
+			date: d,
97
+			day: dd.getDay()
98
+		}
99
+	}
100
+
101
+
102
+	/**
103
+	 * 获取上月剩余天数
104
+	 */
105
+	_getLastMonthDays(firstDay, full) {
106
+		let dateArr = []
107
+		for (let i = firstDay; i > 0; i--) {
108
+			const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate()
109
+			dateArr.push({
110
+				date: beforeDate,
111
+				month: full.month - 1,
112
+				lunar: this.getlunar(full.year, full.month - 1, beforeDate),
113
+				disable: true
114
+			})
115
+		}
116
+		return dateArr
117
+	}
118
+	/**
119
+	 * 获取本月天数
120
+	 */
121
+	_currentMonthDys(dateData, full) {
122
+		let dateArr = []
123
+		let fullDate = this.date.fullDate
124
+		for (let i = 1; i <= dateData; i++) {
125
+			let nowDate = full.year + '-' + (full.month < 10 ?
126
+				full.month : full.month) + '-' + (i < 10 ?
127
+				'0' + i : i)
128
+			// 是否今天
129
+			let isDay = fullDate === nowDate
130
+			// 获取打点信息
131
+			let info = this.selected && this.selected.find((item) => {
132
+				if (this.dateEqual(nowDate, item.date)) {
133
+					return item
134
+				}
135
+			})
136
+
137
+			// 日期禁用
138
+			let disableBefore = true
139
+			let disableAfter = true
140
+			if (this.startDate) {
141
+				// let dateCompBefore = this.dateCompare(this.startDate, fullDate)
142
+				// disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
143
+				disableBefore = this.dateCompare(this.startDate, nowDate)
144
+			}
145
+
146
+			if (this.endDate) {
147
+				// let dateCompAfter = this.dateCompare(fullDate, this.endDate)
148
+				// disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
149
+				disableAfter = this.dateCompare(nowDate, this.endDate)
150
+			}
151
+			let multiples = this.multipleStatus.data
152
+			let checked = false
153
+			let multiplesStatus = -1
154
+			if (this.range) {
155
+				if (multiples) {
156
+					multiplesStatus = multiples.findIndex((item) => {
157
+						return this.dateEqual(item, nowDate)
158
+					})
159
+				}
160
+				if (multiplesStatus !== -1) {
161
+					checked = true
162
+				}
163
+			}
164
+			let data = {
165
+				fullDate: nowDate,
166
+				year: full.year,
167
+				date: i,
168
+				multiple: this.range ? checked : false,
169
+				beforeMultiple: this.dateEqual(this.multipleStatus.before, nowDate),
170
+				afterMultiple: this.dateEqual(this.multipleStatus.after, nowDate),
171
+				month: full.month,
172
+				lunar: this.getlunar(full.year, full.month, i),
173
+				disable: !(disableBefore && disableAfter),
174
+				isDay
175
+			}
176
+			if (info) {
177
+				data.extraInfo = info
178
+			}
179
+
180
+			dateArr.push(data)
181
+		}
182
+		return dateArr
183
+	}
184
+	/**
185
+	 * 获取下月天数
186
+	 */
187
+	_getNextMonthDays(surplus, full) {
188
+		let dateArr = []
189
+		for (let i = 1; i < surplus + 1; i++) {
190
+			dateArr.push({
191
+				date: i,
192
+				month: Number(full.month) + 1,
193
+				lunar: this.getlunar(full.year, Number(full.month) + 1, i),
194
+				disable: true
195
+			})
196
+		}
197
+		return dateArr
198
+	}
199
+
200
+	/**
201
+	 * 获取当前日期详情
202
+	 * @param {Object} date
203
+	 */
204
+	getInfo(date) {
205
+		if (!date) {
206
+			date = new Date()
207
+		}
208
+		const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate)
209
+		return dateInfo
210
+	}
211
+
212
+	/**
213
+	 * 比较时间大小
214
+	 */
215
+	dateCompare(startDate, endDate) {
216
+		// 计算截止时间
217
+		startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
218
+		// 计算详细项的截止时间
219
+		endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
220
+		if (startDate <= endDate) {
221
+			return true
222
+		} else {
223
+			return false
224
+		}
225
+	}
226
+
227
+	/**
228
+	 * 比较时间是否相等
229
+	 */
230
+	dateEqual(before, after) {
231
+		// 计算截止时间
232
+		before = new Date(before.replace('-', '/').replace('-', '/'))
233
+		// 计算详细项的截止时间
234
+		after = new Date(after.replace('-', '/').replace('-', '/'))
235
+		if (before.getTime() - after.getTime() === 0) {
236
+			return true
237
+		} else {
238
+			return false
239
+		}
240
+	}
241
+
242
+
243
+	/**
244
+	 * 获取日期范围内所有日期
245
+	 * @param {Object} begin
246
+	 * @param {Object} end
247
+	 */
248
+	geDateAll(begin, end) {
249
+		var arr = []
250
+		var ab = begin.split('-')
251
+		var ae = end.split('-')
252
+		var db = new Date()
253
+		db.setFullYear(ab[0], ab[1] - 1, ab[2])
254
+		var de = new Date()
255
+		de.setFullYear(ae[0], ae[1] - 1, ae[2])
256
+		var unixDb = db.getTime() - 24 * 60 * 60 * 1000
257
+		var unixDe = de.getTime() - 24 * 60 * 60 * 1000
258
+		for (var k = unixDb; k <= unixDe;) {
259
+			k = k + 24 * 60 * 60 * 1000
260
+			arr.push(this.getDate(new Date(parseInt(k))).fullDate)
261
+		}
262
+		return arr
263
+	}
264
+	/**
265
+	 * 计算阴历日期显示
266
+	 */
267
+	getlunar(year, month, date) {
268
+		return CALENDAR.solar2lunar(year, month, date)
269
+	}
270
+	/**
271
+	 * 设置打点
272
+	 */
273
+	setSelectInfo(data, value) {
274
+		this.selected = value
275
+		this._getWeek(data)
276
+	}
277
+
278
+	/**
279
+	 *  获取多选状态
280
+	 */
281
+	setMultiple(fullDate) {
282
+		let {
283
+			before,
284
+			after
285
+		} = this.multipleStatus
286
+
287
+		if (!this.range) return
288
+		if (before && after) {
289
+			this.multipleStatus.before = ''
290
+			this.multipleStatus.after = ''
291
+			this.multipleStatus.data = []
292
+		} else {
293
+			if (!before) {
294
+				this.multipleStatus.before = fullDate
295
+			} else {
296
+				this.multipleStatus.after = fullDate
297
+				if (this.dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
298
+					this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
299
+				} else {
300
+					this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
301
+				}
302
+			}
303
+		}
304
+		this._getWeek(fullDate)
305
+	}
306
+
307
+	/**
308
+	 * 获取每周数据
309
+	 * @param {Object} dateData
310
+	 */
311
+	_getWeek(dateData) {
312
+		const {
313
+			year,
314
+			month
315
+		} = this.getDate(dateData)
316
+		let firstDay = new Date(year, month - 1, 1).getDay()
317
+		let currentDay = new Date(year, month, 0).getDate()
318
+		let dates = {
319
+			lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天
320
+			currentMonthDys: this._currentMonthDys(currentDay, this.getDate(dateData)), // 本月天数
321
+			nextMonthDays: [], // 下个月开始几天
322
+			weeks: []
323
+		}
324
+		let canlender = []
325
+		const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length)
326
+		dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData))
327
+		canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
328
+		let weeks = {}
329
+		// 拼接数组  上个月开始几天 + 本月天数+ 下个月开始几天
330
+		for (let i = 0; i < canlender.length; i++) {
331
+			if (i % 7 === 0) {
332
+				weeks[parseInt(i / 7)] = new Array(7)
333
+			}
334
+			weeks[parseInt(i / 7)][i % 7] = canlender[i]
335
+		}
336
+		this.canlender = canlender
337
+		this.weeks = weeks
338
+	}
339
+
340
+	//静态方法
341
+	// static init(date) {
342
+	// 	if (!this.instance) {
343
+	// 		this.instance = new Calendar(date);
344
+	// 	}
345
+	// 	return this.instance;
346
+	// }
347
+}
348
+
349
+
350
+export default Calendar

+ 85 - 0
uni_modules/uni-calendar/package.json

@@ -0,0 +1,85 @@
1
+{
2
+  "id": "uni-calendar",
3
+  "displayName": "uni-calendar 日历",
4
+  "version": "1.4.7",
5
+  "description": "日历组件",
6
+  "keywords": [
7
+    "uni-ui",
8
+    "uniui",
9
+    "日历",
10
+    "",
11
+    "打卡",
12
+    "日历选择"
13
+],
14
+  "repository": "https://github.com/dcloudio/uni-ui",
15
+  "engines": {
16
+    "HBuilderX": ""
17
+  },
18
+  "directories": {
19
+    "example": "../../temps/example_temps"
20
+  },
21
+"dcloudext": {
22
+    "sale": {
23
+      "regular": {
24
+        "price": "0.00"
25
+      },
26
+      "sourcecode": {
27
+        "price": "0.00"
28
+      }
29
+    },
30
+    "contact": {
31
+      "qq": ""
32
+    },
33
+    "declaration": {
34
+      "ads": "无",
35
+      "data": "无",
36
+      "permissions": "无"
37
+    },
38
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
39
+    "type": "component-vue"
40
+  },
41
+  "uni_modules": {
42
+    "dependencies": [],
43
+    "encrypt": [],
44
+    "platforms": {
45
+      "cloud": {
46
+        "tcb": "y",
47
+        "aliyun": "y"
48
+      },
49
+      "client": {
50
+        "App": {
51
+          "app-vue": "y",
52
+          "app-nvue": "y"
53
+        },
54
+        "H5-mobile": {
55
+          "Safari": "y",
56
+          "Android Browser": "y",
57
+          "微信浏览器(Android)": "y",
58
+          "QQ浏览器(Android)": "y"
59
+        },
60
+        "H5-pc": {
61
+          "Chrome": "y",
62
+          "IE": "y",
63
+          "Edge": "y",
64
+          "Firefox": "y",
65
+          "Safari": "y"
66
+        },
67
+        "小程序": {
68
+          "微信": "y",
69
+          "阿里": "y",
70
+          "百度": "y",
71
+          "字节跳动": "y",
72
+          "QQ": "y"
73
+        },
74
+        "快应用": {
75
+          "华为": "u",
76
+          "联盟": "u"
77
+        },
78
+        "Vue": {
79
+            "vue2": "y",
80
+            "vue3": "y"
81
+        }
82
+      }
83
+    }
84
+  }
85
+}

+ 103 - 0
uni_modules/uni-calendar/readme.md

@@ -0,0 +1,103 @@
1
+
2
+
3
+## Calendar 日历
4
+> **组件名:uni-calendar**
5
+> 代码块: `uCalendar`
6
+
7
+
8
+日历组件
9
+
10
+> **注意事项**
11
+> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
12
+> - 本组件农历转换使用的js是 [@1900-2100区间内的公历、农历互转](https://github.com/jjonline/calendar.js)  
13
+> - 仅支持自定义组件模式
14
+> - `date`属性传入的应该是一个 String ,如: 2019-06-27 ,而不是 new Date()
15
+> - 通过 `insert` 属性来确定当前的事件是 @change 还是 @confirm 。理应合并为一个事件,但是为了区分模式,现使用两个事件,这里需要注意
16
+> - 弹窗模式下无法阻止后面的元素滚动,如有需要阻止,请在弹窗弹出后,手动设置滚动元素为不可滚动
17
+
18
+
19
+### 安装方式
20
+
21
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
22
+
23
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
24
+
25
+### 基本用法
26
+
27
+在 ``template`` 中使用组件
28
+
29
+```html
30
+<view>
31
+	<uni-calendar 
32
+	:insert="true"
33
+	:lunar="true" 
34
+	:start-date="'2019-3-2'"
35
+	:end-date="'2019-5-20'"
36
+	@change="change"
37
+	 />
38
+</view>
39
+```
40
+
41
+### 通过方法打开日历
42
+
43
+需要设置 `insert` 为 `false`
44
+
45
+```html
46
+<view>
47
+	<uni-calendar 
48
+	ref="calendar"
49
+	:insert="false"
50
+	@confirm="confirm"
51
+	 />
52
+	 <button @click="open">打开日历</button>
53
+</view>
54
+```
55
+
56
+```javascript
57
+
58
+export default {
59
+	data() {
60
+		return {};
61
+	},
62
+	methods: {
63
+		open(){
64
+			this.$refs.calendar.open();
65
+		},
66
+		confirm(e) {
67
+			console.log(e);
68
+		}
69
+	}
70
+};
71
+
72
+```
73
+
74
+
75
+## API
76
+
77
+### Calendar Props
78
+
79
+|  属性名	|    类型	| 默认值| 说明																													|
80
+| 		| 																													|
81
+| date		| String	|-		| 自定义当前时间,默认为今天																							|
82
+| lunar		| Boolean	| false	| 显示农历																												|
83
+| startDate	| String	|-		| 日期选择范围-开始日期																									|
84
+| endDate	| String	|-		| 日期选择范围-结束日期																									|
85
+| range		| Boolean	| false	| 范围选择																												|
86
+| insert	| Boolean	| false	| 插入模式,可选值,ture:插入模式;false:弹窗模式;默认为插入模式														|
87
+|clearDate	|Boolean	|true	|弹窗模式是否清空上次选择内容	|
88
+| selected	| Array		|-		| 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]	|
89
+|showMonth	| Boolean	| true	| 是否显示月份为背景																									|
90
+
91
+### Calendar Events
92
+
93
+|  事件名		| 说明								|返回值|
94
+| 								|		| 									|
95
+| open	| 弹出日历组件,`insert :false` 时生效|- 	|
96
+
97
+
98
+
99
+
100
+
101
+## 组件示例
102
+
103
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/calendar/calendar](https://hellouniapp.dcloud.net.cn/pages/extUI/calendar/calendar)

+ 26 - 0
uni_modules/uni-card/changelog.md

@@ -0,0 +1,26 @@
1
+## 1.3.1(2021-12-20)
2
+- 修复 在vue页面下略缩图显示不正常的bug
3
+## 1.3.0(2021-11-19)
4
+- 重构插槽的用法 ,header 替换为 title 
5
+- 新增 actions 插槽
6
+- 新增 cover 封面图属性和插槽
7
+- 新增 padding 内容默认内边距离
8
+- 新增 margin 卡片默认外边距离
9
+- 新增 spacing 卡片默认内边距
10
+- 新增 shadow 卡片阴影属性
11
+- 取消 mode 属性,可使用组合插槽代替
12
+- 取消 note 属性 ,使用actions插槽代替
13
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
14
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-card](https://uniapp.dcloud.io/component/uniui/uni-card)
15
+## 1.2.1(2021-07-30)
16
+- 优化 vue3下事件警告的问题
17
+## 1.2.0(2021-07-13)
18
+- 组件兼容 vue3,如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
19
+## 1.1.8(2021-07-01)
20
+- 优化 图文卡片无图片加载时,提供占位图标
21
+- 新增 header 插槽,自定义卡片头部( 图文卡片 mode="style" 时,不支持)
22
+- 修复 thumbnail 不存在仍然占位的 bug
23
+## 1.1.7(2021-05-12)
24
+- 新增 组件示例地址
25
+## 1.1.6(2021-02-04)
26
+- 调整为uni_modules目录规范

+ 270 - 0
uni_modules/uni-card/components/uni-card/uni-card.vue

@@ -0,0 +1,270 @@
1
+<template>
2
+	<view class="uni-card" :class="{ 'uni-card--full': isFull, 'uni-card--shadow': isShadow,'uni-card--border':border}"
3
+		:style="{'margin':isFull?0:margin,'padding':spacing,'box-shadow':isShadow?shadow:''}">
4
+		<!-- 封面 -->
5
+		<slot name="cover">
6
+			<view v-if="cover" class="uni-card__cover">
7
+				<image class="uni-card__cover-image" mode="widthFix" @click="onClick('cover')" :src="cover"></image>
8
+			</view>
9
+		</slot>
10
+		<slot name="title">
11
+			<view v-if="title || extra" class="uni-card__header">
12
+				<!-- 卡片标题 -->
13
+				<view class="uni-card__header-box" @click="onClick('title')">
14
+					<view v-if="thumbnail" class="uni-card__header-avatar">
15
+						<image class="uni-card__header-avatar-image" :src="thumbnail" mode="aspectFit" />
16
+					</view>
17
+					<view class="uni-card__header-content">
18
+						<text class="uni-card__header-content-title uni-ellipsis">{{ title }}</text>
19
+						<text v-if="title&&subTitle"
20
+							class="uni-card__header-content-subtitle uni-ellipsis">{{ subTitle }}</text>
21
+					</view>
22
+				</view>
23
+				<view class="uni-card__header-extra" @click="onClick('extra')">
24
+					<text class="uni-card__header-extra-text">{{ extra }}</text>
25
+				</view>
26
+			</view>
27
+		</slot>
28
+		<!-- 卡片内容 -->
29
+		<view class="uni-card__content" :style="{padding:padding}" @click="onClick('content')">
30
+			<slot></slot>
31
+		</view>
32
+		<view class="uni-card__actions" @click="onClick('actions')">
33
+			<slot name="actions"></slot>
34
+		</view>
35
+	</view>
36
+</template>
37
+
38
+<script>
39
+	/**
40
+	 * Card 卡片
41
+	 * @description 卡片视图组件
42
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=22
43
+	 * @property {String} title 标题文字
44
+	 * @property {String} subTitle 副标题
45
+	 * @property {Number} padding 内容内边距
46
+	 * @property {Number} margin 卡片外边距
47
+	 * @property {Number} spacing 卡片内边距
48
+	 * @property {String} extra 标题额外信息
49
+	 * @property {String} cover 封面图(本地路径需要引入)
50
+	 * @property {String} thumbnail 标题左侧缩略图
51
+	 * @property {Boolean} is-full = [true | false] 卡片内容是否通栏,为 true 时将去除padding值
52
+	 * @property {Boolean} is-shadow = [true | false] 卡片内容是否开启阴影
53
+	 * @property {String} shadow 卡片阴影
54
+	 * @property {Boolean} border 卡片边框
55
+	 * @event {Function} click 点击 Card 触发事件
56
+	 */
57
+	export default {
58
+		name: 'UniCard',
59
+		emits: ['click'],
60
+		props: {
61
+			title: {
62
+				type: String,
63
+				default: ''
64
+			},
65
+			subTitle: {
66
+				type: String,
67
+				default: ''
68
+			},
69
+			padding: {
70
+				type: String,
71
+				default: '10px'
72
+			},
73
+			margin: {
74
+				type: String,
75
+				default: '15px'
76
+			},
77
+			spacing: {
78
+				type: String,
79
+				default: '0 10px'
80
+			},
81
+			extra: {
82
+				type: String,
83
+				default: ''
84
+			},
85
+			cover: {
86
+				type: String,
87
+				default: ''
88
+			},
89
+			thumbnail: {
90
+				type: String,
91
+				default: ''
92
+			},
93
+			isFull: {
94
+				// 内容区域是否通栏
95
+				type: Boolean,
96
+				default: false
97
+			},
98
+			isShadow: {
99
+				// 是否开启阴影
100
+				type: Boolean,
101
+				default: true
102
+			},
103
+			shadow: {
104
+				type: String,
105
+				default: '0px 0px 3px 1px rgba(0, 0, 0, 0.08)'
106
+			},
107
+			border: {
108
+				type: Boolean,
109
+				default: true
110
+			}
111
+		},
112
+		methods: {
113
+			onClick(type) {
114
+				this.$emit('click', type)
115
+			}
116
+		}
117
+	}
118
+</script>
119
+
120
+<style lang="scss">
121
+	$uni-border-3: #EBEEF5 !default;
122
+	$uni-shadow-base:0 0px 6px 1px rgba($color: #a5a5a5, $alpha: 0.2) !default;
123
+	$uni-main-color: #3a3a3a !default;
124
+	$uni-base-color: #6a6a6a !default;
125
+	$uni-secondary-color: #909399 !default;
126
+	$uni-spacing-sm: 8px !default;
127
+	$uni-border-color:$uni-border-3;
128
+	$uni-shadow: $uni-shadow-base;
129
+	$uni-card-title: 15px;
130
+	$uni-cart-title-color:$uni-main-color;
131
+	$uni-card-subtitle: 12px;
132
+	$uni-cart-subtitle-color:$uni-secondary-color;
133
+	$uni-card-spacing: 10px;
134
+	$uni-card-content-color: $uni-base-color;
135
+
136
+	.uni-card {
137
+		margin: $uni-card-spacing;
138
+		padding: 0 $uni-spacing-sm;
139
+		border-radius: 4px;
140
+		overflow: hidden;
141
+		font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif;
142
+		background-color: #fff;
143
+		flex: 1;
144
+
145
+		.uni-card__cover {
146
+			position: relative;
147
+			margin-top: $uni-card-spacing;
148
+			flex-direction: row;
149
+			overflow: hidden;
150
+			border-radius: 4px;
151
+			.uni-card__cover-image {
152
+				flex: 1;
153
+				// width: 100%;
154
+				/* #ifndef APP-PLUS */
155
+				vertical-align: middle;
156
+				/* #endif */
157
+			}
158
+		}
159
+
160
+		.uni-card__header {
161
+			display: flex;
162
+			border-bottom: 1px $uni-border-color solid;
163
+			flex-direction: row;
164
+			align-items: center;
165
+			padding: $uni-card-spacing;
166
+			overflow: hidden;
167
+
168
+			.uni-card__header-box {
169
+				/* #ifndef APP-NVUE */
170
+				display: flex;
171
+				/* #endif */
172
+				flex: 1;
173
+				flex-direction: row;
174
+				align-items: center;
175
+				overflow: hidden;
176
+			}
177
+
178
+			.uni-card__header-avatar {
179
+				width: 40px;
180
+				height: 40px;
181
+				overflow: hidden;
182
+				border-radius: 5px;
183
+				margin-right: $uni-card-spacing;
184
+				.uni-card__header-avatar-image {
185
+					flex: 1;
186
+					width: 40px;
187
+					height: 40px;
188
+				}
189
+			}
190
+
191
+			.uni-card__header-content {
192
+				/* #ifndef APP-NVUE */
193
+				display: flex;
194
+				/* #endif */
195
+				flex-direction: column;
196
+				justify-content: center;
197
+				flex: 1;
198
+				// height: 40px;
199
+				overflow: hidden;
200
+
201
+				.uni-card__header-content-title {
202
+					font-size: $uni-card-title;
203
+					color: $uni-cart-title-color;
204
+					// line-height: 22px;
205
+				}
206
+
207
+				.uni-card__header-content-subtitle {
208
+					font-size: $uni-card-subtitle;
209
+					margin-top: 5px;
210
+					color: $uni-cart-subtitle-color;
211
+				}
212
+			}
213
+
214
+			.uni-card__header-extra {
215
+				line-height: 12px;
216
+
217
+				.uni-card__header-extra-text {
218
+					font-size: 12px;
219
+					color: $uni-cart-subtitle-color;
220
+				}
221
+			}
222
+		}
223
+
224
+		.uni-card__content {
225
+			padding: $uni-card-spacing;
226
+			font-size: 14px;
227
+			color: $uni-card-content-color;
228
+			line-height: 22px;
229
+		}
230
+
231
+		.uni-card__actions {
232
+			font-size: 12px;
233
+		}
234
+	}
235
+
236
+	.uni-card--border {
237
+		border: 1px solid $uni-border-color;
238
+	}
239
+
240
+	.uni-card--shadow {
241
+		position: relative;
242
+		/* #ifndef APP-NVUE */
243
+		box-shadow: $uni-shadow;
244
+		/* #endif */
245
+	}
246
+
247
+	.uni-card--full {
248
+		margin: 0;
249
+		border-left-width: 0;
250
+		border-left-width: 0;
251
+		border-radius: 0;
252
+	}
253
+
254
+	/* #ifndef APP-NVUE */
255
+	.uni-card--full:after {
256
+		border-radius: 0;
257
+	}
258
+
259
+	/* #endif */
260
+	.uni-ellipsis {
261
+		/* #ifndef APP-NVUE */
262
+		overflow: hidden;
263
+		white-space: nowrap;
264
+		text-overflow: ellipsis;
265
+		/* #endif */
266
+		/* #ifdef APP-NVUE */
267
+		lines: 1;
268
+		/* #endif */
269
+	}
270
+</style>

+ 90 - 0
uni_modules/uni-card/package.json

@@ -0,0 +1,90 @@
1
+{
2
+  "id": "uni-card",
3
+  "displayName": "uni-card 卡片",
4
+  "version": "1.3.1",
5
+  "description": "Card 组件,提供常见的卡片样式。",
6
+  "keywords": [
7
+    "uni-ui",
8
+    "uniui",
9
+    "card",
10
+    "",
11
+    "卡片"
12
+],
13
+  "repository": "https://github.com/dcloudio/uni-ui",
14
+  "engines": {
15
+    "HBuilderX": ""
16
+  },
17
+  "directories": {
18
+    "example": "../../temps/example_temps"
19
+  },
20
+  "dcloudext": {
21
+    "category": [
22
+      "前端组件",
23
+      "通用组件"
24
+    ],
25
+    "sale": {
26
+      "regular": {
27
+        "price": "0.00"
28
+      },
29
+      "sourcecode": {
30
+        "price": "0.00"
31
+      }
32
+    },
33
+    "contact": {
34
+      "qq": ""
35
+    },
36
+    "declaration": {
37
+      "ads": "无",
38
+      "data": "无",
39
+      "permissions": "无"
40
+    },
41
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
42
+  },
43
+  "uni_modules": {
44
+    "dependencies": [
45
+			"uni-icons",
46
+			"uni-scss"
47
+		],
48
+    "encrypt": [],
49
+    "platforms": {
50
+      "cloud": {
51
+        "tcb": "y",
52
+        "aliyun": "y"
53
+      },
54
+      "client": {
55
+        "App": {
56
+          "app-vue": "y",
57
+          "app-nvue": "y"
58
+        },
59
+        "H5-mobile": {
60
+          "Safari": "y",
61
+          "Android Browser": "y",
62
+          "微信浏览器(Android)": "y",
63
+          "QQ浏览器(Android)": "y"
64
+        },
65
+        "H5-pc": {
66
+          "Chrome": "y",
67
+          "IE": "y",
68
+          "Edge": "y",
69
+          "Firefox": "y",
70
+          "Safari": "y"
71
+        },
72
+        "小程序": {
73
+          "微信": "y",
74
+          "阿里": "y",
75
+          "百度": "y",
76
+          "字节跳动": "y",
77
+          "QQ": "y"
78
+        },
79
+        "快应用": {
80
+          "华为": "u",
81
+          "联盟": "u"
82
+        },
83
+        "Vue": {
84
+            "vue2": "y",
85
+            "vue3": "y"
86
+        }
87
+      }
88
+    }
89
+  }
90
+}

+ 12 - 0
uni_modules/uni-card/readme.md

@@ -0,0 +1,12 @@
1
+
2
+
3
+## Card 卡片
4
+> **组件名:uni-card**
5
+> 代码块: `uCard`
6
+
7
+卡片视图组件。
8
+
9
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-card)
10
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 
11
+
12
+

+ 36 - 0
uni_modules/uni-collapse/changelog.md

@@ -0,0 +1,36 @@
1
+## 1.4.3(2022-01-25)
2
+- 修复 初始化的时候 ,open 属性失效的bug
3
+## 1.4.2(2022-01-21)
4
+- 修复 微信小程序resize后组件收起的bug
5
+## 1.4.1(2021-11-22)
6
+- 修复 vue3中个别scss变量无法找到的问题
7
+## 1.4.0(2021-11-19)
8
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
9
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-collapse](https://uniapp.dcloud.io/component/uniui/uni-collapse)
10
+## 1.3.3(2021-08-17)
11
+- 优化 show-arrow 属性默认为true
12
+## 1.3.2(2021-08-17)
13
+- 新增 show-arrow 属性,控制是否显示右侧箭头
14
+## 1.3.1(2021-07-30)
15
+- 优化 vue3下小程序事件警告的问题
16
+## 1.3.0(2021-07-30)
17
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
18
+## 1.2.2(2021-07-21)
19
+- 修复 由1.2.0版本引起的 change 事件返回 undefined 的Bug
20
+## 1.2.1(2021-07-21)
21
+- 优化 组件示例
22
+## 1.2.0(2021-07-21)
23
+- 新增 组件折叠动画
24
+- 新增 value\v-model 属性 ,动态修改面板折叠状态
25
+- 新增 title 插槽 ,可定义面板标题
26
+- 新增 border 属性 ,显示隐藏面板内容分隔线
27
+- 新增 title-border 属性 ,显示隐藏面板标题分隔线
28
+- 修复 resize 方法失效的Bug
29
+- 修复 change 事件返回参数不正确的Bug
30
+- 优化 H5、App 平台自动更具内容更新高度,无需调用 reszie() 方法
31
+## 1.1.7(2021-05-12)
32
+- 新增 组件示例地址
33
+## 1.1.6(2021-02-05)
34
+- 优化 组件引用关系,通过uni_modules引用组件
35
+## 1.1.5(2021-02-05)
36
+- 调整为uni_modules目录规范

+ 402 - 0
uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue

@@ -0,0 +1,402 @@
1
+<template>
2
+	<view class="uni-collapse-item">
3
+		<!-- onClick(!isOpen) -->
4
+		<view @click="onClick(!isOpen)" class="uni-collapse-item__title"
5
+			:class="{'is-open':isOpen &&titleBorder === 'auto' ,'uni-collapse-item-border':titleBorder !== 'none'}">
6
+			<view class="uni-collapse-item__title-wrap">
7
+				<slot name="title">
8
+					<view class="uni-collapse-item__title-box" :class="{'is-disabled':disabled}">
9
+						<image v-if="thumb" :src="thumb" class="uni-collapse-item__title-img" />
10
+						<text class="uni-collapse-item__title-text">{{ title }}</text>
11
+					</view>
12
+				</slot>
13
+			</view>
14
+			<view v-if="showArrow"
15
+				:class="{ 'uni-collapse-item__title-arrow-active': isOpen, 'uni-collapse-item--animation': showAnimation === true }"
16
+				class="uni-collapse-item__title-arrow">
17
+				<uni-icons :color="disabled?'#ddd':'#bbb'" size="14" type="bottom" />
18
+			</view>
19
+		</view>
20
+		<view class="uni-collapse-item__wrap" :class="{'is--transition':showAnimation}"
21
+			:style="{height: (isOpen?height:0) +'px'}">
22
+			<view :id="elId" ref="collapse--hook" class="uni-collapse-item__wrap-content"
23
+				:class="{open:isheight,'uni-collapse-item--border':border&&isOpen}">
24
+				<slot></slot>
25
+			</view>
26
+		</view>
27
+
28
+	</view>
29
+</template>
30
+
31
+<script>
32
+	// #ifdef APP-NVUE
33
+	const dom = weex.requireModule('dom')
34
+	// #endif
35
+	/**
36
+	 * CollapseItem 折叠面板子组件
37
+	 * @description 折叠面板子组件
38
+	 * @property {String} title 标题文字
39
+	 * @property {String} thumb 标题左侧缩略图
40
+	 * @property {String} name 唯一标志符
41
+	 * @property {Boolean} open = [true|false] 是否展开组件
42
+	 * @property {Boolean} titleBorder = [true|false] 是否显示标题分隔线
43
+	 * @property {Boolean} border = [true|false] 是否显示分隔线
44
+	 * @property {Boolean} disabled = [true|false] 是否展开面板
45
+	 * @property {Boolean} showAnimation = [true|false] 开启动画
46
+	 * @property {Boolean} showArrow = [true|false] 是否显示右侧箭头
47
+	 */
48
+	export default {
49
+		name: 'uniCollapseItem',
50
+		props: {
51
+			// 列表标题
52
+			title: {
53
+				type: String,
54
+				default: ''
55
+			},
56
+			name: {
57
+				type: [Number, String],
58
+				default: ''
59
+			},
60
+			// 是否禁用
61
+			disabled: {
62
+				type: Boolean,
63
+				default: false
64
+			},
65
+			// #ifdef APP-PLUS
66
+			// 是否显示动画,app 端默认不开启动画,卡顿严重
67
+			showAnimation: {
68
+				type: Boolean,
69
+				default: false
70
+			},
71
+			// #endif
72
+			// #ifndef APP-PLUS
73
+			// 是否显示动画
74
+			showAnimation: {
75
+				type: Boolean,
76
+				default: true
77
+			},
78
+			// #endif
79
+			// 是否展开
80
+			open: {
81
+				type: Boolean,
82
+				default: false
83
+			},
84
+			// 缩略图
85
+			thumb: {
86
+				type: String,
87
+				default: ''
88
+			},
89
+			// 标题分隔线显示类型
90
+			titleBorder: {
91
+				type: String,
92
+				default: 'auto'
93
+			},
94
+			border: {
95
+				type: Boolean,
96
+				default: true
97
+			},
98
+			showArrow: {
99
+				type: Boolean,
100
+				default: true
101
+			}
102
+		},
103
+		data() {
104
+			// TODO 随机生生元素ID,解决百度小程序获取同一个元素位置信息的bug
105
+			const elId = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}`
106
+			return {
107
+				isOpen: false,
108
+				isheight: null,
109
+				height: 0,
110
+				elId,
111
+				nameSync: 0
112
+			}
113
+		},
114
+		watch: {
115
+			open(val) {
116
+				this.isOpen = val
117
+				this.onClick(val, 'init')
118
+			}
119
+		},
120
+		updated(e) {
121
+			this.$nextTick(() => {
122
+				this.init(true)
123
+			})
124
+		},
125
+		created() {
126
+			this.collapse = this.getCollapse()
127
+			this.oldHeight = 0
128
+			this.onClick(this.open, 'init')
129
+		},
130
+		// #ifndef VUE3
131
+		// TODO vue2
132
+		destroyed() {
133
+			if (this.__isUnmounted) return
134
+			this.uninstall()
135
+		},
136
+		// #endif
137
+		// #ifdef VUE3
138
+		// TODO vue3
139
+		unmounted() {
140
+			this.__isUnmounted = true
141
+			this.uninstall()
142
+		},
143
+		// #endif
144
+		mounted() {
145
+			if (!this.collapse) return
146
+			if (this.name !== '') {
147
+				this.nameSync = this.name
148
+			} else {
149
+				this.nameSync = this.collapse.childrens.length + ''
150
+			}
151
+			if (this.collapse.names.indexOf(this.nameSync) === -1) {
152
+				this.collapse.names.push(this.nameSync)
153
+			} else {
154
+				console.warn(`name 值 ${this.nameSync} 重复`);
155
+			}
156
+			if (this.collapse.childrens.indexOf(this) === -1) {
157
+				this.collapse.childrens.push(this)
158
+			}
159
+			this.init()
160
+		},
161
+		methods: {
162
+			init(type) {
163
+				// #ifndef APP-NVUE
164
+				this.getCollapseHeight(type)
165
+				// #endif
166
+				// #ifdef APP-NVUE
167
+				this.getNvueHwight(type)
168
+				// #endif
169
+			},
170
+			uninstall() {
171
+				if (this.collapse) {
172
+					this.collapse.childrens.forEach((item, index) => {
173
+						if (item === this) {
174
+							this.collapse.childrens.splice(index, 1)
175
+						}
176
+					})
177
+					this.collapse.names.forEach((item, index) => {
178
+						if (item === this.nameSync) {
179
+							this.collapse.names.splice(index, 1)
180
+						}
181
+					})
182
+				}
183
+			},
184
+			onClick(isOpen, type) {
185
+				if (this.disabled) return
186
+				this.isOpen = isOpen
187
+				if (this.isOpen && this.collapse) {
188
+					this.collapse.setAccordion(this)
189
+				}
190
+				if (type !== 'init') {
191
+					this.collapse.onChange(isOpen, this)
192
+				}
193
+			},
194
+			getCollapseHeight(type, index = 0) {
195
+				const views = uni.createSelectorQuery().in(this)
196
+				views
197
+					.select(`#${this.elId}`)
198
+					.fields({
199
+						size: true
200
+					}, data => {
201
+						// TODO 百度中可能获取不到节点信息 ,需要循环获取
202
+						if (index >= 10) return
203
+						if (!data) {
204
+							index++
205
+							this.getCollapseHeight(false, index)
206
+							return
207
+						}
208
+						// #ifdef APP-NVUE
209
+						this.height = data.height + 1
210
+						// #endif
211
+						// #ifndef APP-NVUE
212
+						this.height = data.height
213
+						// #endif
214
+						this.isheight = true
215
+						if (type) return
216
+						this.onClick(this.isOpen, 'init')
217
+					})
218
+					.exec()
219
+			},
220
+			getNvueHwight(type) {
221
+				const result = dom.getComponentRect(this.$refs['collapse--hook'], option => {
222
+					if (option && option.result && option.size) {
223
+						// #ifdef APP-NVUE
224
+						this.height = option.size.height + 1
225
+						// #endif
226
+						// #ifndef APP-NVUE
227
+						this.height = option.size.height
228
+						// #endif
229
+						this.isheight = true
230
+						if (type) return
231
+						this.onClick(this.open, 'init')
232
+					}
233
+				})
234
+			},
235
+			/**
236
+			 * 获取父元素实例
237
+			 */
238
+			getCollapse(name = 'uniCollapse') {
239
+				let parent = this.$parent;
240
+				let parentName = parent.$options.name;
241
+				while (parentName !== name) {
242
+					parent = parent.$parent;
243
+					if (!parent) return false;
244
+					parentName = parent.$options.name;
245
+				}
246
+				return parent;
247
+			}
248
+		}
249
+	}
250
+</script>
251
+
252
+<style lang="scss">
253
+	.uni-collapse-item {
254
+		/* #ifndef APP-NVUE */
255
+		box-sizing: border-box;
256
+
257
+		/* #endif */
258
+		&__title {
259
+			/* #ifndef APP-NVUE */
260
+			display: flex;
261
+			width: 100%;
262
+			box-sizing: border-box;
263
+			/* #endif */
264
+			flex-direction: row;
265
+			align-items: center;
266
+			transition: border-bottom-color .3s;
267
+
268
+			// transition-property: border-bottom-color;
269
+			// transition-duration: 5s;
270
+			&-wrap {
271
+				width: 100%;
272
+				flex: 1;
273
+
274
+			}
275
+
276
+			&-box {
277
+				padding: 0 15px;
278
+				/* #ifndef APP-NVUE */
279
+				display: flex;
280
+				width: 100%;
281
+				box-sizing: border-box;
282
+				/* #endif */
283
+				flex-direction: row;
284
+				justify-content: space-between;
285
+				align-items: center;
286
+				height: 48px;
287
+				line-height: 48px;
288
+				background-color: #fff;
289
+				color: #303133;
290
+				font-size: 13px;
291
+				font-weight: 500;
292
+				/* #ifdef H5 */
293
+				cursor: pointer;
294
+				outline: none;
295
+
296
+				/* #endif */
297
+				&.is-disabled {
298
+					.uni-collapse-item__title-text {
299
+						color: #999;
300
+					}
301
+				}
302
+
303
+			}
304
+
305
+			&.uni-collapse-item-border {
306
+				border-bottom: 1px solid #ebeef5;
307
+			}
308
+
309
+			&.is-open {
310
+				border-bottom-color: transparent;
311
+			}
312
+
313
+			&-img {
314
+				height: 22px;
315
+				width: 22px;
316
+				margin-right: 10px;
317
+			}
318
+
319
+			&-text {
320
+				flex: 1;
321
+				font-size: 14px;
322
+				/* #ifndef APP-NVUE */
323
+				white-space: nowrap;
324
+				color: inherit;
325
+				/* #endif */
326
+				/* #ifdef APP-NVUE */
327
+				lines: 1;
328
+				/* #endif */
329
+				overflow: hidden;
330
+				text-overflow: ellipsis;
331
+			}
332
+
333
+			&-arrow {
334
+				/* #ifndef APP-NVUE */
335
+				display: flex;
336
+				box-sizing: border-box;
337
+				/* #endif */
338
+				align-items: center;
339
+				justify-content: center;
340
+				width: 20px;
341
+				height: 20px;
342
+				margin-right: 10px;
343
+				transform: rotate(0deg);
344
+
345
+				&-active {
346
+					transform: rotate(-180deg);
347
+				}
348
+			}
349
+
350
+
351
+		}
352
+
353
+		&__wrap {
354
+			/* #ifndef APP-NVUE */
355
+			will-change: height;
356
+			box-sizing: border-box;
357
+			/* #endif */
358
+			background-color: #fff;
359
+			overflow: hidden;
360
+			position: relative;
361
+			height: 0;
362
+
363
+			&.is--transition {
364
+				// transition: all 0.3s;
365
+				transition-property: height, border-bottom-width;
366
+				transition-duration: 0.3s;
367
+				/* #ifndef APP-NVUE */
368
+				will-change: height;
369
+				/* #endif */
370
+			}
371
+
372
+
373
+
374
+			&-content {
375
+				position: absolute;
376
+				font-size: 13px;
377
+				color: #303133;
378
+				// transition: height 0.3s;
379
+				border-bottom-color: transparent;
380
+				border-bottom-style: solid;
381
+				border-bottom-width: 0;
382
+
383
+				&.uni-collapse-item--border {
384
+					border-bottom-width: 1px;
385
+					border-bottom-color: red;
386
+					border-bottom-color: #ebeef5;
387
+				}
388
+
389
+				&.open {
390
+					position: relative;
391
+				}
392
+			}
393
+		}
394
+
395
+		&--animation {
396
+			transition-property: transform;
397
+			transition-duration: 0.3s;
398
+			transition-timing-function: ease;
399
+		}
400
+
401
+	}
402
+</style>

+ 147 - 0
uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue

@@ -0,0 +1,147 @@
1
+<template>
2
+	<view class="uni-collapse">
3
+		<slot />
4
+	</view>
5
+</template>
6
+<script>
7
+	/**
8
+	 * Collapse 折叠面板
9
+	 * @description 展示可以折叠 / 展开的内容区域
10
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=23
11
+	 * @property {String|Array} value 当前激活面板改变时触发(如果是手风琴模式,参数类型为string,否则为array)
12
+	 * @property {Boolean} accordion = [true|false] 是否开启手风琴效果是否开启手风琴效果
13
+	 * @event {Function} change 切换面板时触发,如果是手风琴模式,返回类型为string,否则为array
14
+	 */
15
+	export default {
16
+		name: 'uniCollapse',
17
+		emits:['change','activeItem','input','update:modelValue'],
18
+		props: {
19
+			value: {
20
+				type: [String, Array],
21
+				default: ''
22
+			},
23
+			modelValue: {
24
+				type: [String, Array],
25
+				default: ''
26
+			},
27
+			accordion: {
28
+				// 是否开启手风琴效果
29
+				type: [Boolean, String],
30
+				default: false
31
+			},
32
+		},
33
+		data() {
34
+			return {}
35
+		},
36
+		computed: {
37
+			// TODO 兼容 vue2 和 vue3
38
+			dataValue() {
39
+				let value = (typeof this.value === 'string' && this.value === '') ||
40
+					(Array.isArray(this.value) && this.value.length === 0)
41
+				let modelValue = (typeof this.modelValue === 'string' && this.modelValue === '') ||
42
+					(Array.isArray(this.modelValue) && this.modelValue.length === 0)
43
+				if (value) {
44
+					return this.modelValue
45
+				}
46
+				if (modelValue) {
47
+					return this.value
48
+				}
49
+
50
+				return this.value
51
+			}
52
+		},
53
+		watch: {
54
+			dataValue(val) {
55
+				this.setOpen(val)
56
+			}
57
+		},
58
+		created() {
59
+			this.childrens = []
60
+			this.names = []
61
+		},
62
+		mounted() {
63
+			this.$nextTick(()=>{
64
+				this.setOpen(this.dataValue)
65
+			})
66
+		},
67
+		methods: {
68
+			setOpen(val) {
69
+				let str = typeof val === 'string'
70
+				let arr = Array.isArray(val)
71
+				this.childrens.forEach((vm, index) => {
72
+					if (str) {
73
+						if (val === vm.nameSync) {
74
+							if (!this.accordion) {
75
+								console.warn('accordion 属性为 false ,v-model 类型应该为 array')
76
+								return
77
+							}
78
+							vm.isOpen = true
79
+						}
80
+					}
81
+					if (arr) {
82
+						val.forEach(v => {
83
+							if (v === vm.nameSync) {
84
+								if (this.accordion) {
85
+									console.warn('accordion 属性为 true ,v-model 类型应该为 string')
86
+									return
87
+								}
88
+								vm.isOpen = true
89
+							}
90
+						})
91
+					}
92
+				})
93
+				this.emit(val)
94
+			},
95
+			setAccordion(self) {
96
+				if (!this.accordion) return
97
+				this.childrens.forEach((vm, index) => {
98
+					if (self !== vm) {
99
+						vm.isOpen = false
100
+					}
101
+				})
102
+			},
103
+			resize() {
104
+				this.childrens.forEach((vm, index) => {
105
+					// #ifndef APP-NVUE
106
+					vm.getCollapseHeight()
107
+					// #endif
108
+					// #ifdef APP-NVUE
109
+					vm.getNvueHwight()
110
+					// #endif
111
+				})
112
+			},
113
+			onChange(isOpen, self) {
114
+				let activeItem = []
115
+
116
+				if (this.accordion) {
117
+					activeItem = isOpen ? self.nameSync : ''
118
+				} else {
119
+					this.childrens.forEach((vm, index) => {
120
+						if (vm.isOpen) {
121
+							activeItem.push(vm.nameSync)
122
+						}
123
+					})
124
+				}
125
+				this.$emit('change', activeItem)
126
+				this.emit(activeItem)
127
+			},
128
+			emit(val){
129
+				this.$emit('input', val)
130
+				this.$emit('update:modelValue', val)
131
+			}
132
+		}
133
+	}
134
+</script>
135
+<style lang="scss" >
136
+	.uni-collapse {
137
+		/* #ifndef APP-NVUE */
138
+		width: 100%;
139
+		display: flex;
140
+		/* #endif */
141
+		/* #ifdef APP-NVUE */
142
+		flex: 1;
143
+		/* #endif */
144
+		flex-direction: column;
145
+		background-color: #fff;
146
+	}
147
+</style>

+ 89 - 0
uni_modules/uni-collapse/package.json

@@ -0,0 +1,89 @@
1
+{
2
+  "id": "uni-collapse",
3
+  "displayName": "uni-collapse 折叠面板",
4
+  "version": "1.4.3",
5
+  "description": "Collapse 组件,可以折叠 / 展开的内容区域。",
6
+  "keywords": [
7
+    "uni-ui",
8
+    "折叠",
9
+    "折叠面板",
10
+    "手风琴"
11
+],
12
+  "repository": "https://github.com/dcloudio/uni-ui",
13
+  "engines": {
14
+    "HBuilderX": ""
15
+  },
16
+  "directories": {
17
+    "example": "../../temps/example_temps"
18
+  },
19
+  "dcloudext": {
20
+    "category": [
21
+      "前端组件",
22
+      "通用组件"
23
+    ],
24
+    "sale": {
25
+      "regular": {
26
+        "price": "0.00"
27
+      },
28
+      "sourcecode": {
29
+        "price": "0.00"
30
+      }
31
+    },
32
+    "contact": {
33
+      "qq": ""
34
+    },
35
+    "declaration": {
36
+      "ads": "无",
37
+      "data": "无",
38
+      "permissions": "无"
39
+    },
40
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
41
+  },
42
+  "uni_modules": {
43
+    "dependencies": [
44
+			"uni-scss",
45
+      "uni-icons"
46
+    ],
47
+    "encrypt": [],
48
+    "platforms": {
49
+      "cloud": {
50
+        "tcb": "y",
51
+        "aliyun": "y"
52
+      },
53
+      "client": {
54
+        "App": {
55
+          "app-vue": "y",
56
+          "app-nvue": "y"
57
+        },
58
+        "H5-mobile": {
59
+          "Safari": "y",
60
+          "Android Browser": "y",
61
+          "微信浏览器(Android)": "y",
62
+          "QQ浏览器(Android)": "y"
63
+        },
64
+        "H5-pc": {
65
+          "Chrome": "y",
66
+          "IE": "y",
67
+          "Edge": "y",
68
+          "Firefox": "y",
69
+          "Safari": "y"
70
+        },
71
+        "小程序": {
72
+          "微信": "y",
73
+          "阿里": "y",
74
+          "百度": "y",
75
+          "字节跳动": "y",
76
+          "QQ": "y"
77
+        },
78
+        "快应用": {
79
+          "华为": "u",
80
+          "联盟": "u"
81
+        },
82
+        "Vue": {
83
+            "vue2": "y",
84
+            "vue3": "y"
85
+        }
86
+      }
87
+    }
88
+  }
89
+}

+ 12 - 0
uni_modules/uni-collapse/readme.md

@@ -0,0 +1,12 @@
1
+
2
+
3
+## Collapse 折叠面板
4
+> **组件名:uni-collapse**
5
+> 代码块: `uCollapse`
6
+> 关联组件:`uni-collapse-item`、`uni-icons`。
7
+
8
+
9
+折叠面板用来折叠/显示过长的内容或者是列表。通常是在多内容分类项使用,折叠不重要的内容,显示重要内容。点击可以展开折叠部分。
10
+
11
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-collapse)
12
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 

+ 15 - 0
uni_modules/uni-combox/changelog.md

@@ -0,0 +1,15 @@
1
+## 1.0.1(2021-11-23)
2
+- 优化 label、label-width 属性
3
+## 1.0.0(2021-11-19)
4
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
5
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-combox](https://uniapp.dcloud.io/component/uniui/uni-combox)
6
+## 0.1.0(2021-07-30)
7
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
8
+## 0.0.6(2021-05-12)
9
+- 新增 组件示例地址
10
+## 0.0.5(2021-04-21)
11
+- 优化 添加依赖 uni-icons, 导入后自动下载依赖
12
+## 0.0.4(2021-02-05)
13
+- 优化 组件引用关系,通过uni_modules引用组件
14
+## 0.0.3(2021-02-04)
15
+- 调整为uni_modules目录规范

+ 275 - 0
uni_modules/uni-combox/components/uni-combox/uni-combox.vue

@@ -0,0 +1,275 @@
1
+<template>
2
+	<view class="uni-combox" :class="border ? '' : 'uni-combox__no-border'">
3
+		<view v-if="label" class="uni-combox__label" :style="labelStyle">
4
+			<text>{{label}}</text>
5
+		</view>
6
+		<view class="uni-combox__input-box">
7
+			<input class="uni-combox__input" type="text" :placeholder="placeholder" 
8
+			placeholder-class="uni-combox__input-plac" v-model="inputVal" @input="onInput" @focus="onFocus" 
9
+@blur="onBlur" />
10
+			<uni-icons :type="showSelector? 'top' : 'bottom'" size="14" color="#999" @click="toggleSelector">
11
+			</uni-icons>
12
+		</view>
13
+		<view class="uni-combox__selector" v-if="showSelector">
14
+			<view class="uni-popper__arrow"></view>
15
+			<scroll-view scroll-y="true" class="uni-combox__selector-scroll">
16
+				<view class="uni-combox__selector-empty" v-if="filterCandidatesLength === 0">
17
+					<text>{{emptyTips}}</text>
18
+				</view>
19
+				<view class="uni-combox__selector-item" v-for="(item,index) in filterCandidates" :key="index" 
20
+				@click="onSelectorClick(index)">
21
+					<text>{{item}}</text>
22
+				</view>
23
+			</scroll-view>
24
+		</view>
25
+	</view>
26
+</template>
27
+
28
+<script>
29
+	/**
30
+	 * Combox 组合输入框
31
+	 * @description 组合输入框一般用于既可以输入也可以选择的场景
32
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=1261
33
+	 * @property {String} label 左侧文字
34
+	 * @property {String} labelWidth 左侧内容宽度
35
+	 * @property {String} placeholder 输入框占位符
36
+	 * @property {Array} candidates 候选项列表
37
+	 * @property {String} emptyTips 筛选结果为空时显示的文字
38
+	 * @property {String} value 组合框的值
39
+	 */
40
+	export default {
41
+		name: 'uniCombox',
42
+		emits: ['input', 'update:modelValue'],
43
+		props: {
44
+			border: {
45
+				type: Boolean,
46
+				default: true
47
+			},
48
+			label: {
49
+				type: String,
50
+				default: ''
51
+			},
52
+			labelWidth: {
53
+				type: String,
54
+				default: 'auto'
55
+			},
56
+			placeholder: {
57
+				type: String,
58
+				default: ''
59
+			},
60
+			candidates: {
61
+				type: Array,
62
+				default () {
63
+					return []
64
+				}
65
+			},
66
+			emptyTips: {
67
+				type: String,
68
+				default: '无匹配项'
69
+			},
70
+			// #ifndef VUE3
71
+			value: {
72
+				type: [String, Number],
73
+				default: ''
74
+			},
75
+			// #endif
76
+			// #ifdef VUE3
77
+			modelValue: {
78
+				type: [String, Number],
79
+				default: ''
80
+			},
81
+			// #endif
82
+		},
83
+		data() {
84
+			return {
85
+				showSelector: false,
86
+				inputVal: ''
87
+			}
88
+		},
89
+		computed: {
90
+			labelStyle() {
91
+				if (this.labelWidth === 'auto') {
92
+					return ""
93
+				}
94
+				return `width: ${this.labelWidth}`
95
+			},
96
+			filterCandidates() {
97
+				return this.candidates.filter((item) => {
98
+					return item.toString().indexOf(this.inputVal) > -1
99
+				})
100
+			},
101
+			filterCandidatesLength() {
102
+				return this.filterCandidates.length
103
+			}
104
+		},
105
+		watch: {
106
+			// #ifndef VUE3
107
+			value: {
108
+				handler(newVal) {
109
+					this.inputVal = newVal
110
+				},
111
+				immediate: true
112
+			},
113
+			// #endif
114
+			// #ifdef VUE3
115
+			modelValue: {
116
+				handler(newVal) {
117
+					this.inputVal = newVal
118
+				},
119
+				immediate: true
120
+			},
121
+			// #endif
122
+		},
123
+		methods: {
124
+			toggleSelector() {
125
+				this.showSelector = !this.showSelector
126
+			},
127
+			onFocus() {
128
+				this.showSelector = true
129
+			},
130
+			onBlur() {
131
+				setTimeout(() => {
132
+					this.showSelector = false
133
+				}, 153)
134
+			},
135
+			onSelectorClick(index) {
136
+				this.inputVal = this.filterCandidates[index]
137
+				this.showSelector = false
138
+				this.$emit('input', this.inputVal)
139
+				this.$emit('update:modelValue', this.inputVal)
140
+			},
141
+			onInput() {
142
+				setTimeout(() => {
143
+					this.$emit('input', this.inputVal)
144
+					this.$emit('update:modelValue', this.inputVal)
145
+				})
146
+			}
147
+		}
148
+	}
149
+</script>
150
+
151
+<style lang="scss" >
152
+	.uni-combox {
153
+		font-size: 14px;
154
+		border: 1px solid #DCDFE6;
155
+		border-radius: 4px;
156
+		padding: 6px 10px;
157
+		position: relative;
158
+		/* #ifndef APP-NVUE */
159
+		display: flex;
160
+		/* #endif */
161
+		// height: 40px;
162
+		flex-direction: row;
163
+		align-items: center;
164
+		// border-bottom: solid 1px #DDDDDD;
165
+	}
166
+
167
+	.uni-combox__label {
168
+		font-size: 16px;
169
+		line-height: 22px;
170
+		padding-right: 10px;
171
+		color: #999999;
172
+	}
173
+
174
+	.uni-combox__input-box {
175
+		position: relative;
176
+		/* #ifndef APP-NVUE */
177
+		display: flex;
178
+		/* #endif */
179
+		flex: 1;
180
+		flex-direction: row;
181
+		align-items: center;
182
+	}
183
+
184
+	.uni-combox__input {
185
+		flex: 1;
186
+		font-size: 14px;
187
+		height: 22px;
188
+		line-height: 22px;
189
+	}
190
+
191
+	.uni-combox__input-plac {
192
+		font-size: 14px;
193
+		color: #999;
194
+	}
195
+
196
+	.uni-combox__selector {
197
+		/* #ifndef APP-NVUE */
198
+		box-sizing: border-box;
199
+		/* #endif */
200
+		position: absolute;
201
+		top: calc(100% + 12px);
202
+		left: 0;
203
+		width: 100%;
204
+		background-color: #FFFFFF;
205
+		border: 1px solid #EBEEF5;
206
+		border-radius: 6px;
207
+		box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
208
+		z-index: 2;
209
+		padding: 4px 0;
210
+	}
211
+
212
+	.uni-combox__selector-scroll {
213
+		/* #ifndef APP-NVUE */
214
+		max-height: 200px;
215
+		box-sizing: border-box;
216
+		/* #endif */
217
+	}
218
+
219
+	.uni-combox__selector-empty,
220
+	.uni-combox__selector-item {
221
+		/* #ifndef APP-NVUE */
222
+		display: flex;
223
+		cursor: pointer;
224
+		/* #endif */
225
+		line-height: 36px;
226
+		font-size: 14px;
227
+		text-align: center;
228
+		// border-bottom: solid 1px #DDDDDD;
229
+		padding: 0px 10px;
230
+	}
231
+
232
+	.uni-combox__selector-item:hover {
233
+		background-color: #f9f9f9;
234
+	}
235
+
236
+	.uni-combox__selector-empty:last-child,
237
+	.uni-combox__selector-item:last-child {
238
+		/* #ifndef APP-NVUE */
239
+		border-bottom: none;
240
+		/* #endif */
241
+	}
242
+
243
+	// picker 弹出层通用的指示小三角
244
+	.uni-popper__arrow,
245
+	.uni-popper__arrow::after {
246
+		position: absolute;
247
+		display: block;
248
+		width: 0;
249
+		height: 0;
250
+		border-color: transparent;
251
+		border-style: solid;
252
+		border-width: 6px;
253
+	}
254
+
255
+	.uni-popper__arrow {
256
+		filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
257
+		top: -6px;
258
+		left: 10%;
259
+		margin-right: 3px;
260
+		border-top-width: 0;
261
+		border-bottom-color: #EBEEF5;
262
+	}
263
+
264
+	.uni-popper__arrow::after {
265
+		content: " ";
266
+		top: 1px;
267
+		margin-left: -6px;
268
+		border-top-width: 0;
269
+		border-bottom-color: #fff;
270
+	}
271
+
272
+	.uni-combox__no-border {
273
+		border: none;
274
+	}
275
+</style>

+ 90 - 0
uni_modules/uni-combox/package.json

@@ -0,0 +1,90 @@
1
+{
2
+  "id": "uni-combox",
3
+  "displayName": "uni-combox 组合框",
4
+  "version": "1.0.1",
5
+  "description": "可以选择也可以输入的表单项 ",
6
+  "keywords": [
7
+    "uni-ui",
8
+    "uniui",
9
+    "combox",
10
+    "组合框",
11
+    "select"
12
+],
13
+  "repository": "https://github.com/dcloudio/uni-ui",
14
+  "engines": {
15
+    "HBuilderX": ""
16
+  },
17
+  "directories": {
18
+    "example": "../../temps/example_temps"
19
+  },
20
+  "dcloudext": {
21
+    "category": [
22
+      "前端组件",
23
+      "通用组件"
24
+    ],
25
+    "sale": {
26
+      "regular": {
27
+        "price": "0.00"
28
+      },
29
+      "sourcecode": {
30
+        "price": "0.00"
31
+      }
32
+    },
33
+    "contact": {
34
+      "qq": ""
35
+    },
36
+    "declaration": {
37
+      "ads": "无",
38
+      "data": "无",
39
+      "permissions": "无"
40
+    },
41
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
42
+  },
43
+  "uni_modules": {
44
+    "dependencies": [
45
+			"uni-scss",
46
+			"uni-icons"
47
+		],
48
+    "encrypt": [],
49
+    "platforms": {
50
+      "cloud": {
51
+        "tcb": "y",
52
+        "aliyun": "y"
53
+      },
54
+      "client": {
55
+        "App": {
56
+          "app-vue": "y",
57
+          "app-nvue": "n"
58
+        },
59
+        "H5-mobile": {
60
+          "Safari": "y",
61
+          "Android Browser": "y",
62
+          "微信浏览器(Android)": "y",
63
+          "QQ浏览器(Android)": "y"
64
+        },
65
+        "H5-pc": {
66
+          "Chrome": "y",
67
+          "IE": "y",
68
+          "Edge": "y",
69
+          "Firefox": "y",
70
+          "Safari": "y"
71
+        },
72
+        "小程序": {
73
+          "微信": "y",
74
+          "阿里": "y",
75
+          "百度": "y",
76
+          "字节跳动": "y",
77
+          "QQ": "y"
78
+        },
79
+        "快应用": {
80
+          "华为": "u",
81
+          "联盟": "u"
82
+        },
83
+        "Vue": {
84
+            "vue2": "y",
85
+            "vue3": "y"
86
+        }
87
+      }
88
+    }
89
+  }
90
+}

+ 11 - 0
uni_modules/uni-combox/readme.md

@@ -0,0 +1,11 @@
1
+
2
+
3
+## Combox 组合框
4
+> **组件名:uni-combox**
5
+> 代码块: `uCombox`
6
+
7
+
8
+组合框组件。
9
+
10
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-combox)
11
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 

+ 24 - 0
uni_modules/uni-countdown/changelog.md

@@ -0,0 +1,24 @@
1
+## 1.2.2(2022-01-19)
2
+- 修复 在微信小程序中样式不生效的bug
3
+## 1.2.1(2022-01-18)
4
+- 新增 update 方法 ,在动态更新时间后,刷新组件
5
+## 1.2.0(2021-11-19)
6
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
7
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-countdown](https://uniapp.dcloud.io/component/uniui/uni-countdown)
8
+## 1.1.3(2021-10-18)
9
+- 重构
10
+- 新增 font-size 支持自定义字体大小
11
+## 1.1.2(2021-08-24)
12
+- 新增 支持国际化
13
+## 1.1.1(2021-07-30)
14
+- 优化 vue3下小程序事件警告的问题
15
+## 1.1.0(2021-07-30)
16
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
17
+## 1.0.5(2021-06-18)
18
+- 修复 uni-countdown 重复赋值跳两秒的 bug
19
+## 1.0.4(2021-05-12)
20
+- 新增 组件示例地址
21
+## 1.0.3(2021-05-08)
22
+- 修复 uni-countdown 不能控制倒计时的 bug
23
+## 1.0.2(2021-02-04)
24
+- 调整为uni_modules目录规范

+ 6 - 0
uni_modules/uni-countdown/components/uni-countdown/i18n/en.json

@@ -0,0 +1,6 @@
1
+{
2
+	"uni-countdown.day": "day",
3
+	"uni-countdown.h": "h",
4
+	"uni-countdown.m": "m",
5
+	"uni-countdown.s": "s"
6
+}

+ 8 - 0
uni_modules/uni-countdown/components/uni-countdown/i18n/index.js

@@ -0,0 +1,8 @@
1
+import en from './en.json'
2
+import zhHans from './zh-Hans.json'
3
+import zhHant from './zh-Hant.json'
4
+export default {
5
+	en,
6
+	'zh-Hans': zhHans,
7
+	'zh-Hant': zhHant
8
+}

+ 6 - 0
uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hans.json

@@ -0,0 +1,6 @@
1
+{
2
+	"uni-countdown.day": "天",
3
+	"uni-countdown.h": "时",
4
+	"uni-countdown.m": "分",
5
+	"uni-countdown.s": "秒"
6
+}

+ 6 - 0
uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hant.json

@@ -0,0 +1,6 @@
1
+{
2
+	"uni-countdown.day": "天",
3
+	"uni-countdown.h": "時",
4
+	"uni-countdown.m": "分",
5
+	"uni-countdown.s": "秒"
6
+}

+ 271 - 0
uni_modules/uni-countdown/components/uni-countdown/uni-countdown.vue

@@ -0,0 +1,271 @@
1
+<template>
2
+	<view class="uni-countdown">
3
+		<text v-if="showDay" :style="[timeStyle]" class="uni-countdown__number">{{ d }}</text>
4
+		<text v-if="showDay" :style="[splitorStyle]" class="uni-countdown__splitor">{{dayText}}</text>
5
+		<text :style="[timeStyle]" class="uni-countdown__number">{{ h }}</text>
6
+		<text :style="[splitorStyle]" class="uni-countdown__splitor">{{ showColon ? ':' : hourText }}</text>
7
+		<text :style="[timeStyle]" class="uni-countdown__number">{{ i }}</text>
8
+		<text :style="[splitorStyle]" class="uni-countdown__splitor">{{ showColon ? ':' : minuteText }}</text>
9
+		<text :style="[timeStyle]" class="uni-countdown__number">{{ s }}</text>
10
+		<text v-if="!showColon" :style="[splitorStyle]" class="uni-countdown__splitor">{{secondText}}</text>
11
+	</view>
12
+</template>
13
+<script>
14
+	import {
15
+		initVueI18n
16
+	} from '@dcloudio/uni-i18n'
17
+	import messages from './i18n/index.js'
18
+	const {
19
+		t
20
+	} = initVueI18n(messages)
21
+	/**
22
+	 * Countdown 倒计时
23
+	 * @description 倒计时组件
24
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=25
25
+	 * @property {String} backgroundColor 背景色
26
+	 * @property {String} color 文字颜色
27
+	 * @property {Number} day 天数
28
+	 * @property {Number} hour 小时
29
+	 * @property {Number} minute 分钟
30
+	 * @property {Number} second 秒
31
+	 * @property {Number} timestamp 时间戳
32
+	 * @property {Boolean} showDay = [true|false] 是否显示天数
33
+	 * @property {Boolean} show-colon = [true|false] 是否以冒号为分隔符
34
+	 * @property {String} splitorColor 分割符号颜色
35
+	 * @event {Function} timeup 倒计时时间到触发事件
36
+	 * @example <uni-countdown :day="1" :hour="1" :minute="12" :second="40"></uni-countdown>
37
+	 */
38
+	export default {
39
+		name: 'UniCountdown',
40
+		emits: ['timeup'],
41
+		props: {
42
+			showDay: {
43
+				type: Boolean,
44
+				default: true
45
+			},
46
+			showColon: {
47
+				type: Boolean,
48
+				default: true
49
+			},
50
+			start: {
51
+				type: Boolean,
52
+				default: true
53
+			},
54
+			backgroundColor: {
55
+				type: String,
56
+				default: ''
57
+			},
58
+			color: {
59
+				type: String,
60
+				default: '#333'
61
+			},
62
+			fontSize: {
63
+				type: Number,
64
+				default: 14
65
+			},
66
+			splitorColor: {
67
+				type: String,
68
+				default: '#333'
69
+			},
70
+			day: {
71
+				type: Number,
72
+				default: 0
73
+			},
74
+			hour: {
75
+				type: Number,
76
+				default: 0
77
+			},
78
+			minute: {
79
+				type: Number,
80
+				default: 0
81
+			},
82
+			second: {
83
+				type: Number,
84
+				default: 0
85
+			},
86
+			timestamp: {
87
+				type: Number,
88
+				default: 0
89
+			}
90
+		},
91
+		data() {
92
+			return {
93
+				timer: null,
94
+				syncFlag: false,
95
+				d: '00',
96
+				h: '00',
97
+				i: '00',
98
+				s: '00',
99
+				leftTime: 0,
100
+				seconds: 0
101
+			}
102
+		},
103
+		computed: {
104
+			dayText() {
105
+				return t("uni-countdown.day")
106
+			},
107
+			hourText(val) {
108
+				return t("uni-countdown.h")
109
+			},
110
+			minuteText(val) {
111
+				return t("uni-countdown.m")
112
+			},
113
+			secondText(val) {
114
+				return t("uni-countdown.s")
115
+			},
116
+			timeStyle() {
117
+				const {
118
+					color,
119
+					backgroundColor,
120
+					fontSize
121
+				} = this
122
+				return {
123
+					color,
124
+					backgroundColor,
125
+					fontSize: `${fontSize}px`,
126
+					width: `${fontSize * 22 / 14}px`, // 按字体大小为 14px 时的比例缩放
127
+ 					lineHeight: `${fontSize * 20 / 14}px`,
128
+					borderRadius: `${fontSize * 3 / 14}px`,
129
+				}
130
+			},
131
+			splitorStyle() {
132
+				const { splitorColor, fontSize, backgroundColor } = this
133
+				return {
134
+					color: splitorColor,
135
+					fontSize: `${fontSize * 12 / 14}px`,
136
+					margin: backgroundColor ? `${fontSize * 4 / 14}px` : ''
137
+				}
138
+			}
139
+		},
140
+		watch: {
141
+			day(val) {
142
+				this.changeFlag()
143
+			},
144
+			hour(val) {
145
+				this.changeFlag()
146
+			},
147
+			minute(val) {
148
+				this.changeFlag()
149
+			},
150
+			second(val) {
151
+				this.changeFlag()
152
+			},
153
+			start: {
154
+				immediate: true,
155
+				handler(newVal, oldVal) {
156
+					if (newVal) {
157
+						this.startData();
158
+					} else {
159
+						if (!oldVal) return
160
+						clearInterval(this.timer)
161
+					}
162
+				}
163
+
164
+			}
165
+		},
166
+		created: function(e) {
167
+			this.seconds = this.toSeconds(this.timestamp, this.day, this.hour, this.minute, this.second)
168
+			this.countDown()
169
+		},
170
+		// #ifndef VUE3
171
+		destroyed() {
172
+			clearInterval(this.timer)
173
+		},
174
+		// #endif
175
+		// #ifdef VUE3
176
+		unmounted() {
177
+			clearInterval(this.timer)
178
+		},
179
+		// #endif
180
+		methods: {
181
+			toSeconds(timestamp, day, hours, minutes, seconds) {
182
+				if (timestamp) {
183
+					return timestamp - parseInt(new Date().getTime() / 1000, 10)
184
+				}
185
+				return day * 60 * 60 * 24 + hours * 60 * 60 + minutes * 60 + seconds
186
+			},
187
+			timeUp() {
188
+				clearInterval(this.timer)
189
+				this.$emit('timeup')
190
+			},
191
+			countDown() {
192
+				let seconds = this.seconds
193
+				let [day, hour, minute, second] = [0, 0, 0, 0]
194
+				if (seconds > 0) {
195
+					day = Math.floor(seconds / (60 * 60 * 24))
196
+					hour = Math.floor(seconds / (60 * 60)) - (day * 24)
197
+					minute = Math.floor(seconds / 60) - (day * 24 * 60) - (hour * 60)
198
+					second = Math.floor(seconds) - (day * 24 * 60 * 60) - (hour * 60 * 60) - (minute * 60)
199
+				} else {
200
+					this.timeUp()
201
+				}
202
+				if (day < 10) {
203
+					day = '0' + day
204
+				}
205
+				if (hour < 10) {
206
+					hour = '0' + hour
207
+				}
208
+				if (minute < 10) {
209
+					minute = '0' + minute
210
+				}
211
+				if (second < 10) {
212
+					second = '0' + second
213
+				}
214
+				this.d = day
215
+				this.h = hour
216
+				this.i = minute
217
+				this.s = second
218
+			},
219
+			startData() {
220
+				this.seconds = this.toSeconds(this.timestamp, this.day, this.hour, this.minute, this.second)
221
+				if (this.seconds <= 0) {
222
+					this.seconds = this.toSeconds(0, 0, 0, 0, 0)
223
+					this.countDown()
224
+					return
225
+				}
226
+				clearInterval(this.timer)
227
+				this.countDown()
228
+				this.timer = setInterval(() => {
229
+					this.seconds--
230
+					if (this.seconds < 0) {
231
+						this.timeUp()
232
+						return
233
+					}
234
+					this.countDown()
235
+				}, 1000)
236
+			},
237
+			update(){
238
+				this.startData();
239
+			},
240
+			changeFlag() {
241
+				if (!this.syncFlag) {
242
+					this.seconds = this.toSeconds(this.timestamp, this.day, this.hour, this.minute, this.second)
243
+					this.startData();
244
+					this.syncFlag = true;
245
+				}
246
+			}
247
+		}
248
+	}
249
+</script>
250
+<style lang="scss" scoped>
251
+	$font-size: 14px;
252
+
253
+	.uni-countdown {
254
+		display: flex;
255
+		flex-direction: row;
256
+		justify-content: flex-start;
257
+		align-items: center;
258
+
259
+		&__splitor {
260
+			margin: 0 2px;
261
+			font-size: $font-size;
262
+			color: #333;
263
+		}
264
+
265
+		&__number {
266
+			border-radius: 3px;
267
+			text-align: center;
268
+			font-size: $font-size;
269
+		}
270
+	}
271
+</style>

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

@@ -0,0 +1,86 @@
1
+{
2
+  "id": "uni-countdown",
3
+  "displayName": "uni-countdown 倒计时",
4
+  "version": "1.2.2",
5
+  "description": "CountDown 倒计时组件",
6
+  "keywords": [
7
+    "uni-ui",
8
+    "uniui",
9
+    "countdown",
10
+    "倒计时"
11
+],
12
+  "repository": "https://github.com/dcloudio/uni-ui",
13
+  "engines": {
14
+    "HBuilderX": ""
15
+  },
16
+  "directories": {
17
+    "example": "../../temps/example_temps"
18
+  },
19
+  "dcloudext": {
20
+    "category": [
21
+      "前端组件",
22
+      "通用组件"
23
+    ],
24
+    "sale": {
25
+      "regular": {
26
+        "price": "0.00"
27
+      },
28
+      "sourcecode": {
29
+        "price": "0.00"
30
+      }
31
+    },
32
+    "contact": {
33
+      "qq": ""
34
+    },
35
+    "declaration": {
36
+      "ads": "无",
37
+      "data": "无",
38
+      "permissions": "无"
39
+    },
40
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
41
+  },
42
+  "uni_modules": {
43
+    "dependencies": ["uni-scss"],
44
+    "encrypt": [],
45
+    "platforms": {
46
+      "cloud": {
47
+        "tcb": "y",
48
+        "aliyun": "y"
49
+      },
50
+      "client": {
51
+        "App": {
52
+          "app-vue": "y",
53
+          "app-nvue": "y"
54
+        },
55
+        "H5-mobile": {
56
+          "Safari": "y",
57
+          "Android Browser": "y",
58
+          "微信浏览器(Android)": "y",
59
+          "QQ浏览器(Android)": "y"
60
+        },
61
+        "H5-pc": {
62
+          "Chrome": "y",
63
+          "IE": "y",
64
+          "Edge": "y",
65
+          "Firefox": "y",
66
+          "Safari": "y"
67
+        },
68
+        "小程序": {
69
+          "微信": "y",
70
+          "阿里": "y",
71
+          "百度": "y",
72
+          "字节跳动": "y",
73
+          "QQ": "y"
74
+        },
75
+        "快应用": {
76
+          "华为": "u",
77
+          "联盟": "u"
78
+        },
79
+        "Vue": {
80
+            "vue2": "y",
81
+            "vue3": "y"
82
+        }
83
+      }
84
+    }
85
+  }
86
+}

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

@@ -0,0 +1,10 @@
1
+
2
+
3
+## CountDown 倒计时
4
+> **组件名:uni-countdown**
5
+> 代码块: `uCountDown`
6
+
7
+倒计时组件。
8
+
9
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-countdown)
10
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 

+ 45 - 0
uni_modules/uni-data-checkbox/changelog.md

@@ -0,0 +1,45 @@
1
+## 1.0.3(2022-09-16)
2
+- 可以使用 uni-scss 控制主题色
3
+## 1.0.2(2022-06-30)
4
+- 优化 在 uni-forms 中的依赖注入方式
5
+## 1.0.1(2022-02-07)
6
+- 修复 multiple 为 true 时,v-model 的值为 null 报错的 bug
7
+## 1.0.0(2021-11-19)
8
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
9
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-data-checkbox](https://uniapp.dcloud.io/component/uniui/uni-data-checkbox)
10
+## 0.2.5(2021-08-23)
11
+- 修复 在uni-forms中 modelValue 中不存在当前字段,当前字段必填写也不参与校验的问题
12
+## 0.2.4(2021-08-17)
13
+- 修复 单选 list 模式下 ,icon 为 left 时,选中图标不显示的问题
14
+## 0.2.3(2021-08-11)
15
+- 修复 在 uni-forms 中重置表单,错误信息无法清除的问题
16
+## 0.2.2(2021-07-30)
17
+- 优化 在uni-forms组件,与label不对齐的问题
18
+## 0.2.1(2021-07-27)
19
+- 修复 单选默认值为0不能选中的Bug
20
+## 0.2.0(2021-07-13)
21
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
22
+## 0.1.11(2021-07-06)
23
+- 优化 删除无用日志
24
+## 0.1.10(2021-07-05)
25
+- 修复 由 0.1.9 引起的非 nvue 端图标不显示的问题
26
+## 0.1.9(2021-07-05)
27
+- 修复 nvue 黑框样式问题
28
+## 0.1.8(2021-06-28)
29
+- 修复 selectedTextColor 属性不生效的Bug
30
+## 0.1.7(2021-06-02)
31
+- 新增 map 属性,可以方便映射text/value属性
32
+## 0.1.6(2021-05-26)
33
+- 修复 不关联服务空间的情况下组件报错的Bug
34
+## 0.1.5(2021-05-12)
35
+- 新增 组件示例地址
36
+## 0.1.4(2021-04-09)
37
+- 修复 nvue 下无法选中的问题
38
+## 0.1.3(2021-03-22)
39
+- 新增 disabled属性
40
+## 0.1.2(2021-02-24)
41
+- 优化 默认颜色显示
42
+## 0.1.1(2021-02-24)
43
+- 新增 支持nvue
44
+## 0.1.0(2021-02-18)
45
+- “暂无数据”显示居中

+ 821 - 0
uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue

@@ -0,0 +1,821 @@
1
+<template>
2
+	<view class="uni-data-checklist" :style="{'margin-top':isTop+'px'}">
3
+		<template v-if="!isLocal">
4
+			<view class="uni-data-loading">
5
+				<uni-load-more v-if="!mixinDatacomErrorMessage" status="loading" iconType="snow" :iconSize="18" :content-text="contentText"></uni-load-more>
6
+				<text v-else>{{mixinDatacomErrorMessage}}</text>
7
+			</view>
8
+		</template>
9
+		<template v-else>
10
+			<checkbox-group v-if="multiple" class="checklist-group" :class="{'is-list':mode==='list' || wrap}" @change="chagne">
11
+				<label class="checklist-box" :class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']"
12
+				 :style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index">
13
+					<checkbox class="hidden" hidden :disabled="disabled || !!item.disabled" :value="item[map.value]+''" :checked="item.selected" />
14
+					<view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')" class="checkbox__inner"  :style="item.styleIcon">
15
+						<view class="checkbox__inner-icon"></view>
16
+					</view>
17
+					<view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}">
18
+						<text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text>
19
+						<view v-if="mode === 'list' && icon === 'right'" class="checkobx__list" :style="item.styleBackgroud"></view>
20
+					</view>
21
+				</label>
22
+			</checkbox-group>
23
+			<radio-group v-else class="checklist-group" :class="{'is-list':mode==='list','is-wrap':wrap}" @change="chagne">
24
+				<!-- -->
25
+				<label class="checklist-box" :class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']"
26
+				 :style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index">
27
+					<radio class="hidden" hidden :disabled="disabled || item.disabled" :value="item[map.value]+''" :checked="item.selected" />
28
+					<view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')" class="radio__inner"
29
+					 :style="item.styleBackgroud">
30
+						<view class="radio__inner-icon" :style="item.styleIcon"></view>
31
+					</view>
32
+					<view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}">
33
+						<text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text>
34
+						<view v-if="mode === 'list' && icon === 'right'" :style="item.styleRightIcon" class="checkobx__list"></view>
35
+					</view>
36
+				</label>
37
+			</radio-group>
38
+		</template>
39
+	</view>
40
+</template>
41
+
42
+<script>
43
+	/**
44
+	 * DataChecklist 数据选择器
45
+	 * @description 通过数据渲染 checkbox 和 radio
46
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
47
+	 * @property {String} mode = [default| list | button | tag] 显示模式
48
+	 * @value default  	默认横排模式
49
+	 * @value list		列表模式
50
+	 * @value button	按钮模式
51
+	 * @value tag 		标签模式
52
+	 * @property {Boolean} multiple = [true|false] 是否多选
53
+	 * @property {Array|String|Number} value 默认值
54
+	 * @property {Array} localdata 本地数据 ,格式 [{text:'',value:''}]
55
+	 * @property {Number|String} min 最小选择个数 ,multiple为true时生效
56
+	 * @property {Number|String} max 最大选择个数 ,multiple为true时生效
57
+	 * @property {Boolean} wrap 是否换行显示
58
+	 * @property {String} icon = [left|right]  list 列表模式下icon显示位置
59
+	 * @property {Boolean} selectedColor 选中颜色
60
+	 * @property {Boolean} emptyText 没有数据时显示的文字 ,本地数据无效
61
+	 * @property {Boolean} selectedTextColor 选中文本颜色,如不填写则自动显示
62
+	 * @property {Object} map 字段映射, 默认 map={text:'text',value:'value'}
63
+	 * @value left 左侧显示
64
+	 * @value right 右侧显示
65
+	 * @event {Function} change  选中发生变化触发
66
+	 */
67
+
68
+	export default {
69
+		name: 'uniDataChecklist',
70
+		mixins: [uniCloud.mixinDatacom || {}],
71
+		emits:['input','update:modelValue','change'],
72
+		props: {
73
+			mode: {
74
+				type: String,
75
+				default: 'default'
76
+			},
77
+
78
+			multiple: {
79
+				type: Boolean,
80
+				default: false
81
+			},
82
+			value: {
83
+				type: [Array, String, Number],
84
+				default () {
85
+					return ''
86
+				}
87
+			},
88
+			// TODO vue3
89
+			modelValue: {
90
+				type: [Array, String, Number],
91
+				default() {
92
+					return '';
93
+				}
94
+			},
95
+			localdata: {
96
+				type: Array,
97
+				default () {
98
+					return []
99
+				}
100
+			},
101
+			min: {
102
+				type: [Number, String],
103
+				default: ''
104
+			},
105
+			max: {
106
+				type: [Number, String],
107
+				default: ''
108
+			},
109
+			wrap: {
110
+				type: Boolean,
111
+				default: false
112
+			},
113
+			icon: {
114
+				type: String,
115
+				default: 'left'
116
+			},
117
+			selectedColor: {
118
+				type: String,
119
+				default: ''
120
+			},
121
+			selectedTextColor: {
122
+				type: String,
123
+				default: ''
124
+			},
125
+			emptyText:{
126
+				type: String,
127
+				default: '暂无数据'
128
+			},
129
+			disabled:{
130
+				type: Boolean,
131
+				default: false
132
+			},
133
+			map:{
134
+				type: Object,
135
+				default(){
136
+					return {
137
+						text:'text',
138
+						value:'value'
139
+					}
140
+				}
141
+			}
142
+		},
143
+		watch: {
144
+			localdata: {
145
+				handler(newVal) {
146
+					this.range = newVal
147
+					this.dataList = this.getDataList(this.getSelectedValue(newVal))
148
+				},
149
+				deep: true
150
+			},
151
+			mixinDatacomResData(newVal) {
152
+				this.range = newVal
153
+				this.dataList = this.getDataList(this.getSelectedValue(newVal))
154
+			},
155
+			value(newVal) {
156
+				this.dataList = this.getDataList(newVal)
157
+				// fix by mehaotian is_reset 在 uni-forms 中定义
158
+				// if(!this.is_reset){
159
+				// 	this.is_reset = false
160
+				// 	this.formItem && this.formItem.setValue(newVal)
161
+				// }
162
+			},
163
+			modelValue(newVal) {
164
+				this.dataList = this.getDataList(newVal);
165
+				// if(!this.is_reset){
166
+				// 	this.is_reset = false
167
+				// 	this.formItem && this.formItem.setValue(newVal)
168
+				// }
169
+			}
170
+		},
171
+		data() {
172
+			return {
173
+				dataList: [],
174
+				range: [],
175
+				contentText: {
176
+					contentdown: '查看更多',
177
+					contentrefresh: '加载中',
178
+					contentnomore: '没有更多'
179
+				},
180
+				isLocal:true,
181
+				styles: {
182
+					selectedColor: '#2979ff',
183
+					selectedTextColor: '#666',
184
+				},
185
+				isTop:0
186
+			};
187
+		},
188
+		computed:{
189
+			dataValue(){
190
+				if(this.value === '')return this.modelValue
191
+				if(this.modelValue === '') return this.value
192
+				return this.value
193
+			}
194
+		},
195
+		created() {
196
+			// this.form = this.getForm('uniForms')
197
+			// this.formItem = this.getForm('uniFormsItem')
198
+			// this.formItem && this.formItem.setValue(this.value)
199
+
200
+			// if (this.formItem) {
201
+			// 	this.isTop = 6
202
+			// 	if (this.formItem.name) {
203
+			// 		// 如果存在name添加默认值,否则formData 中不存在这个字段不校验
204
+			// 		if(!this.is_reset){
205
+			// 			this.is_reset = false
206
+			// 			this.formItem.setValue(this.dataValue)
207
+			// 		}
208
+			// 		this.rename = this.formItem.name
209
+			// 		this.form.inputChildrens.push(this)
210
+			// 	}
211
+			// }
212
+
213
+			if (this.localdata && this.localdata.length !== 0) {
214
+				this.isLocal = true
215
+				this.range = this.localdata
216
+				this.dataList = this.getDataList(this.getSelectedValue(this.range))
217
+			} else {
218
+				if (this.collection) {
219
+					this.isLocal = false
220
+					this.loadData()
221
+				}
222
+			}
223
+		},
224
+		methods: {
225
+			loadData() {
226
+				this.mixinDatacomGet().then(res=>{
227
+					this.mixinDatacomResData = res.result.data
228
+					if(this.mixinDatacomResData.length === 0){
229
+						this.isLocal = false
230
+						this.mixinDatacomErrorMessage = this.emptyText
231
+					}else{
232
+						this.isLocal = true
233
+					}
234
+				}).catch(err=>{
235
+					this.mixinDatacomErrorMessage = err.message
236
+				})
237
+			},
238
+			/**
239
+			 * 获取父元素实例
240
+			 */
241
+			getForm(name = 'uniForms') {
242
+				let parent = this.$parent;
243
+				let parentName = parent.$options.name;
244
+				while (parentName !== name) {
245
+					parent = parent.$parent;
246
+					if (!parent) return false
247
+					parentName = parent.$options.name;
248
+				}
249
+				return parent;
250
+			},
251
+			chagne(e) {
252
+				const values = e.detail.value
253
+
254
+				let detail = {
255
+					value: [],
256
+					data: []
257
+				}
258
+
259
+				if (this.multiple) {
260
+					this.range.forEach(item => {
261
+
262
+						if (values.includes(item[this.map.value] + '')) {
263
+							detail.value.push(item[this.map.value])
264
+							detail.data.push(item)
265
+						}
266
+					})
267
+				} else {
268
+					const range = this.range.find(item => (item[this.map.value] + '') === values)
269
+					if (range) {
270
+						detail = {
271
+							value: range[this.map.value],
272
+							data: range
273
+						}
274
+					}
275
+				}
276
+				// this.formItem && this.formItem.setValue(detail.value)
277
+				// TODO 兼容 vue2
278
+				this.$emit('input', detail.value);
279
+				// // TOTO 兼容 vue3
280
+				this.$emit('update:modelValue', detail.value);
281
+				this.$emit('change', {
282
+					detail
283
+				})
284
+				if (this.multiple) {
285
+					// 如果 v-model 没有绑定 ,则走内部逻辑
286
+					// if (this.value.length === 0) {
287
+					this.dataList = this.getDataList(detail.value, true)
288
+					// }
289
+				} else {
290
+					this.dataList = this.getDataList(detail.value)
291
+				}
292
+			},
293
+
294
+			/**
295
+			 * 获取渲染的新数组
296
+			 * @param {Object} value 选中内容
297
+			 */
298
+			getDataList(value) {
299
+				// 解除引用关系,破坏原引用关系,避免污染源数据
300
+				let dataList = JSON.parse(JSON.stringify(this.range))
301
+				let list = []
302
+				if (this.multiple) {
303
+					if (!Array.isArray(value)) {
304
+						value = []
305
+					}
306
+				}
307
+				dataList.forEach((item, index) => {
308
+					item.disabled = item.disable || item.disabled || false
309
+					if (this.multiple) {
310
+						if (value.length > 0) {
311
+							let have = value.find(val => val === item[this.map.value])
312
+							item.selected = have !== undefined
313
+						} else {
314
+							item.selected = false
315
+						}
316
+					} else {
317
+						item.selected = value === item[this.map.value]
318
+					}
319
+
320
+					list.push(item)
321
+				})
322
+				return this.setRange(list)
323
+			},
324
+			/**
325
+			 * 处理最大最小值
326
+			 * @param {Object} list
327
+			 */
328
+			setRange(list) {
329
+				let selectList = list.filter(item => item.selected)
330
+				let min = Number(this.min) || 0
331
+				let max = Number(this.max) || ''
332
+				list.forEach((item, index) => {
333
+					if (this.multiple) {
334
+						if (selectList.length <= min) {
335
+							let have = selectList.find(val => val[this.map.value] === item[this.map.value])
336
+							if (have !== undefined) {
337
+								item.disabled = true
338
+							}
339
+						}
340
+
341
+						if (selectList.length >= max && max !== '') {
342
+							let have = selectList.find(val => val[this.map.value] === item[this.map.value])
343
+							if (have === undefined) {
344
+								item.disabled = true
345
+							}
346
+						}
347
+					}
348
+					this.setStyles(item, index)
349
+					list[index] = item
350
+				})
351
+				return list
352
+			},
353
+			/**
354
+			 * 设置 class
355
+			 * @param {Object} item
356
+			 * @param {Object} index
357
+			 */
358
+			setStyles(item, index) {
359
+				//  设置自定义样式
360
+				item.styleBackgroud = this.setStyleBackgroud(item)
361
+				item.styleIcon = this.setStyleIcon(item)
362
+				item.styleIconText = this.setStyleIconText(item)
363
+				item.styleRightIcon = this.setStyleRightIcon(item)
364
+			},
365
+
366
+			/**
367
+			 * 获取选中值
368
+			 * @param {Object} range
369
+			 */
370
+			getSelectedValue(range) {
371
+				if (!this.multiple) return this.dataValue
372
+				let selectedArr = []
373
+				range.forEach((item) => {
374
+					if (item.selected) {
375
+						selectedArr.push(item[this.map.value])
376
+					}
377
+				})
378
+				return this.dataValue.length > 0 ? this.dataValue : selectedArr
379
+			},
380
+
381
+			/**
382
+			 * 设置背景样式
383
+			 */
384
+			setStyleBackgroud(item) {
385
+				let styles = {}
386
+				let selectedColor = this.selectedColor?this.selectedColor:'#2979ff'
387
+				if (this.selectedColor) {
388
+					if (this.mode !== 'list') {
389
+						styles['border-color'] = item.selected?selectedColor:'#DCDFE6'
390
+					}
391
+					if (this.mode === 'tag') {
392
+						styles['background-color'] = item.selected? selectedColor:'#f5f5f5'
393
+					}
394
+				}
395
+				let classles = ''
396
+				for (let i in styles) {
397
+					classles += `${i}:${styles[i]};`
398
+				}
399
+				return classles
400
+			},
401
+			setStyleIcon(item) {
402
+				let styles = {}
403
+				let classles = ''
404
+				if (this.selectedColor) {
405
+					let selectedColor = this.selectedColor?this.selectedColor:'#2979ff'
406
+					styles['background-color'] = item.selected?selectedColor:'#fff'
407
+					styles['border-color'] = item.selected?selectedColor:'#DCDFE6'
408
+					
409
+					if(!item.selected && item.disabled){
410
+						styles['background-color'] = '#F2F6FC'
411
+						styles['border-color'] = item.selected?selectedColor:'#DCDFE6'
412
+					}
413
+				}
414
+				for (let i in styles) {
415
+					classles += `${i}:${styles[i]};`
416
+				}
417
+				return classles
418
+			},
419
+			setStyleIconText(item) {
420
+				let styles = {}
421
+				let classles = ''
422
+				if (this.selectedColor) {
423
+					let selectedColor = this.selectedColor?this.selectedColor:'#2979ff'
424
+					if (this.mode === 'tag') {
425
+						styles.color = item.selected?(this.selectedTextColor?this.selectedTextColor:'#fff'):'#666'
426
+					} else {
427
+						styles.color = item.selected?(this.selectedTextColor?this.selectedTextColor:selectedColor):'#666'
428
+					}
429
+					if(!item.selected && item.disabled){
430
+						styles.color = '#999'
431
+					}
432
+				}
433
+				for (let i in styles) {
434
+					classles += `${i}:${styles[i]};`
435
+				}
436
+				return classles
437
+			},
438
+			setStyleRightIcon(item) {
439
+				let styles = {}
440
+				let classles = ''
441
+				if (this.mode === 'list') {
442
+					styles['border-color'] = item.selected?this.styles.selectedColor:'#DCDFE6'
443
+				}
444
+				for (let i in styles) {
445
+					classles += `${i}:${styles[i]};`
446
+				}
447
+
448
+				return classles
449
+			}
450
+		}
451
+	}
452
+</script>
453
+
454
+<style lang="scss">
455
+	$uni-primary: #2979ff !default;
456
+	$border-color: #DCDFE6;
457
+	$disable:0.4;
458
+
459
+	@mixin flex {
460
+		/* #ifndef APP-NVUE */
461
+		display: flex;
462
+		/* #endif */
463
+	}
464
+
465
+	.uni-data-loading {
466
+		@include flex;
467
+		flex-direction: row;
468
+		justify-content: center;
469
+		align-items: center;
470
+		height: 36px;
471
+		padding-left: 10px;
472
+		color: #999;
473
+	}
474
+
475
+	.uni-data-checklist {
476
+		position: relative;
477
+		z-index: 0;
478
+		flex: 1;
479
+		// 多选样式
480
+		.checklist-group {
481
+			@include flex;
482
+			flex-direction: row;
483
+			flex-wrap: wrap;
484
+
485
+			&.is-list {
486
+				flex-direction: column;
487
+			}
488
+
489
+			.checklist-box {
490
+				@include flex;
491
+				flex-direction: row;
492
+				align-items: center;
493
+				position: relative;
494
+				margin: 5px 0;
495
+				margin-right: 25px;
496
+
497
+				.hidden {
498
+					position: absolute;
499
+					opacity: 0;
500
+				}
501
+
502
+				// 文字样式
503
+				.checklist-content {
504
+					@include flex;
505
+					flex: 1;
506
+					flex-direction: row;
507
+					align-items: center;
508
+					justify-content: space-between;
509
+					.checklist-text {
510
+						font-size: 14px;
511
+						color: #666;
512
+						margin-left: 5px;
513
+						line-height: 14px;
514
+					}
515
+
516
+					.checkobx__list {
517
+						border-right-width: 1px;
518
+						border-right-color: #007aff;
519
+						border-right-style: solid;
520
+						border-bottom-width:1px;
521
+						border-bottom-color: #007aff;
522
+						border-bottom-style: solid;
523
+						height: 12px;
524
+						width: 6px;
525
+						left: -5px;
526
+						transform-origin: center;
527
+						transform: rotate(45deg);
528
+						opacity: 0;
529
+					}
530
+				}
531
+
532
+				// 多选样式
533
+				.checkbox__inner {
534
+					/* #ifndef APP-NVUE */
535
+					flex-shrink: 0;
536
+					box-sizing: border-box;
537
+					/* #endif */
538
+					position: relative;
539
+					width: 16px;
540
+					height: 16px;
541
+					border: 1px solid $border-color;
542
+					border-radius: 4px;
543
+					background-color: #fff;
544
+					z-index: 1;
545
+					.checkbox__inner-icon {
546
+						position: absolute;
547
+						/* #ifdef APP-NVUE */
548
+						top: 2px;
549
+						/* #endif */
550
+						/* #ifndef APP-NVUE */
551
+						top: 1px;
552
+						/* #endif */
553
+						left: 5px;
554
+						height: 8px;
555
+						width: 4px;
556
+						border-right-width: 1px;
557
+						border-right-color: #fff;
558
+						border-right-style: solid;
559
+						border-bottom-width:1px ;
560
+						border-bottom-color: #fff;
561
+						border-bottom-style: solid;
562
+						opacity: 0;
563
+						transform-origin: center;
564
+						transform: rotate(40deg);
565
+					}
566
+				}
567
+
568
+				// 单选样式
569
+				.radio__inner {
570
+					@include flex;
571
+					/* #ifndef APP-NVUE */
572
+					flex-shrink: 0;
573
+					box-sizing: border-box;
574
+					/* #endif */
575
+					justify-content: center;
576
+					align-items: center;
577
+					position: relative;
578
+					width: 16px;
579
+					height: 16px;
580
+					border: 1px solid $border-color;
581
+					border-radius: 16px;
582
+					background-color: #fff;
583
+					z-index: 1;
584
+
585
+					.radio__inner-icon {
586
+						width: 8px;
587
+						height: 8px;
588
+						border-radius: 10px;
589
+						opacity: 0;
590
+					}
591
+				}
592
+
593
+				// 默认样式
594
+				&.is--default {
595
+
596
+					// 禁用
597
+					&.is-disable {
598
+						/* #ifdef H5 */
599
+						cursor: not-allowed;
600
+						/* #endif */
601
+						.checkbox__inner {
602
+							background-color: #F2F6FC;
603
+							border-color: $border-color;
604
+							/* #ifdef H5 */
605
+							cursor: not-allowed;
606
+							/* #endif */
607
+						}
608
+
609
+						.radio__inner {
610
+							background-color: #F2F6FC;
611
+							border-color: $border-color;
612
+						}
613
+						.checklist-text {
614
+							color: #999;
615
+						}
616
+					}
617
+
618
+					// 选中
619
+					&.is-checked {
620
+						.checkbox__inner {
621
+							border-color: $uni-primary;
622
+							background-color: $uni-primary;
623
+
624
+							.checkbox__inner-icon {
625
+								opacity: 1;
626
+								transform: rotate(45deg);
627
+							}
628
+						}
629
+						.radio__inner {
630
+							border-color: $uni-primary;
631
+							.radio__inner-icon {
632
+								opacity: 1;
633
+								background-color: $uni-primary;
634
+							}
635
+						}
636
+						.checklist-text {
637
+							color: $uni-primary;
638
+						}
639
+						// 选中禁用
640
+						&.is-disable {
641
+							.checkbox__inner {
642
+								opacity: $disable;
643
+							}
644
+
645
+							.checklist-text {
646
+								opacity: $disable;
647
+							}
648
+							.radio__inner {
649
+								opacity: $disable;
650
+							}
651
+						}
652
+					}
653
+				}
654
+
655
+				// 按钮样式
656
+				&.is--button {
657
+					margin-right: 10px;
658
+					padding: 5px 10px;
659
+					border: 1px $border-color solid;
660
+					border-radius: 3px;
661
+					transition: border-color 0.2s;
662
+
663
+					// 禁用
664
+					&.is-disable {
665
+						/* #ifdef H5 */
666
+						cursor: not-allowed;
667
+						/* #endif */
668
+						border: 1px #eee solid;
669
+						opacity: $disable;
670
+						.checkbox__inner {
671
+							background-color: #F2F6FC;
672
+							border-color: $border-color;
673
+							/* #ifdef H5 */
674
+							cursor: not-allowed;
675
+							/* #endif */
676
+						}
677
+						.radio__inner {
678
+							background-color: #F2F6FC;
679
+							border-color: $border-color;
680
+							/* #ifdef H5 */
681
+							cursor: not-allowed;
682
+							/* #endif */
683
+						}
684
+						.checklist-text {
685
+							color: #999;
686
+						}
687
+					}
688
+
689
+					&.is-checked {
690
+						border-color: $uni-primary;
691
+						.checkbox__inner {
692
+							border-color: $uni-primary;
693
+							background-color: $uni-primary;
694
+							.checkbox__inner-icon {
695
+								opacity: 1;
696
+								transform: rotate(45deg);
697
+							}
698
+						}
699
+
700
+						.radio__inner {
701
+							border-color: $uni-primary;
702
+
703
+							.radio__inner-icon {
704
+								opacity: 1;
705
+								background-color: $uni-primary;
706
+							}
707
+						}
708
+
709
+						.checklist-text {
710
+							color: $uni-primary;
711
+						}
712
+
713
+						// 选中禁用
714
+						&.is-disable {
715
+							opacity: $disable;
716
+						}
717
+					}
718
+				}
719
+
720
+				// 标签样式
721
+				&.is--tag {
722
+					margin-right: 10px;
723
+					padding: 5px 10px;
724
+					border: 1px $border-color solid;
725
+					border-radius: 3px;
726
+					background-color: #f5f5f5;
727
+
728
+					.checklist-text {
729
+						margin: 0;
730
+						color: #666;
731
+					}
732
+
733
+					// 禁用
734
+					&.is-disable {
735
+						/* #ifdef H5 */
736
+						cursor: not-allowed;
737
+						/* #endif */
738
+						opacity: $disable;
739
+					}
740
+
741
+					&.is-checked {
742
+						background-color: $uni-primary;
743
+						border-color: $uni-primary;
744
+
745
+						.checklist-text {
746
+							color: #fff;
747
+						}
748
+					}
749
+				}
750
+				// 列表样式
751
+				&.is--list {
752
+					/* #ifndef APP-NVUE */
753
+					display: flex;
754
+					/* #endif */
755
+					padding: 10px 15px;
756
+					padding-left: 0;
757
+					margin: 0;
758
+
759
+					&.is-list-border {
760
+						border-top: 1px #eee solid;
761
+					}
762
+
763
+					// 禁用
764
+					&.is-disable {
765
+						/* #ifdef H5 */
766
+						cursor: not-allowed;
767
+						/* #endif */
768
+						.checkbox__inner {
769
+							background-color: #F2F6FC;
770
+							border-color: $border-color;
771
+							/* #ifdef H5 */
772
+							cursor: not-allowed;
773
+							/* #endif */
774
+						}
775
+						.checklist-text {
776
+							color: #999;
777
+						}
778
+					}
779
+
780
+					&.is-checked {
781
+						.checkbox__inner {
782
+							border-color: $uni-primary;
783
+							background-color: $uni-primary;
784
+
785
+							.checkbox__inner-icon {
786
+								opacity: 1;
787
+								transform: rotate(45deg);
788
+							}
789
+						}
790
+						.radio__inner {
791
+							.radio__inner-icon {
792
+								opacity: 1;
793
+							}
794
+						}
795
+						.checklist-text {
796
+							color: $uni-primary;
797
+						}
798
+
799
+						.checklist-content {
800
+							.checkobx__list {
801
+								opacity: 1;
802
+								border-color: $uni-primary;
803
+							}
804
+						}
805
+
806
+						// 选中禁用
807
+						&.is-disable {
808
+							.checkbox__inner {
809
+								opacity: $disable;
810
+							}
811
+
812
+							.checklist-text {
813
+								opacity: $disable;
814
+							}
815
+						}
816
+					}
817
+				}
818
+			}
819
+		}
820
+	}
821
+</style>

+ 84 - 0
uni_modules/uni-data-checkbox/package.json

@@ -0,0 +1,84 @@
1
+{
2
+  "id": "uni-data-checkbox",
3
+  "displayName": "uni-data-checkbox 数据选择器",
4
+  "version": "1.0.3",
5
+  "description": "通过数据驱动的单选框和复选框",
6
+  "keywords": [
7
+    "uni-ui",
8
+    "checkbox",
9
+    "单选",
10
+    "多选",
11
+    "单选多选"
12
+],
13
+  "repository": "https://github.com/dcloudio/uni-ui",
14
+  "engines": {
15
+    "HBuilderX": "^3.1.1"
16
+  },
17
+  "directories": {
18
+    "example": "../../temps/example_temps"
19
+  },
20
+"dcloudext": {
21
+    "sale": {
22
+      "regular": {
23
+        "price": "0.00"
24
+      },
25
+      "sourcecode": {
26
+        "price": "0.00"
27
+      }
28
+    },
29
+    "contact": {
30
+      "qq": ""
31
+    },
32
+    "declaration": {
33
+      "ads": "无",
34
+      "data": "无",
35
+      "permissions": "无"
36
+    },
37
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
38
+    "type": "component-vue"
39
+  },
40
+  "uni_modules": {
41
+    "dependencies": ["uni-load-more","uni-scss"],
42
+    "encrypt": [],
43
+    "platforms": {
44
+      "cloud": {
45
+        "tcb": "y",
46
+        "aliyun": "y"
47
+      },
48
+      "client": {
49
+        "App": {
50
+          "app-vue": "y",
51
+          "app-nvue": "y"
52
+        },
53
+        "H5-mobile": {
54
+          "Safari": "y",
55
+          "Android Browser": "y",
56
+          "微信浏览器(Android)": "y",
57
+          "QQ浏览器(Android)": "y"
58
+        },
59
+        "H5-pc": {
60
+          "Chrome": "y",
61
+          "IE": "y",
62
+          "Edge": "y",
63
+          "Firefox": "y",
64
+          "Safari": "y"
65
+        },
66
+        "小程序": {
67
+          "微信": "y",
68
+          "阿里": "y",
69
+          "百度": "y",
70
+          "字节跳动": "y",
71
+          "QQ": "y"
72
+        },
73
+        "快应用": {
74
+          "华为": "u",
75
+          "联盟": "u"
76
+        },
77
+        "Vue": {
78
+            "vue2": "y",
79
+            "vue3": "y"
80
+        }
81
+      }
82
+    }
83
+  }
84
+}

+ 18 - 0
uni_modules/uni-data-checkbox/readme.md

@@ -0,0 +1,18 @@
1
+
2
+
3
+## DataCheckbox 数据驱动的单选复选框
4
+> **组件名:uni-data-checkbox**
5
+> 代码块: `uDataCheckbox`
6
+
7
+
8
+本组件是基于uni-app基础组件checkbox的封装。本组件要解决问题包括:
9
+
10
+1. 数据绑定型组件:给本组件绑定一个data,会自动渲染一组候选内容。再以往,开发者需要编写不少代码实现类似功能
11
+2. 自动的表单校验:组件绑定了data,且符合[uni-forms](https://ext.dcloud.net.cn/plugin?id=2773)组件的表单校验规范,搭配使用会自动实现表单校验
12
+3. 本组件合并了单选多选
13
+4. 本组件有若干风格选择,如普通的单选多选框、并列button风格、tag风格。开发者可以快速选择需要的风格。但作为一个封装组件,样式代码虽然不用自己写了,却会牺牲一定的样式自定义性
14
+
15
+在uniCloud开发中,`DB Schema`中配置了enum枚举等类型后,在web控制台的[自动生成表单](https://uniapp.dcloud.io/uniCloud/schema?id=autocode)功能中,会自动生成``uni-data-checkbox``组件并绑定好data
16
+
17
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-checkbox)
18
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 

+ 66 - 0
uni_modules/uni-data-picker/changelog.md

@@ -0,0 +1,66 @@
1
+## 1.0.8(2022-09-16)
2
+- 可以使用 uni-scss 控制主题色
3
+## 1.0.7(2022-07-06)
4
+- 优化 pc端图标位置不正确的问题
5
+## 1.0.6(2022-07-05)
6
+- 优化 显示样式
7
+## 1.0.5(2022-07-04)
8
+- 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug
9
+## 1.0.4(2022-04-19)
10
+- 修复 字节小程序 本地数据无法选择下一级的Bug
11
+## 1.0.3(2022-02-25)
12
+- 修复 nvue 不支持的 v-show 的 bug
13
+## 1.0.2(2022-02-25)
14
+- 修复 条件编译 nvue 不支持的 css 样式
15
+## 1.0.1(2021-11-23)
16
+- 修复 由上个版本引发的map、v-model等属性不生效的bug
17
+## 1.0.0(2021-11-19)
18
+- 优化 组件 UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
19
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-data-picker](https://uniapp.dcloud.io/component/uniui/uni-data-picker)
20
+## 0.4.9(2021-10-28)
21
+- 修复 VUE2 v-model 概率无效的 bug
22
+## 0.4.8(2021-10-27)
23
+- 修复 v-model 概率无效的 bug
24
+## 0.4.7(2021-10-25)
25
+- 新增 属性 spaceInfo 服务空间配置 HBuilderX 3.2.11+
26
+- 修复 树型 uniCloud 数据类型为 int 时报错的 bug
27
+## 0.4.6(2021-10-19)
28
+- 修复 非 VUE3 v-model 为 0 时无法选中的 bug
29
+## 0.4.5(2021-09-26)
30
+- 新增 清除已选项的功能(通过 clearIcon 属性配置是否显示按钮),同时提供 clear 方法以供调用,二者等效
31
+- 修复 readonly 为 true 时报错的 bug
32
+## 0.4.4(2021-09-26)
33
+- 修复 上一版本造成的 map 属性失效的 bug
34
+- 新增 ellipsis 属性,支持配置 tab 选项长度过长时是否自动省略
35
+## 0.4.3(2021-09-24)
36
+- 修复 某些情况下级联未触发的 bug
37
+## 0.4.2(2021-09-23)
38
+- 新增 提供 show 和 hide 方法,开发者可以通过 ref 调用
39
+- 新增 选项内容过长自动添加省略号
40
+## 0.4.1(2021-09-15)
41
+- 新增 map 属性 字段映射,将 text/value 映射到数据中的其他字段
42
+## 0.4.0(2021-07-13)
43
+- 组件兼容 vue3,如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
44
+## 0.3.5(2021-06-04)
45
+- 修复 无法加载云端数据的问题
46
+## 0.3.4(2021-05-28)
47
+- 修复 v-model 无效问题
48
+- 修复 loaddata 为空数据组时加载时间过长问题
49
+- 修复 上个版本引出的本地数据无法选择带有 children 的 2 级节点
50
+## 0.3.3(2021-05-12)
51
+- 新增 组件示例地址
52
+## 0.3.2(2021-04-22)
53
+- 修复 非树形数据有 where 属性查询报错的问题
54
+## 0.3.1(2021-04-15)
55
+- 修复 本地数据概率无法回显时问题
56
+## 0.3.0(2021-04-07)
57
+- 新增 支持云端非树形表结构数据
58
+- 修复 根节点 parent_field 字段等于 null 时选择界面错乱问题
59
+## 0.2.0(2021-03-15)
60
+- 修复 nodeclick、popupopened、popupclosed 事件无法触发的问题
61
+## 0.1.9(2021-03-09)
62
+- 修复 微信小程序某些情况下无法选择的问题
63
+## 0.1.8(2021-02-05)
64
+- 优化 部分样式在 nvue 上的兼容表现
65
+## 0.1.7(2021-02-05)
66
+- 调整为 uni_modules 目录规范

+ 45 - 0
uni_modules/uni-data-picker/components/uni-data-picker/keypress.js

@@ -0,0 +1,45 @@
1
+// #ifdef H5
2
+export default {
3
+  name: 'Keypress',
4
+  props: {
5
+    disable: {
6
+      type: Boolean,
7
+      default: false
8
+    }
9
+  },
10
+  mounted () {
11
+    const keyNames = {
12
+      esc: ['Esc', 'Escape'],
13
+      tab: 'Tab',
14
+      enter: 'Enter',
15
+      space: [' ', 'Spacebar'],
16
+      up: ['Up', 'ArrowUp'],
17
+      left: ['Left', 'ArrowLeft'],
18
+      right: ['Right', 'ArrowRight'],
19
+      down: ['Down', 'ArrowDown'],
20
+      delete: ['Backspace', 'Delete', 'Del']
21
+    }
22
+    const listener = ($event) => {
23
+      if (this.disable) {
24
+        return
25
+      }
26
+      const keyName = Object.keys(keyNames).find(key => {
27
+        const keyName = $event.key
28
+        const value = keyNames[key]
29
+        return value === keyName || (Array.isArray(value) && value.includes(keyName))
30
+      })
31
+      if (keyName) {
32
+        // 避免和其他按键事件冲突
33
+        setTimeout(() => {
34
+          this.$emit(keyName, {})
35
+        }, 0)
36
+      }
37
+    }
38
+    document.addEventListener('keyup', listener)
39
+    this.$once('hook:beforeDestroy', () => {
40
+      document.removeEventListener('keyup', listener)
41
+    })
42
+  },
43
+	render: () => {}
44
+}
45
+// #endif

+ 547 - 0
uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue

@@ -0,0 +1,547 @@
1
+<template>
2
+  <view class="uni-data-tree">
3
+    <view class="uni-data-tree-input" @click="handleInput">
4
+      <slot :options="options" :data="inputSelected" :error="errorMessage">
5
+        <view class="input-value" :class="{'input-value-border': border}">
6
+          <text v-if="errorMessage" class="selected-area error-text">{{errorMessage}}</text>
7
+          <view v-else-if="loading && !isOpened" class="selected-area">
8
+            <uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
9
+          </view>
10
+          <scroll-view v-else-if="inputSelected.length" class="selected-area" scroll-x="true">
11
+            <view class="selected-list">
12
+              <view class="selected-item" v-for="(item,index) in inputSelected" :key="index">
13
+                <text class="text-color">{{item.text}}</text><text v-if="index<inputSelected.length-1"
14
+                  class="input-split-line">{{split}}</text>
15
+              </view>
16
+            </view>
17
+          </scroll-view>
18
+          <text v-else class="selected-area placeholder">{{placeholder}}</text>
19
+          <view v-if="clearIcon && !readonly && inputSelected.length" class="icon-clear" @click.stop="clear">
20
+            <uni-icons type="clear" color="#c0c4cc" size="24"></uni-icons>
21
+          </view>
22
+          <view class="arrow-area" v-if="(!clearIcon || !inputSelected.length) && !readonly ">
23
+            <view class="input-arrow"></view>
24
+          </view>
25
+        </view>
26
+      </slot>
27
+    </view>
28
+    <view class="uni-data-tree-cover" v-if="isOpened" @click="handleClose"></view>
29
+    <view class="uni-data-tree-dialog" v-if="isOpened">
30
+      <view class="uni-popper__arrow"></view>
31
+      <view class="dialog-caption">
32
+        <view class="title-area">
33
+          <text class="dialog-title">{{popupTitle}}</text>
34
+        </view>
35
+        <view class="dialog-close" @click="handleClose">
36
+          <view class="dialog-close-plus" data-id="close"></view>
37
+          <view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
38
+        </view>
39
+      </view>
40
+      <data-picker-view class="picker-view" ref="pickerView" v-model="dataValue" :localdata="localdata"
41
+        :preload="preload" :collection="collection" :field="field" :orderby="orderby" :where="where"
42
+        :step-searh="stepSearh" :self-field="selfField" :parent-field="parentField" :managed-mode="true" :map="map"
43
+        :ellipsis="ellipsis" @change="onchange" @datachange="ondatachange" @nodeclick="onnodeclick">
44
+      </data-picker-view>
45
+    </view>
46
+  </view>
47
+</template>
48
+
49
+<script>
50
+  import dataPicker from "../uni-data-pickerview/uni-data-picker.js"
51
+  import DataPickerView from "../uni-data-pickerview/uni-data-pickerview.vue"
52
+
53
+  /**
54
+   * DataPicker 级联选择
55
+   * @description 支持单列、和多列级联选择。列数没有限制,如果屏幕显示不全,顶部tab区域会左右滚动。
56
+   * @tutorial https://ext.dcloud.net.cn/plugin?id=3796
57
+   * @property {String} popup-title 弹出窗口标题
58
+   * @property {Array} localdata 本地数据,参考
59
+   * @property {Boolean} border = [true|false] 是否有边框
60
+   * @property {Boolean} readonly = [true|false] 是否仅读
61
+   * @property {Boolean} preload = [true|false] 是否预加载数据
62
+   * @value true 开启预加载数据,点击弹出窗口后显示已加载数据
63
+   * @value false 关闭预加载数据,点击弹出窗口后开始加载数据
64
+   * @property {Boolean} step-searh = [true|false] 是否分布查询
65
+   * @value true 启用分布查询,仅查询当前选中节点
66
+   * @value false 关闭分布查询,一次查询出所有数据
67
+   * @property {String|DBFieldString} self-field 分布查询当前字段名称
68
+   * @property {String|DBFieldString} parent-field 分布查询父字段名称
69
+   * @property {String|DBCollectionString} collection 表名
70
+   * @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
71
+   * @property {String} orderby 排序字段及正序倒叙设置
72
+   * @property {String|JQLString} where 查询条件
73
+   * @event {Function} popupshow 弹出的选择窗口打开时触发此事件
74
+   * @event {Function} popuphide 弹出的选择窗口关闭时触发此事件
75
+   */
76
+  export default {
77
+    name: 'UniDataPicker',
78
+    emits: ['popupopened', 'popupclosed', 'nodeclick', 'input', 'change', 'update:modelValue'],
79
+    mixins: [dataPicker],
80
+    components: {
81
+      DataPickerView
82
+    },
83
+    props: {
84
+      options: {
85
+        type: [Object, Array],
86
+        default () {
87
+          return {}
88
+        }
89
+      },
90
+      popupTitle: {
91
+        type: String,
92
+        default: '请选择'
93
+      },
94
+      placeholder: {
95
+        type: String,
96
+        default: '请选择'
97
+      },
98
+      heightMobile: {
99
+        type: String,
100
+        default: ''
101
+      },
102
+      readonly: {
103
+        type: Boolean,
104
+        default: false
105
+      },
106
+      clearIcon: {
107
+        type: Boolean,
108
+        default: true
109
+      },
110
+      border: {
111
+        type: Boolean,
112
+        default: true
113
+      },
114
+      split: {
115
+        type: String,
116
+        default: '/'
117
+      },
118
+      ellipsis: {
119
+        type: Boolean,
120
+        default: true
121
+      }
122
+    },
123
+    data() {
124
+      return {
125
+        isOpened: false,
126
+        inputSelected: []
127
+      }
128
+    },
129
+    created() {
130
+      this.$nextTick(() => {
131
+        this.load();
132
+      })
133
+    },
134
+    methods: {
135
+      clear() {
136
+        this.modelValue = null;
137
+        this._dispatchEvent([]);
138
+      },
139
+      onPropsChange() {
140
+        this._treeData = [];
141
+        this.selectedIndex = 0;
142
+
143
+        this.load();
144
+      },
145
+      load() {
146
+        if (this.readonly) {
147
+          this._processReadonly(this.localdata, this.dataValue);
148
+          return;
149
+        }
150
+
151
+        if (!this.hasValue) {
152
+          return;
153
+        }
154
+
155
+        // 回显本地数据
156
+        if (this.isLocalData) {
157
+          this.loadData();
158
+          this.inputSelected = this.selected.slice(0);
159
+        } else if (this.isCloudDataList || this.isCloudDataTree) { // 回显 Cloud 数据
160
+          this.loading = true;
161
+          this.getCloudDataValue().then((res) => {
162
+            this.loading = false;
163
+            this.inputSelected = res;
164
+          }).catch((err) => {
165
+            this.loading = false;
166
+            this.errorMessage = err;
167
+          })
168
+        }
169
+      },
170
+      show() {
171
+        this.isOpened = true
172
+        setTimeout(() => {
173
+          this.$refs.pickerView.updateData({
174
+            treeData: this._treeData,
175
+            selected: this.selected,
176
+            selectedIndex: this.selectedIndex
177
+          })
178
+        }, 200)
179
+        this.$emit('popupopened')
180
+      },
181
+      hide() {
182
+        this.isOpened = false
183
+        this.$emit('popupclosed')
184
+      },
185
+      handleInput() {
186
+        if (this.readonly) {
187
+          return
188
+        }
189
+        this.show()
190
+      },
191
+      handleClose(e) {
192
+        this.hide()
193
+      },
194
+      onnodeclick(e) {
195
+        this.$emit('nodeclick', e)
196
+      },
197
+      ondatachange(e) {
198
+        this._treeData = this.$refs.pickerView._treeData
199
+      },
200
+      onchange(e) {
201
+        this.hide()
202
+        this.$nextTick(() => {
203
+          this.inputSelected = e;
204
+        })
205
+        this._dispatchEvent(e)
206
+      },
207
+      _processReadonly(dataList, value) {
208
+        var isTree = dataList.findIndex((item) => {
209
+          return item.children
210
+        })
211
+        if (isTree > -1) {
212
+          let inputValue
213
+          if (Array.isArray(value)) {
214
+            inputValue = value[value.length - 1]
215
+            if (typeof inputValue === 'object' && inputValue.value) {
216
+              inputValue = inputValue.value
217
+            }
218
+          } else {
219
+            inputValue = value
220
+          }
221
+          this.inputSelected = this._findNodePath(inputValue, this.localdata)
222
+          return
223
+        }
224
+
225
+        if (!this.hasValue) {
226
+          this.inputSelected = []
227
+          return
228
+        }
229
+
230
+        let result = []
231
+        for (let i = 0; i < value.length; i++) {
232
+          var val = value[i]
233
+          var item = dataList.find((v) => {
234
+            return v.value == val
235
+          })
236
+          if (item) {
237
+            result.push(item)
238
+          }
239
+        }
240
+        if (result.length) {
241
+          this.inputSelected = result
242
+        }
243
+      },
244
+      _filterForArray(data, valueArray) {
245
+        var result = []
246
+        for (let i = 0; i < valueArray.length; i++) {
247
+          var value = valueArray[i]
248
+          var found = data.find((item) => {
249
+            return item.value == value
250
+          })
251
+          if (found) {
252
+            result.push(found)
253
+          }
254
+        }
255
+        return result
256
+      },
257
+      _dispatchEvent(selected) {
258
+        let item = {}
259
+        if (selected.length) {
260
+          var value = new Array(selected.length)
261
+          for (var i = 0; i < selected.length; i++) {
262
+            value[i] = selected[i].value
263
+          }
264
+          item = selected[selected.length - 1]
265
+        } else {
266
+          item.value = ''
267
+        }
268
+        if (this.formItem) {
269
+          this.formItem.setValue(item.value)
270
+        }
271
+
272
+        this.$emit('input', item.value)
273
+        this.$emit('update:modelValue', item.value)
274
+        this.$emit('change', {
275
+          detail: {
276
+            value: selected
277
+          }
278
+        })
279
+      }
280
+    }
281
+  }
282
+</script>
283
+
284
+<style>
285
+  .uni-data-tree {
286
+    flex: 1;
287
+    position: relative;
288
+    font-size: 14px;
289
+  }
290
+
291
+  .error-text {
292
+    color: #DD524D;
293
+  }
294
+
295
+  .input-value {
296
+    /* #ifndef APP-NVUE */
297
+    display: flex;
298
+    /* #endif */
299
+    flex-direction: row;
300
+    align-items: center;
301
+    flex-wrap: nowrap;
302
+    font-size: 14px;
303
+    /* line-height: 35px; */
304
+    padding: 0 10px;
305
+    padding-right: 5px;
306
+    overflow: hidden;
307
+    height: 35px;
308
+    /* #ifndef APP-NVUE */
309
+    box-sizing: border-box;
310
+    /* #endif */
311
+  }
312
+
313
+  .input-value-border {
314
+    border: 1px solid #e5e5e5;
315
+    border-radius: 5px;
316
+  }
317
+
318
+  .selected-area {
319
+    flex: 1;
320
+    overflow: hidden;
321
+    /* #ifndef APP-NVUE */
322
+    display: flex;
323
+    /* #endif */
324
+    flex-direction: row;
325
+  }
326
+
327
+  .load-more {
328
+    /* #ifndef APP-NVUE */
329
+    margin-right: auto;
330
+    /* #endif */
331
+    /* #ifdef APP-NVUE */
332
+    width: 40px;
333
+    /* #endif */
334
+  }
335
+
336
+  .selected-list {
337
+    /* #ifndef APP-NVUE */
338
+    display: flex;
339
+    /* #endif */
340
+    flex-direction: row;
341
+    flex-wrap: nowrap;
342
+    /* padding: 0 5px; */
343
+  }
344
+
345
+  .selected-item {
346
+    flex-direction: row;
347
+    /* padding: 0 1px; */
348
+    /* #ifndef APP-NVUE */
349
+    white-space: nowrap;
350
+    /* #endif */
351
+  }
352
+
353
+  .text-color {
354
+    color: #333;
355
+  }
356
+
357
+  .placeholder {
358
+    color: grey;
359
+    font-size: 12px;
360
+  }
361
+
362
+  .input-split-line {
363
+    opacity: .5;
364
+  }
365
+
366
+  .arrow-area {
367
+    position: relative;
368
+    width: 20px;
369
+    /* #ifndef APP-NVUE */
370
+    margin-bottom: 5px;
371
+    margin-left: auto;
372
+    display: flex;
373
+    /* #endif */
374
+    justify-content: center;
375
+    transform: rotate(-45deg);
376
+    transform-origin: center;
377
+  }
378
+
379
+  .input-arrow {
380
+    width: 7px;
381
+    height: 7px;
382
+    border-left: 1px solid #999;
383
+    border-bottom: 1px solid #999;
384
+  }
385
+
386
+  .uni-data-tree-cover {
387
+    position: fixed;
388
+    left: 0;
389
+    top: 0;
390
+    right: 0;
391
+    bottom: 0;
392
+    background-color: rgba(0, 0, 0, .4);
393
+    /* #ifndef APP-NVUE */
394
+    display: flex;
395
+    /* #endif */
396
+    flex-direction: column;
397
+    z-index: 100;
398
+  }
399
+
400
+  .uni-data-tree-dialog {
401
+    position: fixed;
402
+    left: 0;
403
+    /* #ifndef APP-NVUE */
404
+    top: 20%;
405
+    /* #endif */
406
+    /* #ifdef APP-NVUE */
407
+    top: 200px;
408
+    /* #endif */
409
+    right: 0;
410
+    bottom: 0;
411
+    background-color: #FFFFFF;
412
+    border-top-left-radius: 10px;
413
+    border-top-right-radius: 10px;
414
+    /* #ifndef APP-NVUE */
415
+    display: flex;
416
+    /* #endif */
417
+    flex-direction: column;
418
+    z-index: 102;
419
+    overflow: hidden;
420
+    /* #ifdef APP-NVUE */
421
+    width: 750rpx;
422
+    /* #endif */
423
+  }
424
+
425
+  .dialog-caption {
426
+    position: relative;
427
+    /* #ifndef APP-NVUE */
428
+    display: flex;
429
+    /* #endif */
430
+    flex-direction: row;
431
+    /* border-bottom: 1px solid #f0f0f0; */
432
+  }
433
+
434
+  .title-area {
435
+    /* #ifndef APP-NVUE */
436
+    display: flex;
437
+    /* #endif */
438
+    align-items: center;
439
+    /* #ifndef APP-NVUE */
440
+    margin: auto;
441
+    /* #endif */
442
+    padding: 0 10px;
443
+  }
444
+
445
+  .dialog-title {
446
+    /* font-weight: bold; */
447
+    line-height: 44px;
448
+  }
449
+
450
+  .dialog-close {
451
+    position: absolute;
452
+    top: 0;
453
+    right: 0;
454
+    bottom: 0;
455
+    /* #ifndef APP-NVUE */
456
+    display: flex;
457
+    /* #endif */
458
+    flex-direction: row;
459
+    align-items: center;
460
+    padding: 0 15px;
461
+  }
462
+
463
+  .dialog-close-plus {
464
+    width: 16px;
465
+    height: 2px;
466
+    background-color: #666;
467
+    border-radius: 2px;
468
+    transform: rotate(45deg);
469
+  }
470
+
471
+  .dialog-close-rotate {
472
+    position: absolute;
473
+    transform: rotate(-45deg);
474
+  }
475
+
476
+  .picker-view {
477
+    flex: 1;
478
+    overflow: hidden;
479
+  }
480
+
481
+  .icon-clear {
482
+    display: flex;
483
+    align-items: center;
484
+  }
485
+
486
+  /* #ifdef H5 */
487
+  @media all and (min-width: 768px) {
488
+    .uni-data-tree-cover {
489
+      background-color: transparent;
490
+    }
491
+
492
+    .uni-data-tree-dialog {
493
+      position: absolute;
494
+      top: 55px;
495
+      height: auto;
496
+      min-height: 400px;
497
+      max-height: 50vh;
498
+      background-color: #fff;
499
+      border: 1px solid #EBEEF5;
500
+      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
501
+      border-radius: 4px;
502
+      overflow: unset;
503
+    }
504
+
505
+    .dialog-caption {
506
+      display: none;
507
+    }
508
+
509
+    .icon-clear {
510
+      /* margin-right: 5px; */
511
+    }
512
+  }
513
+
514
+  /* #endif */
515
+
516
+  /* picker 弹出层通用的指示小三角, todo:扩展至上下左右方向定位 */
517
+  /* #ifndef APP-NVUE */
518
+  .uni-popper__arrow,
519
+  .uni-popper__arrow::after {
520
+    position: absolute;
521
+    display: block;
522
+    width: 0;
523
+    height: 0;
524
+    border-color: transparent;
525
+    border-style: solid;
526
+    border-width: 6px;
527
+  }
528
+
529
+  .uni-popper__arrow {
530
+    filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
531
+    top: -6px;
532
+    left: 10%;
533
+    margin-right: 3px;
534
+    border-top-width: 0;
535
+    border-bottom-color: #EBEEF5;
536
+  }
537
+
538
+  .uni-popper__arrow::after {
539
+    content: " ";
540
+    top: 1px;
541
+    margin-left: -6px;
542
+    border-top-width: 0;
543
+    border-bottom-color: #fff;
544
+  }
545
+
546
+  /* #endif */
547
+</style>

+ 622 - 0
uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js

@@ -0,0 +1,622 @@
1
+export default {
2
+  props: {
3
+    localdata: {
4
+      type: [Array, Object],
5
+      default () {
6
+        return []
7
+      }
8
+    },
9
+    spaceInfo: {
10
+      type: Object,
11
+      default () {
12
+        return {}
13
+      }
14
+    },
15
+    collection: {
16
+      type: String,
17
+      default: ''
18
+    },
19
+    action: {
20
+      type: String,
21
+      default: ''
22
+    },
23
+    field: {
24
+      type: String,
25
+      default: ''
26
+    },
27
+    orderby: {
28
+      type: String,
29
+      default: ''
30
+    },
31
+    where: {
32
+      type: [String, Object],
33
+      default: ''
34
+    },
35
+    pageData: {
36
+      type: String,
37
+      default: 'add'
38
+    },
39
+    pageCurrent: {
40
+      type: Number,
41
+      default: 1
42
+    },
43
+    pageSize: {
44
+      type: Number,
45
+      default: 500
46
+    },
47
+    getcount: {
48
+      type: [Boolean, String],
49
+      default: false
50
+    },
51
+    getone: {
52
+      type: [Boolean, String],
53
+      default: false
54
+    },
55
+    gettree: {
56
+      type: [Boolean, String],
57
+      default: false
58
+    },
59
+    manual: {
60
+      type: Boolean,
61
+      default: false
62
+    },
63
+    value: {
64
+      type: [Array, String, Number],
65
+      default () {
66
+        return []
67
+      }
68
+    },
69
+    modelValue: {
70
+      type: [Array, String, Number],
71
+      default () {
72
+        return []
73
+      }
74
+    },
75
+    preload: {
76
+      type: Boolean,
77
+      default: false
78
+    },
79
+    stepSearh: {
80
+      type: Boolean,
81
+      default: true
82
+    },
83
+    selfField: {
84
+      type: String,
85
+      default: ''
86
+    },
87
+    parentField: {
88
+      type: String,
89
+      default: ''
90
+    },
91
+    multiple: {
92
+      type: Boolean,
93
+      default: false
94
+    },
95
+    map: {
96
+      type: Object,
97
+      default () {
98
+        return {
99
+          text: "text",
100
+          value: "value"
101
+        }
102
+      }
103
+    }
104
+  },
105
+  data() {
106
+    return {
107
+      loading: false,
108
+      errorMessage: '',
109
+      loadMore: {
110
+        contentdown: '',
111
+        contentrefresh: '',
112
+        contentnomore: ''
113
+      },
114
+      dataList: [],
115
+      selected: [],
116
+      selectedIndex: 0,
117
+      page: {
118
+        current: this.pageCurrent,
119
+        size: this.pageSize,
120
+        count: 0
121
+      }
122
+    }
123
+  },
124
+  computed: {
125
+    isLocalData() {
126
+      return !this.collection.length;
127
+    },
128
+    isCloudData() {
129
+      return this.collection.length > 0;
130
+    },
131
+    isCloudDataList() {
132
+      return (this.isCloudData && (!this.parentField && !this.selfField));
133
+    },
134
+    isCloudDataTree() {
135
+      return (this.isCloudData && this.parentField && this.selfField);
136
+    },
137
+    dataValue() {
138
+      let isModelValue = Array.isArray(this.modelValue) ? (this.modelValue.length > 0) : (this.modelValue !== null ||
139
+        this.modelValue !== undefined);
140
+      return isModelValue ? this.modelValue : this.value;
141
+    },
142
+    hasValue() {
143
+      if (typeof this.dataValue === 'number') {
144
+        return true
145
+      }
146
+      return (this.dataValue != null) && (this.dataValue.length > 0)
147
+    }
148
+  },
149
+  created() {
150
+    this.$watch(() => {
151
+      var al = [];
152
+      ['pageCurrent',
153
+        'pageSize',
154
+        'spaceInfo',
155
+        'value',
156
+        'modelValue',
157
+        'localdata',
158
+        'collection',
159
+        'action',
160
+        'field',
161
+        'orderby',
162
+        'where',
163
+        'getont',
164
+        'getcount',
165
+        'gettree'
166
+      ].forEach(key => {
167
+        al.push(this[key])
168
+      });
169
+      return al
170
+    }, (newValue, oldValue) => {
171
+      let needReset = false
172
+      for (let i = 2; i < newValue.length; i++) {
173
+        if (newValue[i] != oldValue[i]) {
174
+          needReset = true
175
+          break
176
+        }
177
+      }
178
+      if (newValue[0] != oldValue[0]) {
179
+        this.page.current = this.pageCurrent
180
+      }
181
+      this.page.size = this.pageSize
182
+
183
+      this.onPropsChange()
184
+    })
185
+    this._treeData = []
186
+  },
187
+  methods: {
188
+    onPropsChange() {
189
+      this._treeData = [];
190
+    },
191
+
192
+    // 填充 pickview 数据
193
+    async loadData() {
194
+      if (this.isLocalData) {
195
+        this.loadLocalData();
196
+      } else if (this.isCloudDataList) {
197
+        this.loadCloudDataList();
198
+      } else if (this.isCloudDataTree) {
199
+        this.loadCloudDataTree();
200
+      }
201
+    },
202
+
203
+    // 加载本地数据
204
+    async loadLocalData() {
205
+      this._treeData = [];
206
+      this._extractTree(this.localdata, this._treeData);
207
+
208
+      let inputValue = this.dataValue;
209
+      if (inputValue === undefined) {
210
+        return;
211
+      }
212
+
213
+      if (Array.isArray(inputValue)) {
214
+        inputValue = inputValue[inputValue.length - 1];
215
+        if (typeof inputValue === 'object' && inputValue[this.map.value]) {
216
+          inputValue = inputValue[this.map.value];
217
+        }
218
+      }
219
+
220
+      this.selected = this._findNodePath(inputValue, this.localdata);
221
+    },
222
+
223
+    // 加载 Cloud 数据 (单列)
224
+    async loadCloudDataList() {
225
+      if (this.loading) {
226
+        return;
227
+      }
228
+      this.loading = true;
229
+
230
+      try {
231
+        let response = await this.getCommand();
232
+        let responseData = response.result.data;
233
+
234
+        this._treeData = responseData;
235
+
236
+        this._updateBindData();
237
+        this._updateSelected();
238
+
239
+        this.onDataChange();
240
+      } catch (e) {
241
+        this.errorMessage = e;
242
+      } finally {
243
+        this.loading = false;
244
+      }
245
+    },
246
+
247
+    // 加载 Cloud 数据 (树形)
248
+    async loadCloudDataTree() {
249
+      if (this.loading) {
250
+        return;
251
+      }
252
+      this.loading = true;
253
+
254
+      try {
255
+        let commandOptions = {
256
+          field: this._cloudDataPostField(),
257
+          where: this._cloudDataTreeWhere()
258
+        };
259
+        if (this.gettree) {
260
+          commandOptions.startwith = `${this.selfField}=='${this.dataValue}'`;
261
+        }
262
+
263
+        let response = await this.getCommand(commandOptions);
264
+        let responseData = response.result.data;
265
+
266
+        this._treeData = responseData;
267
+        this._updateBindData();
268
+        this._updateSelected();
269
+
270
+        this.onDataChange();
271
+      } catch (e) {
272
+        this.errorMessage = e;
273
+      } finally {
274
+        this.loading = false;
275
+      }
276
+    },
277
+
278
+    // 加载 Cloud 数据 (节点)
279
+    async loadCloudDataNode(callback) {
280
+      if (this.loading) {
281
+        return;
282
+      }
283
+      this.loading = true;
284
+
285
+      try {
286
+        let commandOptions = {
287
+          field: this._cloudDataPostField(),
288
+          where: this._cloudDataNodeWhere()
289
+        };
290
+
291
+        let response = await this.getCommand(commandOptions);
292
+        let responseData = response.result.data;
293
+
294
+        callback(responseData);
295
+      } catch (e) {
296
+        this.errorMessage = e;
297
+      } finally {
298
+        this.loading = false;
299
+      }
300
+    },
301
+
302
+    // 回显 Cloud 数据
303
+    getCloudDataValue() {
304
+      if (this.isCloudDataList) {
305
+        return this.getCloudDataListValue();
306
+      }
307
+
308
+      if (this.isCloudDataTree) {
309
+        return this.getCloudDataTreeValue();
310
+      }
311
+    },
312
+
313
+    // 回显 Cloud 数据 (单列)
314
+    getCloudDataListValue() {
315
+      // 根据 field's as value标识匹配 where 条件
316
+      let where = [];
317
+      let whereField = this._getForeignKeyByField();
318
+      if (whereField) {
319
+        where.push(`${whereField} == '${this.dataValue}'`)
320
+      }
321
+
322
+      where = where.join(' || ');
323
+
324
+      if (this.where) {
325
+        where = `(${this.where}) && (${where})`
326
+      }
327
+
328
+      return this.getCommand({
329
+        field: this._cloudDataPostField(),
330
+        where
331
+      }).then((res) => {
332
+        this.selected = res.result.data;
333
+        return res.result.data;
334
+      });
335
+    },
336
+
337
+    // 回显 Cloud 数据 (树形)
338
+    getCloudDataTreeValue() {
339
+      return this.getCommand({
340
+        field: this._cloudDataPostField(),
341
+        getTreePath: {
342
+          startWith: `${this.selfField}=='${this.dataValue}'`
343
+        }
344
+      }).then((res) => {
345
+        let treePath = [];
346
+        this._extractTreePath(res.result.data, treePath);
347
+        this.selected = treePath;
348
+        return treePath;
349
+      });
350
+    },
351
+
352
+    getCommand(options = {}) {
353
+      /* eslint-disable no-undef */
354
+      let db = uniCloud.database(this.spaceInfo)
355
+
356
+      const action = options.action || this.action
357
+      if (action) {
358
+        db = db.action(action)
359
+      }
360
+
361
+      const collection = options.collection || this.collection
362
+      db = db.collection(collection)
363
+
364
+      const where = options.where || this.where
365
+      if (!(!where || !Object.keys(where).length)) {
366
+        db = db.where(where)
367
+      }
368
+
369
+      const field = options.field || this.field
370
+      if (field) {
371
+        db = db.field(field)
372
+      }
373
+
374
+      const orderby = options.orderby || this.orderby
375
+      if (orderby) {
376
+        db = db.orderBy(orderby)
377
+      }
378
+
379
+      const current = options.pageCurrent !== undefined ? options.pageCurrent : this.page.current
380
+      const size = options.pageSize !== undefined ? options.pageSize : this.page.size
381
+      const getCount = options.getcount !== undefined ? options.getcount : this.getcount
382
+      const getTree = options.gettree !== undefined ? options.gettree : this.gettree
383
+
384
+      const getOptions = {
385
+        getCount,
386
+        getTree
387
+      }
388
+      if (options.getTreePath) {
389
+        getOptions.getTreePath = options.getTreePath
390
+      }
391
+
392
+      db = db.skip(size * (current - 1)).limit(size).get(getOptions)
393
+
394
+      return db
395
+    },
396
+
397
+    _cloudDataPostField() {
398
+      let fields = [this.field];
399
+      if (this.parentField) {
400
+        fields.push(`${this.parentField} as parent_value`);
401
+      }
402
+      return fields.join(',');
403
+    },
404
+
405
+    _cloudDataTreeWhere() {
406
+      let result = []
407
+      let selected = this.selected
408
+      let parentField = this.parentField
409
+      if (parentField) {
410
+        result.push(`${parentField} == null || ${parentField} == ""`)
411
+      }
412
+      if (selected.length) {
413
+        for (var i = 0; i < selected.length - 1; i++) {
414
+          result.push(`${parentField} == '${selected[i].value}'`)
415
+        }
416
+      }
417
+
418
+      let where = []
419
+      if (this.where) {
420
+        where.push(`(${this.where})`)
421
+      }
422
+
423
+      if (result.length) {
424
+        where.push(`(${result.join(' || ')})`)
425
+      }
426
+
427
+      return where.join(' && ')
428
+    },
429
+
430
+    _cloudDataNodeWhere() {
431
+      let where = []
432
+      let selected = this.selected;
433
+      if (selected.length) {
434
+        where.push(`${this.parentField} == '${selected[selected.length - 1].value}'`);
435
+      }
436
+
437
+      where = where.join(' || ');
438
+
439
+      if (this.where) {
440
+        return `(${this.where}) && (${where})`
441
+      }
442
+
443
+      return where
444
+    },
445
+
446
+    _getWhereByForeignKey() {
447
+      let result = []
448
+      let whereField = this._getForeignKeyByField();
449
+      if (whereField) {
450
+        result.push(`${whereField} == '${this.dataValue}'`)
451
+      }
452
+
453
+      if (this.where) {
454
+        return `(${this.where}) && (${result.join(' || ')})`
455
+      }
456
+
457
+      return result.join(' || ')
458
+    },
459
+
460
+    _getForeignKeyByField() {
461
+      let fields = this.field.split(',');
462
+      let whereField = null;
463
+      for (let i = 0; i < fields.length; i++) {
464
+        const items = fields[i].split('as');
465
+        if (items.length < 2) {
466
+          continue;
467
+        }
468
+        if (items[1].trim() === 'value') {
469
+          whereField = items[0].trim();
470
+          break;
471
+        }
472
+      }
473
+      return whereField;
474
+    },
475
+
476
+    _updateBindData(node) {
477
+      const {
478
+        dataList,
479
+        hasNodes
480
+      } = this._filterData(this._treeData, this.selected)
481
+
482
+      let isleaf = this._stepSearh === false && !hasNodes
483
+
484
+      if (node) {
485
+        node.isleaf = isleaf
486
+      }
487
+
488
+      this.dataList = dataList
489
+      this.selectedIndex = dataList.length - 1
490
+
491
+      if (!isleaf && this.selected.length < dataList.length) {
492
+        this.selected.push({
493
+          value: null,
494
+          text: "请选择"
495
+        })
496
+      }
497
+
498
+      return {
499
+        isleaf,
500
+        hasNodes
501
+      }
502
+    },
503
+
504
+    _updateSelected() {
505
+      let dl = this.dataList
506
+      let sl = this.selected
507
+      let textField = this.map.text
508
+      let valueField = this.map.value
509
+      for (let i = 0; i < sl.length; i++) {
510
+        let value = sl[i].value
511
+        let dl2 = dl[i]
512
+        for (let j = 0; j < dl2.length; j++) {
513
+          let item2 = dl2[j]
514
+          if (item2[valueField] === value) {
515
+            sl[i].text = item2[textField]
516
+            break
517
+          }
518
+        }
519
+      }
520
+    },
521
+
522
+    _filterData(data, paths) {
523
+      let dataList = []
524
+      let hasNodes = true
525
+
526
+      dataList.push(data.filter((item) => {
527
+        return (item.parent_value === null || item.parent_value === undefined || item.parent_value === '')
528
+      }))
529
+      for (let i = 0; i < paths.length; i++) {
530
+        let value = paths[i].value
531
+        let nodes = data.filter((item) => {
532
+          return item.parent_value === value
533
+        })
534
+
535
+        if (nodes.length) {
536
+          dataList.push(nodes)
537
+        } else {
538
+          hasNodes = false
539
+        }
540
+      }
541
+
542
+      return {
543
+        dataList,
544
+        hasNodes
545
+      }
546
+    },
547
+
548
+    _extractTree(nodes, result, parent_value) {
549
+      let list = result || []
550
+      let valueField = this.map.value
551
+      for (let i = 0; i < nodes.length; i++) {
552
+        let node = nodes[i]
553
+
554
+        let child = {}
555
+        for (let key in node) {
556
+          if (key !== 'children') {
557
+            child[key] = node[key]
558
+          }
559
+        }
560
+        if (parent_value !== null && parent_value !== undefined && parent_value !== '') {
561
+          child.parent_value = parent_value
562
+        }
563
+        result.push(child)
564
+
565
+        let children = node.children
566
+        if (children) {
567
+          this._extractTree(children, result, node[valueField])
568
+        }
569
+      }
570
+    },
571
+
572
+    _extractTreePath(nodes, result) {
573
+      let list = result || []
574
+      for (let i = 0; i < nodes.length; i++) {
575
+        let node = nodes[i]
576
+
577
+        let child = {}
578
+        for (let key in node) {
579
+          if (key !== 'children') {
580
+            child[key] = node[key]
581
+          }
582
+        }
583
+        result.push(child)
584
+
585
+        let children = node.children
586
+        if (children) {
587
+          this._extractTreePath(children, result)
588
+        }
589
+      }
590
+    },
591
+
592
+    _findNodePath(key, nodes, path = []) {
593
+      let textField = this.map.text
594
+      let valueField = this.map.value
595
+      for (let i = 0; i < nodes.length; i++) {
596
+        let node = nodes[i]
597
+        let children = node.children
598
+        let text = node[textField]
599
+        let value = node[valueField]
600
+
601
+        path.push({
602
+          value,
603
+          text
604
+        })
605
+
606
+        if (value === key) {
607
+          return path
608
+        }
609
+
610
+        if (children) {
611
+          const p = this._findNodePath(key, children, path)
612
+          if (p.length) {
613
+            return p
614
+          }
615
+        }
616
+
617
+        path.pop()
618
+      }
619
+      return []
620
+    }
621
+  }
622
+}

+ 321 - 0
uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue

@@ -0,0 +1,321 @@
1
+<template>
2
+  <view class="uni-data-pickerview">
3
+    <scroll-view v-if="!isCloudDataList" class="selected-area" scroll-x="true">
4
+      <view class="selected-list">
5
+        <template v-for="(item,index) in selected">
6
+          <view class="selected-item"
7
+            :class="{'selected-item-active':index==selectedIndex}"
8
+            v-if="item.text" @click="handleSelect(index)">
9
+            <text>{{item.text}}</text>
10
+          </view>
11
+        </template>
12
+      </view>
13
+    </scroll-view>
14
+    <view class="tab-c">
15
+      <template v-for="(child, i) in dataList">
16
+        <scroll-view class="list" :key="i" v-if="i==selectedIndex" :scroll-y="true">
17
+          <view class="item" :class="{'is-disabled': !!item.disable}" v-for="(item, j) in child"
18
+            @click="handleNodeClick(item, i, j)">
19
+            <text class="item-text">{{item[map.text]}}</text>
20
+            <view class="check" v-if="selected.length > i && item[map.value] == selected[i].value"></view>
21
+          </view>
22
+        </scroll-view>
23
+      </template>
24
+
25
+      <view class="loading-cover" v-if="loading">
26
+        <uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
27
+      </view>
28
+      <view class="error-message" v-if="errorMessage">
29
+        <text class="error-text">{{errorMessage}}</text>
30
+      </view>
31
+    </view>
32
+  </view>
33
+</template>
34
+
35
+<script>
36
+  import dataPicker from "./uni-data-picker.js"
37
+
38
+  /**
39
+   * DataPickerview
40
+   * @description uni-data-pickerview
41
+   * @tutorial https://ext.dcloud.net.cn/plugin?id=3796
42
+   * @property {Array} localdata 本地数据,参考
43
+   * @property {Boolean} step-searh = [true|false] 是否分布查询
44
+   * @value true 启用分布查询,仅查询当前选中节点
45
+   * @value false 关闭分布查询,一次查询出所有数据
46
+   * @property {String|DBFieldString} self-field 分布查询当前字段名称
47
+   * @property {String|DBFieldString} parent-field 分布查询父字段名称
48
+   * @property {String|DBCollectionString} collection 表名
49
+   * @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
50
+   * @property {String} orderby 排序字段及正序倒叙设置
51
+   * @property {String|JQLString} where 查询条件
52
+   */
53
+  export default {
54
+    name: 'UniDataPickerView',
55
+    emits: ['nodeclick', 'change', 'datachange', 'update:modelValue'],
56
+    mixins: [dataPicker],
57
+    props: {
58
+      managedMode: {
59
+        type: Boolean,
60
+        default: false
61
+      },
62
+      ellipsis: {
63
+        type: Boolean,
64
+        default: true
65
+      }
66
+    },
67
+    created() {
68
+      if (!this.managedMode) {
69
+        this.$nextTick(() => {
70
+          this.loadData();
71
+        })
72
+      }
73
+    },
74
+    methods: {
75
+      onPropsChange() {
76
+        this._treeData = [];
77
+        this.selectedIndex = 0;
78
+        this.$nextTick(() => {
79
+          this.loadData();
80
+        })
81
+      },
82
+      handleSelect(index) {
83
+        this.selectedIndex = index;
84
+      },
85
+      handleNodeClick(item, i, j) {
86
+        if (item.disable) {
87
+          return;
88
+        }
89
+
90
+        const node = this.dataList[i][j];
91
+        const text = node[this.map.text];
92
+        const value = node[this.map.value];
93
+
94
+        if (i < this.selected.length - 1) {
95
+          this.selected.splice(i, this.selected.length - i)
96
+          this.selected.push({
97
+            text,
98
+            value
99
+          })
100
+        } else if (i === this.selected.length - 1) {
101
+          this.selected.splice(i, 1, {
102
+            text,
103
+            value
104
+          })
105
+        }
106
+
107
+        if (node.isleaf) {
108
+          this.onSelectedChange(node, node.isleaf)
109
+          return
110
+        }
111
+
112
+        const {
113
+          isleaf,
114
+          hasNodes
115
+        } = this._updateBindData()
116
+
117
+        // 本地数据
118
+        if (this.isLocalData) {
119
+          this.onSelectedChange(node, (!hasNodes || isleaf))
120
+        } else if (this.isCloudDataList) { // Cloud 数据 (单列)
121
+          this.onSelectedChange(node, true)
122
+        } else if (this.isCloudDataTree) { // Cloud 数据 (树形)
123
+          if (isleaf) {
124
+            this.onSelectedChange(node, node.isleaf)
125
+          } else if (!hasNodes) { // 请求一次服务器以确定是否为叶子节点
126
+            this.loadCloudDataNode((data) => {
127
+              if (!data.length) {
128
+                node.isleaf = true
129
+              } else {
130
+                this._treeData.push(...data)
131
+                this._updateBindData(node)
132
+              }
133
+              this.onSelectedChange(node, node.isleaf)
134
+            })
135
+          }
136
+        }
137
+      },
138
+      updateData(data) {
139
+        this._treeData = data.treeData
140
+        this.selected = data.selected
141
+        if (!this._treeData.length) {
142
+          this.loadData()
143
+        } else {
144
+          //this.selected = data.selected
145
+          this._updateBindData()
146
+        }
147
+      },
148
+      onDataChange() {
149
+        this.$emit('datachange');
150
+      },
151
+      onSelectedChange(node, isleaf) {
152
+        if (isleaf) {
153
+          this._dispatchEvent()
154
+        }
155
+
156
+        if (node) {
157
+          this.$emit('nodeclick', node)
158
+        }
159
+      },
160
+      _dispatchEvent() {
161
+        this.$emit('change', this.selected.slice(0))
162
+      }
163
+    }
164
+  }
165
+</script>
166
+
167
+<style lang="scss">
168
+	$uni-primary: #007aff !default;
169
+
170
+	.uni-data-pickerview {
171
+		flex: 1;
172
+		/* #ifndef APP-NVUE */
173
+		display: flex;
174
+		/* #endif */
175
+		flex-direction: column;
176
+		overflow: hidden;
177
+		height: 100%;
178
+	}
179
+
180
+  .error-text {
181
+    color: #DD524D;
182
+  }
183
+
184
+  .loading-cover {
185
+    position: absolute;
186
+    left: 0;
187
+    top: 0;
188
+    right: 0;
189
+    bottom: 0;
190
+    background-color: rgba(255, 255, 255, .5);
191
+    /* #ifndef APP-NVUE */
192
+    display: flex;
193
+    /* #endif */
194
+    flex-direction: column;
195
+    align-items: center;
196
+    z-index: 1001;
197
+  }
198
+
199
+  .load-more {
200
+    /* #ifndef APP-NVUE */
201
+    margin: auto;
202
+    /* #endif */
203
+  }
204
+
205
+  .error-message {
206
+    background-color: #fff;
207
+    position: absolute;
208
+    left: 0;
209
+    top: 0;
210
+    right: 0;
211
+    bottom: 0;
212
+    padding: 15px;
213
+    opacity: .9;
214
+    z-index: 102;
215
+  }
216
+
217
+  /* #ifdef APP-NVUE */
218
+  .selected-area {
219
+    width: 750rpx;
220
+  }
221
+  /* #endif */
222
+
223
+  .selected-list {
224
+    /* #ifndef APP-NVUE */
225
+    display: flex;
226
+    flex-wrap: nowrap;
227
+    /* #endif */
228
+    flex-direction: row;
229
+    padding: 0 5px;
230
+    border-bottom: 1px solid #f8f8f8;
231
+  }
232
+
233
+  .selected-item {
234
+    margin-left: 10px;
235
+    margin-right: 10px;
236
+    padding: 12px 0;
237
+    text-align: center;
238
+    /* #ifndef APP-NVUE */
239
+    white-space: nowrap;
240
+    /* #endif */
241
+  }
242
+
243
+  .selected-item-text-overflow {
244
+    width: 168px;
245
+    /* fix nvue */
246
+    overflow: hidden;
247
+    /* #ifndef APP-NVUE */
248
+    width: 6em;
249
+    white-space: nowrap;
250
+    text-overflow: ellipsis;
251
+    -o-text-overflow: ellipsis;
252
+    /* #endif */
253
+  }
254
+
255
+	.selected-item-active {
256
+		border-bottom: 2px solid $uni-primary;
257
+	}
258
+
259
+	.selected-item-text {
260
+		color: $uni-primary;
261
+	}
262
+
263
+  .tab-c {
264
+    position: relative;
265
+    flex: 1;
266
+    /* #ifndef APP-NVUE */
267
+    display: flex;
268
+    /* #endif */
269
+    flex-direction: row;
270
+    overflow: hidden;
271
+  }
272
+
273
+  .list {
274
+    flex: 1;
275
+  }
276
+
277
+  .item {
278
+    padding: 12px 15px;
279
+    /* border-bottom: 1px solid #f0f0f0; */
280
+    /* #ifndef APP-NVUE */
281
+    display: flex;
282
+    /* #endif */
283
+    flex-direction: row;
284
+    justify-content: space-between;
285
+  }
286
+
287
+  .is-disabled {
288
+    opacity: .5;
289
+  }
290
+
291
+  .item-text {
292
+    /* flex: 1; */
293
+    color: #333333;
294
+  }
295
+
296
+  .item-text-overflow {
297
+    width: 280px;
298
+    /* fix nvue */
299
+    overflow: hidden;
300
+    /* #ifndef APP-NVUE */
301
+    width: 20em;
302
+    white-space: nowrap;
303
+    text-overflow: ellipsis;
304
+    -o-text-overflow: ellipsis;
305
+    /* #endif */
306
+  }
307
+
308
+	.check {
309
+		margin-right: 5px;
310
+		border: 2px solid $uni-primary;
311
+		border-left: 0;
312
+		border-top: 0;
313
+		height: 12px;
314
+		width: 6px;
315
+		transform-origin: center;
316
+		/* #ifndef APP-NVUE */
317
+		transition: all 0.3s;
318
+		/* #endif */
319
+		transform: rotate(45deg);
320
+	}
321
+</style>

+ 90 - 0
uni_modules/uni-data-picker/package.json

@@ -0,0 +1,90 @@
1
+{
2
+  "id": "uni-data-picker",
3
+  "displayName": "uni-data-picker 数据驱动的picker选择器",
4
+  "version": "1.0.8",
5
+  "description": "单列、多列级联选择器,常用于省市区城市选择、公司部门选择、多级分类等场景",
6
+  "keywords": [
7
+    "uni-ui",
8
+    "uniui",
9
+    "picker",
10
+    "级联",
11
+    "省市区",
12
+    ""
13
+],
14
+  "repository": "https://github.com/dcloudio/uni-ui",
15
+  "engines": {
16
+    "HBuilderX": ""
17
+  },
18
+  "directories": {
19
+    "example": "../../temps/example_temps"
20
+  },
21
+"dcloudext": {
22
+    "sale": {
23
+      "regular": {
24
+        "price": "0.00"
25
+      },
26
+      "sourcecode": {
27
+        "price": "0.00"
28
+      }
29
+    },
30
+    "contact": {
31
+      "qq": ""
32
+    },
33
+    "declaration": {
34
+      "ads": "无",
35
+      "data": "无",
36
+      "permissions": "无"
37
+    },
38
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
39
+    "type": "component-vue"
40
+  },
41
+  "uni_modules": {
42
+    "dependencies": [
43
+      "uni-load-more",
44
+			"uni-icons",
45
+			"uni-scss"
46
+    ],
47
+    "encrypt": [],
48
+    "platforms": {
49
+      "cloud": {
50
+        "tcb": "y",
51
+        "aliyun": "y"
52
+      },
53
+      "client": {
54
+        "App": {
55
+          "app-vue": "y",
56
+          "app-nvue": "u"
57
+        },
58
+        "H5-mobile": {
59
+          "Safari": "y",
60
+          "Android Browser": "y",
61
+          "微信浏览器(Android)": "y",
62
+          "QQ浏览器(Android)": "y"
63
+        },
64
+        "H5-pc": {
65
+          "Chrome": "y",
66
+          "IE": "y",
67
+          "Edge": "y",
68
+          "Firefox": "y",
69
+          "Safari": "y"
70
+        },
71
+        "小程序": {
72
+          "微信": "y",
73
+          "阿里": "y",
74
+          "百度": "y",
75
+          "字节跳动": "y",
76
+        "QQ": "y",
77
+        "京东": "u"
78
+        },
79
+        "快应用": {
80
+          "华为": "u",
81
+          "联盟": "u"
82
+        },
83
+        "Vue": {
84
+            "vue2": "y",
85
+            "vue3": "y"
86
+        }
87
+      }
88
+    }
89
+  }
90
+}

+ 22 - 0
uni_modules/uni-data-picker/readme.md

@@ -0,0 +1,22 @@
1
+## DataPicker 级联选择
2
+> **组件名:uni-data-picker**
3
+> 代码块: `uDataPicker`
4
+> 关联组件:`uni-data-pickerview`、`uni-load-more`。
5
+
6
+
7
+`<uni-data-picker>` 是一个选择类[datacom组件](https://uniapp.dcloud.net.cn/component/datacom)。
8
+
9
+支持单列、和多列级联选择。列数没有限制,如果屏幕显示不全,顶部tab区域会左右滚动。
10
+
11
+候选数据支持一次性加载完毕,也支持懒加载,比如示例图中,选择了“北京”后,动态加载北京的区县数据。
12
+
13
+`<uni-data-picker>` 组件尤其适用于地址选择、分类选择等选择类。
14
+
15
+`<uni-data-picker>` 支持本地数据、云端静态数据(json),uniCloud云数据库数据。
16
+
17
+`<uni-data-picker>` 可以通过JQL直连uniCloud云数据库,配套[DB Schema](https://uniapp.dcloud.net.cn/uniCloud/schema),可在schema2code中自动生成前端页面,还支持服务器端校验。
18
+
19
+在uniCloud数据表中新建表“uni-id-address”和“opendb-city-china”,这2个表的schema自带foreignKey关联。在“uni-id-address”表的表结构页面使用schema2code生成前端页面,会自动生成地址管理的维护页面,自动从“opendb-city-china”表包含的中国所有省市区信息里选择地址。
20
+
21
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-picker)
22
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 

+ 22 - 0
uni_modules/uni-data-select/changelog.md

@@ -0,0 +1,22 @@
1
+## 0.1.9(2022-09-05)
2
+- 修复 微信小程序下拉框出现后选择会点击到蒙板后面的输入框
3
+## 0.1.8(2022-08-29)
4
+- 修复 点击的位置不准确
5
+## 0.1.7(2022-08-12)
6
+- 新增 支持 disabled 属性
7
+## 0.1.6(2022-07-06)
8
+- 修复 pc端宽度异常的bug
9
+## 0.1.5
10
+- 修复 pc端宽度异常的bug
11
+## 0.1.4(2022-07-05)
12
+- 优化 显示样式
13
+## 0.1.3(2022-06-02)
14
+- 修复 localdata 赋值不生效的 bug
15
+- 新增 支持  uni.scss 修改颜色
16
+- 新增 支持选项禁用(数据选项设置 disabled: true 即禁用)
17
+## 0.1.2(2022-05-08)
18
+- 修复 当 value 为 0 时选择不生效的 bug
19
+## 0.1.1(2022-05-07)
20
+- 新增 记住上次的选项(仅 collection 存在时有效)
21
+## 0.1.0(2022-04-22)
22
+- 初始化

+ 440 - 0
uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue

@@ -0,0 +1,440 @@
1
+<template>
2
+	<view class="uni-stat__select">
3
+		<span v-if="label" class="uni-label-text hide-on-phone">{{label + ':'}}</span>
4
+		<view class="uni-stat-box" :class="{'uni-stat__actived': current}">
5
+			<view class="uni-select"  :class="{'uni-select--disabled':disabled}">
6
+				<view class="uni-select__input-box" @click="toggleSelector">
7
+					<view v-if="current" class="uni-select__input-text">{{current}}</view>
8
+					<view v-else class="uni-select__input-text uni-select__input-placeholder">{{typePlaceholder}}</view>
9
+					<uni-icons v-if="current && clear" type="clear" color="#c0c4cc" size="24" @click="clearVal" />
10
+					<uni-icons v-else :type="showSelector? 'top' : 'bottom'" size="14" color="#999" />
11
+				</view>
12
+				<view class="uni-select--mask" v-if="showSelector" @click="toggleSelector" />
13
+				<view class="uni-select__selector" v-if="showSelector">
14
+					<view class="uni-popper__arrow"></view>
15
+					<scroll-view scroll-y="true" class="uni-select__selector-scroll">
16
+						<view class="uni-select__selector-empty" v-if="mixinDatacomResData.length === 0">
17
+							<text>{{emptyTips}}</text>
18
+						</view>
19
+						<view v-else class="uni-select__selector-item" v-for="(item,index) in mixinDatacomResData"
20
+							:key="index" @click="change(item)">
21
+							<text
22
+								:class="{'uni-select__selector__disabled': item.disable}">{{formatItemName(item)}}</text>
23
+						</view>
24
+					</scroll-view>
25
+				</view>
26
+			</view>
27
+		</view>
28
+	</view>
29
+</template>
30
+
31
+<script>
32
+	/**
33
+	 * DataChecklist 数据选择器
34
+	 * @description 通过数据渲染的下拉框组件
35
+	 * @tutorial https://uniapp.dcloud.io/component/uniui/uni-data-select
36
+	 * @property {String} value 默认值
37
+	 * @property {Array} localdata 本地数据 ,格式 [{text:'',value:''}]
38
+	 * @property {Boolean} clear 是否可以清空已选项
39
+	 * @property {Boolean} emptyText 没有数据时显示的文字 ,本地数据无效
40
+	 * @property {String} label 左侧标题
41
+	 * @property {String} placeholder 输入框的提示文字
42
+	 * @property {Boolean} disabled 是否禁用
43
+	 * @event {Function} change  选中发生变化触发
44
+	 */
45
+
46
+	export default {
47
+		name: "uni-stat-select",
48
+		mixins: [uniCloud.mixinDatacom || {}],
49
+		data() {
50
+			return {
51
+				showSelector: false,
52
+				current: '',
53
+				mixinDatacomResData: [],
54
+				apps: [],
55
+				channels: []
56
+			};
57
+		},
58
+		props: {
59
+			localdata: {
60
+				type: Array,
61
+				default () {
62
+					return []
63
+				}
64
+			},
65
+			value: {
66
+				type: [String, Number],
67
+				default: ''
68
+			},
69
+			modelValue: {
70
+				type: [String, Number],
71
+				default: ''
72
+			},
73
+			label: {
74
+				type: String,
75
+				default: ''
76
+			},
77
+			placeholder: {
78
+				type: String,
79
+				default: '请选择'
80
+			},
81
+			emptyTips: {
82
+				type: String,
83
+				default: '无选项'
84
+			},
85
+			clear: {
86
+				type: Boolean,
87
+				default: true
88
+			},
89
+			defItem: {
90
+				type: Number,
91
+				default: 0
92
+			},
93
+      disabled: {
94
+				type: Boolean,
95
+				default: false
96
+			}
97
+		},
98
+		created() {
99
+			this.last = `${this.collection}_last_selected_option_value`
100
+			if (this.collection && !this.localdata.length) {
101
+				this.mixinDatacomEasyGet()
102
+			}
103
+		},
104
+		computed: {
105
+			typePlaceholder() {
106
+				const text = {
107
+					'opendb-stat-app-versions': '版本',
108
+					'opendb-app-channels': '渠道',
109
+					'opendb-app-list': '应用'
110
+				}
111
+				const common = this.placeholder
112
+				const placeholder = text[this.collection]
113
+				return placeholder ?
114
+					common + placeholder :
115
+					common
116
+			}
117
+		},
118
+		watch: {
119
+			localdata: {
120
+				immediate: true,
121
+				handler(val, old) {
122
+					if (Array.isArray(val) && old !== val) {
123
+						this.mixinDatacomResData = val
124
+					}
125
+				}
126
+			},
127
+			// #ifndef VUE3
128
+			value() {
129
+				this.initDefVal()
130
+			},
131
+			// #endif
132
+			// #ifdef VUE3
133
+			modelValue() {
134
+				this.initDefVal()
135
+			},
136
+			// #endif
137
+			mixinDatacomResData: {
138
+				immediate: true,
139
+				handler(val) {
140
+					if (val.length) {
141
+						this.initDefVal()
142
+					}
143
+				}
144
+			}
145
+		},
146
+		methods: {
147
+			initDefVal() {
148
+				let defValue = ''
149
+				if ((this.value || this.value === 0) && !this.isDisabled(this.value)) {
150
+					defValue = this.value
151
+				} else if ((this.modelValue || this.modelValue === 0) && !this.isDisabled(this.modelValue)) {
152
+					defValue = this.modelValue
153
+				} else {
154
+					let strogeValue
155
+					if (this.collection) {
156
+						strogeValue = uni.getStorageSync(this.last)
157
+					}
158
+					if (strogeValue || strogeValue === 0) {
159
+						defValue = strogeValue
160
+					} else {
161
+						let defItem = ''
162
+						if (this.defItem > 0 && this.defItem < this.mixinDatacomResData.length) {
163
+							defItem = this.mixinDatacomResData[this.defItem - 1].value
164
+						}
165
+						defValue = defItem
166
+					}
167
+					this.emit(defValue)
168
+				}
169
+				const def = this.mixinDatacomResData.find(item => item.value === defValue)
170
+				this.current = def ? this.formatItemName(def) : ''
171
+			},
172
+
173
+			/**
174
+			 * @param {[String, Number]} value
175
+			 * 判断用户给的 value 是否同时为禁用状态
176
+			 */
177
+			isDisabled(value) {
178
+				let isDisabled = false;
179
+
180
+				this.mixinDatacomResData.forEach(item => {
181
+					if (item.value === value) {
182
+						isDisabled = item.disable
183
+					}
184
+				})
185
+
186
+				return isDisabled;
187
+			},
188
+
189
+			clearVal() {
190
+				this.emit('')
191
+				if (this.collection) {
192
+					uni.removeStorageSync(this.last)
193
+				}
194
+			},
195
+			change(item) {
196
+				if (!item.disable) {
197
+					this.showSelector = false
198
+					this.current = this.formatItemName(item)
199
+					this.emit(item.value)
200
+				}
201
+			},
202
+			emit(val) {
203
+				this.$emit('change', val)
204
+				this.$emit('input', val)
205
+				this.$emit('update:modelValue', val)
206
+				if (this.collection) {
207
+					uni.setStorageSync(this.last, val)
208
+				}
209
+			},
210
+
211
+			toggleSelector() {
212
+        if(this.disabled){
213
+          return
214
+        }
215
+
216
+				this.showSelector = !this.showSelector
217
+			},
218
+			formatItemName(item) {
219
+				let {
220
+					text,
221
+					value,
222
+					channel_code
223
+				} = item
224
+				channel_code = channel_code ? `(${channel_code})` : ''
225
+				return this.collection.indexOf('app-list') > 0 ?
226
+					`${text}(${value})` :
227
+					(
228
+						text ?
229
+						text :
230
+						`未命名${channel_code}`
231
+					)
232
+			}
233
+		}
234
+	}
235
+</script>
236
+
237
+<style lang="scss">
238
+	$uni-base-color: #6a6a6a !default;
239
+	$uni-main-color: #333 !default;
240
+	$uni-secondary-color: #909399 !default;
241
+	$uni-border-3: #e5e5e5;
242
+
243
+
244
+	/* #ifndef APP-NVUE */
245
+	@media screen and (max-width: 500px) {
246
+		.hide-on-phone {
247
+			display: none;
248
+		}
249
+	}
250
+
251
+	/* #endif */
252
+	.uni-stat__select {
253
+		display: flex;
254
+		align-items: center;
255
+		// padding: 15px;
256
+		cursor: pointer;
257
+		width: 100%;
258
+		flex: 1;
259
+		box-sizing: border-box;
260
+	}
261
+
262
+	.uni-stat-box {
263
+		width: 100%;
264
+		flex: 1;
265
+	}
266
+
267
+	.uni-stat__actived {
268
+		width: 100%;
269
+		flex: 1;
270
+		// outline: 1px solid #2979ff;
271
+	}
272
+
273
+	.uni-label-text {
274
+		font-size: 14px;
275
+		font-weight: bold;
276
+		color: $uni-base-color;
277
+		margin: auto 0;
278
+		margin-right: 5px;
279
+	}
280
+
281
+	.uni-select {
282
+		font-size: 14px;
283
+		border: 1px solid $uni-border-3;
284
+		box-sizing: border-box;
285
+		border-radius: 4px;
286
+		padding: 0 5px;
287
+		padding-left: 10px;
288
+		position: relative;
289
+		/* #ifndef APP-NVUE */
290
+		display: flex;
291
+		user-select: none;
292
+		/* #endif */
293
+		flex-direction: row;
294
+		align-items: center;
295
+		border-bottom: solid 1px $uni-border-3;
296
+		width: 100%;
297
+		flex: 1;
298
+		height: 35px;
299
+
300
+    &--disabled{
301
+      background-color: #f5f7fa;
302
+      cursor: not-allowed;
303
+    }
304
+	}
305
+
306
+	.uni-select__label {
307
+		font-size: 16px;
308
+		// line-height: 22px;
309
+		height: 35px;
310
+		padding-right: 10px;
311
+		color: $uni-secondary-color;
312
+	}
313
+
314
+	.uni-select__input-box {
315
+		height: 35px;
316
+		position: relative;
317
+		/* #ifndef APP-NVUE */
318
+		display: flex;
319
+		/* #endif */
320
+		flex: 1;
321
+		flex-direction: row;
322
+		align-items: center;
323
+	}
324
+
325
+	.uni-select__input {
326
+		flex: 1;
327
+		font-size: 14px;
328
+		height: 22px;
329
+		line-height: 22px;
330
+	}
331
+
332
+	.uni-select__input-plac {
333
+		font-size: 14px;
334
+		color: $uni-secondary-color;
335
+	}
336
+
337
+	.uni-select__selector {
338
+		/* #ifndef APP-NVUE */
339
+		box-sizing: border-box;
340
+		/* #endif */
341
+		position: absolute;
342
+		top: calc(100% + 12px);
343
+		left: 0;
344
+		width: 100%;
345
+		background-color: #FFFFFF;
346
+		border: 1px solid #EBEEF5;
347
+		border-radius: 6px;
348
+		box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
349
+		z-index: 3;
350
+		padding: 4px 0;
351
+	}
352
+
353
+	.uni-select__selector-scroll {
354
+		/* #ifndef APP-NVUE */
355
+		max-height: 200px;
356
+		box-sizing: border-box;
357
+		/* #endif */
358
+	}
359
+
360
+	.uni-select__selector-empty,
361
+	.uni-select__selector-item {
362
+		/* #ifndef APP-NVUE */
363
+		display: flex;
364
+		cursor: pointer;
365
+		/* #endif */
366
+		line-height: 35px;
367
+		font-size: 14px;
368
+		text-align: center;
369
+		/* border-bottom: solid 1px $uni-border-3; */
370
+		padding: 0px 10px;
371
+	}
372
+
373
+	.uni-select__selector-item:hover {
374
+		background-color: #f9f9f9;
375
+	}
376
+
377
+	.uni-select__selector-empty:last-child,
378
+	.uni-select__selector-item:last-child {
379
+		/* #ifndef APP-NVUE */
380
+		border-bottom: none;
381
+		/* #endif */
382
+	}
383
+
384
+	.uni-select__selector__disabled {
385
+		opacity: 0.4;
386
+		cursor: default;
387
+	}
388
+
389
+	/* picker 弹出层通用的指示小三角 */
390
+	.uni-popper__arrow,
391
+	.uni-popper__arrow::after {
392
+		position: absolute;
393
+		display: block;
394
+		width: 0;
395
+		height: 0;
396
+		border-color: transparent;
397
+		border-style: solid;
398
+		border-width: 6px;
399
+	}
400
+
401
+	.uni-popper__arrow {
402
+		filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
403
+		top: -6px;
404
+		left: 10%;
405
+		margin-right: 3px;
406
+		border-top-width: 0;
407
+		border-bottom-color: #EBEEF5;
408
+	}
409
+
410
+	.uni-popper__arrow::after {
411
+		content: " ";
412
+		top: 1px;
413
+		margin-left: -6px;
414
+		border-top-width: 0;
415
+		border-bottom-color: #fff;
416
+	}
417
+
418
+	.uni-select__input-text {
419
+		// width: 280px;
420
+		width: 100%;
421
+		color: $uni-main-color;
422
+		white-space: nowrap;
423
+		text-overflow: ellipsis;
424
+		-o-text-overflow: ellipsis;
425
+		overflow: hidden;
426
+	}
427
+
428
+	.uni-select__input-placeholder {
429
+		color: $uni-base-color;
430
+		font-size: 12px;
431
+	}
432
+
433
+	.uni-select--mask {
434
+		position: fixed;
435
+		top: 0;
436
+		bottom: 0;
437
+		right: 0;
438
+		left: 0;
439
+	}
440
+</style>

+ 85 - 0
uni_modules/uni-data-select/package.json

@@ -0,0 +1,85 @@
1
+{
2
+  "id": "uni-data-select",
3
+  "displayName": "uni-data-select 下拉框选择器",
4
+  "version": "0.1.9",
5
+  "description": "通过数据驱动的下拉框选择器",
6
+  "keywords": [
7
+    "uni-ui",
8
+    "select",
9
+    "uni-data-select",
10
+    "下拉框",
11
+    "下拉选"
12
+],
13
+  "repository": "https://github.com/dcloudio/uni-ui",
14
+  "engines": {
15
+    "HBuilderX": "^3.1.1"
16
+  },
17
+  "directories": {
18
+    "example": "../../temps/example_temps"
19
+  },
20
+"dcloudext": {
21
+    "sale": {
22
+      "regular": {
23
+        "price": "0.00"
24
+      },
25
+      "sourcecode": {
26
+        "price": "0.00"
27
+      }
28
+    },
29
+    "contact": {
30
+      "qq": ""
31
+    },
32
+    "declaration": {
33
+      "ads": "无",
34
+      "data": "无",
35
+      "permissions": "无"
36
+    },
37
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
38
+    "type": "component-vue"
39
+  },
40
+  "uni_modules": {
41
+    "dependencies": ["uni-load-more"],
42
+    "encrypt": [],
43
+    "platforms": {
44
+      "cloud": {
45
+        "tcb": "y",
46
+        "aliyun": "y"
47
+      },
48
+      "client": {
49
+        "App": {
50
+          "app-vue": "u",
51
+          "app-nvue": "n"
52
+        },
53
+        "H5-mobile": {
54
+          "Safari": "y",
55
+          "Android Browser": "y",
56
+          "微信浏览器(Android)": "y",
57
+          "QQ浏览器(Android)": "y"
58
+        },
59
+        "H5-pc": {
60
+          "Chrome": "y",
61
+          "IE": "y",
62
+          "Edge": "y",
63
+          "Firefox": "y",
64
+          "Safari": "y"
65
+        },
66
+        "小程序": {
67
+          "微信": "y",
68
+          "阿里": "u",
69
+          "百度": "u",
70
+          "字节跳动": "u",
71
+        "QQ": "u",
72
+        "京东": "u"
73
+        },
74
+        "快应用": {
75
+          "华为": "u",
76
+          "联盟": "u"
77
+        },
78
+        "Vue": {
79
+            "vue2": "y",
80
+            "vue3": "y"
81
+        }
82
+      }
83
+    }
84
+  }
85
+}

+ 8 - 0
uni_modules/uni-data-select/readme.md

@@ -0,0 +1,8 @@
1
+## DataSelect 下拉框选择器
2
+> **组件名:uni-data-select**
3
+> 代码块: `uDataSelect`
4
+
5
+当选项过多时,使用下拉菜单展示并选择内容
6
+
7
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-select)
8
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 

+ 10 - 0
uni_modules/uni-dateformat/changelog.md

@@ -0,0 +1,10 @@
1
+## 1.0.0(2021-11-19)
2
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
3
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-dateformat](https://uniapp.dcloud.io/component/uniui/uni-dateformat)
4
+## 0.0.5(2021-07-08)
5
+- 调整 默认时间不再是当前时间,而是显示'-'字符
6
+## 0.0.4(2021-05-12)
7
+- 新增 组件示例地址
8
+## 0.0.3(2021-02-04)
9
+- 调整为uni_modules目录规范
10
+- 修复 iOS 平台日期格式化出错的问题

+ 200 - 0
uni_modules/uni-dateformat/components/uni-dateformat/date-format.js

@@ -0,0 +1,200 @@
1
+// yyyy-MM-dd hh:mm:ss.SSS 所有支持的类型
2
+function pad(str, length = 2) {
3
+	str += ''
4
+	while (str.length < length) {
5
+		str = '0' + str
6
+	}
7
+	return str.slice(-length)
8
+}
9
+
10
+const parser = {
11
+	yyyy: (dateObj) => {
12
+		return pad(dateObj.year, 4)
13
+	},
14
+	yy: (dateObj) => {
15
+		return pad(dateObj.year)
16
+	},
17
+	MM: (dateObj) => {
18
+		return pad(dateObj.month)
19
+	},
20
+	M: (dateObj) => {
21
+		return dateObj.month
22
+	},
23
+	dd: (dateObj) => {
24
+		return pad(dateObj.day)
25
+	},
26
+	d: (dateObj) => {
27
+		return dateObj.day
28
+	},
29
+	hh: (dateObj) => {
30
+		return pad(dateObj.hour)
31
+	},
32
+	h: (dateObj) => {
33
+		return dateObj.hour
34
+	},
35
+	mm: (dateObj) => {
36
+		return pad(dateObj.minute)
37
+	},
38
+	m: (dateObj) => {
39
+		return dateObj.minute
40
+	},
41
+	ss: (dateObj) => {
42
+		return pad(dateObj.second)
43
+	},
44
+	s: (dateObj) => {
45
+		return dateObj.second
46
+	},
47
+	SSS: (dateObj) => {
48
+		return pad(dateObj.millisecond, 3)
49
+	},
50
+	S: (dateObj) => {
51
+		return dateObj.millisecond
52
+	},
53
+}
54
+
55
+// 这都n年了iOS依然不认识2020-12-12,需要转换为2020/12/12
56
+function getDate(time) {
57
+	if (time instanceof Date) {
58
+		return time
59
+	}
60
+	switch (typeof time) {
61
+		case 'string':
62
+			{
63
+				// 2020-12-12T12:12:12.000Z、2020-12-12T12:12:12.000
64
+				if (time.indexOf('T') > -1) {
65
+					return new Date(time)
66
+				}
67
+				return new Date(time.replace(/-/g, '/'))
68
+			}
69
+		default:
70
+			return new Date(time)
71
+	}
72
+}
73
+
74
+export function formatDate(date, format = 'yyyy/MM/dd hh:mm:ss') {
75
+	if (!date && date !== 0) {
76
+		return ''
77
+	}
78
+	date = getDate(date)
79
+	const dateObj = {
80
+		year: date.getFullYear(),
81
+		month: date.getMonth() + 1,
82
+		day: date.getDate(),
83
+		hour: date.getHours(),
84
+		minute: date.getMinutes(),
85
+		second: date.getSeconds(),
86
+		millisecond: date.getMilliseconds()
87
+	}
88
+	const tokenRegExp = /yyyy|yy|MM|M|dd|d|hh|h|mm|m|ss|s|SSS|SS|S/
89
+	let flag = true
90
+	let result = format
91
+	while (flag) {
92
+		flag = false
93
+		result = result.replace(tokenRegExp, function(matched) {
94
+			flag = true
95
+			return parser[matched](dateObj)
96
+		})
97
+	}
98
+	return result
99
+}
100
+
101
+export function friendlyDate(time, {
102
+	locale = 'zh',
103
+	threshold = [60000, 3600000],
104
+	format = 'yyyy/MM/dd hh:mm:ss'
105
+}) {
106
+	if (time === '-') {
107
+		return time
108
+	}
109
+	if (!time && time !== 0) {
110
+		return ''
111
+	}
112
+	const localeText = {
113
+		zh: {
114
+			year: '年',
115
+			month: '月',
116
+			day: '天',
117
+			hour: '小时',
118
+			minute: '分钟',
119
+			second: '秒',
120
+			ago: '前',
121
+			later: '后',
122
+			justNow: '刚刚',
123
+			soon: '马上',
124
+			template: '{num}{unit}{suffix}'
125
+		},
126
+		en: {
127
+			year: 'year',
128
+			month: 'month',
129
+			day: 'day',
130
+			hour: 'hour',
131
+			minute: 'minute',
132
+			second: 'second',
133
+			ago: 'ago',
134
+			later: 'later',
135
+			justNow: 'just now',
136
+			soon: 'soon',
137
+			template: '{num} {unit} {suffix}'
138
+		}
139
+	}
140
+	const text = localeText[locale] || localeText.zh
141
+	let date = getDate(time)
142
+	let ms = date.getTime() - Date.now()
143
+	let absMs = Math.abs(ms)
144
+	if (absMs < threshold[0]) {
145
+		return ms < 0 ? text.justNow : text.soon
146
+	}
147
+	if (absMs >= threshold[1]) {
148
+		return formatDate(date, format)
149
+	}
150
+	let num
151
+	let unit
152
+	let suffix = text.later
153
+	if (ms < 0) {
154
+		suffix = text.ago
155
+		ms = -ms
156
+	}
157
+	const seconds = Math.floor((ms) / 1000)
158
+	const minutes = Math.floor(seconds / 60)
159
+	const hours = Math.floor(minutes / 60)
160
+	const days = Math.floor(hours / 24)
161
+	const months = Math.floor(days / 30)
162
+	const years = Math.floor(months / 12)
163
+	switch (true) {
164
+		case years > 0:
165
+			num = years
166
+			unit = text.year
167
+			break
168
+		case months > 0:
169
+			num = months
170
+			unit = text.month
171
+			break
172
+		case days > 0:
173
+			num = days
174
+			unit = text.day
175
+			break
176
+		case hours > 0:
177
+			num = hours
178
+			unit = text.hour
179
+			break
180
+		case minutes > 0:
181
+			num = minutes
182
+			unit = text.minute
183
+			break
184
+		default:
185
+			num = seconds
186
+			unit = text.second
187
+			break
188
+	}
189
+
190
+	if (locale === 'en') {
191
+		if (num === 1) {
192
+			num = 'a'
193
+		} else {
194
+			unit += 's'
195
+		}
196
+	}
197
+
198
+	return text.template.replace(/{\s*num\s*}/g, num + '').replace(/{\s*unit\s*}/g, unit).replace(/{\s*suffix\s*}/g,
199
+		suffix)
200
+}

+ 88 - 0
uni_modules/uni-dateformat/components/uni-dateformat/uni-dateformat.vue

@@ -0,0 +1,88 @@
1
+<template>
2
+	<text>{{dateShow}}</text>
3
+</template>
4
+
5
+<script>
6
+	import {friendlyDate} from './date-format.js'
7
+	/**
8
+	 * Dateformat 日期格式化
9
+	 * @description 日期格式化组件
10
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=3279
11
+	 * @property {Object|String|Number} date 日期对象/日期字符串/时间戳
12
+	 * @property {String} locale 格式化使用的语言
13
+	 * 	@value zh 中文
14
+	 * 	@value en 英文
15
+	 * @property {Array} threshold 应用不同类型格式化的阈值
16
+	 * @property {String} format 输出日期字符串时的格式
17
+	 */
18
+	export default {
19
+		name: 'uniDateformat',
20
+		props: {
21
+			date: {
22
+				type: [Object, String, Number],
23
+				default () {
24
+					return '-'
25
+				}
26
+			},
27
+			locale: {
28
+				type: String,
29
+				default: 'zh',
30
+			},
31
+			threshold: {
32
+				type: Array,
33
+				default () {
34
+					return [0, 0]
35
+				}
36
+			},
37
+			format: {
38
+				type: String,
39
+				default: 'yyyy/MM/dd hh:mm:ss'
40
+			},
41
+			// refreshRate使用不当可能导致性能问题,谨慎使用
42
+			refreshRate: {
43
+				type: [Number, String],
44
+				default: 0
45
+			}
46
+		},
47
+		data() {
48
+			return {
49
+				refreshMark: 0
50
+			}
51
+		},
52
+		computed: {
53
+			dateShow() {
54
+				this.refreshMark
55
+				return friendlyDate(this.date, {
56
+					locale: this.locale,
57
+					threshold: this.threshold,
58
+					format: this.format
59
+				})
60
+			}
61
+		},
62
+		watch: {
63
+			refreshRate: {
64
+				handler() {
65
+					this.setAutoRefresh()
66
+				},
67
+				immediate: true
68
+			}
69
+		},
70
+		methods: {
71
+			refresh() {
72
+				this.refreshMark++
73
+			},
74
+			setAutoRefresh() {
75
+				clearInterval(this.refreshInterval)
76
+				if (this.refreshRate) {
77
+					this.refreshInterval = setInterval(() => {
78
+						this.refresh()
79
+					}, parseInt(this.refreshRate))
80
+				}
81
+			}
82
+		}
83
+	}
84
+</script>
85
+
86
+<style>
87
+
88
+</style>

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

@@ -0,0 +1,88 @@
1
+{
2
+  "id": "uni-dateformat",
3
+  "displayName": "uni-dateformat 日期格式化",
4
+  "version": "1.0.0",
5
+  "description": "日期格式化组件,可以将日期格式化为1分钟前、刚刚等形式",
6
+  "keywords": [
7
+    "uni-ui",
8
+    "uniui",
9
+    "日期格式化",
10
+    "时间格式化",
11
+    "格式化时间",
12
+    ""
13
+],
14
+  "repository": "https://github.com/dcloudio/uni-ui",
15
+  "engines": {
16
+    "HBuilderX": ""
17
+  },
18
+  "directories": {
19
+    "example": "../../temps/example_temps"
20
+  },
21
+  "dcloudext": {
22
+    "category": [
23
+      "前端组件",
24
+      "通用组件"
25
+    ],
26
+    "sale": {
27
+      "regular": {
28
+        "price": "0.00"
29
+      },
30
+      "sourcecode": {
31
+        "price": "0.00"
32
+      }
33
+    },
34
+    "contact": {
35
+      "qq": ""
36
+    },
37
+    "declaration": {
38
+      "ads": "无",
39
+      "data": "无",
40
+      "permissions": "无"
41
+    },
42
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
43
+  },
44
+  "uni_modules": {
45
+    "dependencies": ["uni-scss"],
46
+    "encrypt": [],
47
+    "platforms": {
48
+      "cloud": {
49
+        "tcb": "y",
50
+        "aliyun": "y"
51
+      },
52
+      "client": {
53
+        "App": {
54
+          "app-vue": "y",
55
+          "app-nvue": "y"
56
+        },
57
+        "H5-mobile": {
58
+          "Safari": "y",
59
+          "Android Browser": "y",
60
+          "微信浏览器(Android)": "y",
61
+          "QQ浏览器(Android)": "y"
62
+        },
63
+        "H5-pc": {
64
+          "Chrome": "y",
65
+          "IE": "y",
66
+          "Edge": "y",
67
+          "Firefox": "y",
68
+          "Safari": "y"
69
+        },
70
+        "小程序": {
71
+          "微信": "y",
72
+          "阿里": "y",
73
+          "百度": "y",
74
+          "字节跳动": "y",
75
+          "QQ": "y"
76
+        },
77
+        "快应用": {
78
+          "华为": "y",
79
+          "联盟": "y"
80
+        },
81
+        "Vue": {
82
+            "vue2": "y",
83
+            "vue3": "y"
84
+        }
85
+      }
86
+    }
87
+  }
88
+}

+ 11 - 0
uni_modules/uni-dateformat/readme.md

@@ -0,0 +1,11 @@
1
+
2
+
3
+### DateFormat 日期格式化
4
+> **组件名:uni-dateformat**
5
+> 代码块: `uDateformat`
6
+
7
+
8
+日期格式化组件。
9
+
10
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-dateformat)
11
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 

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

@@ -0,0 +1,103 @@
1
+## 2.2.11(2022-09-19)
2
+- 修复,支付宝小程序样式错乱,[详情](https://github.com/dcloudio/uni-app/issues/3861)
3
+## 2.2.10(2022-09-19)
4
+- 修复,反向选择日期范围,日期显示异常,[详情](https://ask.dcloud.net.cn/question/153401?item_id=212892&rf=false)
5
+## 2.2.9(2022-09-16)
6
+- 可以使用 uni-scss 控制主题色
7
+## 2.2.8(2022-09-08)
8
+- 修复 close事件无效的 bug
9
+## 2.2.7(2022-09-05)
10
+- 修复 移动端 maskClick 无效的 bug,详见:[https://ask.dcloud.net.cn/question/140824?item_id=209458&rf=false](https://ask.dcloud.net.cn/question/140824?item_id=209458&rf=false)
11
+## 2.2.6(2022-06-30)
12
+- 优化 组件样式,调整了组件图标大小、高度、颜色等,与uni-ui风格保持一致
13
+## 2.2.5(2022-06-24)
14
+- 修复 日历顶部年月及底部确认未国际化 bug
15
+## 2.2.4(2022-03-31)
16
+- 修复 Vue3 下动态赋值,单选类型未响应的 bug
17
+## 2.2.3(2022-03-28)
18
+- 修复 Vue3 下动态赋值未响应的 bug
19
+## 2.2.2(2021-12-10)
20
+- 修复 clear-icon 属性在小程序平台不生效的 bug
21
+## 2.2.1(2021-12-10)
22
+- 修复 日期范围选在小程序平台,必须多点击一次才能取消选中状态的 bug
23
+## 2.2.0(2021-11-19)
24
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
25
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-datetime-picker](https://uniapp.dcloud.io/component/uniui/uni-datetime-picker)
26
+## 2.1.5(2021-11-09) 
27
+- 新增 提供组件设计资源,组件样式调整
28
+## 2.1.4(2021-09-10)
29
+- 修复 hide-second 在移动端的 bug
30
+- 修复 单选赋默认值时,赋值日期未高亮的 bug
31
+- 修复 赋默认值时,移动端未正确显示时间的 bug
32
+## 2.1.3(2021-09-09)
33
+- 新增 hide-second 属性,支持只使用时分,隐藏秒
34
+## 2.1.2(2021-09-03)
35
+- 优化 取消选中时(范围选)直接开始下一次选择, 避免多点一次
36
+- 优化 移动端支持清除按钮,同时支持通过 ref 调用组件的 clear 方法
37
+- 优化 调整字号大小,美化日历界面
38
+- 修复 因国际化导致的 placeholder 失效的 bug
39
+## 2.1.1(2021-08-24)
40
+- 新增 支持国际化
41
+- 优化 范围选择器在 pc 端过宽的问题
42
+## 2.1.0(2021-08-09)
43
+- 新增 适配 vue3
44
+## 2.0.19(2021-08-09)
45
+- 新增 支持作为 uni-forms 子组件相关功能
46
+- 修复 在 uni-forms 中使用时,选择时间报 NAN 错误的 bug
47
+## 2.0.18(2021-08-05)
48
+- 修复 type 属性动态赋值无效的 bug
49
+- 修复 ‘确认’按钮被 tabbar 遮盖 bug
50
+- 修复 组件未赋值时范围选左、右日历相同的 bug
51
+## 2.0.17(2021-08-04)
52
+- 修复 范围选未正确显示当前值的 bug
53
+- 修复 h5 平台(移动端)报错 'cale' of undefined 的 bug
54
+## 2.0.16(2021-07-21)
55
+- 新增 return-type 属性支持返回 date 日期对象
56
+## 2.0.15(2021-07-14)
57
+- 修复 单选日期类型,初始赋值后不在当前日历的 bug
58
+- 新增 clearIcon 属性,显示框的清空按钮可配置显示隐藏(仅 pc 有效)
59
+- 优化 移动端移除显示框的清空按钮,无实际用途
60
+## 2.0.14(2021-07-14)
61
+- 修复 组件赋值为空,界面未更新的 bug
62
+- 修复 start 和 end 不能动态赋值的 bug
63
+- 修复 范围选类型,用户选择后再次选择右侧日历(结束日期)显示不正确的 bug
64
+## 2.0.13(2021-07-08)
65
+- 修复 范围选择不能动态赋值的 bug
66
+## 2.0.12(2021-07-08)
67
+- 修复 范围选择的初始时间在一个月内时,造成无法选择的bug
68
+## 2.0.11(2021-07-08)
69
+- 优化 弹出层在超出视窗边缘定位不准确的问题
70
+## 2.0.10(2021-07-08)
71
+- 修复 范围起始点样式的背景色与今日样式的字体前景色融合,导致日期字体看不清的 bug
72
+- 优化 弹出层在超出视窗边缘被遮盖的问题
73
+## 2.0.9(2021-07-07)
74
+- 新增 maskClick 事件
75
+- 修复 特殊情况日历 rpx 布局错误的 bug,rpx -> px
76
+- 修复 范围选择时清空返回值不合理的bug,['', ''] -> []
77
+## 2.0.8(2021-07-07)
78
+- 新增 日期时间显示框支持插槽
79
+## 2.0.7(2021-07-01)
80
+- 优化 添加 uni-icons 依赖
81
+## 2.0.6(2021-05-22)
82
+- 修复 图标在小程序上不显示的 bug
83
+- 优化 重命名引用组件,避免潜在组件命名冲突
84
+## 2.0.5(2021-05-20)
85
+- 优化 代码目录扁平化
86
+## 2.0.4(2021-05-12)
87
+- 新增 组件示例地址
88
+## 2.0.3(2021-05-10)
89
+- 修复 ios 下不识别 '-' 日期格式的 bug
90
+- 优化 pc 下弹出层添加边框和阴影
91
+## 2.0.2(2021-05-08)
92
+- 修复 在 admin 中获取弹出层定位错误的bug
93
+## 2.0.1(2021-05-08)
94
+- 修复 type 属性向下兼容,默认值从 date 变更为 datetime
95
+## 2.0.0(2021-04-30)
96
+- 支持日历形式的日期+时间的范围选择
97
+ > 注意:此版本不向后兼容,不再支持单独时间选择(type=time)及相关的 hide-second 属性(时间选可使用内置组件 picker)
98
+## 1.0.6(2021-03-18)
99
+- 新增 hide-second 属性,时间支持仅选择时、分
100
+- 修复 选择跟显示的日期不一样的 bug
101
+- 修复 chang事件触发2次的 bug
102
+- 修复 分、秒 end 范围错误的 bug
103
+- 优化 更好的 nvue 适配

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

@@ -0,0 +1,187 @@
1
+<template>
2
+	<view class="uni-calendar-item__weeks-box" :class="{
3
+		'uni-calendar-item--disable':weeks.disable,
4
+		'uni-calendar-item--before-checked-x':weeks.beforeMultiple,
5
+		'uni-calendar-item--multiple': weeks.multiple,
6
+		'uni-calendar-item--after-checked-x':weeks.afterMultiple,
7
+		}" @click="choiceDate(weeks)" @mouseenter="handleMousemove(weeks)">
8
+		<view class="uni-calendar-item__weeks-box-item" :class="{
9
+				'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && (calendar.userChecked || !checkHover),
10
+				'uni-calendar-item--checked-range-text': checkHover,
11
+				'uni-calendar-item--before-checked':weeks.beforeMultiple,
12
+				'uni-calendar-item--multiple': weeks.multiple,
13
+				'uni-calendar-item--after-checked':weeks.afterMultiple,
14
+				'uni-calendar-item--disable':weeks.disable,
15
+				}">
16
+			<text v-if="selected&&weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text>
17
+			<text class="uni-calendar-item__weeks-box-text uni-calendar-item__weeks-box-text-disable uni-calendar-item--checked-text">{{weeks.date}}</text>
18
+		</view>
19
+		<view :class="{'uni-calendar-item--isDay': weeks.isDay}"></view>
20
+	</view>
21
+</template>
22
+
23
+<script>
24
+	export default {
25
+		props: {
26
+			weeks: {
27
+				type: Object,
28
+				default () {
29
+					return {}
30
+				}
31
+			},
32
+			calendar: {
33
+				type: Object,
34
+				default: () => {
35
+					return {}
36
+				}
37
+			},
38
+			selected: {
39
+				type: Array,
40
+				default: () => {
41
+					return []
42
+				}
43
+			},
44
+			lunar: {
45
+				type: Boolean,
46
+				default: false
47
+			},
48
+			checkHover: {
49
+				type: Boolean,
50
+				default: false
51
+			}
52
+		},
53
+		methods: {
54
+			choiceDate(weeks) {
55
+				this.$emit('change', weeks)
56
+			},
57
+			handleMousemove(weeks) {
58
+				this.$emit('handleMouse', weeks)
59
+			}
60
+		}
61
+	}
62
+</script>
63
+
64
+<style lang="scss" >
65
+	$uni-primary: #007aff !default;
66
+
67
+	.uni-calendar-item__weeks-box {
68
+		flex: 1;
69
+		/* #ifndef APP-NVUE */
70
+		display: flex;
71
+		/* #endif */
72
+		flex-direction: column;
73
+		justify-content: center;
74
+		align-items: center;
75
+		margin: 1px 0;
76
+		position: relative;
77
+	}
78
+
79
+	.uni-calendar-item__weeks-box-text {
80
+		font-size: 14px;
81
+		// font-family: Lato-Bold, Lato;
82
+		font-weight: bold;
83
+		color: darken($color: $uni-primary, $amount: 40%);
84
+	}
85
+
86
+	.uni-calendar-item__weeks-lunar-text {
87
+		font-size: 12px;
88
+		color: #333;
89
+	}
90
+
91
+	.uni-calendar-item__weeks-box-item {
92
+		position: relative;
93
+		/* #ifndef APP-NVUE */
94
+		display: flex;
95
+		/* #endif */
96
+		flex-direction: column;
97
+		justify-content: center;
98
+		align-items: center;
99
+		width: 40px;
100
+		height: 40px;
101
+		/* #ifdef H5 */
102
+		cursor: pointer;
103
+		/* #endif */
104
+	}
105
+
106
+
107
+	.uni-calendar-item__weeks-box-circle {
108
+		position: absolute;
109
+		top: 5px;
110
+		right: 5px;
111
+		width: 8px;
112
+		height: 8px;
113
+		border-radius: 8px;
114
+		background-color: #dd524d;
115
+
116
+	}
117
+
118
+	.uni-calendar-item__weeks-box .uni-calendar-item--disable {
119
+		// background-color: rgba(249, 249, 249, $uni-opacity-disabled);
120
+		cursor: default;
121
+	}
122
+
123
+	.uni-calendar-item--disable .uni-calendar-item__weeks-box-text-disable {
124
+		color: #D1D1D1;
125
+	}
126
+
127
+	.uni-calendar-item--isDay {
128
+		position: absolute;
129
+		top: 10px;
130
+		right: 17%;
131
+		background-color: #dd524d;
132
+		width:6px;
133
+		height: 6px;
134
+		border-radius: 50%;
135
+	}
136
+
137
+	.uni-calendar-item--extra {
138
+		color: #dd524d;
139
+		opacity: 0.8;
140
+	}
141
+
142
+	.uni-calendar-item__weeks-box .uni-calendar-item--checked {
143
+		background-color: $uni-primary;
144
+		border-radius: 50%;
145
+		box-sizing: border-box;
146
+		border: 3px solid #fff;
147
+	}
148
+
149
+	.uni-calendar-item--checked .uni-calendar-item--checked-text {
150
+		color: #fff;
151
+	}
152
+
153
+	.uni-calendar-item--multiple .uni-calendar-item--checked-range-text {
154
+		color: #333;
155
+	}
156
+
157
+	.uni-calendar-item--multiple {
158
+		background-color:  #F6F7FC;
159
+		// color: #fff;
160
+	}
161
+
162
+	.uni-calendar-item--multiple .uni-calendar-item--before-checked,
163
+	.uni-calendar-item--multiple .uni-calendar-item--after-checked {
164
+		background-color: $uni-primary;
165
+		border-radius: 50%;
166
+		box-sizing: border-box;
167
+		border: 3px solid #F6F7FC;
168
+	}
169
+
170
+	.uni-calendar-item--before-checked .uni-calendar-item--checked-text,
171
+	.uni-calendar-item--after-checked .uni-calendar-item--checked-text {
172
+		color: #fff;
173
+	}
174
+
175
+	.uni-calendar-item--before-checked-x {
176
+		border-top-left-radius: 50px;
177
+		border-bottom-left-radius: 50px;
178
+		box-sizing: border-box;
179
+		background-color: #F6F7FC;
180
+	}
181
+
182
+	.uni-calendar-item--after-checked-x {
183
+		border-top-right-radius: 50px;
184
+		border-bottom-right-radius: 50px;
185
+		background-color: #F6F7FC;
186
+	}
187
+</style>

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

@@ -0,0 +1,924 @@
1
+<template>
2
+	<view class="uni-calendar" @mouseleave="leaveCale">
3
+		<view v-if="!insert&&show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}"
4
+			@click="clean();maskClick()"></view>
5
+		<view v-if="insert || show" class="uni-calendar__content"
6
+			:class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow, 'uni-calendar__content-mobile': aniMaskShow}">
7
+			<view class="uni-calendar__header" :class="{'uni-calendar__header-mobile' :!insert}">
8
+				<view v-if="left" class="uni-calendar__header-btn-box" @click.stop="pre">
9
+					<view class="uni-calendar__header-btn uni-calendar--left"></view>
10
+				</view>
11
+				<picker mode="date" :value="date" fields="month" @change="bindDateChange">
12
+					<text
13
+						class="uni-calendar__header-text">{{ (nowDate.year||'') + yearText + ( nowDate.month||'') + monthText}}</text>
14
+				</picker>
15
+				<view v-if="right" class="uni-calendar__header-btn-box" @click.stop="next">
16
+					<view class="uni-calendar__header-btn uni-calendar--right"></view>
17
+				</view>
18
+				<view v-if="!insert" class="dialog-close" @click="clean">
19
+					<view class="dialog-close-plus" data-id="close"></view>
20
+					<view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
21
+				</view>
22
+
23
+				<!-- <text class="uni-calendar__backtoday" @click="backtoday">回到今天</text> -->
24
+			</view>
25
+			<view class="uni-calendar__box">
26
+				<view v-if="showMonth" class="uni-calendar__box-bg">
27
+					<text class="uni-calendar__box-bg-text">{{nowDate.month}}</text>
28
+				</view>
29
+				<view class="uni-calendar__weeks" style="padding-bottom: 7px;">
30
+					<view class="uni-calendar__weeks-day">
31
+						<text class="uni-calendar__weeks-day-text">{{SUNText}}</text>
32
+					</view>
33
+					<view class="uni-calendar__weeks-day">
34
+						<text class="uni-calendar__weeks-day-text">{{MONText}}</text>
35
+					</view>
36
+					<view class="uni-calendar__weeks-day">
37
+						<text class="uni-calendar__weeks-day-text">{{TUEText}}</text>
38
+					</view>
39
+					<view class="uni-calendar__weeks-day">
40
+						<text class="uni-calendar__weeks-day-text">{{WEDText}}</text>
41
+					</view>
42
+					<view class="uni-calendar__weeks-day">
43
+						<text class="uni-calendar__weeks-day-text">{{THUText}}</text>
44
+					</view>
45
+					<view class="uni-calendar__weeks-day">
46
+						<text class="uni-calendar__weeks-day-text">{{FRIText}}</text>
47
+					</view>
48
+					<view class="uni-calendar__weeks-day">
49
+						<text class="uni-calendar__weeks-day-text">{{SATText}}</text>
50
+					</view>
51
+				</view>
52
+				<view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
53
+					<view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
54
+						<calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar"
55
+							:selected="selected" :lunar="lunar" :checkHover="range" @change="choiceDate"
56
+							@handleMouse="handleMouse">
57
+						</calendar-item>
58
+					</view>
59
+				</view>
60
+			</view>
61
+			<view v-if="!insert && !range && typeHasTime" class="uni-date-changed uni-calendar--fixed-top"
62
+				style="padding: 0 80px;">
63
+				<view class="uni-date-changed--time-date">{{tempSingleDate ? tempSingleDate : selectDateText}}</view>
64
+				<time-picker type="time" :start="reactStartTime" :end="reactEndTime" v-model="time"
65
+					:disabled="!tempSingleDate" :border="false" :hide-second="hideSecond" class="time-picker-style">
66
+				</time-picker>
67
+			</view>
68
+
69
+			<view v-if="!insert && range && typeHasTime" class="uni-date-changed uni-calendar--fixed-top">
70
+				<view class="uni-date-changed--time-start">
71
+					<view class="uni-date-changed--time-date">{{tempRange.before ? tempRange.before : startDateText}}
72
+					</view>
73
+					<time-picker type="time" :start="reactStartTime" v-model="timeRange.startTime" :border="false"
74
+						:hide-second="hideSecond" :disabled="!tempRange.before" class="time-picker-style">
75
+					</time-picker>
76
+				</view>
77
+				<view style="line-height: 50px;">
78
+					<uni-icons type="arrowthinright" color="#999"></uni-icons>
79
+				</view>
80
+				<view class="uni-date-changed--time-end">
81
+					<view class="uni-date-changed--time-date">{{tempRange.after ? tempRange.after : endDateText}}</view>
82
+					<time-picker type="time" :end="reactEndTime" v-model="timeRange.endTime" :border="false"
83
+						:hide-second="hideSecond" :disabled="!tempRange.after" class="time-picker-style">
84
+					</time-picker>
85
+				</view>
86
+			</view>
87
+			<view v-if="!insert" class="uni-date-changed uni-date-btn--ok">
88
+				<!-- <view class="uni-calendar__header-btn-box">
89
+					<text class="uni-calendar__button-text uni-calendar--fixed-width">{{okText}}</text>
90
+				</view> -->
91
+				<view class="uni-datetime-picker--btn" @click="confirm">{{confirmText}}</view>
92
+			</view>
93
+		</view>
94
+	</view>
95
+</template>
96
+
97
+<script>
98
+	import Calendar from './util.js';
99
+	import calendarItem from './calendar-item.vue'
100
+	import timePicker from './time-picker.vue'
101
+	import {
102
+		initVueI18n
103
+	} from '@dcloudio/uni-i18n'
104
+	import messages from './i18n/index.js'
105
+	const {
106
+		t
107
+	} = initVueI18n(messages)
108
+	/**
109
+	 * Calendar 日历
110
+	 * @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等
111
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=56
112
+	 * @property {String} date 自定义当前时间,默认为今天
113
+	 * @property {Boolean} lunar 显示农历
114
+	 * @property {String} startDate 日期选择范围-开始日期
115
+	 * @property {String} endDate 日期选择范围-结束日期
116
+	 * @property {Boolean} range 范围选择
117
+	 * @property {Boolean} insert = [true|false] 插入模式,默认为false
118
+	 * 	@value true 弹窗模式
119
+	 * 	@value false 插入模式
120
+	 * @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容
121
+	 * @property {Array} selected 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]
122
+	 * @property {Boolean} showMonth 是否选择月份为背景
123
+	 * @event {Function} change 日期改变,`insert :ture` 时生效
124
+	 * @event {Function} confirm 确认选择`insert :false` 时生效
125
+	 * @event {Function} monthSwitch 切换月份时触发
126
+	 * @example <uni-calendar :insert="true":lunar="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
127
+	 */
128
+	export default {
129
+		components: {
130
+			calendarItem,
131
+			timePicker
132
+		},
133
+		props: {
134
+			date: {
135
+				type: String,
136
+				default: ''
137
+			},
138
+			defTime: {
139
+				type: [String, Object],
140
+				default: ''
141
+			},
142
+			selectableTimes: {
143
+				type: [Object],
144
+				default () {
145
+					return {}
146
+				}
147
+			},
148
+			selected: {
149
+				type: Array,
150
+				default () {
151
+					return []
152
+				}
153
+			},
154
+			lunar: {
155
+				type: Boolean,
156
+				default: false
157
+			},
158
+			startDate: {
159
+				type: String,
160
+				default: ''
161
+			},
162
+			endDate: {
163
+				type: String,
164
+				default: ''
165
+			},
166
+			range: {
167
+				type: Boolean,
168
+				default: false
169
+			},
170
+			typeHasTime: {
171
+				type: Boolean,
172
+				default: false
173
+			},
174
+			insert: {
175
+				type: Boolean,
176
+				default: true
177
+			},
178
+			showMonth: {
179
+				type: Boolean,
180
+				default: true
181
+			},
182
+			clearDate: {
183
+				type: Boolean,
184
+				default: true
185
+			},
186
+			left: {
187
+				type: Boolean,
188
+				default: true
189
+			},
190
+			right: {
191
+				type: Boolean,
192
+				default: true
193
+			},
194
+			checkHover: {
195
+				type: Boolean,
196
+				default: true
197
+			},
198
+			hideSecond: {
199
+				type: [Boolean],
200
+				default: false
201
+			},
202
+			pleStatus: {
203
+				type: Object,
204
+				default () {
205
+					return {
206
+						before: '',
207
+						after: '',
208
+						data: [],
209
+						fulldate: ''
210
+					}
211
+				}
212
+			}
213
+		},
214
+		data() {
215
+			return {
216
+				show: false,
217
+				weeks: [],
218
+				calendar: {},
219
+				nowDate: '',
220
+				aniMaskShow: false,
221
+				firstEnter: true,
222
+				time: '',
223
+				timeRange: {
224
+					startTime: '',
225
+					endTime: ''
226
+				},
227
+				tempSingleDate: '',
228
+				tempRange: {
229
+					before: '',
230
+					after: ''
231
+				}
232
+			}
233
+		},
234
+		watch: {
235
+			date: {
236
+				immediate: true,
237
+				handler(newVal, oldVal) {
238
+					if (!this.range) {
239
+						this.tempSingleDate = newVal
240
+						setTimeout(() => {
241
+							this.init(newVal)
242
+						}, 100)
243
+					}
244
+				}
245
+			},
246
+			defTime: {
247
+				immediate: true,
248
+				handler(newVal, oldVal) {
249
+					if (!this.range) {
250
+						this.time = newVal
251
+					} else {
252
+						// console.log('-----', newVal);
253
+						this.timeRange.startTime = newVal.start
254
+						this.timeRange.endTime = newVal.end
255
+					}
256
+				}
257
+			},
258
+			startDate(val) {
259
+				this.cale.resetSatrtDate(val)
260
+				this.cale.setDate(this.nowDate.fullDate)
261
+				this.weeks = this.cale.weeks
262
+			},
263
+			endDate(val) {
264
+				this.cale.resetEndDate(val)
265
+				this.cale.setDate(this.nowDate.fullDate)
266
+				this.weeks = this.cale.weeks
267
+			},
268
+			selected(newVal) {
269
+				this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
270
+				this.weeks = this.cale.weeks
271
+			},
272
+			pleStatus: {
273
+				immediate: true,
274
+				handler(newVal, oldVal) {
275
+					const {
276
+						before,
277
+						after,
278
+						fulldate,
279
+						which
280
+					} = newVal
281
+					this.tempRange.before = before
282
+					this.tempRange.after = after
283
+					setTimeout(() => {
284
+						if (fulldate) {
285
+							this.cale.setHoverMultiple(fulldate)
286
+							if (before && after) {
287
+								this.cale.lastHover = true
288
+								if (this.rangeWithinMonth(after, before)) return
289
+								this.setDate(before)
290
+							} else {
291
+								this.cale.setMultiple(fulldate)
292
+								this.setDate(this.nowDate.fullDate)
293
+								this.calendar.fullDate = ''
294
+								this.cale.lastHover = false
295
+							}
296
+						} else {
297
+							this.cale.setDefaultMultiple(before, after)
298
+							if (which === 'left') {
299
+								this.setDate(before)
300
+								this.weeks = this.cale.weeks
301
+							} else {
302
+								this.setDate(after)
303
+								this.weeks = this.cale.weeks
304
+							}
305
+							this.cale.lastHover = true
306
+						}
307
+					}, 16)
308
+				}
309
+			}
310
+		},
311
+		computed: {
312
+			reactStartTime() {
313
+				const activeDate = this.range ? this.tempRange.before : this.calendar.fullDate
314
+				const res = activeDate === this.startDate ? this.selectableTimes.start : ''
315
+				return res
316
+			},
317
+			reactEndTime() {
318
+				const activeDate = this.range ? this.tempRange.after : this.calendar.fullDate
319
+				const res = activeDate === this.endDate ? this.selectableTimes.end : ''
320
+				return res
321
+			},
322
+			/**
323
+			 * for i18n
324
+			 */
325
+			selectDateText() {
326
+				return t("uni-datetime-picker.selectDate")
327
+			},
328
+			startDateText() {
329
+				return this.startPlaceholder || t("uni-datetime-picker.startDate")
330
+			},
331
+			endDateText() {
332
+				return this.endPlaceholder || t("uni-datetime-picker.endDate")
333
+			},
334
+			okText() {
335
+				return t("uni-datetime-picker.ok")
336
+			},
337
+			yearText() {
338
+				return t("uni-datetime-picker.year")
339
+			},
340
+			monthText() {
341
+				return t("uni-datetime-picker.month")
342
+			},
343
+			MONText() {
344
+				return t("uni-calender.MON")
345
+			},
346
+			TUEText() {
347
+				return t("uni-calender.TUE")
348
+			},
349
+			WEDText() {
350
+				return t("uni-calender.WED")
351
+			},
352
+			THUText() {
353
+				return t("uni-calender.THU")
354
+			},
355
+			FRIText() {
356
+				return t("uni-calender.FRI")
357
+			},
358
+			SATText() {
359
+				return t("uni-calender.SAT")
360
+			},
361
+			SUNText() {
362
+				return t("uni-calender.SUN")
363
+			},
364
+			confirmText() {
365
+				return t("uni-calender.confirm")
366
+			},
367
+		},
368
+		created() {
369
+			// 获取日历方法实例
370
+			this.cale = new Calendar({
371
+				// date: new Date(),
372
+				selected: this.selected,
373
+				startDate: this.startDate,
374
+				endDate: this.endDate,
375
+				range: this.range,
376
+				// multipleStatus: this.pleStatus
377
+			})
378
+			// 选中某一天
379
+			// this.cale.setDate(this.date)
380
+			this.init(this.date)
381
+			// this.setDay
382
+		},
383
+		methods: {
384
+			leaveCale() {
385
+				this.firstEnter = true
386
+			},
387
+			handleMouse(weeks) {
388
+				if (weeks.disable) return
389
+				if (this.cale.lastHover) return
390
+				let {
391
+					before,
392
+					after
393
+				} = this.cale.multipleStatus
394
+				if (!before) return
395
+				this.calendar = weeks
396
+				// 设置范围选
397
+				this.cale.setHoverMultiple(this.calendar.fullDate)
398
+				this.weeks = this.cale.weeks
399
+				// hover时,进入一个日历,更新另一个
400
+				if (this.firstEnter) {
401
+					this.$emit('firstEnterCale', this.cale.multipleStatus)
402
+					this.firstEnter = false
403
+				}
404
+			},
405
+			rangeWithinMonth(A, B) {
406
+				const [yearA, monthA] = A.split('-')
407
+				const [yearB, monthB] = B.split('-')
408
+				return yearA === yearB && monthA === monthB
409
+			},
410
+
411
+			// 取消穿透
412
+			clean() {
413
+				this.close()
414
+			},
415
+
416
+			// 蒙版点击事件
417
+			maskClick() {
418
+				this.$emit('maskClose')
419
+			},
420
+
421
+			clearCalender() {
422
+				if (this.range) {
423
+					this.timeRange.startTime = ''
424
+					this.timeRange.endTime = ''
425
+					this.tempRange.before = ''
426
+					this.tempRange.after = ''
427
+					this.cale.multipleStatus.before = ''
428
+					this.cale.multipleStatus.after = ''
429
+					this.cale.multipleStatus.data = []
430
+					this.cale.lastHover = false
431
+				} else {
432
+					this.time = ''
433
+					this.tempSingleDate = ''
434
+				}
435
+				this.calendar.fullDate = ''
436
+				this.setDate()
437
+			},
438
+
439
+			bindDateChange(e) {
440
+				const value = e.detail.value + '-1'
441
+				this.init(value)
442
+			},
443
+			/**
444
+			 * 初始化日期显示
445
+			 * @param {Object} date
446
+			 */
447
+			init(date) {
448
+				this.cale.setDate(date)
449
+				this.weeks = this.cale.weeks
450
+				this.nowDate = this.calendar = this.cale.getInfo(date)
451
+			},
452
+			// choiceDate(weeks) {
453
+			// 	if (weeks.disable) return
454
+			// 	this.calendar = weeks
455
+			// 	// 设置多选
456
+			// 	this.cale.setMultiple(this.calendar.fullDate, true)
457
+			// 	this.weeks = this.cale.weeks
458
+			// 	this.tempSingleDate = this.calendar.fullDate
459
+			// 	this.tempRange.before = this.cale.multipleStatus.before
460
+			// 	this.tempRange.after = this.cale.multipleStatus.after
461
+			// 	this.change()
462
+			// },
463
+			/**
464
+			 * 打开日历弹窗
465
+			 */
466
+			open() {
467
+				// 弹窗模式并且清理数据
468
+				if (this.clearDate && !this.insert) {
469
+					this.cale.cleanMultipleStatus()
470
+					// this.cale.setDate(this.date)
471
+					this.init(this.date)
472
+				}
473
+				this.show = true
474
+				this.$nextTick(() => {
475
+					setTimeout(() => {
476
+						this.aniMaskShow = true
477
+					}, 50)
478
+				})
479
+			},
480
+			/**
481
+			 * 关闭日历弹窗
482
+			 */
483
+			close() {
484
+				this.aniMaskShow = false
485
+				this.$nextTick(() => {
486
+					setTimeout(() => {
487
+						this.show = false
488
+						this.$emit('close')
489
+					}, 300)
490
+				})
491
+			},
492
+			/**
493
+			 * 确认按钮
494
+			 */
495
+			confirm() {
496
+				this.setEmit('confirm')
497
+				this.close()
498
+			},
499
+			/**
500
+			 * 变化触发
501
+			 */
502
+			change() {
503
+				if (!this.insert) return
504
+				this.setEmit('change')
505
+			},
506
+			/**
507
+			 * 选择月份触发
508
+			 */
509
+			monthSwitch() {
510
+				let {
511
+					year,
512
+					month
513
+				} = this.nowDate
514
+				this.$emit('monthSwitch', {
515
+					year,
516
+					month: Number(month)
517
+				})
518
+			},
519
+			/**
520
+			 * 派发事件
521
+			 * @param {Object} name
522
+			 */
523
+			setEmit(name) {
524
+				let {
525
+					year,
526
+					month,
527
+					date,
528
+					fullDate,
529
+					lunar,
530
+					extraInfo
531
+				} = this.calendar
532
+				this.$emit(name, {
533
+					range: this.cale.multipleStatus,
534
+					year,
535
+					month,
536
+					date,
537
+					time: this.time,
538
+					timeRange: this.timeRange,
539
+					fulldate: fullDate,
540
+					lunar,
541
+					extraInfo: extraInfo || {}
542
+				})
543
+			},
544
+			/**
545
+			 * 选择天触发
546
+			 * @param {Object} weeks
547
+			 */
548
+			choiceDate(weeks) {
549
+				if (weeks.disable) return
550
+				this.calendar = weeks
551
+				this.calendar.userChecked = true
552
+				// 设置多选
553
+				this.cale.setMultiple(this.calendar.fullDate, true)
554
+				this.weeks = this.cale.weeks
555
+				this.tempSingleDate = this.calendar.fullDate
556
+				const beforeStatus = this.cale.multipleStatus.before
557
+				const beforeDate = new Date(this.cale.multipleStatus.before).getTime()
558
+				const afterDate = new Date(this.cale.multipleStatus.after).getTime()
559
+				if (beforeDate > afterDate && afterDate) {
560
+					this.tempRange.before = this.cale.multipleStatus.after
561
+					this.tempRange.after = this.cale.multipleStatus.before
562
+				} else {
563
+					this.tempRange.before = this.cale.multipleStatus.before
564
+					this.tempRange.after = this.cale.multipleStatus.after
565
+				}
566
+				this.change()
567
+			},
568
+			/**
569
+			 * 回到今天
570
+			 */
571
+			backtoday() {
572
+				let date = this.cale.getDate(new Date()).fullDate
573
+				// this.cale.setDate(date)
574
+				this.init(date)
575
+				this.change()
576
+			},
577
+			/**
578
+			 * 比较时间大小
579
+			 */
580
+			dateCompare(startDate, endDate) {
581
+				// 计算截止时间
582
+				startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
583
+				// 计算详细项的截止时间
584
+				endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
585
+				if (startDate <= endDate) {
586
+					return true
587
+				} else {
588
+					return false
589
+				}
590
+			},
591
+			/**
592
+			 * 上个月
593
+			 */
594
+			pre() {
595
+				const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate
596
+				this.setDate(preDate)
597
+				this.monthSwitch()
598
+
599
+			},
600
+			/**
601
+			 * 下个月
602
+			 */
603
+			next() {
604
+				const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate
605
+				this.setDate(nextDate)
606
+				this.monthSwitch()
607
+			},
608
+			/**
609
+			 * 设置日期
610
+			 * @param {Object} date
611
+			 */
612
+			setDate(date) {
613
+				this.cale.setDate(date)
614
+				this.weeks = this.cale.weeks
615
+				this.nowDate = this.cale.getInfo(date)
616
+			}
617
+		}
618
+	}
619
+</script>
620
+
621
+<style lang="scss" >
622
+	$uni-primary: #007aff !default;
623
+
624
+	.uni-calendar {
625
+		/* #ifndef APP-NVUE */
626
+		display: flex;
627
+		/* #endif */
628
+		flex-direction: column;
629
+	}
630
+
631
+	.uni-calendar__mask {
632
+		position: fixed;
633
+		bottom: 0;
634
+		top: 0;
635
+		left: 0;
636
+		right: 0;
637
+		background-color: rgba(0, 0, 0, 0.4);
638
+		transition-property: opacity;
639
+		transition-duration: 0.3s;
640
+		opacity: 0;
641
+		/* #ifndef APP-NVUE */
642
+		z-index: 99;
643
+		/* #endif */
644
+	}
645
+
646
+	.uni-calendar--mask-show {
647
+		opacity: 1
648
+	}
649
+
650
+	.uni-calendar--fixed {
651
+		position: fixed;
652
+		bottom: calc(var(--window-bottom));
653
+		left: 0;
654
+		right: 0;
655
+		transition-property: transform;
656
+		transition-duration: 0.3s;
657
+		transform: translateY(460px);
658
+		/* #ifndef APP-NVUE */
659
+		z-index: 99;
660
+		/* #endif */
661
+	}
662
+
663
+	.uni-calendar--ani-show {
664
+		transform: translateY(0);
665
+	}
666
+
667
+	.uni-calendar__content {
668
+		background-color: #fff;
669
+	}
670
+
671
+	.uni-calendar__content-mobile {
672
+		border-top-left-radius: 10px;
673
+		border-top-right-radius: 10px;
674
+		box-shadow: 0px 0px 5px 3px rgba(0, 0, 0, 0.1);
675
+	}
676
+
677
+	.uni-calendar__header {
678
+		position: relative;
679
+		/* #ifndef APP-NVUE */
680
+		display: flex;
681
+		/* #endif */
682
+		flex-direction: row;
683
+		justify-content: center;
684
+		align-items: center;
685
+		height: 50px;
686
+	}
687
+
688
+	.uni-calendar__header-mobile {
689
+		padding: 10px;
690
+		padding-bottom: 0;
691
+	}
692
+
693
+	.uni-calendar--fixed-top {
694
+		/* #ifndef APP-NVUE */
695
+		display: flex;
696
+		/* #endif */
697
+		flex-direction: row;
698
+		justify-content: space-between;
699
+		border-top-color: rgba(0, 0, 0, 0.4);
700
+		border-top-style: solid;
701
+		border-top-width: 1px;
702
+	}
703
+
704
+	.uni-calendar--fixed-width {
705
+		width: 50px;
706
+	}
707
+
708
+	.uni-calendar__backtoday {
709
+		position: absolute;
710
+		right: 0;
711
+		top: 25rpx;
712
+		padding: 0 5px;
713
+		padding-left: 10px;
714
+		height: 25px;
715
+		line-height: 25px;
716
+		font-size: 12px;
717
+		border-top-left-radius: 25px;
718
+		border-bottom-left-radius: 25px;
719
+		color: #fff;
720
+		background-color: #f1f1f1;
721
+	}
722
+
723
+	.uni-calendar__header-text {
724
+		text-align: center;
725
+		width: 100px;
726
+		font-size: 15px;
727
+		color: #666;
728
+	}
729
+
730
+	.uni-calendar__button-text {
731
+		text-align: center;
732
+		width: 100px;
733
+		font-size: 14px;
734
+		color: $uni-primary;
735
+		/* #ifndef APP-NVUE */
736
+		letter-spacing: 3px;
737
+		/* #endif */
738
+	}
739
+
740
+	.uni-calendar__header-btn-box {
741
+		/* #ifndef APP-NVUE */
742
+		display: flex;
743
+		/* #endif */
744
+		flex-direction: row;
745
+		align-items: center;
746
+		justify-content: center;
747
+		width: 50px;
748
+		height: 50px;
749
+	}
750
+
751
+	.uni-calendar__header-btn {
752
+		width: 9px;
753
+		height: 9px;
754
+		border-left-color: #808080;
755
+		border-left-style: solid;
756
+		border-left-width: 1px;
757
+		border-top-color: #555555;
758
+		border-top-style: solid;
759
+		border-top-width: 1px;
760
+	}
761
+
762
+	.uni-calendar--left {
763
+		transform: rotate(-45deg);
764
+	}
765
+
766
+	.uni-calendar--right {
767
+		transform: rotate(135deg);
768
+	}
769
+
770
+
771
+	.uni-calendar__weeks {
772
+		position: relative;
773
+		/* #ifndef APP-NVUE */
774
+		display: flex;
775
+		/* #endif */
776
+		flex-direction: row;
777
+	}
778
+
779
+	.uni-calendar__weeks-item {
780
+		flex: 1;
781
+	}
782
+
783
+	.uni-calendar__weeks-day {
784
+		flex: 1;
785
+		/* #ifndef APP-NVUE */
786
+		display: flex;
787
+		/* #endif */
788
+		flex-direction: column;
789
+		justify-content: center;
790
+		align-items: center;
791
+		height: 40px;
792
+		border-bottom-color: #F5F5F5;
793
+		border-bottom-style: solid;
794
+		border-bottom-width: 1px;
795
+	}
796
+
797
+	.uni-calendar__weeks-day-text {
798
+		font-size: 12px;
799
+		color: #B2B2B2;
800
+	}
801
+
802
+	.uni-calendar__box {
803
+		position: relative;
804
+		// padding: 0 10px;
805
+		padding-bottom: 7px;
806
+	}
807
+
808
+	.uni-calendar__box-bg {
809
+		/* #ifndef APP-NVUE */
810
+		display: flex;
811
+		/* #endif */
812
+		justify-content: center;
813
+		align-items: center;
814
+		position: absolute;
815
+		top: 0;
816
+		left: 0;
817
+		right: 0;
818
+		bottom: 0;
819
+	}
820
+
821
+	.uni-calendar__box-bg-text {
822
+		font-size: 200px;
823
+		font-weight: bold;
824
+		color: #999;
825
+		opacity: 0.1;
826
+		text-align: center;
827
+		/* #ifndef APP-NVUE */
828
+		line-height: 1;
829
+		/* #endif */
830
+	}
831
+
832
+	.uni-date-changed {
833
+		padding: 0 10px;
834
+		// line-height: 50px;
835
+		text-align: center;
836
+		color: #333;
837
+		border-top-color: #DCDCDC;
838
+		;
839
+		border-top-style: solid;
840
+		border-top-width: 1px;
841
+		flex: 1;
842
+	}
843
+
844
+	.uni-date-btn--ok {
845
+		padding: 20px 15px;
846
+	}
847
+
848
+	.uni-date-changed--time-start {
849
+		/* #ifndef APP-NVUE */
850
+		display: flex;
851
+		/* #endif */
852
+		align-items: center;
853
+	}
854
+
855
+	.uni-date-changed--time-end {
856
+		/* #ifndef APP-NVUE */
857
+		display: flex;
858
+		/* #endif */
859
+		align-items: center;
860
+	}
861
+
862
+	.uni-date-changed--time-date {
863
+		color: #999;
864
+		line-height: 50px;
865
+		margin-right: 5px;
866
+		// opacity: 0.6;
867
+	}
868
+
869
+	.time-picker-style {
870
+		// width: 62px;
871
+		/* #ifndef APP-NVUE */
872
+		display: flex;
873
+		/* #endif */
874
+		justify-content: center;
875
+		align-items: center
876
+	}
877
+
878
+	.mr-10 {
879
+		margin-right: 10px;
880
+	}
881
+
882
+	.dialog-close {
883
+		position: absolute;
884
+		top: 0;
885
+		right: 0;
886
+		bottom: 0;
887
+		/* #ifndef APP-NVUE */
888
+		display: flex;
889
+		/* #endif */
890
+		flex-direction: row;
891
+		align-items: center;
892
+		padding: 0 25px;
893
+		margin-top: 10px;
894
+	}
895
+
896
+	.dialog-close-plus {
897
+		width: 16px;
898
+		height: 2px;
899
+		background-color: #737987;
900
+		border-radius: 2px;
901
+		transform: rotate(45deg);
902
+	}
903
+
904
+	.dialog-close-rotate {
905
+		position: absolute;
906
+		transform: rotate(-45deg);
907
+	}
908
+
909
+	.uni-datetime-picker--btn {
910
+		border-radius: 100px;
911
+		height: 40px;
912
+		line-height: 40px;
913
+		background-color: $uni-primary;
914
+		color: #fff;
915
+		font-size: 16px;
916
+		letter-spacing: 2px;
917
+	}
918
+
919
+	/* #ifndef APP-NVUE */
920
+	.uni-datetime-picker--btn:active {
921
+		opacity: 0.7;
922
+	}
923
+	/* #endif */
924
+</style>

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

@@ -0,0 +1,22 @@
1
+{
2
+	"uni-datetime-picker.selectDate": "select date",
3
+	"uni-datetime-picker.selectTime": "select time",
4
+	"uni-datetime-picker.selectDateTime": "select datetime",
5
+	"uni-datetime-picker.startDate": "start date",
6
+	"uni-datetime-picker.endDate": "end date",
7
+	"uni-datetime-picker.startTime": "start time",
8
+	"uni-datetime-picker.endTime": "end time",
9
+	"uni-datetime-picker.ok": "ok",
10
+	"uni-datetime-picker.clear": "clear",
11
+	"uni-datetime-picker.cancel": "cancel",
12
+	"uni-datetime-picker.year": "-",
13
+	"uni-datetime-picker.month": "",
14
+	"uni-calender.MON": "MON",
15
+	"uni-calender.TUE": "TUE",
16
+	"uni-calender.WED": "WED",
17
+	"uni-calender.THU": "THU",
18
+	"uni-calender.FRI": "FRI",
19
+	"uni-calender.SAT": "SAT",
20
+	"uni-calender.SUN": "SUN",
21
+	"uni-calender.confirm": "confirm"
22
+}

+ 8 - 0
uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js

@@ -0,0 +1,8 @@
1
+import en from './en.json'
2
+import zhHans from './zh-Hans.json'
3
+import zhHant from './zh-Hant.json'
4
+export default {
5
+	en,
6
+	'zh-Hans': zhHans,
7
+	'zh-Hant': zhHant
8
+}

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

@@ -0,0 +1,22 @@
1
+{
2
+	"uni-datetime-picker.selectDate": "选择日期",
3
+	"uni-datetime-picker.selectTime": "选择时间",
4
+	"uni-datetime-picker.selectDateTime": "选择日期时间",
5
+	"uni-datetime-picker.startDate": "开始日期",
6
+	"uni-datetime-picker.endDate": "结束日期",
7
+	"uni-datetime-picker.startTime": "开始时间",
8
+	"uni-datetime-picker.endTime": "结束时间",
9
+	"uni-datetime-picker.ok": "确定",
10
+	"uni-datetime-picker.clear": "清除",
11
+	"uni-datetime-picker.cancel": "取消",
12
+	"uni-datetime-picker.year": "年",
13
+	"uni-datetime-picker.month": "月",
14
+	"uni-calender.SUN": "日",
15
+	"uni-calender.MON": "一",
16
+	"uni-calender.TUE": "二",
17
+	"uni-calender.WED": "三",
18
+	"uni-calender.THU": "四",
19
+	"uni-calender.FRI": "五",
20
+	"uni-calender.SAT": "六",
21
+	"uni-calender.confirm": "确认"
22
+}

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

@@ -0,0 +1,22 @@
1
+{
2
+  "uni-datetime-picker.selectDate": "選擇日期",
3
+  "uni-datetime-picker.selectTime": "選擇時間",
4
+  "uni-datetime-picker.selectDateTime": "選擇日期時間",
5
+  "uni-datetime-picker.startDate": "開始日期",
6
+  "uni-datetime-picker.endDate": "結束日期",
7
+  "uni-datetime-picker.startTime": "開始时间",
8
+  "uni-datetime-picker.endTime": "結束时间",
9
+  "uni-datetime-picker.ok": "確定",
10
+  "uni-datetime-picker.clear": "清除",
11
+  "uni-datetime-picker.cancel": "取消",
12
+  "uni-datetime-picker.year": "年",
13
+  "uni-datetime-picker.month": "月",
14
+  "uni-calender.SUN": "日",
15
+  "uni-calender.MON": "一",
16
+  "uni-calender.TUE": "二",
17
+  "uni-calender.WED": "三",
18
+  "uni-calender.THU": "四",
19
+  "uni-calender.FRI": "五",
20
+  "uni-calender.SAT": "六",
21
+  "uni-calender.confirm": "確認"
22
+}

+ 45 - 0
uni_modules/uni-datetime-picker/components/uni-datetime-picker/keypress.js

@@ -0,0 +1,45 @@
1
+// #ifdef H5
2
+export default {
3
+  name: 'Keypress',
4
+  props: {
5
+    disable: {
6
+      type: Boolean,
7
+      default: false
8
+    }
9
+  },
10
+  mounted () {
11
+    const keyNames = {
12
+      esc: ['Esc', 'Escape'],
13
+      tab: 'Tab',
14
+      enter: 'Enter',
15
+      space: [' ', 'Spacebar'],
16
+      up: ['Up', 'ArrowUp'],
17
+      left: ['Left', 'ArrowLeft'],
18
+      right: ['Right', 'ArrowRight'],
19
+      down: ['Down', 'ArrowDown'],
20
+      delete: ['Backspace', 'Delete', 'Del']
21
+    }
22
+    const listener = ($event) => {
23
+      if (this.disable) {
24
+        return
25
+      }
26
+      const keyName = Object.keys(keyNames).find(key => {
27
+        const keyName = $event.key
28
+        const value = keyNames[key]
29
+        return value === keyName || (Array.isArray(value) && value.includes(keyName))
30
+      })
31
+      if (keyName) {
32
+        // 避免和其他按键事件冲突
33
+        setTimeout(() => {
34
+          this.$emit(keyName, {})
35
+        }, 0)
36
+      }
37
+    }
38
+    document.addEventListener('keyup', listener)
39
+    this.$once('hook:beforeDestroy', () => {
40
+      document.removeEventListener('keyup', listener)
41
+    })
42
+  },
43
+	render: () => {}
44
+}
45
+// #endif

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

@@ -0,0 +1,946 @@
1
+<template>
2
+	<view class="uni-datetime-picker">
3
+		<view @click="initTimePicker">
4
+			<slot>
5
+				<view class="uni-datetime-picker-timebox-pointer"
6
+					:class="{'uni-datetime-picker-disabled': disabled, 'uni-datetime-picker-timebox': border}">
7
+					<text class="uni-datetime-picker-text">{{time}}</text>
8
+					<view v-if="!time" class="uni-datetime-picker-time">
9
+						<text class="uni-datetime-picker-text">{{selectTimeText}}</text>
10
+					</view>
11
+				</view>
12
+			</slot>
13
+		</view>
14
+		<view v-if="visible" id="mask" class="uni-datetime-picker-mask" @click="tiggerTimePicker"></view>
15
+		<view v-if="visible" class="uni-datetime-picker-popup" :class="[dateShow && timeShow ? '' : 'fix-nvue-height']"
16
+			:style="fixNvueBug">
17
+			<view class="uni-title">
18
+				<text class="uni-datetime-picker-text">{{selectTimeText}}</text>
19
+			</view>
20
+			<view v-if="dateShow" class="uni-datetime-picker__container-box">
21
+				<picker-view class="uni-datetime-picker-view" :indicator-style="indicatorStyle" :value="ymd"
22
+					@change="bindDateChange">
23
+					<picker-view-column>
24
+						<view class="uni-datetime-picker-item" v-for="(item,index) in years" :key="index">
25
+							<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
26
+						</view>
27
+					</picker-view-column>
28
+					<picker-view-column>
29
+						<view class="uni-datetime-picker-item" v-for="(item,index) in months" :key="index">
30
+							<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
31
+						</view>
32
+					</picker-view-column>
33
+					<picker-view-column>
34
+						<view class="uni-datetime-picker-item" v-for="(item,index) in days" :key="index">
35
+							<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
36
+						</view>
37
+					</picker-view-column>
38
+				</picker-view>
39
+				<!-- 兼容 nvue 不支持伪类 -->
40
+				<text class="uni-datetime-picker-sign sign-left">-</text>
41
+				<text class="uni-datetime-picker-sign sign-right">-</text>
42
+			</view>
43
+			<view v-if="timeShow" class="uni-datetime-picker__container-box">
44
+				<picker-view class="uni-datetime-picker-view" :class="[hideSecond ? 'time-hide-second' : '']"
45
+					:indicator-style="indicatorStyle" :value="hms" @change="bindTimeChange">
46
+					<picker-view-column>
47
+						<view class="uni-datetime-picker-item" v-for="(item,index) in hours" :key="index">
48
+							<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
49
+						</view>
50
+					</picker-view-column>
51
+					<picker-view-column>
52
+						<view class="uni-datetime-picker-item" v-for="(item,index) in minutes" :key="index">
53
+							<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
54
+						</view>
55
+					</picker-view-column>
56
+					<picker-view-column v-if="!hideSecond">
57
+						<view class="uni-datetime-picker-item" v-for="(item,index) in seconds" :key="index">
58
+							<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
59
+						</view>
60
+					</picker-view-column>
61
+				</picker-view>
62
+				<!-- 兼容 nvue 不支持伪类 -->
63
+				<text class="uni-datetime-picker-sign" :class="[hideSecond ? 'sign-center' : 'sign-left']">:</text>
64
+				<text v-if="!hideSecond" class="uni-datetime-picker-sign sign-right">:</text>
65
+			</view>
66
+			<view class="uni-datetime-picker-btn">
67
+				<view @click="clearTime">
68
+					<text class="uni-datetime-picker-btn-text">{{clearText}}</text>
69
+				</view>
70
+				<view class="uni-datetime-picker-btn-group">
71
+					<view class="uni-datetime-picker-cancel" @click="tiggerTimePicker">
72
+						<text class="uni-datetime-picker-btn-text">{{cancelText}}</text>
73
+					</view>
74
+					<view @click="setTime">
75
+						<text class="uni-datetime-picker-btn-text">{{okText}}</text>
76
+					</view>
77
+				</view>
78
+			</view>
79
+		</view>
80
+		<!-- #ifdef H5 -->
81
+		<!-- <keypress v-if="visible" @esc="tiggerTimePicker" @enter="setTime" /> -->
82
+		<!-- #endif -->
83
+	</view>
84
+</template>
85
+
86
+<script>
87
+	// #ifdef H5
88
+	import keypress from './keypress'
89
+	// #endif
90
+	import {
91
+		initVueI18n
92
+	} from '@dcloudio/uni-i18n'
93
+	import messages from './i18n/index.js'
94
+	const {	t	} = initVueI18n(messages)
95
+
96
+	/**
97
+	 * DatetimePicker 时间选择器
98
+	 * @description 可以同时选择日期和时间的选择器
99
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
100
+	 * @property {String} type = [datetime | date | time] 显示模式
101
+	 * @property {Boolean} multiple = [true|false] 是否多选
102
+	 * @property {String|Number} value 默认值
103
+	 * @property {String|Number} start 起始日期或时间
104
+	 * @property {String|Number} end 起始日期或时间
105
+	 * @property {String} return-type = [timestamp | string]
106
+	 * @event {Function} change  选中发生变化触发
107
+	 */
108
+
109
+	export default {
110
+		name: 'UniDatetimePicker',
111
+		components: {
112
+			// #ifdef H5
113
+			keypress
114
+			// #endif
115
+		},
116
+		data() {
117
+			return {
118
+				indicatorStyle: `height: 50px;`,
119
+				visible: false,
120
+				fixNvueBug: {},
121
+				dateShow: true,
122
+				timeShow: true,
123
+				title: '日期和时间',
124
+				// 输入框当前时间
125
+				time: '',
126
+				// 当前的年月日时分秒
127
+				year: 1920,
128
+				month: 0,
129
+				day: 0,
130
+				hour: 0,
131
+				minute: 0,
132
+				second: 0,
133
+				// 起始时间
134
+				startYear: 1920,
135
+				startMonth: 1,
136
+				startDay: 1,
137
+				startHour: 0,
138
+				startMinute: 0,
139
+				startSecond: 0,
140
+				// 结束时间
141
+				endYear: 2120,
142
+				endMonth: 12,
143
+				endDay: 31,
144
+				endHour: 23,
145
+				endMinute: 59,
146
+				endSecond: 59,
147
+			}
148
+		},
149
+		props: {
150
+			type: {
151
+				type: String,
152
+				default: 'datetime'
153
+			},
154
+			value: {
155
+				type: [String, Number],
156
+				default: ''
157
+			},
158
+			modelValue: {
159
+				type: [String, Number],
160
+				default: ''
161
+			},
162
+			start: {
163
+				type: [Number, String],
164
+				default: ''
165
+			},
166
+			end: {
167
+				type: [Number, String],
168
+				default: ''
169
+			},
170
+			returnType: {
171
+				type: String,
172
+				default: 'string'
173
+			},
174
+			disabled: {
175
+				type: [Boolean, String],
176
+				default: false
177
+			},
178
+			border: {
179
+				type: [Boolean, String],
180
+				default: true
181
+			},
182
+			hideSecond: {
183
+				type: [Boolean, String],
184
+				default: false
185
+			}
186
+		},
187
+		watch: {
188
+			// #ifndef VUE3
189
+			value: {
190
+				handler(newVal, oldVal) {
191
+					if (newVal) {
192
+						this.parseValue(this.fixIosDateFormat(newVal)) //兼容 iOS、safari 日期格式
193
+						this.initTime(false)
194
+					} else {
195
+						this.time = ''
196
+						this.parseValue(Date.now())
197
+					}
198
+				},
199
+				immediate: true
200
+			},
201
+			// #endif
202
+			// #ifdef VUE3
203
+			modelValue: {
204
+				handler(newVal, oldVal) {
205
+					if (newVal) {
206
+						this.parseValue(this.fixIosDateFormat(newVal)) //兼容 iOS、safari 日期格式
207
+						this.initTime(false)
208
+					} else {
209
+						this.time = ''
210
+						this.parseValue(Date.now())
211
+					}
212
+				},
213
+				immediate: true
214
+			},
215
+			// #endif
216
+			type: {
217
+				handler(newValue) {
218
+					if (newValue === 'date') {
219
+						this.dateShow = true
220
+						this.timeShow = false
221
+						this.title = '日期'
222
+					} else if (newValue === 'time') {
223
+						this.dateShow = false
224
+						this.timeShow = true
225
+						this.title = '时间'
226
+					} else {
227
+						this.dateShow = true
228
+						this.timeShow = true
229
+						this.title = '日期和时间'
230
+					}
231
+				},
232
+				immediate: true
233
+			},
234
+			start: {
235
+				handler(newVal) {
236
+					this.parseDatetimeRange(this.fixIosDateFormat(newVal), 'start') //兼容 iOS、safari 日期格式
237
+				},
238
+				immediate: true
239
+			},
240
+			end: {
241
+				handler(newVal) {
242
+					this.parseDatetimeRange(this.fixIosDateFormat(newVal), 'end') //兼容 iOS、safari 日期格式
243
+				},
244
+				immediate: true
245
+			},
246
+
247
+			// 月、日、时、分、秒可选范围变化后,检查当前值是否在范围内,不在则当前值重置为可选范围第一项
248
+			months(newVal) {
249
+				this.checkValue('month', this.month, newVal)
250
+			},
251
+			days(newVal) {
252
+				this.checkValue('day', this.day, newVal)
253
+			},
254
+			hours(newVal) {
255
+				this.checkValue('hour', this.hour, newVal)
256
+			},
257
+			minutes(newVal) {
258
+				this.checkValue('minute', this.minute, newVal)
259
+			},
260
+			seconds(newVal) {
261
+				this.checkValue('second', this.second, newVal)
262
+			}
263
+		},
264
+		computed: {
265
+			// 当前年、月、日、时、分、秒选择范围
266
+			years() {
267
+				return this.getCurrentRange('year')
268
+			},
269
+
270
+			months() {
271
+				return this.getCurrentRange('month')
272
+			},
273
+
274
+			days() {
275
+				return this.getCurrentRange('day')
276
+			},
277
+
278
+			hours() {
279
+				return this.getCurrentRange('hour')
280
+			},
281
+
282
+			minutes() {
283
+				return this.getCurrentRange('minute')
284
+			},
285
+
286
+			seconds() {
287
+				return this.getCurrentRange('second')
288
+			},
289
+
290
+			// picker 当前值数组
291
+			ymd() {
292
+				return [this.year - this.minYear, this.month - this.minMonth, this.day - this.minDay]
293
+			},
294
+			hms() {
295
+				return [this.hour - this.minHour, this.minute - this.minMinute, this.second - this.minSecond]
296
+			},
297
+
298
+			// 当前 date 是 start
299
+			currentDateIsStart() {
300
+				return this.year === this.startYear && this.month === this.startMonth && this.day === this.startDay
301
+			},
302
+
303
+			// 当前 date 是 end
304
+			currentDateIsEnd() {
305
+				return this.year === this.endYear && this.month === this.endMonth && this.day === this.endDay
306
+			},
307
+
308
+			// 当前年、月、日、时、分、秒的最小值和最大值
309
+			minYear() {
310
+				return this.startYear
311
+			},
312
+			maxYear() {
313
+				return this.endYear
314
+			},
315
+			minMonth() {
316
+				if (this.year === this.startYear) {
317
+					return this.startMonth
318
+				} else {
319
+					return 1
320
+				}
321
+			},
322
+			maxMonth() {
323
+				if (this.year === this.endYear) {
324
+					return this.endMonth
325
+				} else {
326
+					return 12
327
+				}
328
+			},
329
+			minDay() {
330
+				if (this.year === this.startYear && this.month === this.startMonth) {
331
+					return this.startDay
332
+				} else {
333
+					return 1
334
+				}
335
+			},
336
+			maxDay() {
337
+				if (this.year === this.endYear && this.month === this.endMonth) {
338
+					return this.endDay
339
+				} else {
340
+					return this.daysInMonth(this.year, this.month)
341
+				}
342
+			},
343
+			minHour() {
344
+				if (this.type === 'datetime') {
345
+					if (this.currentDateIsStart) {
346
+						return this.startHour
347
+					} else {
348
+						return 0
349
+					}
350
+				}
351
+				if (this.type === 'time') {
352
+					return this.startHour
353
+				}
354
+			},
355
+			maxHour() {
356
+				if (this.type === 'datetime') {
357
+					if (this.currentDateIsEnd) {
358
+						return this.endHour
359
+					} else {
360
+						return 23
361
+					}
362
+				}
363
+				if (this.type === 'time') {
364
+					return this.endHour
365
+				}
366
+			},
367
+			minMinute() {
368
+				if (this.type === 'datetime') {
369
+					if (this.currentDateIsStart && this.hour === this.startHour) {
370
+						return this.startMinute
371
+					} else {
372
+						return 0
373
+					}
374
+				}
375
+				if (this.type === 'time') {
376
+					if (this.hour === this.startHour) {
377
+						return this.startMinute
378
+					} else {
379
+						return 0
380
+					}
381
+				}
382
+			},
383
+			maxMinute() {
384
+				if (this.type === 'datetime') {
385
+					if (this.currentDateIsEnd && this.hour === this.endHour) {
386
+						return this.endMinute
387
+					} else {
388
+						return 59
389
+					}
390
+				}
391
+				if (this.type === 'time') {
392
+					if (this.hour === this.endHour) {
393
+						return this.endMinute
394
+					} else {
395
+						return 59
396
+					}
397
+				}
398
+			},
399
+			minSecond() {
400
+				if (this.type === 'datetime') {
401
+					if (this.currentDateIsStart && this.hour === this.startHour && this.minute === this.startMinute) {
402
+						return this.startSecond
403
+					} else {
404
+						return 0
405
+					}
406
+				}
407
+				if (this.type === 'time') {
408
+					if (this.hour === this.startHour && this.minute === this.startMinute) {
409
+						return this.startSecond
410
+					} else {
411
+						return 0
412
+					}
413
+				}
414
+			},
415
+			maxSecond() {
416
+				if (this.type === 'datetime') {
417
+					if (this.currentDateIsEnd && this.hour === this.endHour && this.minute === this.endMinute) {
418
+						return this.endSecond
419
+					} else {
420
+						return 59
421
+					}
422
+				}
423
+				if (this.type === 'time') {
424
+					if (this.hour === this.endHour && this.minute === this.endMinute) {
425
+						return this.endSecond
426
+					} else {
427
+						return 59
428
+					}
429
+				}
430
+			},
431
+
432
+			/**
433
+			 * for i18n
434
+			 */
435
+			selectTimeText() {
436
+				return t("uni-datetime-picker.selectTime")
437
+			},
438
+			okText() {
439
+				return t("uni-datetime-picker.ok")
440
+			},
441
+			clearText() {
442
+				return t("uni-datetime-picker.clear")
443
+			},
444
+			cancelText() {
445
+				return t("uni-datetime-picker.cancel")
446
+			}
447
+		},
448
+
449
+		mounted() {
450
+			// #ifdef APP-NVUE
451
+			const res = uni.getSystemInfoSync();
452
+			this.fixNvueBug = {
453
+				top: res.windowHeight / 2,
454
+				left: res.windowWidth / 2
455
+			}
456
+			// #endif
457
+		},
458
+
459
+		methods: {
460
+			/**
461
+			 * @param {Object} item
462
+			 * 小于 10 在前面加个 0
463
+			 */
464
+
465
+			lessThanTen(item) {
466
+				return item < 10 ? '0' + item : item
467
+			},
468
+
469
+			/**
470
+			 * 解析时分秒字符串,例如:00:00:00
471
+			 * @param {String} timeString
472
+			 */
473
+			parseTimeType(timeString) {
474
+				if (timeString) {
475
+					let timeArr = timeString.split(':')
476
+					this.hour = Number(timeArr[0])
477
+					this.minute = Number(timeArr[1])
478
+					this.second = Number(timeArr[2])
479
+				}
480
+			},
481
+
482
+			/**
483
+			 * 解析选择器初始值,类型可以是字符串、时间戳,例如:2000-10-02、'08:30:00'、 1610695109000
484
+			 * @param {String | Number} datetime
485
+			 */
486
+			initPickerValue(datetime) {
487
+				let defaultValue = null
488
+				if (datetime) {
489
+					defaultValue = this.compareValueWithStartAndEnd(datetime, this.start, this.end)
490
+				} else {
491
+					defaultValue = Date.now()
492
+					defaultValue = this.compareValueWithStartAndEnd(defaultValue, this.start, this.end)
493
+				}
494
+				this.parseValue(defaultValue)
495
+			},
496
+
497
+			/**
498
+			 * 初始值规则:
499
+			 * - 用户设置初始值 value
500
+			 * 	- 设置了起始时间 start、终止时间 end,并 start < value < end,初始值为 value, 否则初始值为 start
501
+			 * 	- 只设置了起始时间 start,并 start < value,初始值为 value,否则初始值为 start
502
+			 * 	- 只设置了终止时间 end,并 value < end,初始值为 value,否则初始值为 end
503
+			 * 	- 无起始终止时间,则初始值为 value
504
+			 * - 无初始值 value,则初始值为当前本地时间 Date.now()
505
+			 * @param {Object} value
506
+			 * @param {Object} dateBase
507
+			 */
508
+			compareValueWithStartAndEnd(value, start, end) {
509
+				let winner = null
510
+				value = this.superTimeStamp(value)
511
+				start = this.superTimeStamp(start)
512
+				end = this.superTimeStamp(end)
513
+
514
+				if (start && end) {
515
+					if (value < start) {
516
+						winner = new Date(start)
517
+					} else if (value > end) {
518
+						winner = new Date(end)
519
+					} else {
520
+						winner = new Date(value)
521
+					}
522
+				} else if (start && !end) {
523
+					winner = start <= value ? new Date(value) : new Date(start)
524
+				} else if (!start && end) {
525
+					winner = value <= end ? new Date(value) : new Date(end)
526
+				} else {
527
+					winner = new Date(value)
528
+				}
529
+
530
+				return winner
531
+			},
532
+
533
+			/**
534
+			 * 转换为可比较的时间戳,接受日期、时分秒、时间戳
535
+			 * @param {Object} value
536
+			 */
537
+			superTimeStamp(value) {
538
+				let dateBase = ''
539
+				if (this.type === 'time' && value && typeof value === 'string') {
540
+					const now = new Date()
541
+					const year = now.getFullYear()
542
+					const month = now.getMonth() + 1
543
+					const day = now.getDate()
544
+					dateBase = year + '/' + month + '/' + day + ' '
545
+				}
546
+				if (Number(value) && typeof value !== NaN) {
547
+					value = parseInt(value)
548
+					dateBase = 0
549
+				}
550
+				return this.createTimeStamp(dateBase + value)
551
+			},
552
+
553
+			/**
554
+			 * 解析默认值 value,字符串、时间戳
555
+			 * @param {Object} defaultTime
556
+			 */
557
+			parseValue(value) {
558
+				if (!value) {
559
+					return
560
+				}
561
+				if (this.type === 'time' && typeof value === "string") {
562
+					this.parseTimeType(value)
563
+				} else {
564
+					let defaultDate = null
565
+					defaultDate = new Date(value)
566
+					if (this.type !== 'time') {
567
+						this.year = defaultDate.getFullYear()
568
+						this.month = defaultDate.getMonth() + 1
569
+						this.day = defaultDate.getDate()
570
+					}
571
+					if (this.type !== 'date') {
572
+						this.hour = defaultDate.getHours()
573
+						this.minute = defaultDate.getMinutes()
574
+						this.second = defaultDate.getSeconds()
575
+					}
576
+				}
577
+				if (this.hideSecond) {
578
+					this.second = 0
579
+				}
580
+			},
581
+
582
+			/**
583
+			 * 解析可选择时间范围 start、end,年月日字符串、时间戳
584
+			 * @param {Object} defaultTime
585
+			 */
586
+			parseDatetimeRange(point, pointType) {
587
+				// 时间为空,则重置为初始值
588
+				if (!point) {
589
+					if (pointType === 'start') {
590
+						this.startYear = 1920
591
+						this.startMonth = 1
592
+						this.startDay = 1
593
+						this.startHour = 0
594
+						this.startMinute = 0
595
+						this.startSecond = 0
596
+					}
597
+					if (pointType === 'end') {
598
+						this.endYear = 2120
599
+						this.endMonth = 12
600
+						this.endDay = 31
601
+						this.endHour = 23
602
+						this.endMinute = 59
603
+						this.endSecond = 59
604
+					}
605
+					return
606
+				}
607
+				if (this.type === 'time') {
608
+					const pointArr = point.split(':')
609
+					this[pointType + 'Hour'] = Number(pointArr[0])
610
+					this[pointType + 'Minute'] = Number(pointArr[1])
611
+					this[pointType + 'Second'] = Number(pointArr[2])
612
+				} else {
613
+					if (!point) {
614
+						pointType === 'start' ? this.startYear = this.year - 60 : this.endYear = this.year + 60
615
+						return
616
+					}
617
+					if (Number(point) && Number(point) !== NaN) {
618
+						point = parseInt(point)
619
+					}
620
+					// datetime 的 end 没有时分秒, 则不限制
621
+					const hasTime = /[0-9]:[0-9]/
622
+					if (this.type === 'datetime' && pointType === 'end' && typeof point === 'string' && !hasTime.test(
623
+							point)) {
624
+						point = point + ' 23:59:59'
625
+					}
626
+					const pointDate = new Date(point)
627
+					this[pointType + 'Year'] = pointDate.getFullYear()
628
+					this[pointType + 'Month'] = pointDate.getMonth() + 1
629
+					this[pointType + 'Day'] = pointDate.getDate()
630
+					if (this.type === 'datetime') {
631
+						this[pointType + 'Hour'] = pointDate.getHours()
632
+						this[pointType + 'Minute'] = pointDate.getMinutes()
633
+						this[pointType + 'Second'] = pointDate.getSeconds()
634
+					}
635
+				}
636
+			},
637
+
638
+			// 获取 年、月、日、时、分、秒 当前可选范围
639
+			getCurrentRange(value) {
640
+				const range = []
641
+				for (let i = this['min' + this.capitalize(value)]; i <= this['max' + this.capitalize(value)]; i++) {
642
+					range.push(i)
643
+				}
644
+				return range
645
+			},
646
+
647
+			// 字符串首字母大写
648
+			capitalize(str) {
649
+				return str.charAt(0).toUpperCase() + str.slice(1)
650
+			},
651
+
652
+			// 检查当前值是否在范围内,不在则当前值重置为可选范围第一项
653
+			checkValue(name, value, values) {
654
+				if (values.indexOf(value) === -1) {
655
+					this[name] = values[0]
656
+				}
657
+			},
658
+
659
+			// 每个月的实际天数
660
+			daysInMonth(year, month) { // Use 1 for January, 2 for February, etc.
661
+				return new Date(year, month, 0).getDate();
662
+			},
663
+
664
+			//兼容 iOS、safari 日期格式
665
+			fixIosDateFormat(value) {
666
+				if (typeof value === 'string') {
667
+					value = value.replace(/-/g, '/')
668
+				}
669
+				return value
670
+			},
671
+
672
+			/**
673
+			 * 生成时间戳
674
+			 * @param {Object} time
675
+			 */
676
+			createTimeStamp(time) {
677
+				if (!time) return
678
+				if (typeof time === "number") {
679
+					return time
680
+				} else {
681
+					time = time.replace(/-/g, '/')
682
+					if (this.type === 'date') {
683
+						time = time + ' ' + '00:00:00'
684
+					}
685
+					return Date.parse(time)
686
+				}
687
+			},
688
+
689
+			/**
690
+			 * 生成日期或时间的字符串
691
+			 */
692
+			createDomSting() {
693
+				const yymmdd = this.year +
694
+					'-' +
695
+					this.lessThanTen(this.month) +
696
+					'-' +
697
+					this.lessThanTen(this.day)
698
+
699
+				let hhmmss = this.lessThanTen(this.hour) +
700
+					':' +
701
+					this.lessThanTen(this.minute)
702
+
703
+				if (!this.hideSecond) {
704
+					hhmmss = hhmmss + ':' + this.lessThanTen(this.second)
705
+				}
706
+
707
+				if (this.type === 'date') {
708
+					return yymmdd
709
+				} else if (this.type === 'time') {
710
+					return hhmmss
711
+				} else {
712
+					return yymmdd + ' ' + hhmmss
713
+				}
714
+			},
715
+
716
+			/**
717
+			 * 初始化返回值,并抛出 change 事件
718
+			 */
719
+			initTime(emit = true) {
720
+				this.time = this.createDomSting()
721
+				if (!emit) return
722
+				if (this.returnType === 'timestamp' && this.type !== 'time') {
723
+					this.$emit('change', this.createTimeStamp(this.time))
724
+					this.$emit('input', this.createTimeStamp(this.time))
725
+					this.$emit('update:modelValue', this.createTimeStamp(this.time))
726
+				} else {
727
+					this.$emit('change', this.time)
728
+					this.$emit('input', this.time)
729
+					this.$emit('update:modelValue', this.time)
730
+				}
731
+			},
732
+
733
+			/**
734
+			 * 用户选择日期或时间更新 data
735
+			 * @param {Object} e
736
+			 */
737
+			bindDateChange(e) {
738
+				const val = e.detail.value
739
+				this.year = this.years[val[0]]
740
+				this.month = this.months[val[1]]
741
+				this.day = this.days[val[2]]
742
+			},
743
+			bindTimeChange(e) {
744
+				const val = e.detail.value
745
+				this.hour = this.hours[val[0]]
746
+				this.minute = this.minutes[val[1]]
747
+				this.second = this.seconds[val[2]]
748
+			},
749
+
750
+			/**
751
+			 * 初始化弹出层
752
+			 */
753
+			initTimePicker() {
754
+				if (this.disabled) return
755
+				const value = this.fixIosDateFormat(this.value)
756
+				this.initPickerValue(value)
757
+				this.visible = !this.visible
758
+			},
759
+
760
+			/**
761
+			 * 触发或关闭弹框
762
+			 */
763
+			tiggerTimePicker(e) {
764
+				this.visible = !this.visible
765
+			},
766
+
767
+			/**
768
+			 * 用户点击“清空”按钮,清空当前值
769
+			 */
770
+			clearTime() {
771
+				this.time = ''
772
+				this.$emit('change', this.time)
773
+				this.$emit('input', this.time)
774
+				this.$emit('update:modelValue', this.time)
775
+				this.tiggerTimePicker()
776
+			},
777
+
778
+			/**
779
+			 * 用户点击“确定”按钮
780
+			 */
781
+			setTime() {
782
+				this.initTime()
783
+				this.tiggerTimePicker()
784
+			}
785
+		}
786
+	}
787
+</script>
788
+
789
+<style lang="scss">
790
+	$uni-primary: #007aff !default;
791
+
792
+	.uni-datetime-picker {
793
+		/* #ifndef APP-NVUE */
794
+		/* width: 100%; */
795
+		/* #endif */
796
+	}
797
+
798
+	.uni-datetime-picker-view {
799
+		height: 130px;
800
+		width: 270px;
801
+		/* #ifndef APP-NVUE */
802
+		cursor: pointer;
803
+		/* #endif */
804
+	}
805
+
806
+	.uni-datetime-picker-item {
807
+		height: 50px;
808
+		line-height: 50px;
809
+		text-align: center;
810
+		font-size: 14px;
811
+	}
812
+
813
+	.uni-datetime-picker-btn {
814
+		margin-top: 60px;
815
+		/* #ifndef APP-NVUE */
816
+		display: flex;
817
+		cursor: pointer;
818
+		/* #endif */
819
+		flex-direction: row;
820
+		justify-content: space-between;
821
+	}
822
+
823
+	.uni-datetime-picker-btn-text {
824
+		font-size: 14px;
825
+		color: $uni-primary;
826
+	}
827
+
828
+	.uni-datetime-picker-btn-group {
829
+		/* #ifndef APP-NVUE */
830
+		display: flex;
831
+		/* #endif */
832
+		flex-direction: row;
833
+	}
834
+
835
+	.uni-datetime-picker-cancel {
836
+		margin-right: 30px;
837
+	}
838
+
839
+	.uni-datetime-picker-mask {
840
+		position: fixed;
841
+		bottom: 0px;
842
+		top: 0px;
843
+		left: 0px;
844
+		right: 0px;
845
+		background-color: rgba(0, 0, 0, 0.4);
846
+		transition-duration: 0.3s;
847
+		z-index: 998;
848
+	}
849
+
850
+	.uni-datetime-picker-popup {
851
+		border-radius: 8px;
852
+		padding: 30px;
853
+		width: 270px;
854
+		/* #ifdef APP-NVUE */
855
+		height: 500px;
856
+		/* #endif */
857
+		/* #ifdef APP-NVUE */
858
+		width: 330px;
859
+		/* #endif */
860
+		background-color: #fff;
861
+		position: fixed;
862
+		top: 50%;
863
+		left: 50%;
864
+		transform: translate(-50%, -50%);
865
+		transition-duration: 0.3s;
866
+		z-index: 999;
867
+	}
868
+
869
+	.fix-nvue-height {
870
+		/* #ifdef APP-NVUE */
871
+		height: 330px;
872
+		/* #endif */
873
+	}
874
+
875
+	.uni-datetime-picker-time {
876
+		color: grey;
877
+	}
878
+
879
+	.uni-datetime-picker-column {
880
+		height: 50px;
881
+	}
882
+
883
+	.uni-datetime-picker-timebox {
884
+
885
+		border: 1px solid #E5E5E5;
886
+		border-radius: 5px;
887
+		padding: 7px 10px;
888
+		/* #ifndef APP-NVUE */
889
+		box-sizing: border-box;
890
+		cursor: pointer;
891
+		/* #endif */
892
+	}
893
+
894
+	.uni-datetime-picker-timebox-pointer {
895
+		/* #ifndef APP-NVUE */
896
+		cursor: pointer;
897
+		/* #endif */
898
+	}
899
+
900
+
901
+	.uni-datetime-picker-disabled {
902
+		opacity: 0.4;
903
+		/* #ifdef H5 */
904
+		cursor: not-allowed !important;
905
+		/* #endif */
906
+	}
907
+
908
+	.uni-datetime-picker-text {
909
+		font-size: 14px;
910
+		line-height: 50px
911
+	}
912
+
913
+	.uni-datetime-picker-sign {
914
+		position: absolute;
915
+		top: 53px;
916
+		/* 减掉 10px 的元素高度,兼容nvue */
917
+		color: #999;
918
+		/* #ifdef APP-NVUE */
919
+		font-size: 16px;
920
+		/* #endif */
921
+	}
922
+
923
+	.sign-left {
924
+		left: 86px;
925
+	}
926
+
927
+	.sign-right {
928
+		right: 86px;
929
+	}
930
+
931
+	.sign-center {
932
+		left: 135px;
933
+	}
934
+
935
+	.uni-datetime-picker__container-box {
936
+		position: relative;
937
+		display: flex;
938
+		align-items: center;
939
+		justify-content: center;
940
+		margin-top: 40px;
941
+	}
942
+
943
+	.time-hide-second {
944
+		width: 180px;
945
+	}
946
+</style>

文件差异内容过多而无法显示
+ 1015 - 0
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 @@
1
+class Calendar {
2
+	constructor({
3
+		date,
4
+		selected,
5
+		startDate,
6
+		endDate,
7
+		range,
8
+		// multipleStatus
9
+	} = {}) {
10
+		// 当前日期
11
+		this.date = this.getDate(new Date()) // 当前初入日期
12
+		// 打点信息
13
+		this.selected = selected || [];
14
+		// 范围开始
15
+		this.startDate = startDate
16
+		// 范围结束
17
+		this.endDate = endDate
18
+		this.range = range
19
+		// 多选状态
20
+		this.cleanMultipleStatus()
21
+		// 每周日期
22
+		this.weeks = {}
23
+		// this._getWeek(this.date.fullDate)
24
+		// this.multipleStatus = multipleStatus
25
+		this.lastHover = false
26
+	}
27
+	/**
28
+	 * 设置日期
29
+	 * @param {Object} date
30
+	 */
31
+	setDate(date) {
32
+		this.selectDate = this.getDate(date)
33
+		this._getWeek(this.selectDate.fullDate)
34
+	}
35
+
36
+	/**
37
+	 * 清理多选状态
38
+	 */
39
+	cleanMultipleStatus() {
40
+		this.multipleStatus = {
41
+			before: '',
42
+			after: '',
43
+			data: []
44
+		}
45
+	}
46
+
47
+	/**
48
+	 * 重置开始日期
49
+	 */
50
+	resetSatrtDate(startDate) {
51
+		// 范围开始
52
+		this.startDate = startDate
53
+
54
+	}
55
+
56
+	/**
57
+	 * 重置结束日期
58
+	 */
59
+	resetEndDate(endDate) {
60
+		// 范围结束
61
+		this.endDate = endDate
62
+	}
63
+
64
+	/**
65
+	 * 获取任意时间
66
+	 */
67
+	getDate(date, AddDayCount = 0, str = 'day') {
68
+		if (!date) {
69
+			date = new Date()
70
+		}
71
+		if (typeof date !== 'object') {
72
+			date = date.replace(/-/g, '/')
73
+		}
74
+		const dd = new Date(date)
75
+		switch (str) {
76
+			case 'day':
77
+				dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
78
+				break
79
+			case 'month':
80
+				if (dd.getDate() === 31) {
81
+					dd.setDate(dd.getDate() + AddDayCount)
82
+				} else {
83
+					dd.setMonth(dd.getMonth() + AddDayCount) // 获取AddDayCount天后的日期
84
+				}
85
+				break
86
+			case 'year':
87
+				dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
88
+				break
89
+		}
90
+		const y = dd.getFullYear()
91
+		const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
92
+		const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
93
+		return {
94
+			fullDate: y + '-' + m + '-' + d,
95
+			year: y,
96
+			month: m,
97
+			date: d,
98
+			day: dd.getDay()
99
+		}
100
+	}
101
+
102
+
103
+	/**
104
+	 * 获取上月剩余天数
105
+	 */
106
+	_getLastMonthDays(firstDay, full) {
107
+		let dateArr = []
108
+		for (let i = firstDay; i > 0; i--) {
109
+			const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate()
110
+			dateArr.push({
111
+				date: beforeDate,
112
+				month: full.month - 1,
113
+				disable: true
114
+			})
115
+		}
116
+		return dateArr
117
+	}
118
+	/**
119
+	 * 获取本月天数
120
+	 */
121
+	_currentMonthDys(dateData, full) {
122
+		let dateArr = []
123
+		let fullDate = this.date.fullDate
124
+		for (let i = 1; i <= dateData; i++) {
125
+			let isinfo = false
126
+			let nowDate = full.year + '-' + (full.month < 10 ?
127
+				full.month : full.month) + '-' + (i < 10 ?
128
+				'0' + i : i)
129
+			// 是否今天
130
+			let isDay = fullDate === nowDate
131
+			// 获取打点信息
132
+			let info = this.selected && this.selected.find((item) => {
133
+				if (this.dateEqual(nowDate, item.date)) {
134
+					return item
135
+				}
136
+			})
137
+
138
+			// 日期禁用
139
+			let disableBefore = true
140
+			let disableAfter = true
141
+			if (this.startDate) {
142
+				// let dateCompBefore = this.dateCompare(this.startDate, fullDate)
143
+				// disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
144
+				disableBefore = this.dateCompare(this.startDate, nowDate)
145
+			}
146
+
147
+			if (this.endDate) {
148
+				// let dateCompAfter = this.dateCompare(fullDate, this.endDate)
149
+				// disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
150
+				disableAfter = this.dateCompare(nowDate, this.endDate)
151
+			}
152
+			let multiples = this.multipleStatus.data
153
+			let checked = false
154
+			let multiplesStatus = -1
155
+			if (this.range) {
156
+				if (multiples) {
157
+					multiplesStatus = multiples.findIndex((item) => {
158
+						return this.dateEqual(item, nowDate)
159
+					})
160
+				}
161
+				if (multiplesStatus !== -1) {
162
+					checked = true
163
+				}
164
+			}
165
+			let data = {
166
+				fullDate: nowDate,
167
+				year: full.year,
168
+				date: i,
169
+				multiple: this.range ? checked : false,
170
+				beforeMultiple: this.isLogicBefore(nowDate, this.multipleStatus.before, this.multipleStatus.after),
171
+				afterMultiple: this.isLogicAfter(nowDate, this.multipleStatus.before, this.multipleStatus.after),
172
+				month: full.month,
173
+				disable: !(disableBefore && disableAfter),
174
+				isDay,
175
+				userChecked: false
176
+			}
177
+			if (info) {
178
+				data.extraInfo = info
179
+			}
180
+
181
+			dateArr.push(data)
182
+		}
183
+		return dateArr
184
+	}
185
+	/**
186
+	 * 获取下月天数
187
+	 */
188
+	_getNextMonthDays(surplus, full) {
189
+		let dateArr = []
190
+		for (let i = 1; i < surplus + 1; i++) {
191
+			dateArr.push({
192
+				date: i,
193
+				month: Number(full.month) + 1,
194
+				disable: true
195
+			})
196
+		}
197
+		return dateArr
198
+	}
199
+
200
+	/**
201
+	 * 获取当前日期详情
202
+	 * @param {Object} date
203
+	 */
204
+	getInfo(date) {
205
+		if (!date) {
206
+			date = new Date()
207
+		}
208
+		const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate)
209
+		return dateInfo
210
+	}
211
+
212
+	/**
213
+	 * 比较时间大小
214
+	 */
215
+	dateCompare(startDate, endDate) {
216
+		// 计算截止时间
217
+		startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
218
+		// 计算详细项的截止时间
219
+		endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
220
+		if (startDate <= endDate) {
221
+			return true
222
+		} else {
223
+			return false
224
+		}
225
+	}
226
+
227
+	/**
228
+	 * 比较时间是否相等
229
+	 */
230
+	dateEqual(before, after) {
231
+		// 计算截止时间
232
+		before = new Date(before.replace('-', '/').replace('-', '/'))
233
+		// 计算详细项的截止时间
234
+		after = new Date(after.replace('-', '/').replace('-', '/'))
235
+		if (before.getTime() - after.getTime() === 0) {
236
+			return true
237
+		} else {
238
+			return false
239
+		}
240
+	}
241
+
242
+	/**
243
+	 *  比较真实起始日期
244
+	 */
245
+
246
+	isLogicBefore(currentDay, before, after) {
247
+		let logicBefore = before
248
+		if (before && after) {
249
+			logicBefore = this.dateCompare(before, after) ? before : after
250
+		}
251
+		return this.dateEqual(logicBefore, currentDay)
252
+	}
253
+
254
+	isLogicAfter(currentDay, before, after) {
255
+		let logicAfter = after
256
+		if (before && after) {
257
+			logicAfter = this.dateCompare(before, after) ? after : before
258
+		}
259
+		return this.dateEqual(logicAfter, currentDay)
260
+	}
261
+
262
+	/**
263
+	 * 获取日期范围内所有日期
264
+	 * @param {Object} begin
265
+	 * @param {Object} end
266
+	 */
267
+	geDateAll(begin, end) {
268
+		var arr = []
269
+		var ab = begin.split('-')
270
+		var ae = end.split('-')
271
+		var db = new Date()
272
+		db.setFullYear(ab[0], ab[1] - 1, ab[2])
273
+		var de = new Date()
274
+		de.setFullYear(ae[0], ae[1] - 1, ae[2])
275
+		var unixDb = db.getTime() - 24 * 60 * 60 * 1000
276
+		var unixDe = de.getTime() - 24 * 60 * 60 * 1000
277
+		for (var k = unixDb; k <= unixDe;) {
278
+			k = k + 24 * 60 * 60 * 1000
279
+			arr.push(this.getDate(new Date(parseInt(k))).fullDate)
280
+		}
281
+		return arr
282
+	}
283
+
284
+	/**
285
+	 *  获取多选状态
286
+	 */
287
+	setMultiple(fullDate) {
288
+		let {
289
+			before,
290
+			after
291
+		} = this.multipleStatus
292
+		if (!this.range) return
293
+		if (before && after) {
294
+			if (!this.lastHover) {
295
+				this.lastHover = true
296
+				return
297
+			}
298
+			this.multipleStatus.before = fullDate
299
+			this.multipleStatus.after = ''
300
+			this.multipleStatus.data = []
301
+			this.multipleStatus.fulldate = ''
302
+			this.lastHover = false
303
+		} else {
304
+			if (!before) {
305
+				this.multipleStatus.before = fullDate
306
+				this.lastHover = false
307
+			} else {
308
+				this.multipleStatus.after = fullDate
309
+				if (this.dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
310
+					this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus
311
+						.after);
312
+				} else {
313
+					this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus
314
+						.before);
315
+				}
316
+				this.lastHover = true
317
+			}
318
+		}
319
+		this._getWeek(fullDate)
320
+	}
321
+
322
+	/**
323
+	 *  鼠标 hover 更新多选状态
324
+	 */
325
+	setHoverMultiple(fullDate) {
326
+		let {
327
+			before,
328
+			after
329
+		} = this.multipleStatus
330
+
331
+		if (!this.range) return
332
+		if (this.lastHover) return
333
+
334
+		if (!before) {
335
+			this.multipleStatus.before = fullDate
336
+		} else {
337
+			this.multipleStatus.after = fullDate
338
+			if (this.dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
339
+				this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
340
+			} else {
341
+				this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
342
+			}
343
+		}
344
+		this._getWeek(fullDate)
345
+	}
346
+
347
+	/**
348
+	 * 更新默认值多选状态
349
+	 */
350
+	setDefaultMultiple(before, after) {
351
+		this.multipleStatus.before = before
352
+		this.multipleStatus.after = after
353
+		if (before && after) {
354
+			if (this.dateCompare(before, after)) {
355
+				this.multipleStatus.data = this.geDateAll(before, after);
356
+				this._getWeek(after)
357
+			} else {
358
+				this.multipleStatus.data = this.geDateAll(after, before);
359
+				this._getWeek(before)
360
+			}
361
+		}
362
+	}
363
+
364
+	/**
365
+	 * 获取每周数据
366
+	 * @param {Object} dateData
367
+	 */
368
+	_getWeek(dateData) {
369
+		const {
370
+			fullDate,
371
+			year,
372
+			month,
373
+			date,
374
+			day
375
+		} = this.getDate(dateData)
376
+		let firstDay = new Date(year, month - 1, 1).getDay()
377
+		let currentDay = new Date(year, month, 0).getDate()
378
+		let dates = {
379
+			lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天
380
+			currentMonthDys: this._currentMonthDys(currentDay, this.getDate(dateData)), // 本月天数
381
+			nextMonthDays: [], // 下个月开始几天
382
+			weeks: []
383
+		}
384
+		let canlender = []
385
+		const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length)
386
+		dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData))
387
+		canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
388
+		let weeks = {}
389
+		// 拼接数组  上个月开始几天 + 本月天数+ 下个月开始几天
390
+		for (let i = 0; i < canlender.length; i++) {
391
+			if (i % 7 === 0) {
392
+				weeks[parseInt(i / 7)] = new Array(7)
393
+			}
394
+			weeks[parseInt(i / 7)][i % 7] = canlender[i]
395
+		}
396
+		this.canlender = canlender
397
+		this.weeks = weeks
398
+	}
399
+
400
+	//静态方法
401
+	// static init(date) {
402
+	// 	if (!this.instance) {
403
+	// 		this.instance = new Calendar(date);
404
+	// 	}
405
+	// 	return this.instance;
406
+	// }
407
+}
408
+
409
+
410
+export default Calendar

+ 87 - 0
uni_modules/uni-datetime-picker/package.json

@@ -0,0 +1,87 @@
1
+{
2
+  "id": "uni-datetime-picker",
3
+  "displayName": "uni-datetime-picker 日期选择器",
4
+  "version": "2.2.11",
5
+  "description": "uni-datetime-picker 日期时间选择器,支持日历,支持范围选择",
6
+  "keywords": [
7
+    "uni-datetime-picker",
8
+    "uni-ui",
9
+    "uniui",
10
+    "日期时间选择器",
11
+    "日期时间"
12
+],
13
+  "repository": "https://github.com/dcloudio/uni-ui",
14
+  "engines": {
15
+    "HBuilderX": ""
16
+  },
17
+  "directories": {
18
+    "example": "../../temps/example_temps"
19
+  },
20
+"dcloudext": {
21
+    "sale": {
22
+      "regular": {
23
+        "price": "0.00"
24
+      },
25
+      "sourcecode": {
26
+        "price": "0.00"
27
+      }
28
+    },
29
+    "contact": {
30
+      "qq": ""
31
+    },
32
+    "declaration": {
33
+      "ads": "无",
34
+      "data": "无",
35
+      "permissions": "无"
36
+    },
37
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
38
+    "type": "component-vue"
39
+  },
40
+  "uni_modules": {
41
+    "dependencies": [
42
+			"uni-scss",
43
+			"uni-icons"
44
+		],
45
+    "encrypt": [],
46
+    "platforms": {
47
+      "cloud": {
48
+        "tcb": "y",
49
+        "aliyun": "y"
50
+      },
51
+      "client": {
52
+        "App": {
53
+          "app-vue": "y",
54
+          "app-nvue": "n"
55
+        },
56
+        "H5-mobile": {
57
+          "Safari": "y",
58
+          "Android Browser": "y",
59
+          "微信浏览器(Android)": "y",
60
+          "QQ浏览器(Android)": "y"
61
+        },
62
+        "H5-pc": {
63
+          "Chrome": "y",
64
+          "IE": "y",
65
+          "Edge": "y",
66
+          "Firefox": "y",
67
+          "Safari": "y"
68
+        },
69
+        "小程序": {
70
+          "微信": "y",
71
+          "阿里": "y",
72
+          "百度": "y",
73
+          "字节跳动": "y",
74
+          "QQ": "y"
75
+        },
76
+        "快应用": {
77
+          "华为": "u",
78
+          "联盟": "u"
79
+        },
80
+        "Vue": {
81
+            "vue2": "y",
82
+            "vue3": "y"
83
+        }
84
+      }
85
+    }
86
+  }
87
+}

+ 21 - 0
uni_modules/uni-datetime-picker/readme.md

@@ -0,0 +1,21 @@
1
+
2
+
3
+> `重要通知:组件升级更新 2.0.0 后,支持日期+时间范围选择,组件 ui 将使用日历选择日期,ui 变化较大,同时支持 PC 和 移动端。此版本不向后兼容,不再支持单独的时间选择(type=time)及相关的 hide-second 属性(时间选可使用内置组件 picker)。若仍需使用旧版本,可在插件市场下载*非uni_modules版本*,旧版本将不再维护`
4
+
5
+## DatetimePicker 时间选择器
6
+
7
+> **组件名:uni-datetime-picker**
8
+> 代码块: `uDatetimePicker`
9
+
10
+
11
+该组件的优势是,支持**时间戳**输入和输出(起始时间、终止时间也支持时间戳),可**同时选择**日期和时间。
12
+
13
+若只是需要单独选择日期和时间,不需要时间戳输入和输出,可使用原生的 picker 组件。
14
+
15
+**_点击 picker 默认值规则:_**
16
+
17
+- 若设置初始值 value, 会显示在 picker 显示框中
18
+- 若无初始值 value,则初始值 value 为当前本地时间 Date.now(), 但不会显示在 picker 显示框中
19
+
20
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-datetime-picker)
21
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 

+ 13 - 0
uni_modules/uni-drawer/changelog.md

@@ -0,0 +1,13 @@
1
+## 1.2.1(2021-11-22)
2
+- 修复 vue3中个别scss变量无法找到的问题
3
+## 1.2.0(2021-11-19)
4
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
5
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-drawer](https://uniapp.dcloud.io/component/uniui/uni-drawer)
6
+## 1.1.1(2021-07-30)
7
+- 优化 vue3下事件警告的问题
8
+## 1.1.0(2021-07-13)
9
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
10
+## 1.0.7(2021-05-12)
11
+- 新增 组件示例地址
12
+## 1.0.6(2021-02-04)
13
+- 调整为uni_modules目录规范

+ 45 - 0
uni_modules/uni-drawer/components/uni-drawer/keypress.js

@@ -0,0 +1,45 @@
1
+// #ifdef H5
2
+export default {
3
+  name: 'Keypress',
4
+  props: {
5
+    disable: {
6
+      type: Boolean,
7
+      default: false
8
+    }
9
+  },
10
+  mounted () {
11
+    const keyNames = {
12
+      esc: ['Esc', 'Escape'],
13
+      tab: 'Tab',
14
+      enter: 'Enter',
15
+      space: [' ', 'Spacebar'],
16
+      up: ['Up', 'ArrowUp'],
17
+      left: ['Left', 'ArrowLeft'],
18
+      right: ['Right', 'ArrowRight'],
19
+      down: ['Down', 'ArrowDown'],
20
+      delete: ['Backspace', 'Delete', 'Del']
21
+    }
22
+    const listener = ($event) => {
23
+      if (this.disable) {
24
+        return
25
+      }
26
+      const keyName = Object.keys(keyNames).find(key => {
27
+        const keyName = $event.key
28
+        const value = keyNames[key]
29
+        return value === keyName || (Array.isArray(value) && value.includes(keyName))
30
+      })
31
+      if (keyName) {
32
+        // 避免和其他按键事件冲突
33
+        setTimeout(() => {
34
+          this.$emit(keyName, {})
35
+        }, 0)
36
+      }
37
+    }
38
+    document.addEventListener('keyup', listener)
39
+    // this.$once('hook:beforeDestroy', () => {
40
+    //   document.removeEventListener('keyup', listener)
41
+    // })
42
+  },
43
+	render: () => {}
44
+}
45
+// #endif

+ 183 - 0
uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue

@@ -0,0 +1,183 @@
1
+<template>
2
+	<view v-if="visibleSync" :class="{ 'uni-drawer--visible': showDrawer }" class="uni-drawer" @touchmove.stop.prevent="clear">
3
+		<view class="uni-drawer__mask" :class="{ 'uni-drawer__mask--visible': showDrawer && mask }" @tap="close('mask')" />
4
+		<view class="uni-drawer__content" :class="{'uni-drawer--right': rightMode,'uni-drawer--left': !rightMode, 'uni-drawer__content--visible': showDrawer}" :style="{width:drawerWidth+'px'}">
5
+			<slot />
6
+		</view>
7
+		<!-- #ifdef H5 -->
8
+		<keypress @esc="close('mask')" />
9
+		<!-- #endif -->
10
+	</view>
11
+</template>
12
+
13
+<script>
14
+	// #ifdef H5
15
+	import keypress from './keypress.js'
16
+	// #endif
17
+	/**
18
+	 * Drawer 抽屉
19
+	 * @description 抽屉侧滑菜单
20
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=26
21
+	 * @property {Boolean} mask = [true | false] 是否显示遮罩
22
+	 * @property {Boolean} maskClick = [true | false] 点击遮罩是否关闭
23
+	 * @property {Boolean} mode = [left | right] Drawer 滑出位置
24
+	 * 	@value left 从左侧滑出
25
+	 * 	@value right 从右侧侧滑出
26
+	 * @property {Number} width 抽屉的宽度 ,仅 vue 页面生效
27
+	 * @event {Function} close 组件关闭时触发事件
28
+	 */
29
+	export default {
30
+		name: 'UniDrawer',
31
+		components: {
32
+			// #ifdef H5
33
+			keypress
34
+			// #endif
35
+		},
36
+		emits:['change'],
37
+		props: {
38
+			/**
39
+			 * 显示模式(左、右),只在初始化生效
40
+			 */
41
+			mode: {
42
+				type: String,
43
+				default: ''
44
+			},
45
+			/**
46
+			 * 蒙层显示状态
47
+			 */
48
+			mask: {
49
+				type: Boolean,
50
+				default: true
51
+			},
52
+			/**
53
+			 * 遮罩是否可点击关闭
54
+			 */
55
+			maskClick:{
56
+				type: Boolean,
57
+				default: true
58
+			},
59
+			/**
60
+			 * 抽屉宽度
61
+			 */
62
+			width: {
63
+				type: Number,
64
+				default: 220
65
+			}
66
+		},
67
+		data() {
68
+			return {
69
+				visibleSync: false,
70
+				showDrawer: false,
71
+				rightMode: false,
72
+				watchTimer: null,
73
+				drawerWidth: 220
74
+			}
75
+		},
76
+		created() {
77
+			// #ifndef APP-NVUE
78
+			this.drawerWidth = this.width
79
+			// #endif
80
+			this.rightMode = this.mode === 'right'
81
+		},
82
+		methods: {
83
+			clear(){},
84
+			close(type) {
85
+				// fixed by mehaotian 抽屉尚未完全关闭或遮罩禁止点击时不触发以下逻辑
86
+				if((type === 'mask' && !this.maskClick) || !this.visibleSync) return
87
+				this._change('showDrawer', 'visibleSync', false)
88
+			},
89
+			open() {
90
+				// fixed by mehaotian 处理重复点击打开的事件
91
+				if(this.visibleSync) return
92
+				this._change('visibleSync', 'showDrawer', true)
93
+			},
94
+			_change(param1, param2, status) {
95
+				this[param1] = status
96
+				if (this.watchTimer) {
97
+					clearTimeout(this.watchTimer)
98
+				}
99
+				this.watchTimer = setTimeout(() => {
100
+					this[param2] = status
101
+					this.$emit('change',status)
102
+				}, status ? 50 : 300)
103
+			}
104
+		}
105
+	}
106
+</script>
107
+
108
+<style lang="scss" >
109
+	$uni-mask: rgba($color: #000000, $alpha: 0.4) ;
110
+	// 抽屉宽度
111
+	$drawer-width: 220px;
112
+
113
+	.uni-drawer {
114
+		/* #ifndef APP-NVUE */
115
+		display: block;
116
+		/* #endif */
117
+		position: fixed;
118
+		top: 0;
119
+		left: 0;
120
+		right: 0;
121
+		bottom: 0;
122
+		overflow: hidden;
123
+		z-index: 999;
124
+	}
125
+
126
+	.uni-drawer__content {
127
+		/* #ifndef APP-NVUE */
128
+		display: block;
129
+		/* #endif */
130
+		position: absolute;
131
+		top: 0;
132
+		width: $drawer-width;
133
+		bottom: 0;
134
+		background-color: $uni-bg-color;
135
+		transition: transform 0.3s ease;
136
+	}
137
+
138
+	.uni-drawer--left {
139
+		left: 0;
140
+		/* #ifdef APP-NVUE */
141
+		transform: translateX(-$drawer-width);
142
+		/* #endif */
143
+		/* #ifndef APP-NVUE */
144
+		transform: translateX(-100%);
145
+		/* #endif */
146
+	}
147
+
148
+	.uni-drawer--right {
149
+		right: 0;
150
+		/* #ifdef APP-NVUE */
151
+		transform: translateX($drawer-width);
152
+		/* #endif */
153
+		/* #ifndef APP-NVUE */
154
+		transform: translateX(100%);
155
+		/* #endif */
156
+	}
157
+
158
+	.uni-drawer__content--visible {
159
+		transform: translateX(0px);
160
+	}
161
+
162
+
163
+	.uni-drawer__mask {
164
+		/* #ifndef APP-NVUE */
165
+		display: block;
166
+		/* #endif */
167
+		opacity: 0;
168
+		position: absolute;
169
+		top: 0;
170
+		left: 0;
171
+		bottom: 0;
172
+		right: 0;
173
+		background-color: $uni-mask;
174
+		transition: opacity 0.3s;
175
+	}
176
+
177
+	.uni-drawer__mask--visible {
178
+		/* #ifndef APP-NVUE */
179
+		display: block;
180
+		/* #endif */
181
+		opacity: 1;
182
+	}
183
+</style>

+ 87 - 0
uni_modules/uni-drawer/package.json

@@ -0,0 +1,87 @@
1
+{
2
+  "id": "uni-drawer",
3
+  "displayName": "uni-drawer 抽屉",
4
+  "version": "1.2.1",
5
+  "description": "抽屉式导航,用于展示侧滑菜单,侧滑导航。",
6
+  "keywords": [
7
+    "uni-ui",
8
+    "uniui",
9
+    "drawer",
10
+    "抽屉",
11
+    "侧滑导航"
12
+],
13
+  "repository": "https://github.com/dcloudio/uni-ui",
14
+  "engines": {
15
+    "HBuilderX": ""
16
+  },
17
+  "directories": {
18
+    "example": "../../temps/example_temps"
19
+  },
20
+  "dcloudext": {
21
+    "category": [
22
+      "前端组件",
23
+      "通用组件"
24
+    ],
25
+    "sale": {
26
+      "regular": {
27
+        "price": "0.00"
28
+      },
29
+      "sourcecode": {
30
+        "price": "0.00"
31
+      }
32
+    },
33
+    "contact": {
34
+      "qq": ""
35
+    },
36
+    "declaration": {
37
+      "ads": "无",
38
+      "data": "无",
39
+      "permissions": "无"
40
+    },
41
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
42
+  },
43
+  "uni_modules": {
44
+    "dependencies": ["uni-scss"],
45
+    "encrypt": [],
46
+    "platforms": {
47
+      "cloud": {
48
+        "tcb": "y",
49
+        "aliyun": "y"
50
+      },
51
+      "client": {
52
+        "App": {
53
+          "app-vue": "y",
54
+          "app-nvue": "y"
55
+        },
56
+        "H5-mobile": {
57
+          "Safari": "y",
58
+          "Android Browser": "y",
59
+          "微信浏览器(Android)": "y",
60
+          "QQ浏览器(Android)": "y"
61
+        },
62
+        "H5-pc": {
63
+          "Chrome": "y",
64
+          "IE": "y",
65
+          "Edge": "y",
66
+          "Firefox": "y",
67
+          "Safari": "y"
68
+        },
69
+        "小程序": {
70
+          "微信": "y",
71
+          "阿里": "y",
72
+          "百度": "y",
73
+          "字节跳动": "y",
74
+          "QQ": "y"
75
+        },
76
+        "快应用": {
77
+          "华为": "u",
78
+          "联盟": "u"
79
+        },
80
+        "Vue": {
81
+            "vue2": "y",
82
+            "vue3": "y"
83
+        }
84
+      }
85
+    }
86
+  }
87
+}

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

@@ -0,0 +1,10 @@
1
+
2
+
3
+## Drawer 抽屉
4
+> **组件名:uni-drawer**
5
+> 代码块: `uDrawer`
6
+
7
+抽屉侧滑菜单。
8
+
9
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-drawer)
10
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 

+ 86 - 0
uni_modules/uni-easyinput/changelog.md

@@ -0,0 +1,86 @@
1
+## 1.1.0(2022-06-30)
2
+
3
+- 新增 在 uni-forms 1.4.0 中使用可以在 blur 时校验内容
4
+- 新增 clear 事件,点击右侧叉号图标触发
5
+- 新增 change 事件 ,仅在输入框失去焦点或用户按下回车时触发
6
+- 优化 组件样式,组件获取焦点时高亮显示,图标颜色调整等
7
+-
8
+
9
+## 1.0.5(2022-06-07)
10
+
11
+- 优化 clearable 显示策略
12
+
13
+## 1.0.4(2022-06-07)
14
+
15
+- 优化 clearable 显示策略
16
+
17
+## 1.0.3(2022-05-20)
18
+
19
+- 修复 关闭图标某些情况下无法取消的 bug
20
+
21
+## 1.0.2(2022-04-12)
22
+
23
+- 修复 默认值不生效的 bug
24
+
25
+## 1.0.1(2022-04-02)
26
+
27
+- 修复 value 不能为 0 的 bug
28
+
29
+## 1.0.0(2021-11-19)
30
+
31
+- 优化 组件 UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
32
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-easyinput](https://uniapp.dcloud.io/component/uniui/uni-easyinput)
33
+
34
+## 0.1.4(2021-08-20)
35
+
36
+- 修复 在 uni-forms 的动态表单中默认值校验不通过的 bug
37
+
38
+## 0.1.3(2021-08-11)
39
+
40
+- 修复 在 uni-forms 中重置表单,错误信息无法清除的问题
41
+
42
+## 0.1.2(2021-07-30)
43
+
44
+- 优化 vue3 下事件警告的问题
45
+
46
+## 0.1.1
47
+
48
+- 优化 errorMessage 属性支持 Boolean 类型
49
+
50
+## 0.1.0(2021-07-13)
51
+
52
+- 组件兼容 vue3,如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
53
+
54
+## 0.0.16(2021-06-29)
55
+
56
+- 修复 confirmType 属性(仅 type="text" 生效)导致多行文本框无法换行的 bug
57
+
58
+## 0.0.15(2021-06-21)
59
+
60
+- 修复 passwordIcon 属性拼写错误的 bug
61
+
62
+## 0.0.14(2021-06-18)
63
+
64
+- 新增 passwordIcon 属性,当 type=password 时是否显示小眼睛图标
65
+- 修复 confirmType 属性不生效的问题
66
+
67
+## 0.0.13(2021-06-04)
68
+
69
+- 修复 disabled 状态可清出内容的 bug
70
+
71
+## 0.0.12(2021-05-12)
72
+
73
+- 新增 组件示例地址
74
+
75
+## 0.0.11(2021-05-07)
76
+
77
+- 修复 input-border 属性不生效的问题
78
+
79
+## 0.0.10(2021-04-30)
80
+
81
+- 修复 ios 遮挡文字、显示一半的问题
82
+
83
+## 0.0.9(2021-02-05)
84
+
85
+- 调整为 uni_modules 目录规范
86
+- 优化 兼容 nvue 页面

+ 0 - 0
uni_modules/uni-easyinput/components/uni-easyinput/common.js


部分文件因为文件数量过多而无法显示