seimin 11 mēneši atpakaļ
vecāks
revīzija
c82e2f6590
100 mainītis faili ar 12623 papildinājumiem un 0 dzēšanām
  1. 16 0
      .hbuilderx/launch.json
  2. 32 0
      App.vue
  3. 20 0
      index.html
  4. 25 0
      main.js
  5. 60 0
      manifest.json
  6. 17 0
      pages.json
  7. 29 0
      pages/index/index.vue
  8. BIN
      static/c1.png
  9. BIN
      static/c2.png
  10. BIN
      static/c3.png
  11. BIN
      static/c4.png
  12. BIN
      static/c5.png
  13. BIN
      static/c6.png
  14. BIN
      static/c7.png
  15. BIN
      static/c8.png
  16. BIN
      static/c9.png
  17. 20 0
      static/customicons.css
  18. BIN
      static/customicons.ttf
  19. BIN
      static/logo.png
  20. BIN
      static/uni.png
  21. 1 0
      uni.scss
  22. 33 0
      uni_modules/uni-badge/changelog.md
  23. 268 0
      uni_modules/uni-badge/components/uni-badge/uni-badge.vue
  24. 85 0
      uni_modules/uni-badge/package.json
  25. 10 0
      uni_modules/uni-badge/readme.md
  26. 6 0
      uni_modules/uni-breadcrumb/changelog.md
  27. 121 0
      uni_modules/uni-breadcrumb/components/uni-breadcrumb-item/uni-breadcrumb-item.vue
  28. 41 0
      uni_modules/uni-breadcrumb/components/uni-breadcrumb/uni-breadcrumb.vue
  29. 88 0
      uni_modules/uni-breadcrumb/package.json
  30. 66 0
      uni_modules/uni-breadcrumb/readme.md
  31. 26 0
      uni_modules/uni-calendar/changelog.md
  32. 546 0
      uni_modules/uni-calendar/components/uni-calendar/calendar.js
  33. 12 0
      uni_modules/uni-calendar/components/uni-calendar/i18n/en.json
  34. 8 0
      uni_modules/uni-calendar/components/uni-calendar/i18n/index.js
  35. 12 0
      uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hans.json
  36. 12 0
      uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json
  37. 187 0
      uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue
  38. 566 0
      uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue
  39. 360 0
      uni_modules/uni-calendar/components/uni-calendar/util.js
  40. 85 0
      uni_modules/uni-calendar/package.json
  41. 103 0
      uni_modules/uni-calendar/readme.md
  42. 26 0
      uni_modules/uni-card/changelog.md
  43. 272 0
      uni_modules/uni-card/components/uni-card/uni-card.vue
  44. 90 0
      uni_modules/uni-card/package.json
  45. 12 0
      uni_modules/uni-card/readme.md
  46. 36 0
      uni_modules/uni-collapse/changelog.md
  47. 402 0
      uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue
  48. 147 0
      uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue
  49. 89 0
      uni_modules/uni-collapse/package.json
  50. 12 0
      uni_modules/uni-collapse/readme.md
  51. 15 0
      uni_modules/uni-combox/changelog.md
  52. 294 0
      uni_modules/uni-combox/components/uni-combox/uni-combox.vue
  53. 90 0
      uni_modules/uni-combox/package.json
  54. 11 0
      uni_modules/uni-combox/readme.md
  55. 24 0
      uni_modules/uni-countdown/changelog.md
  56. 6 0
      uni_modules/uni-countdown/components/uni-countdown/i18n/en.json
  57. 8 0
      uni_modules/uni-countdown/components/uni-countdown/i18n/index.js
  58. 6 0
      uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hans.json
  59. 6 0
      uni_modules/uni-countdown/components/uni-countdown/i18n/zh-Hant.json
  60. 267 0
      uni_modules/uni-countdown/components/uni-countdown/uni-countdown.vue
  61. 86 0
      uni_modules/uni-countdown/package.json
  62. 10 0
      uni_modules/uni-countdown/readme.md
  63. 45 0
      uni_modules/uni-data-checkbox/changelog.md
  64. 821 0
      uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue
  65. 84 0
      uni_modules/uni-data-checkbox/package.json
  66. 18 0
      uni_modules/uni-data-checkbox/readme.md
  67. 75 0
      uni_modules/uni-data-picker/changelog.md
  68. 45 0
      uni_modules/uni-data-picker/components/uni-data-picker/keypress.js
  69. 551 0
      uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue
  70. 622 0
      uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js
  71. 323 0
      uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue
  72. 90 0
      uni_modules/uni-data-picker/package.json
  73. 22 0
      uni_modules/uni-data-picker/readme.md
  74. 35 0
      uni_modules/uni-data-select/changelog.md
  75. 517 0
      uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue
  76. 85 0
      uni_modules/uni-data-select/package.json
  77. 8 0
      uni_modules/uni-data-select/readme.md
  78. 10 0
      uni_modules/uni-dateformat/changelog.md
  79. 200 0
      uni_modules/uni-dateformat/components/uni-dateformat/date-format.js
  80. 88 0
      uni_modules/uni-dateformat/components/uni-dateformat/uni-dateformat.vue
  81. 88 0
      uni_modules/uni-dateformat/package.json
  82. 11 0
      uni_modules/uni-dateformat/readme.md
  83. 133 0
      uni_modules/uni-datetime-picker/changelog.md
  84. 177 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue
  85. 928 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue
  86. 22 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json
  87. 8 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js
  88. 22 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json
  89. 22 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json
  90. 934 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue
  91. 1026 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue
  92. 403 0
      uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js
  93. 87 0
      uni_modules/uni-datetime-picker/package.json
  94. 21 0
      uni_modules/uni-datetime-picker/readme.md
  95. 13 0
      uni_modules/uni-drawer/changelog.md
  96. 45 0
      uni_modules/uni-drawer/components/uni-drawer/keypress.js
  97. 183 0
      uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue
  98. 87 0
      uni_modules/uni-drawer/package.json
  99. 10 0
      uni_modules/uni-drawer/readme.md
  100. 0 0
      uni_modules/uni-easyinput/changelog.md

+ 16 - 0
.hbuilderx/launch.json

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

+ 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>

+ 20 - 0
index.html

@@ -0,0 +1,20 @@
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
+    <title></title>
13
+    <!--preload-links-->
14
+    <!--app-context-->
15
+  </head>
16
+  <body>
17
+    <div id="app"><!--app-html--></div>
18
+    <script type="module" src="/main.js"></script>
19
+  </body>
20
+</html>

+ 25 - 0
main.js

@@ -0,0 +1,25 @@
1
+
2
+// #ifndef VUE3
3
+import Vue from 'vue'
4
+import App from './App'
5
+
6
+Vue.config.productionTip = false
7
+
8
+App.mpType = 'app'
9
+
10
+const app = new Vue({
11
+    ...App
12
+})
13
+app.$mount()
14
+// #endif
15
+
16
+// #ifdef VUE3
17
+import { createSSRApp } from 'vue'
18
+import App from './App.vue'
19
+export function createApp() {
20
+  const app = createSSRApp(App)
21
+  return {
22
+    app
23
+  }
24
+}
25
+// #endif

+ 60 - 0
manifest.json

@@ -0,0 +1,60 @@
1
+{
2
+    "name" : "itsm-wx-handle",
3
+    "appid" : "",
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
+        /* 模块配置 */
21
+        "distribute" : {
22
+            /* 应用发布信息 */
23
+            "android" : {
24
+                /* android打包配置 */
25
+                "permissions" : [
26
+                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
27
+                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
28
+                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
29
+                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
30
+                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
31
+                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
32
+                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
33
+                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
34
+                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
35
+                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
36
+                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
37
+                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
38
+                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
39
+                    "<uses-feature android:name=\"android.hardware.camera\"/>",
40
+                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
41
+                ]
42
+            },
43
+            "ios" : {},
44
+            /* ios打包配置 */
45
+            "sdkConfigs" : {}
46
+        }
47
+    },
48
+    /* SDK配置 */
49
+    "quickapp" : {},
50
+    /* 快应用特有相关 */
51
+    "mp-weixin" : {
52
+        /* 小程序特有相关 */
53
+        "appid" : "",
54
+        "setting" : {
55
+            "urlCheck" : false
56
+        },
57
+        "usingComponents" : true
58
+    },
59
+    "vueVersion" : "3"
60
+}

+ 17 - 0
pages.json

@@ -0,0 +1,17 @@
1
+{
2
+	"pages": [{
3
+		"path": "pages/index/index",
4
+		"style": {
5
+			"navigationBarTitleText": "uni-app"
6
+		}
7
+	}],
8
+	"globalStyle": {
9
+		"navigationBarTextStyle": "black",
10
+		"navigationBarTitleText": "uni-app",
11
+		"navigationBarBackgroundColor": "#F8F8F8",
12
+		"backgroundColor": "#F8F8F8",
13
+		"app-plus": {
14
+			"background": "#efeff4"
15
+		}
16
+	}
17
+}

+ 29 - 0
pages/index/index.vue

@@ -0,0 +1,29 @@
1
+<template>
2
+	<view class="container">
3
+		
4
+		<view class="intro">本项目已包含uni ui组件,无需import和注册,可直接使用。在代码区键入字母u,即可通过代码助手列出所有可用组件。光标置于组件名称处按F1,即可查看组件文档。</view>
5
+		<text class="intro">详见:</text>
6
+		<uni-link :href="href" :text="href"></uni-link>
7
+	</view>
8
+</template>
9
+
10
+<script>
11
+	export default {
12
+		data() {
13
+			return {
14
+				href: 'https://uniapp.dcloud.io/component/README?id=uniui'
15
+			}
16
+		},
17
+		methods: {
18
+
19
+		}
20
+	}
21
+</script>
22
+
23
+<style>
24
+	.container {
25
+		padding: 20px;
26
+		font-size: 14px;
27
+		line-height: 24px;
28
+	}
29
+</style>

BIN
static/c1.png


BIN
static/c2.png


BIN
static/c3.png


BIN
static/c4.png


BIN
static/c5.png


BIN
static/c6.png


BIN
static/c7.png


BIN
static/c8.png


BIN
static/c9.png


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

BIN
static/customicons.ttf


BIN
static/logo.png


BIN
static/uni.png


+ 1 - 0
uni.scss

@@ -0,0 +1 @@
1
+@import '@/uni_modules/uni-scss/variables.scss';

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

@@ -0,0 +1,33 @@
1
+## 1.2.2(2023-01-28)
2
+- 修复 运行/打包 控制台警告问题
3
+## 1.2.1(2022-09-05)
4
+- 修复 当 text 超过 max-num 时,badge 的宽度计算是根据 text 的长度计算,更改为 css 计算实际展示宽度,详见:[https://ask.dcloud.net.cn/question/150473](https://ask.dcloud.net.cn/question/150473)
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-badge](https://uniapp.dcloud.io/component/uniui/uni-badge)
8
+## 1.1.7(2021-11-08)
9
+- 优化 升级ui
10
+- 修改 size 属性默认值调整为 small
11
+- 修改 type 属性,默认值调整为 error,info 替换 default
12
+## 1.1.6(2021-09-22)
13
+- 修复 在字节小程序上样式不生效的 bug
14
+## 1.1.5(2021-07-30)
15
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
16
+## 1.1.4(2021-07-29)
17
+- 修复 去掉 nvue 不支持css 的 align-self 属性,nvue 下不暂支持 absolute 属性
18
+## 1.1.3(2021-06-24)
19
+- 优化 示例项目
20
+## 1.1.1(2021-05-12)
21
+- 新增 组件示例地址
22
+## 1.1.0(2021-05-12)
23
+- 新增 uni-badge 的 absolute 属性,支持定位
24
+- 新增 uni-badge 的 offset 属性,支持定位偏移
25
+- 新增 uni-badge 的 is-dot 属性,支持仅显示有一个小点
26
+- 新增 uni-badge 的 max-num 属性,支持自定义封顶的数字值,超过 99 显示99+
27
+- 优化 uni-badge 属性 custom-style, 支持以对象形式自定义样式
28
+## 1.0.7(2021-05-07)
29
+- 修复 uni-badge 在 App 端,数字小于10时不是圆形的bug
30
+- 修复 uni-badge 在父元素不是 flex 布局时,宽度缩小的bug
31
+- 新增 uni-badge 属性 custom-style, 支持自定义样式
32
+## 1.0.6(2021-02-04)
33
+- 调整为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
+		font-feature-settings: "tnum";
196
+		min-width: 20px;
197
+		/* #endif */
198
+		justify-content: center;
199
+		flex-direction: row;
200
+		height: 20px;
201
+		padding: 0 4px;
202
+		line-height: 18px;
203
+		color: #fff;
204
+		border-radius: 100px;
205
+		background-color: $uni-info;
206
+		background-color: transparent;
207
+		border: 1px solid #fff;
208
+		text-align: center;
209
+		font-family: 'Helvetica Neue', Helvetica, sans-serif;
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.2",
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 不显示的Bug
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)

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

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

+ 187 - 0
uni_modules/uni-calendar/components/uni-calendar/uni-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--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 { initVueI18n } from '@dcloudio/uni-i18n'
55
+	import i18nMessages from './i18n/index.js'
56
+	const {	t	} = initVueI18n(i18nMessages)
57
+
58
+	export default {
59
+		emits:['change'],
60
+		props: {
61
+			weeks: {
62
+				type: Object,
63
+				default () {
64
+					return {}
65
+				}
66
+			},
67
+			calendar: {
68
+				type: Object,
69
+				default: () => {
70
+					return {}
71
+				}
72
+			},
73
+			selected: {
74
+				type: Array,
75
+				default: () => {
76
+					return []
77
+				}
78
+			},
79
+			lunar: {
80
+				type: Boolean,
81
+				default: false
82
+			}
83
+		},
84
+		computed: {
85
+			todayText() {
86
+				return t("uni-calender.today")
87
+			},
88
+		},
89
+		methods: {
90
+			choiceDate(weeks) {
91
+				this.$emit('change', weeks)
92
+			}
93
+		}
94
+	}
95
+</script>
96
+
97
+<style lang="scss" scoped>
98
+	$uni-font-size-base:14px;
99
+	$uni-text-color:#333;
100
+	$uni-font-size-sm:12px;
101
+	$uni-color-error: #e43d33;
102
+	$uni-opacity-disabled: 0.3;
103
+	$uni-text-color-disable:#c0c0c0;
104
+	$uni-primary: #2979ff !default;
105
+	.uni-calendar-item__weeks-box {
106
+		flex: 1;
107
+		/* #ifndef APP-NVUE */
108
+		display: flex;
109
+		/* #endif */
110
+		flex-direction: column;
111
+		justify-content: center;
112
+		align-items: center;
113
+	}
114
+
115
+	.uni-calendar-item__weeks-box-text {
116
+		font-size: $uni-font-size-base;
117
+		color: $uni-text-color;
118
+	}
119
+
120
+	.uni-calendar-item__weeks-lunar-text {
121
+		font-size: $uni-font-size-sm;
122
+		color: $uni-text-color;
123
+	}
124
+
125
+	.uni-calendar-item__weeks-box-item {
126
+		position: relative;
127
+		/* #ifndef APP-NVUE */
128
+		display: flex;
129
+		/* #endif */
130
+		flex-direction: column;
131
+		justify-content: center;
132
+		align-items: center;
133
+		width: 100rpx;
134
+		height: 100rpx;
135
+	}
136
+
137
+	.uni-calendar-item__weeks-box-circle {
138
+		position: absolute;
139
+		top: 5px;
140
+		right: 5px;
141
+		width: 8px;
142
+		height: 8px;
143
+		border-radius: 8px;
144
+		background-color: $uni-color-error;
145
+
146
+	}
147
+
148
+	.uni-calendar-item--disable {
149
+		background-color: rgba(249, 249, 249, $uni-opacity-disabled);
150
+		color: $uni-text-color-disable;
151
+	}
152
+
153
+	.uni-calendar-item--isDay-text {
154
+		color: $uni-primary;
155
+	}
156
+
157
+	.uni-calendar-item--isDay {
158
+		background-color: $uni-primary;
159
+		opacity: 0.8;
160
+		color: #fff;
161
+	}
162
+
163
+	.uni-calendar-item--extra {
164
+		color: $uni-color-error;
165
+		opacity: 0.8;
166
+	}
167
+
168
+	.uni-calendar-item--checked {
169
+		background-color: $uni-primary;
170
+		color: #fff;
171
+		opacity: 0.8;
172
+	}
173
+
174
+	.uni-calendar-item--multiple {
175
+		background-color: $uni-primary;
176
+		color: #fff;
177
+		opacity: 0.8;
178
+	}
179
+	.uni-calendar-item--before-checked {
180
+		background-color: #ff5a5f;
181
+		color: #fff;
182
+	}
183
+	.uni-calendar-item--after-checked {
184
+		background-color: #ff5a5f;
185
+		color: #fff;
186
+	}
187
+</style>

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

@@ -0,0 +1,566 @@
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
+
67
+	import { initVueI18n } from '@dcloudio/uni-i18n'
68
+	import i18nMessages from './i18n/index.js'
69
+	const {	t	} = initVueI18n(i18nMessages)
70
+
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
+			this.cale = new Calendar({
203
+				selected: this.selected,
204
+				startDate: this.startDate,
205
+				endDate: this.endDate,
206
+				range: this.range,
207
+			})
208
+			this.init(this.date)
209
+		},
210
+		methods: {
211
+			// 取消穿透
212
+			clean() {},
213
+			bindDateChange(e) {
214
+				const value = e.detail.value + '-1'
215
+				this.setDate(value)
216
+
217
+				const { year,month } = this.cale.getDate(value)
218
+        this.$emit('monthSwitch', {
219
+            year,
220
+            month
221
+        })
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
+				const nowYearMonth = `${this.nowDate.year}-${this.nowDate.month}`
328
+				const date = this.cale.getDate(new Date())
329
+        const todayYearMonth = `${date.year}-${date.month}`
330
+
331
+        if(nowYearMonth !== todayYearMonth) {
332
+          this.monthSwitch()
333
+        }
334
+
335
+				this.init(date.fullDate)
336
+				this.change()
337
+			},
338
+			/**
339
+			 * 上个月
340
+			 */
341
+			pre() {
342
+				const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate
343
+				this.setDate(preDate)
344
+				this.monthSwitch()
345
+
346
+			},
347
+			/**
348
+			 * 下个月
349
+			 */
350
+			next() {
351
+				const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate
352
+				this.setDate(nextDate)
353
+				this.monthSwitch()
354
+			},
355
+			/**
356
+			 * 设置日期
357
+			 * @param {Object} date
358
+			 */
359
+			setDate(date) {
360
+				this.cale.setDate(date)
361
+				this.weeks = this.cale.weeks
362
+				this.nowDate = this.cale.getInfo(date)
363
+			}
364
+		}
365
+	}
366
+</script>
367
+
368
+<style lang="scss" scoped>
369
+	$uni-bg-color-mask: rgba($color: #000000, $alpha: 0.4);
370
+	$uni-border-color: #EDEDED;
371
+	$uni-text-color: #333;
372
+	$uni-bg-color-hover:#f1f1f1;
373
+	$uni-font-size-base:14px;
374
+	$uni-text-color-placeholder: #808080;
375
+	$uni-color-subtitle: #555555;
376
+	$uni-text-color-grey:#999;
377
+	.uni-calendar {
378
+		/* #ifndef APP-NVUE */
379
+		display: flex;
380
+		/* #endif */
381
+		flex-direction: column;
382
+	}
383
+
384
+	.uni-calendar__mask {
385
+		position: fixed;
386
+		bottom: 0;
387
+		top: 0;
388
+		left: 0;
389
+		right: 0;
390
+		background-color: $uni-bg-color-mask;
391
+		transition-property: opacity;
392
+		transition-duration: 0.3s;
393
+		opacity: 0;
394
+		/* #ifndef APP-NVUE */
395
+		z-index: 99;
396
+		/* #endif */
397
+	}
398
+
399
+	.uni-calendar--mask-show {
400
+		opacity: 1
401
+	}
402
+
403
+	.uni-calendar--fixed {
404
+		position: fixed;
405
+		/* #ifdef APP-NVUE */
406
+		bottom: 0;
407
+		/* #endif */
408
+		left: 0;
409
+		right: 0;
410
+		transition-property: transform;
411
+		transition-duration: 0.3s;
412
+		transform: translateY(460px);
413
+		/* #ifndef APP-NVUE */
414
+		bottom: calc(var(--window-bottom));
415
+		z-index: 99;
416
+		/* #endif */
417
+	}
418
+
419
+	.uni-calendar--ani-show {
420
+		transform: translateY(0);
421
+	}
422
+
423
+	.uni-calendar__content {
424
+		background-color: #fff;
425
+	}
426
+
427
+	.uni-calendar__header {
428
+		position: relative;
429
+		/* #ifndef APP-NVUE */
430
+		display: flex;
431
+		/* #endif */
432
+		flex-direction: row;
433
+		justify-content: center;
434
+		align-items: center;
435
+		height: 50px;
436
+		border-bottom-color: $uni-border-color;
437
+		border-bottom-style: solid;
438
+		border-bottom-width: 1px;
439
+	}
440
+
441
+	.uni-calendar--fixed-top {
442
+		/* #ifndef APP-NVUE */
443
+		display: flex;
444
+		/* #endif */
445
+		flex-direction: row;
446
+		justify-content: space-between;
447
+		border-top-color: $uni-border-color;
448
+		border-top-style: solid;
449
+		border-top-width: 1px;
450
+	}
451
+
452
+	.uni-calendar--fixed-width {
453
+		width: 50px;
454
+	}
455
+
456
+	.uni-calendar__backtoday {
457
+		position: absolute;
458
+		right: 0;
459
+		top: 25rpx;
460
+		padding: 0 5px;
461
+		padding-left: 10px;
462
+		height: 25px;
463
+		line-height: 25px;
464
+		font-size: 12px;
465
+		border-top-left-radius: 25px;
466
+		border-bottom-left-radius: 25px;
467
+		color: $uni-text-color;
468
+		background-color: $uni-bg-color-hover;
469
+	}
470
+
471
+	.uni-calendar__header-text {
472
+		text-align: center;
473
+		width: 100px;
474
+		font-size: $uni-font-size-base;
475
+		color: $uni-text-color;
476
+	}
477
+
478
+	.uni-calendar__header-btn-box {
479
+		/* #ifndef APP-NVUE */
480
+		display: flex;
481
+		/* #endif */
482
+		flex-direction: row;
483
+		align-items: center;
484
+		justify-content: center;
485
+		width: 50px;
486
+		height: 50px;
487
+	}
488
+
489
+	.uni-calendar__header-btn {
490
+		width: 10px;
491
+		height: 10px;
492
+		border-left-color: $uni-text-color-placeholder;
493
+		border-left-style: solid;
494
+		border-left-width: 2px;
495
+		border-top-color: $uni-color-subtitle;
496
+		border-top-style: solid;
497
+		border-top-width: 2px;
498
+	}
499
+
500
+	.uni-calendar--left {
501
+		transform: rotate(-45deg);
502
+	}
503
+
504
+	.uni-calendar--right {
505
+		transform: rotate(135deg);
506
+	}
507
+
508
+
509
+	.uni-calendar__weeks {
510
+		position: relative;
511
+		/* #ifndef APP-NVUE */
512
+		display: flex;
513
+		/* #endif */
514
+		flex-direction: row;
515
+	}
516
+
517
+	.uni-calendar__weeks-item {
518
+		flex: 1;
519
+	}
520
+
521
+	.uni-calendar__weeks-day {
522
+		flex: 1;
523
+		/* #ifndef APP-NVUE */
524
+		display: flex;
525
+		/* #endif */
526
+		flex-direction: column;
527
+		justify-content: center;
528
+		align-items: center;
529
+		height: 45px;
530
+		border-bottom-color: #F5F5F5;
531
+		border-bottom-style: solid;
532
+		border-bottom-width: 1px;
533
+	}
534
+
535
+	.uni-calendar__weeks-day-text {
536
+		font-size: 14px;
537
+	}
538
+
539
+	.uni-calendar__box {
540
+		position: relative;
541
+	}
542
+
543
+	.uni-calendar__box-bg {
544
+		/* #ifndef APP-NVUE */
545
+		display: flex;
546
+		/* #endif */
547
+		justify-content: center;
548
+		align-items: center;
549
+		position: absolute;
550
+		top: 0;
551
+		left: 0;
552
+		right: 0;
553
+		bottom: 0;
554
+	}
555
+
556
+	.uni-calendar__box-bg-text {
557
+		font-size: 200px;
558
+		font-weight: bold;
559
+		color: $uni-text-color-grey;
560
+		opacity: 0.1;
561
+		text-align: center;
562
+		/* #ifndef APP-NVUE */
563
+		line-height: 1;
564
+		/* #endif */
565
+	}
566
+</style>

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

@@ -0,0 +1,360 @@
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 && AddDayCount>0) {
80
+					dd.setDate(dd.getDate() + AddDayCount)
81
+				} else {
82
+					const preMonth = dd.getMonth()
83
+					dd.setMonth(preMonth + AddDayCount) // 获取AddDayCount天后的日期
84
+					const nextMonth = dd.getMonth()
85
+					// 处理 pre 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
86
+					if(AddDayCount<0 && preMonth!==0 && nextMonth-preMonth>AddDayCount){
87
+						dd.setMonth(nextMonth+(nextMonth-preMonth+AddDayCount))
88
+					}
89
+					// 处理 next 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
90
+					if(AddDayCount>0 && nextMonth-preMonth>AddDayCount){
91
+						dd.setMonth(nextMonth-(nextMonth-preMonth-AddDayCount))
92
+					}
93
+				}
94
+				break
95
+			case 'year':
96
+				dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
97
+				break
98
+		}
99
+		const y = dd.getFullYear()
100
+		const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
101
+		const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
102
+		return {
103
+			fullDate: y + '-' + m + '-' + d,
104
+			year: y,
105
+			month: m,
106
+			date: d,
107
+			day: dd.getDay()
108
+		}
109
+	}
110
+
111
+
112
+	/**
113
+	 * 获取上月剩余天数
114
+	 */
115
+	_getLastMonthDays(firstDay, full) {
116
+		let dateArr = []
117
+		for (let i = firstDay; i > 0; i--) {
118
+			const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate()
119
+			dateArr.push({
120
+				date: beforeDate,
121
+				month: full.month - 1,
122
+				lunar: this.getlunar(full.year, full.month - 1, beforeDate),
123
+				disable: true
124
+			})
125
+		}
126
+		return dateArr
127
+	}
128
+	/**
129
+	 * 获取本月天数
130
+	 */
131
+	_currentMonthDys(dateData, full) {
132
+		let dateArr = []
133
+		let fullDate = this.date.fullDate
134
+		for (let i = 1; i <= dateData; i++) {
135
+			let nowDate = full.year + '-' + (full.month < 10 ?
136
+				full.month : full.month) + '-' + (i < 10 ?
137
+				'0' + i : i)
138
+			// 是否今天
139
+			let isDay = fullDate === nowDate
140
+			// 获取打点信息
141
+			let info = this.selected && this.selected.find((item) => {
142
+				if (this.dateEqual(nowDate, item.date)) {
143
+					return item
144
+				}
145
+			})
146
+
147
+			// 日期禁用
148
+			let disableBefore = true
149
+			let disableAfter = true
150
+			if (this.startDate) {
151
+				// let dateCompBefore = this.dateCompare(this.startDate, fullDate)
152
+				// disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
153
+				disableBefore = this.dateCompare(this.startDate, nowDate)
154
+			}
155
+
156
+			if (this.endDate) {
157
+				// let dateCompAfter = this.dateCompare(fullDate, this.endDate)
158
+				// disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
159
+				disableAfter = this.dateCompare(nowDate, this.endDate)
160
+			}
161
+			let multiples = this.multipleStatus.data
162
+			let checked = false
163
+			let multiplesStatus = -1
164
+			if (this.range) {
165
+				if (multiples) {
166
+					multiplesStatus = multiples.findIndex((item) => {
167
+						return this.dateEqual(item, nowDate)
168
+					})
169
+				}
170
+				if (multiplesStatus !== -1) {
171
+					checked = true
172
+				}
173
+			}
174
+			let data = {
175
+				fullDate: nowDate,
176
+				year: full.year,
177
+				date: i,
178
+				multiple: this.range ? checked : false,
179
+				beforeMultiple: this.dateEqual(this.multipleStatus.before, nowDate),
180
+				afterMultiple: this.dateEqual(this.multipleStatus.after, nowDate),
181
+				month: full.month,
182
+				lunar: this.getlunar(full.year, full.month, i),
183
+				disable: !(disableBefore && disableAfter),
184
+				isDay
185
+			}
186
+			if (info) {
187
+				data.extraInfo = info
188
+			}
189
+
190
+			dateArr.push(data)
191
+		}
192
+		return dateArr
193
+	}
194
+	/**
195
+	 * 获取下月天数
196
+	 */
197
+	_getNextMonthDays(surplus, full) {
198
+		let dateArr = []
199
+		for (let i = 1; i < surplus + 1; i++) {
200
+			dateArr.push({
201
+				date: i,
202
+				month: Number(full.month) + 1,
203
+				lunar: this.getlunar(full.year, Number(full.month) + 1, i),
204
+				disable: true
205
+			})
206
+		}
207
+		return dateArr
208
+	}
209
+
210
+	/**
211
+	 * 获取当前日期详情
212
+	 * @param {Object} date
213
+	 */
214
+	getInfo(date) {
215
+		if (!date) {
216
+			date = new Date()
217
+		}
218
+		const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate)
219
+		return dateInfo
220
+	}
221
+
222
+	/**
223
+	 * 比较时间大小
224
+	 */
225
+	dateCompare(startDate, endDate) {
226
+		// 计算截止时间
227
+		startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
228
+		// 计算详细项的截止时间
229
+		endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
230
+		if (startDate <= endDate) {
231
+			return true
232
+		} else {
233
+			return false
234
+		}
235
+	}
236
+
237
+	/**
238
+	 * 比较时间是否相等
239
+	 */
240
+	dateEqual(before, after) {
241
+		// 计算截止时间
242
+		before = new Date(before.replace('-', '/').replace('-', '/'))
243
+		// 计算详细项的截止时间
244
+		after = new Date(after.replace('-', '/').replace('-', '/'))
245
+		if (before.getTime() - after.getTime() === 0) {
246
+			return true
247
+		} else {
248
+			return false
249
+		}
250
+	}
251
+
252
+
253
+	/**
254
+	 * 获取日期范围内所有日期
255
+	 * @param {Object} begin
256
+	 * @param {Object} end
257
+	 */
258
+	geDateAll(begin, end) {
259
+		var arr = []
260
+		var ab = begin.split('-')
261
+		var ae = end.split('-')
262
+		var db = new Date()
263
+		db.setFullYear(ab[0], ab[1] - 1, ab[2])
264
+		var de = new Date()
265
+		de.setFullYear(ae[0], ae[1] - 1, ae[2])
266
+		var unixDb = db.getTime() - 24 * 60 * 60 * 1000
267
+		var unixDe = de.getTime() - 24 * 60 * 60 * 1000
268
+		for (var k = unixDb; k <= unixDe;) {
269
+			k = k + 24 * 60 * 60 * 1000
270
+			arr.push(this.getDate(new Date(parseInt(k))).fullDate)
271
+		}
272
+		return arr
273
+	}
274
+	/**
275
+	 * 计算阴历日期显示
276
+	 */
277
+	getlunar(year, month, date) {
278
+		return CALENDAR.solar2lunar(year, month, date)
279
+	}
280
+	/**
281
+	 * 设置打点
282
+	 */
283
+	setSelectInfo(data, value) {
284
+		this.selected = value
285
+		this._getWeek(data)
286
+	}
287
+
288
+	/**
289
+	 *  获取多选状态
290
+	 */
291
+	setMultiple(fullDate) {
292
+		let {
293
+			before,
294
+			after
295
+		} = this.multipleStatus
296
+
297
+		if (!this.range) return
298
+		if (before && after) {
299
+			this.multipleStatus.before = ''
300
+			this.multipleStatus.after = ''
301
+			this.multipleStatus.data = []
302
+		} else {
303
+			if (!before) {
304
+				this.multipleStatus.before = fullDate
305
+			} else {
306
+				this.multipleStatus.after = fullDate
307
+				if (this.dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
308
+					this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
309
+				} else {
310
+					this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
311
+				}
312
+			}
313
+		}
314
+		this._getWeek(fullDate)
315
+	}
316
+
317
+	/**
318
+	 * 获取每周数据
319
+	 * @param {Object} dateData
320
+	 */
321
+	_getWeek(dateData) {
322
+		const {
323
+			year,
324
+			month
325
+		} = this.getDate(dateData)
326
+		let firstDay = new Date(year, month - 1, 1).getDay()
327
+		let currentDay = new Date(year, month, 0).getDate()
328
+		let dates = {
329
+			lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天
330
+			currentMonthDys: this._currentMonthDys(currentDay, this.getDate(dateData)), // 本月天数
331
+			nextMonthDays: [], // 下个月开始几天
332
+			weeks: []
333
+		}
334
+		let canlender = []
335
+		const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length)
336
+		dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData))
337
+		canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
338
+		let weeks = {}
339
+		// 拼接数组  上个月开始几天 + 本月天数+ 下个月开始几天
340
+		for (let i = 0; i < canlender.length; i++) {
341
+			if (i % 7 === 0) {
342
+				weeks[parseInt(i / 7)] = new Array(7)
343
+			}
344
+			weeks[parseInt(i / 7)][i % 7] = canlender[i]
345
+		}
346
+		this.canlender = canlender
347
+		this.weeks = weeks
348
+	}
349
+
350
+	//静态方法
351
+	// static init(date) {
352
+	// 	if (!this.instance) {
353
+	// 		this.instance = new Calendar(date);
354
+	// 	}
355
+	// 	return this.instance;
356
+	// }
357
+}
358
+
359
+
360
+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.10",
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目录规范

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

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

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

@@ -0,0 +1,294 @@
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" @blur="onBlur" />
9
+			<uni-icons :type="showSelector? 'top' : 'bottom'" size="14" color="#999" @click="toggleSelector">
10
+			</uni-icons>
11
+		</view>
12
+		<view class="uni-combox__selector" v-if="showSelector">
13
+			<view class="uni-popper__arrow"></view>
14
+			<scroll-view scroll-y="true" class="uni-combox__selector-scroll" @scroll="onScroll">
15
+				<view class="uni-combox__selector-empty" v-if="filterCandidatesLength === 0">
16
+					<text>{{emptyTips}}</text>
17
+				</view>
18
+				<view class="uni-combox__selector-item" v-for="(item,index) in filterCandidates" :key="index" @click="onSelectorClick(index)">
19
+					<text>{{item}}</text>
20
+				</view>
21
+			</scroll-view>
22
+		</view>
23
+		<!-- 新增蒙层,点击蒙层时关闭选项显示 -->
24
+		<view class="uni-combox__mask" v-show="showSelector" @click="showSelector = false"></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
+				blurTimer:null,
88
+			}
89
+		},
90
+		computed: {
91
+			labelStyle() {
92
+				if (this.labelWidth === 'auto') {
93
+					return ""
94
+				}
95
+				return `width: ${this.labelWidth}`
96
+			},
97
+			filterCandidates() {
98
+				if (this.inputVal !== 0 && !this.inputVal) {
99
+					return this.candidates
100
+				}
101
+				return this.candidates.filter((item) => {
102
+					return item.toString().indexOf(this.inputVal) > -1
103
+				})
104
+			},
105
+			filterCandidatesLength() {
106
+				return this.filterCandidates.length
107
+			}
108
+		},
109
+		watch: {
110
+			// #ifndef VUE3
111
+			value: {
112
+				handler(newVal) {
113
+					this.inputVal = newVal
114
+				},
115
+				immediate: true
116
+			},
117
+			// #endif
118
+			// #ifdef VUE3
119
+			modelValue: {
120
+				handler(newVal) {
121
+					this.inputVal = newVal
122
+				},
123
+				immediate: true
124
+			},
125
+			// #endif
126
+		},
127
+		methods: {
128
+			toggleSelector() {
129
+				this.showSelector = !this.showSelector
130
+			},
131
+			onFocus() {
132
+				this.showSelector = true
133
+			},
134
+			onBlur() {
135
+				this.blurTimer = setTimeout(() => {
136
+					this.showSelector = false
137
+				}, 153)
138
+			},
139
+			onScroll(){ // 滚动时将blur的定时器关掉
140
+				if(this.blurTimer) {
141
+					clearTimeout(this.blurTimer)
142
+					this.blurTimer = null
143
+				}
144
+			},
145
+			onSelectorClick(index) {
146
+				this.inputVal = this.filterCandidates[index]
147
+				this.showSelector = false
148
+				this.$emit('input', this.inputVal)
149
+				this.$emit('update:modelValue', this.inputVal)
150
+			},
151
+			onInput() {
152
+				setTimeout(() => {
153
+					this.$emit('input', this.inputVal)
154
+					this.$emit('update:modelValue', this.inputVal)
155
+				})
156
+			}
157
+		}
158
+	}
159
+</script>
160
+
161
+<style lang="scss">
162
+	.uni-combox {
163
+		font-size: 14px;
164
+		border: 1px solid #DCDFE6;
165
+		border-radius: 4px;
166
+		padding: 6px 10px;
167
+		position: relative;
168
+		/* #ifndef APP-NVUE */
169
+		display: flex;
170
+		/* #endif */
171
+		// height: 40px;
172
+		flex-direction: row;
173
+		align-items: center;
174
+		// border-bottom: solid 1px #DDDDDD;
175
+	}
176
+
177
+	.uni-combox__label {
178
+		font-size: 16px;
179
+		line-height: 22px;
180
+		padding-right: 10px;
181
+		color: #999999;
182
+	}
183
+
184
+	.uni-combox__input-box {
185
+		position: relative;
186
+		/* #ifndef APP-NVUE */
187
+		display: flex;
188
+		/* #endif */
189
+		flex: 1;
190
+		flex-direction: row;
191
+		align-items: center;
192
+	}
193
+
194
+	.uni-combox__input {
195
+		flex: 1;
196
+		font-size: 14px;
197
+		height: 22px;
198
+		line-height: 22px;
199
+	}
200
+
201
+	.uni-combox__input-plac {
202
+		font-size: 14px;
203
+		color: #999;
204
+	}
205
+
206
+	.uni-combox__selector {
207
+		/* #ifndef APP-NVUE */
208
+		box-sizing: border-box;
209
+		/* #endif */
210
+		position: absolute;
211
+		top: calc(100% + 12px);
212
+		left: 0;
213
+		width: 100%;
214
+		background-color: #FFFFFF;
215
+		border: 1px solid #EBEEF5;
216
+		border-radius: 6px;
217
+		box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
218
+		z-index: 3;
219
+		padding: 4px 0;
220
+	}
221
+
222
+	.uni-combox__selector-scroll {
223
+		/* #ifndef APP-NVUE */
224
+		max-height: 200px;
225
+		box-sizing: border-box;
226
+		/* #endif */
227
+	}
228
+
229
+	.uni-combox__selector-empty,
230
+	.uni-combox__selector-item {
231
+		/* #ifndef APP-NVUE */
232
+		display: flex;
233
+		cursor: pointer;
234
+		/* #endif */
235
+		line-height: 36px;
236
+		font-size: 14px;
237
+		text-align: center;
238
+		// border-bottom: solid 1px #DDDDDD;
239
+		padding: 0px 10px;
240
+	}
241
+
242
+	.uni-combox__selector-item:hover {
243
+		background-color: #f9f9f9;
244
+	}
245
+
246
+	.uni-combox__selector-empty:last-child,
247
+	.uni-combox__selector-item:last-child {
248
+		/* #ifndef APP-NVUE */
249
+		border-bottom: none;
250
+		/* #endif */
251
+	}
252
+
253
+	// picker 弹出层通用的指示小三角
254
+	.uni-popper__arrow,
255
+	.uni-popper__arrow::after {
256
+		position: absolute;
257
+		display: block;
258
+		width: 0;
259
+		height: 0;
260
+		border-color: transparent;
261
+		border-style: solid;
262
+		border-width: 6px;
263
+	}
264
+
265
+	.uni-popper__arrow {
266
+		filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
267
+		top: -6px;
268
+		left: 10%;
269
+		margin-right: 3px;
270
+		border-top-width: 0;
271
+		border-bottom-color: #EBEEF5;
272
+	}
273
+
274
+	.uni-popper__arrow::after {
275
+		content: " ";
276
+		top: 1px;
277
+		margin-left: -6px;
278
+		border-top-width: 0;
279
+		border-bottom-color: #fff;
280
+	}
281
+
282
+	.uni-combox__no-border {
283
+		border: none;
284
+	}
285
+
286
+	.uni-combox__mask {
287
+		width:100%;
288
+		height:100%;
289
+		position: fixed;
290
+		top: 0;
291
+		left: 0;
292
+    z-index: 1;
293
+	}
294
+</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
+}

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

@@ -0,0 +1,267 @@
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
+      zeroPad: {
91
+				type: Boolean,
92
+				default: true
93
+			}
94
+		},
95
+		data() {
96
+			return {
97
+				timer: null,
98
+				syncFlag: false,
99
+				d: '00',
100
+				h: '00',
101
+				i: '00',
102
+				s: '00',
103
+				leftTime: 0,
104
+				seconds: 0
105
+			}
106
+		},
107
+		computed: {
108
+			dayText() {
109
+				return t("uni-countdown.day")
110
+			},
111
+			hourText(val) {
112
+				return t("uni-countdown.h")
113
+			},
114
+			minuteText(val) {
115
+				return t("uni-countdown.m")
116
+			},
117
+			secondText(val) {
118
+				return t("uni-countdown.s")
119
+			},
120
+			timeStyle() {
121
+				const {
122
+					color,
123
+					backgroundColor,
124
+					fontSize
125
+				} = this
126
+				return {
127
+					color,
128
+					backgroundColor,
129
+					fontSize: `${fontSize}px`,
130
+					width: `${fontSize * 22 / 14}px`, // 按字体大小为 14px 时的比例缩放
131
+ 					lineHeight: `${fontSize * 20 / 14}px`,
132
+					borderRadius: `${fontSize * 3 / 14}px`,
133
+				}
134
+			},
135
+			splitorStyle() {
136
+				const { splitorColor, fontSize, backgroundColor } = this
137
+				return {
138
+					color: splitorColor,
139
+					fontSize: `${fontSize * 12 / 14}px`,
140
+					margin: backgroundColor ? `${fontSize * 4 / 14}px` : ''
141
+				}
142
+			}
143
+		},
144
+		watch: {
145
+			day(val) {
146
+				this.changeFlag()
147
+			},
148
+			hour(val) {
149
+				this.changeFlag()
150
+			},
151
+			minute(val) {
152
+				this.changeFlag()
153
+			},
154
+			second(val) {
155
+				this.changeFlag()
156
+			},
157
+			start: {
158
+				immediate: true,
159
+				handler(newVal, oldVal) {
160
+					if (newVal) {
161
+						this.startData();
162
+					} else {
163
+						if (!oldVal) return
164
+						clearInterval(this.timer)
165
+					}
166
+				}
167
+
168
+			}
169
+		},
170
+		created: function(e) {
171
+			this.seconds = this.toSeconds(this.timestamp, this.day, this.hour, this.minute, this.second)
172
+			this.countDown()
173
+		},
174
+		// #ifndef VUE3
175
+		destroyed() {
176
+			clearInterval(this.timer)
177
+		},
178
+		// #endif
179
+		// #ifdef VUE3
180
+		unmounted() {
181
+			clearInterval(this.timer)
182
+		},
183
+		// #endif
184
+		methods: {
185
+			toSeconds(timestamp, day, hours, minutes, seconds) {
186
+				if (timestamp) {
187
+					return timestamp - parseInt(new Date().getTime() / 1000, 10)
188
+				}
189
+				return day * 60 * 60 * 24 + hours * 60 * 60 + minutes * 60 + seconds
190
+			},
191
+			timeUp() {
192
+				clearInterval(this.timer)
193
+				this.$emit('timeup')
194
+			},
195
+			countDown() {
196
+				let seconds = this.seconds
197
+				let [day, hour, minute, second] = [0, 0, 0, 0]
198
+				if (seconds > 0) {
199
+					day = Math.floor(seconds / (60 * 60 * 24))
200
+					hour = Math.floor(seconds / (60 * 60)) - (day * 24)
201
+					minute = Math.floor(seconds / 60) - (day * 24 * 60) - (hour * 60)
202
+					second = Math.floor(seconds) - (day * 24 * 60 * 60) - (hour * 60 * 60) - (minute * 60)
203
+				} else {
204
+					this.timeUp()
205
+				}
206
+        day = (day < 10 && this.zeroPad) ? `0${day}` : day
207
+				hour = (hour < 10 && this.zeroPad) ? `0${hour}` : hour
208
+				minute = (minute < 10 && this.zeroPad) ? `0${minute}` : minute
209
+				second = (second < 10 && this.zeroPad) ? `0${second}` : second
210
+				this.d = day
211
+				this.h = hour
212
+				this.i = minute
213
+				this.s = second
214
+			},
215
+			startData() {
216
+				this.seconds = this.toSeconds(this.timestamp, this.day, this.hour, this.minute, this.second)
217
+				if (this.seconds <= 0) {
218
+					this.seconds = this.toSeconds(0, 0, 0, 0, 0)
219
+					this.countDown()
220
+					return
221
+				}
222
+				clearInterval(this.timer)
223
+				this.countDown()
224
+				this.timer = setInterval(() => {
225
+					this.seconds--
226
+					if (this.seconds < 0) {
227
+						this.timeUp()
228
+						return
229
+					}
230
+					this.countDown()
231
+				}, 1000)
232
+			},
233
+			update(){
234
+				this.startData();
235
+			},
236
+			changeFlag() {
237
+				if (!this.syncFlag) {
238
+					this.seconds = this.toSeconds(this.timestamp, this.day, this.hour, this.minute, this.second)
239
+					this.startData();
240
+					this.syncFlag = true;
241
+				}
242
+			}
243
+		}
244
+	}
245
+</script>
246
+<style lang="scss" scoped>
247
+	$font-size: 14px;
248
+
249
+	.uni-countdown {
250
+		display: flex;
251
+		flex-direction: row;
252
+		justify-content: flex-start;
253
+		align-items: center;
254
+
255
+		&__splitor {
256
+			margin: 0 2px;
257
+			font-size: $font-size;
258
+			color: #333;
259
+		}
260
+
261
+		&__number {
262
+			border-radius: 3px;
263
+			text-align: center;
264
+			font-size: $font-size;
265
+		}
266
+	}
267
+</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 

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

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

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

@@ -0,0 +1,551 @@
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','inputclick'],
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
+    watch: {
135
+			localdata: {
136
+				handler() {
137
+					this.load()
138
+				},
139
+        deep: true
140
+			},
141
+    },
142
+    methods: {
143
+      clear() {
144
+        this._dispatchEvent([]);
145
+      },
146
+      onPropsChange() {
147
+        this._treeData = [];
148
+        this.selectedIndex = 0;
149
+
150
+        this.load();
151
+      },
152
+      load() {
153
+        if (this.readonly) {
154
+          this._processReadonly(this.localdata, this.dataValue);
155
+          return;
156
+        }
157
+
158
+        // 回显本地数据
159
+        if (this.isLocalData) {
160
+          this.loadData();
161
+          this.inputSelected = this.selected.slice(0);
162
+        } else if (this.isCloudDataList || this.isCloudDataTree) { // 回显 Cloud 数据
163
+          this.loading = true;
164
+          this.getCloudDataValue().then((res) => {
165
+            this.loading = false;
166
+            this.inputSelected = res;
167
+          }).catch((err) => {
168
+            this.loading = false;
169
+            this.errorMessage = err;
170
+          })
171
+        }
172
+      },
173
+      show() {
174
+        this.isOpened = true
175
+        setTimeout(() => {
176
+          this.$refs.pickerView.updateData({
177
+            treeData: this._treeData,
178
+            selected: this.selected,
179
+            selectedIndex: this.selectedIndex
180
+          })
181
+        }, 200)
182
+        this.$emit('popupopened')
183
+      },
184
+      hide() {
185
+        this.isOpened = false
186
+        this.$emit('popupclosed')
187
+      },
188
+      handleInput() {
189
+        if (this.readonly) {
190
+					this.$emit('inputclick')
191
+          return
192
+        }
193
+        this.show()
194
+      },
195
+      handleClose(e) {
196
+        this.hide()
197
+      },
198
+      onnodeclick(e) {
199
+        this.$emit('nodeclick', e)
200
+      },
201
+      ondatachange(e) {
202
+        this._treeData = this.$refs.pickerView._treeData
203
+      },
204
+      onchange(e) {
205
+        this.hide()
206
+        this.$nextTick(() => {
207
+          this.inputSelected = e;
208
+        })
209
+        this._dispatchEvent(e)
210
+      },
211
+      _processReadonly(dataList, value) {
212
+        var isTree = dataList.findIndex((item) => {
213
+          return item.children
214
+        })
215
+        if (isTree > -1) {
216
+          let inputValue
217
+          if (Array.isArray(value)) {
218
+            inputValue = value[value.length - 1]
219
+            if (typeof inputValue === 'object' && inputValue.value) {
220
+              inputValue = inputValue.value
221
+            }
222
+          } else {
223
+            inputValue = value
224
+          }
225
+          this.inputSelected = this._findNodePath(inputValue, this.localdata)
226
+          return
227
+        }
228
+
229
+        if (!this.hasValue) {
230
+          this.inputSelected = []
231
+          return
232
+        }
233
+
234
+        let result = []
235
+        for (let i = 0; i < value.length; i++) {
236
+          var val = value[i]
237
+          var item = dataList.find((v) => {
238
+            return v.value == val
239
+          })
240
+          if (item) {
241
+            result.push(item)
242
+          }
243
+        }
244
+        if (result.length) {
245
+          this.inputSelected = result
246
+        }
247
+      },
248
+      _filterForArray(data, valueArray) {
249
+        var result = []
250
+        for (let i = 0; i < valueArray.length; i++) {
251
+          var value = valueArray[i]
252
+          var found = data.find((item) => {
253
+            return item.value == value
254
+          })
255
+          if (found) {
256
+            result.push(found)
257
+          }
258
+        }
259
+        return result
260
+      },
261
+      _dispatchEvent(selected) {
262
+        let item = {}
263
+        if (selected.length) {
264
+          var value = new Array(selected.length)
265
+          for (var i = 0; i < selected.length; i++) {
266
+            value[i] = selected[i].value
267
+          }
268
+          item = selected[selected.length - 1]
269
+        } else {
270
+          item.value = ''
271
+        }
272
+        if (this.formItem) {
273
+          this.formItem.setValue(item.value)
274
+        }
275
+
276
+        this.$emit('input', item.value)
277
+        this.$emit('update:modelValue', item.value)
278
+        this.$emit('change', {
279
+          detail: {
280
+            value: selected
281
+          }
282
+        })
283
+      }
284
+    }
285
+  }
286
+</script>
287
+
288
+<style>
289
+  .uni-data-tree {
290
+    flex: 1;
291
+    position: relative;
292
+    font-size: 14px;
293
+  }
294
+
295
+  .error-text {
296
+    color: #DD524D;
297
+  }
298
+
299
+  .input-value {
300
+    /* #ifndef APP-NVUE */
301
+    display: flex;
302
+    /* #endif */
303
+    flex-direction: row;
304
+    align-items: center;
305
+    flex-wrap: nowrap;
306
+    font-size: 14px;
307
+    /* line-height: 35px; */
308
+    padding: 0 10px;
309
+    padding-right: 5px;
310
+    overflow: hidden;
311
+    height: 35px;
312
+    /* #ifndef APP-NVUE */
313
+    box-sizing: border-box;
314
+    /* #endif */
315
+  }
316
+
317
+  .input-value-border {
318
+    border: 1px solid #e5e5e5;
319
+    border-radius: 5px;
320
+  }
321
+
322
+  .selected-area {
323
+    flex: 1;
324
+    overflow: hidden;
325
+    /* #ifndef APP-NVUE */
326
+    display: flex;
327
+    /* #endif */
328
+    flex-direction: row;
329
+  }
330
+
331
+  .load-more {
332
+    /* #ifndef APP-NVUE */
333
+    margin-right: auto;
334
+    /* #endif */
335
+    /* #ifdef APP-NVUE */
336
+    width: 40px;
337
+    /* #endif */
338
+  }
339
+
340
+  .selected-list {
341
+    /* #ifndef APP-NVUE */
342
+    display: flex;
343
+    /* #endif */
344
+    flex-direction: row;
345
+    flex-wrap: nowrap;
346
+    /* padding: 0 5px; */
347
+  }
348
+
349
+  .selected-item {
350
+    flex-direction: row;
351
+    /* padding: 0 1px; */
352
+    /* #ifndef APP-NVUE */
353
+    white-space: nowrap;
354
+    /* #endif */
355
+  }
356
+
357
+  .text-color {
358
+    color: #333;
359
+  }
360
+
361
+  .placeholder {
362
+    color: grey;
363
+    font-size: 12px;
364
+  }
365
+
366
+  .input-split-line {
367
+    opacity: .5;
368
+  }
369
+
370
+  .arrow-area {
371
+    position: relative;
372
+    width: 20px;
373
+    /* #ifndef APP-NVUE */
374
+    margin-bottom: 5px;
375
+    margin-left: auto;
376
+    display: flex;
377
+    /* #endif */
378
+    justify-content: center;
379
+    transform: rotate(-45deg);
380
+    transform-origin: center;
381
+  }
382
+
383
+  .input-arrow {
384
+    width: 7px;
385
+    height: 7px;
386
+    border-left: 1px solid #999;
387
+    border-bottom: 1px solid #999;
388
+  }
389
+
390
+  .uni-data-tree-cover {
391
+    position: fixed;
392
+    left: 0;
393
+    top: 0;
394
+    right: 0;
395
+    bottom: 0;
396
+    background-color: rgba(0, 0, 0, .4);
397
+    /* #ifndef APP-NVUE */
398
+    display: flex;
399
+    /* #endif */
400
+    flex-direction: column;
401
+    z-index: 100;
402
+  }
403
+
404
+  .uni-data-tree-dialog {
405
+    position: fixed;
406
+    left: 0;
407
+    /* #ifndef APP-NVUE */
408
+    top: 20%;
409
+    /* #endif */
410
+    /* #ifdef APP-NVUE */
411
+    top: 200px;
412
+    /* #endif */
413
+    right: 0;
414
+    bottom: 0;
415
+    background-color: #FFFFFF;
416
+    border-top-left-radius: 10px;
417
+    border-top-right-radius: 10px;
418
+    /* #ifndef APP-NVUE */
419
+    display: flex;
420
+    /* #endif */
421
+    flex-direction: column;
422
+    z-index: 102;
423
+    overflow: hidden;
424
+    /* #ifdef APP-NVUE */
425
+    width: 750rpx;
426
+    /* #endif */
427
+  }
428
+
429
+  .dialog-caption {
430
+    position: relative;
431
+    /* #ifndef APP-NVUE */
432
+    display: flex;
433
+    /* #endif */
434
+    flex-direction: row;
435
+    /* border-bottom: 1px solid #f0f0f0; */
436
+  }
437
+
438
+  .title-area {
439
+    /* #ifndef APP-NVUE */
440
+    display: flex;
441
+    /* #endif */
442
+    align-items: center;
443
+    /* #ifndef APP-NVUE */
444
+    margin: auto;
445
+    /* #endif */
446
+    padding: 0 10px;
447
+  }
448
+
449
+  .dialog-title {
450
+    /* font-weight: bold; */
451
+    line-height: 44px;
452
+  }
453
+
454
+  .dialog-close {
455
+    position: absolute;
456
+    top: 0;
457
+    right: 0;
458
+    bottom: 0;
459
+    /* #ifndef APP-NVUE */
460
+    display: flex;
461
+    /* #endif */
462
+    flex-direction: row;
463
+    align-items: center;
464
+    padding: 0 15px;
465
+  }
466
+
467
+  .dialog-close-plus {
468
+    width: 16px;
469
+    height: 2px;
470
+    background-color: #666;
471
+    border-radius: 2px;
472
+    transform: rotate(45deg);
473
+  }
474
+
475
+  .dialog-close-rotate {
476
+    position: absolute;
477
+    transform: rotate(-45deg);
478
+  }
479
+
480
+  .picker-view {
481
+    flex: 1;
482
+    overflow: hidden;
483
+  }
484
+
485
+  .icon-clear {
486
+    display: flex;
487
+    align-items: center;
488
+  }
489
+
490
+  /* #ifdef H5 */
491
+  @media all and (min-width: 768px) {
492
+    .uni-data-tree-cover {
493
+      background-color: transparent;
494
+    }
495
+
496
+    .uni-data-tree-dialog {
497
+      position: absolute;
498
+      top: 55px;
499
+      height: auto;
500
+      min-height: 400px;
501
+      max-height: 50vh;
502
+      background-color: #fff;
503
+      border: 1px solid #EBEEF5;
504
+      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
505
+      border-radius: 4px;
506
+      overflow: unset;
507
+    }
508
+
509
+    .dialog-caption {
510
+      display: none;
511
+    }
512
+
513
+    .icon-clear {
514
+      /* margin-right: 5px; */
515
+    }
516
+  }
517
+
518
+  /* #endif */
519
+
520
+  /* picker 弹出层通用的指示小三角, todo:扩展至上下左右方向定位 */
521
+  /* #ifndef APP-NVUE */
522
+  .uni-popper__arrow,
523
+  .uni-popper__arrow::after {
524
+    position: absolute;
525
+    display: block;
526
+    width: 0;
527
+    height: 0;
528
+    border-color: transparent;
529
+    border-style: solid;
530
+    border-width: 6px;
531
+  }
532
+
533
+  .uni-popper__arrow {
534
+    filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
535
+    top: -6px;
536
+    left: 10%;
537
+    margin-right: 3px;
538
+    border-top-width: 0;
539
+    border-bottom-color: #EBEEF5;
540
+  }
541
+
542
+  .uni-popper__arrow::after {
543
+    content: " ";
544
+    top: 1px;
545
+    margin-left: -6px;
546
+    border-top-width: 0;
547
+    border-bottom-color: #fff;
548
+  }
549
+
550
+  /* #endif */
551
+</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
+}

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

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

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

@@ -0,0 +1,35 @@
1
+## 1.0.6(2023-04-12)
2
+- 修复 微信小程序点击时会改变背景颜色的 bug
3
+## 1.0.5(2023-02-03)
4
+- 修复 禁用时会显示清空按钮
5
+## 1.0.4(2023-02-02)
6
+- 优化 查询条件短期内多次变更只查询最后一次变更后的结果
7
+- 调整 内部缓存键名调整为 uni-data-select-lastSelectedValue
8
+## 1.0.3(2023-01-16)
9
+- 修复 不关联服务空间报错的问题
10
+## 1.0.2(2023-01-14)
11
+- 新增  属性 `format` 可用于格式化显示选项内容
12
+## 1.0.1(2022-12-06)
13
+- 修复  当where变化时,数据不会自动更新的问题
14
+## 0.1.9(2022-09-05)
15
+- 修复 微信小程序下拉框出现后选择会点击到蒙板后面的输入框
16
+## 0.1.8(2022-08-29)
17
+- 修复 点击的位置不准确
18
+## 0.1.7(2022-08-12)
19
+- 新增 支持 disabled 属性
20
+## 0.1.6(2022-07-06)
21
+- 修复 pc端宽度异常的bug
22
+## 0.1.5
23
+- 修复 pc端宽度异常的bug
24
+## 0.1.4(2022-07-05)
25
+- 优化 显示样式
26
+## 0.1.3(2022-06-02)
27
+- 修复 localdata 赋值不生效的 bug
28
+- 新增 支持  uni.scss 修改颜色
29
+- 新增 支持选项禁用(数据选项设置 disabled: true 即禁用)
30
+## 0.1.2(2022-05-08)
31
+- 修复 当 value 为 0 时选择不生效的 bug
32
+## 0.1.1(2022-05-07)
33
+- 新增 记住上次的选项(仅 collection 存在时有效)
34
+## 0.1.0(2022-04-22)
35
+- 初始化

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

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

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

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

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

@@ -0,0 +1,177 @@
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--today': weeks.isToday}"></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
+			checkHover: {
45
+				type: Boolean,
46
+				default: false
47
+			}
48
+		},
49
+		methods: {
50
+			choiceDate(weeks) {
51
+				this.$emit('change', weeks)
52
+			},
53
+			handleMousemove(weeks) {
54
+				this.$emit('handleMouse', weeks)
55
+			}
56
+		}
57
+	}
58
+</script>
59
+
60
+<style lang="scss" >
61
+	$uni-primary: #007aff !default;
62
+
63
+	.uni-calendar-item__weeks-box {
64
+		flex: 1;
65
+		/* #ifndef APP-NVUE */
66
+		display: flex;
67
+		/* #endif */
68
+		flex-direction: column;
69
+		justify-content: center;
70
+		align-items: center;
71
+		margin: 1px 0;
72
+		position: relative;
73
+	}
74
+
75
+	.uni-calendar-item__weeks-box-text {
76
+		font-size: 14px;
77
+		// font-family: Lato-Bold, Lato;
78
+		font-weight: bold;
79
+		color: darken($color: $uni-primary, $amount: 40%);
80
+	}
81
+
82
+	.uni-calendar-item__weeks-box-item {
83
+		position: relative;
84
+		/* #ifndef APP-NVUE */
85
+		display: flex;
86
+		/* #endif */
87
+		flex-direction: column;
88
+		justify-content: center;
89
+		align-items: center;
90
+		width: 40px;
91
+		height: 40px;
92
+		/* #ifdef H5 */
93
+		cursor: pointer;
94
+		/* #endif */
95
+	}
96
+
97
+
98
+	.uni-calendar-item__weeks-box-circle {
99
+		position: absolute;
100
+		top: 5px;
101
+		right: 5px;
102
+		width: 8px;
103
+		height: 8px;
104
+		border-radius: 8px;
105
+		background-color: #dd524d;
106
+
107
+	}
108
+
109
+	.uni-calendar-item__weeks-box .uni-calendar-item--disable {
110
+		cursor: default;
111
+	}
112
+
113
+	.uni-calendar-item--disable .uni-calendar-item__weeks-box-text-disable {
114
+		color: #D1D1D1;
115
+	}
116
+
117
+	.uni-calendar-item--today {
118
+		position: absolute;
119
+		top: 10px;
120
+		right: 17%;
121
+		background-color: #dd524d;
122
+		width:6px;
123
+		height: 6px;
124
+		border-radius: 50%;
125
+	}
126
+
127
+	.uni-calendar-item--extra {
128
+		color: #dd524d;
129
+		opacity: 0.8;
130
+	}
131
+
132
+	.uni-calendar-item__weeks-box .uni-calendar-item--checked {
133
+		background-color: $uni-primary;
134
+		border-radius: 50%;
135
+		box-sizing: border-box;
136
+		border: 3px solid #fff;
137
+	}
138
+
139
+	.uni-calendar-item--checked .uni-calendar-item--checked-text {
140
+		color: #fff;
141
+	}
142
+
143
+	.uni-calendar-item--multiple .uni-calendar-item--checked-range-text {
144
+		color: #333;
145
+	}
146
+
147
+	.uni-calendar-item--multiple {
148
+		background-color:  #F6F7FC;
149
+		// color: #fff;
150
+	}
151
+
152
+	.uni-calendar-item--multiple .uni-calendar-item--before-checked,
153
+	.uni-calendar-item--multiple .uni-calendar-item--after-checked {
154
+		background-color: $uni-primary;
155
+		border-radius: 50%;
156
+		box-sizing: border-box;
157
+		border: 3px solid #F6F7FC;
158
+	}
159
+
160
+	.uni-calendar-item--before-checked .uni-calendar-item--checked-text,
161
+	.uni-calendar-item--after-checked .uni-calendar-item--checked-text {
162
+		color: #fff;
163
+	}
164
+
165
+	.uni-calendar-item--before-checked-x {
166
+		border-top-left-radius: 50px;
167
+		border-bottom-left-radius: 50px;
168
+		box-sizing: border-box;
169
+		background-color: #F6F7FC;
170
+	}
171
+
172
+	.uni-calendar-item--after-checked-x {
173
+		border-top-right-radius: 50px;
174
+		border-bottom-right-radius: 50px;
175
+		background-color: #F6F7FC;
176
+	}
177
+</style>

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

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

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

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

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1026 - 0
uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue


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

@@ -0,0 +1,403 @@
1
+class Calendar {
2
+	constructor({
3
+		selected,
4
+		startDate,
5
+		endDate,
6
+		range,
7
+	} = {}) {
8
+		// 当前日期
9
+		this.date = this.getDateObj(new Date()) // 当前初入日期
10
+		// 打点信息
11
+		this.selected = selected || [];
12
+		// 起始时间
13
+		this.startDate = startDate
14
+		// 终止时间
15
+		this.endDate = endDate
16
+    // 是否范围选择
17
+		this.range = range
18
+		// 多选状态
19
+		this.cleanMultipleStatus()
20
+		// 每周日期
21
+		this.weeks = {}
22
+		this.lastHover = false
23
+	}
24
+	/**
25
+	 * 设置日期
26
+	 * @param {Object} date
27
+	 */
28
+	setDate(date) {
29
+		const selectDate = this.getDateObj(date)
30
+		this.getWeeks(selectDate.fullDate)
31
+	}
32
+
33
+	/**
34
+	 * 清理多选状态
35
+	 */
36
+	cleanMultipleStatus() {
37
+		this.multipleStatus = {
38
+			before: '',
39
+			after: '',
40
+			data: []
41
+		}
42
+	}
43
+
44
+	setStartDate(startDate) {
45
+		this.startDate = startDate
46
+	}
47
+
48
+	setEndDate(endDate) {
49
+		this.endDate = endDate
50
+	}
51
+
52
+  getPreMonthObj(date){
53
+    date = fixIosDateFormat(date)
54
+    date = new Date(date)
55
+
56
+    const oldMonth = date.getMonth()
57
+    date.setMonth(oldMonth - 1)
58
+    const newMonth = date.getMonth()
59
+    if(oldMonth !== 0 && newMonth - oldMonth === 0){
60
+      date.setMonth(newMonth - 1)
61
+    }
62
+    return this.getDateObj(date)
63
+  }
64
+  getNextMonthObj(date){
65
+    date = fixIosDateFormat(date)
66
+    date = new Date(date)
67
+
68
+    const oldMonth = date.getMonth()
69
+    date.setMonth(oldMonth + 1)
70
+    const newMonth = date.getMonth()
71
+    if(newMonth - oldMonth > 1){
72
+      date.setMonth(newMonth - 1)
73
+    }
74
+    return this.getDateObj(date)
75
+  }
76
+
77
+	/**
78
+	 * 获取指定格式Date对象
79
+	 */
80
+	getDateObj(date) {
81
+    date = fixIosDateFormat(date)
82
+    date = new Date(date)
83
+
84
+		return {
85
+			fullDate: getDate(date),
86
+      year: date.getFullYear(),
87
+      month: addZero(date.getMonth() + 1),
88
+      date: addZero(date.getDate()),
89
+      day: date.getDay()
90
+		}
91
+	}
92
+
93
+	/**
94
+	 * 获取上一个月日期集合
95
+	 */
96
+	getPreMonthDays(amount, dateObj) {
97
+		const result = []
98
+		for (let i = amount - 1; i >= 0; i--) {
99
+      const month = dateObj.month - 1
100
+			result.push({
101
+				date: new Date(dateObj.year, month, -i).getDate(),
102
+				month,
103
+				disable: true
104
+			})
105
+		}
106
+		return result
107
+	}
108
+	/**
109
+	 * 获取本月日期集合
110
+	 */
111
+	getCurrentMonthDays(amount, dateObj) {
112
+		const result = []
113
+		const fullDate = this.date.fullDate
114
+		for (let i = 1; i <= amount; i++) {
115
+			const currentDate = `${dateObj.year}-${dateObj.month}-${addZero(i)}`
116
+			const isToday = fullDate === currentDate
117
+			// 获取打点信息
118
+			const info = this.selected && this.selected.find((item) => {
119
+				if (this.dateEqual(currentDate, item.date)) {
120
+					return item
121
+				}
122
+			})
123
+
124
+			// 日期禁用
125
+			let disableBefore = true
126
+			let disableAfter = true
127
+			if (this.startDate) {
128
+				disableBefore = dateCompare(this.startDate, currentDate)
129
+			}
130
+
131
+			if (this.endDate) {
132
+				disableAfter = dateCompare(currentDate, this.endDate)
133
+			}
134
+
135
+			let multiples = this.multipleStatus.data
136
+			let multiplesStatus = -1
137
+			if (this.range && multiples) {
138
+        multiplesStatus = multiples.findIndex((item) => {
139
+          return this.dateEqual(item, currentDate)
140
+        })
141
+			}
142
+      const checked = multiplesStatus !== -1
143
+
144
+			result.push({
145
+				fullDate: currentDate,
146
+				year: dateObj.year,
147
+				date: i,
148
+				multiple: this.range ? checked : false,
149
+				beforeMultiple: this.isLogicBefore(currentDate, this.multipleStatus.before, this.multipleStatus.after),
150
+				afterMultiple: this.isLogicAfter(currentDate, this.multipleStatus.before, this.multipleStatus.after),
151
+				month: dateObj.month,
152
+				disable: (this.startDate && !dateCompare(this.startDate, currentDate)) || (this.endDate && !dateCompare(currentDate,this.endDate)),
153
+				isToday,
154
+				userChecked: false,
155
+        extraInfo: info
156
+			})
157
+		}
158
+		return result
159
+	}
160
+	/**
161
+	 * 获取下一个月日期集合
162
+	 */
163
+	_getNextMonthDays(amount, dateObj) {
164
+		const result = []
165
+    const month = dateObj.month + 1
166
+		for (let i = 1; i <= amount; i++) {
167
+			result.push({
168
+				date: i,
169
+				month,
170
+				disable: true
171
+			})
172
+		}
173
+		return result
174
+	}
175
+
176
+	/**
177
+	 * 获取当前日期详情
178
+	 * @param {Object} date
179
+	 */
180
+	getInfo(date) {
181
+		if (!date) {
182
+			date = new Date()
183
+		}
184
+
185
+		return this.calendar.find(item => item.fullDate === this.getDateObj(date).fullDate)
186
+	}
187
+
188
+	/**
189
+	 * 比较时间是否相等
190
+	 */
191
+	dateEqual(before, after) {
192
+		before = new Date(fixIosDateFormat(before))
193
+		after = new Date(fixIosDateFormat(after))
194
+		return before.valueOf() === after.valueOf()
195
+	}
196
+
197
+	/**
198
+	 *  比较真实起始日期
199
+	 */
200
+
201
+	isLogicBefore(currentDate, before, after) {
202
+		let logicBefore = before
203
+		if (before && after) {
204
+			logicBefore = dateCompare(before, after) ? before : after
205
+		}
206
+		return this.dateEqual(logicBefore, currentDate)
207
+	}
208
+
209
+	isLogicAfter(currentDate, before, after) {
210
+		let logicAfter = after
211
+		if (before && after) {
212
+			logicAfter = dateCompare(before, after) ? after : before
213
+		}
214
+		return this.dateEqual(logicAfter, currentDate)
215
+	}
216
+
217
+	/**
218
+	 * 获取日期范围内所有日期
219
+	 * @param {Object} begin
220
+	 * @param {Object} end
221
+	 */
222
+	geDateAll(begin, end) {
223
+		var arr = []
224
+		var ab = begin.split('-')
225
+		var ae = end.split('-')
226
+		var db = new Date()
227
+		db.setFullYear(ab[0], ab[1] - 1, ab[2])
228
+		var de = new Date()
229
+		de.setFullYear(ae[0], ae[1] - 1, ae[2])
230
+		var unixDb = db.getTime() - 24 * 60 * 60 * 1000
231
+		var unixDe = de.getTime() - 24 * 60 * 60 * 1000
232
+		for (var k = unixDb; k <= unixDe;) {
233
+			k = k + 24 * 60 * 60 * 1000
234
+			arr.push(this.getDateObj(new Date(parseInt(k))).fullDate)
235
+		}
236
+		return arr
237
+	}
238
+
239
+	/**
240
+	 *  获取多选状态
241
+	 */
242
+	setMultiple(fullDate) {
243
+    if (!this.range) return
244
+
245
+		let {
246
+			before,
247
+			after
248
+		} = this.multipleStatus
249
+		if (before && after) {
250
+			if (!this.lastHover) {
251
+				this.lastHover = true
252
+				return
253
+			}
254
+			this.multipleStatus.before = fullDate
255
+			this.multipleStatus.after = ''
256
+			this.multipleStatus.data = []
257
+			this.multipleStatus.fulldate = ''
258
+			this.lastHover = false
259
+		} else {
260
+			if (!before) {
261
+				this.multipleStatus.before = fullDate
262
+				this.lastHover = false
263
+			} else {
264
+				this.multipleStatus.after = fullDate
265
+				if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
266
+					this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus
267
+						.after);
268
+				} else {
269
+					this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus
270
+						.before);
271
+				}
272
+				this.lastHover = true
273
+			}
274
+		}
275
+		this.getWeeks(fullDate)
276
+	}
277
+
278
+	/**
279
+	 *  鼠标 hover 更新多选状态
280
+	 */
281
+	setHoverMultiple(fullDate) {
282
+    if (!this.range || this.lastHover) return
283
+
284
+		const { before } = this.multipleStatus
285
+
286
+		if (!before) {
287
+			this.multipleStatus.before = fullDate
288
+		} else {
289
+			this.multipleStatus.after = fullDate
290
+			if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
291
+				this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
292
+			} else {
293
+				this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
294
+			}
295
+		}
296
+		this.getWeeks(fullDate)
297
+	}
298
+
299
+	/**
300
+	 * 更新默认值多选状态
301
+	 */
302
+	setDefaultMultiple(before, after) {
303
+		this.multipleStatus.before = before
304
+		this.multipleStatus.after = after
305
+		if (before && after) {
306
+			if (dateCompare(before, after)) {
307
+				this.multipleStatus.data = this.geDateAll(before, after);
308
+				this.getWeeks(after)
309
+			} else {
310
+				this.multipleStatus.data = this.geDateAll(after, before);
311
+				this.getWeeks(before)
312
+			}
313
+		}
314
+	}
315
+
316
+	/**
317
+	 * 获取每周数据
318
+	 * @param {Object} dateData
319
+	 */
320
+	getWeeks(dateData) {
321
+		const {
322
+			year,
323
+			month,
324
+		} = this.getDateObj(dateData)
325
+
326
+		const preMonthDayAmount = new Date(year, month - 1, 1).getDay()
327
+    const preMonthDays = this.getPreMonthDays(preMonthDayAmount, this.getDateObj(dateData))
328
+
329
+		const currentMonthDayAmount = new Date(year, month, 0).getDate()
330
+    const currentMonthDays = this.getCurrentMonthDays(currentMonthDayAmount, this.getDateObj(dateData))
331
+
332
+    const nextMonthDayAmount = 42 - preMonthDayAmount - currentMonthDayAmount
333
+    const nextMonthDays = this._getNextMonthDays(nextMonthDayAmount, this.getDateObj(dateData))
334
+
335
+		const calendarDays = [...preMonthDays, ...currentMonthDays, ...nextMonthDays]
336
+
337
+		const weeks = new Array(6)
338
+		for (let i = 0; i < calendarDays.length; i++) {
339
+      const index = Math.floor(i / 7)
340
+      if(!weeks[index]){
341
+        weeks[index] = new Array(7)
342
+      }
343
+			weeks[index][i % 7] = calendarDays[i]
344
+		}
345
+
346
+		this.calendar = calendarDays
347
+		this.weeks = weeks
348
+	}
349
+}
350
+
351
+function getDateTime(date, hideSecond){
352
+  return `${getDate(date)} ${getTime(date, hideSecond)}`
353
+}
354
+
355
+function getDate(date) {
356
+  date = fixIosDateFormat(date)
357
+  date = new Date(date)
358
+  const year = date.getFullYear()
359
+  const month = date.getMonth()+1
360
+  const day = date.getDate()
361
+  return `${year}-${addZero(month)}-${addZero(day)}`
362
+}
363
+
364
+function getTime(date, hideSecond){
365
+  date = fixIosDateFormat(date)
366
+  date = new Date(date)
367
+  const hour = date.getHours()
368
+  const minute = date.getMinutes()
369
+  const second = date.getSeconds()
370
+  return hideSecond ? `${addZero(hour)}:${addZero(minute)}` : `${addZero(hour)}:${addZero(minute)}:${addZero(second)}`
371
+}
372
+
373
+function addZero(num) {
374
+  if(num < 10){
375
+    num = `0${num}`
376
+  }
377
+  return num
378
+}
379
+
380
+function getDefaultSecond(hideSecond) {
381
+  return hideSecond ? '00:00' : '00:00:00'
382
+}
383
+
384
+function dateCompare(startDate, endDate) {
385
+  startDate = new Date(fixIosDateFormat(startDate))
386
+  endDate = new Date(fixIosDateFormat(endDate))
387
+  return startDate <= endDate
388
+}
389
+
390
+function checkDate(date){
391
+  const dateReg = /((19|20)\d{2})(-|\/)\d{1,2}(-|\/)\d{1,2}/g
392
+  return date.match(dateReg)
393
+}
394
+
395
+const dateTimeReg = /^\d{4}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])( [0-5][0-9]:[0-5][0-9]:[0-5][0-9])?$/
396
+function fixIosDateFormat(value) {
397
+  if (typeof value === 'string' && dateTimeReg.test(value)) {
398
+    value = value.replace(/-/g, '/')
399
+  }
400
+  return value
401
+}
402
+
403
+export {Calendar, getDateTime, getDate, getTime, addZero, getDefaultSecond, dateCompare, checkDate, fixIosDateFormat}

+ 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.22",
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 

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


Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels