19124812874 5 سال پیش
کامیت
4e68cf8cfa
100فایلهای تغییر یافته به همراه13707 افزوده شده و 0 حذف شده
  1. 21 0
      App.vue
  2. 205 0
      assets/colorui/app.css
  3. 36 0
      assets/colorui/icon.css
  4. 3914 0
      assets/colorui/main.css
  5. 13 0
      assets/http/api.js
  6. 80 0
      assets/http/service.js
  7. 123 0
      components/dt_custom_bar.vue
  8. 69 0
      components/hot-consult/hot-consult.vue
  9. 69 0
      components/uploadimg/uploadImg.vue
  10. 51 0
      main.js
  11. 78 0
      manifest.json
  12. 190 0
      pages.json
  13. 223 0
      pages/auth/auth.vue
  14. 190 0
      pages/company/company.vue
  15. 24 0
      pages/index/access-record/access-record.vue
  16. 301 0
      pages/index/index.vue
  17. 85 0
      pages/index/my-temperature/deatil.vue
  18. 60 0
      pages/index/my-temperature/my-temperature.vue
  19. 291 0
      pages/login/login.vue
  20. 49 0
      pages/login/login1.vue
  21. 250 0
      pages/mine/feedback/feedback.vue
  22. 111 0
      pages/mine/mine-info/mine-info.vue
  23. 365 0
      pages/mine/mine.vue
  24. 24 0
      pages/mine/protocol/protocol.vue
  25. 35 0
      pages/mine/setting/setting.vue
  26. 194 0
      pages/my-camera/my-camera.vue
  27. 74 0
      pages/news/detail.vue
  28. 184 0
      pages/news/news.vue
  29. 219 0
      pages/test/test.vue
  30. 24 0
      pages/test/test1.vue
  31. BIN
      static/camera/back.png
  32. BIN
      static/camera/card.png
  33. BIN
      static/camera/change.png
  34. BIN
      static/camera/confirm1.png
  35. BIN
      static/camera/rephoto.png
  36. BIN
      static/camera/takephoto.png
  37. BIN
      static/index/blue/avatar1.png
  38. BIN
      static/index/blue/contact.png
  39. BIN
      static/index/blue/face.png
  40. BIN
      static/index/blue/fankui.png
  41. BIN
      static/index/blue/msg.png
  42. BIN
      static/index/blue/setting.png
  43. BIN
      static/index/blue/shenfen.png
  44. BIN
      static/index/blue/shuoming.png
  45. BIN
      static/index/blue/touxiang.png
  46. BIN
      static/index/blue/wuye.png
  47. BIN
      static/index/blue/xieyi1.png
  48. BIN
      static/index/fire/more.png
  49. BIN
      static/index/fire/ranqi.png
  50. BIN
      static/index/fire/xiaofang.png
  51. BIN
      static/index/fire/yangan.png
  52. BIN
      static/index/gander/cewen.png
  53. BIN
      static/index/gander/cewen1.png
  54. BIN
      static/index/gander/qiye.png
  55. BIN
      static/index/gander/renzheng.png
  56. BIN
      static/index/gander/renzheng1.png
  57. BIN
      static/index/gander/tongxing.png
  58. BIN
      static/login/2.png
  59. BIN
      static/login/3.png
  60. BIN
      static/login/sj.png
  61. BIN
      static/login/wx.png
  62. BIN
      static/login/yz.png
  63. BIN
      static/tarbar/home.png
  64. BIN
      static/tarbar/home0.png
  65. BIN
      static/tarbar/my.png
  66. BIN
      static/tarbar/my0.png
  67. BIN
      static/tarbar/news.png
  68. BIN
      static/tarbar/news0.png
  69. 76 0
      uni.scss
  70. 114 0
      utils/cache.js
  71. 88 0
      utils/my-request/adapters/index.js
  72. 51 0
      utils/my-request/core/InterceptorManager.js
  73. 199 0
      utils/my-request/core/Request.js
  74. 20 0
      utils/my-request/core/buildFullPath.js
  75. 30 0
      utils/my-request/core/defaults.js
  76. 6 0
      utils/my-request/core/dispatchRequest.js
  77. 89 0
      utils/my-request/core/mergeConfig.js
  78. 16 0
      utils/my-request/core/settle.js
  79. 69 0
      utils/my-request/helpers/buildURL.js
  80. 14 0
      utils/my-request/helpers/combineURLs.js
  81. 14 0
      utils/my-request/helpers/isAbsoluteURL.js
  82. 2 0
      utils/my-request/index.js
  83. 131 0
      utils/my-request/utils.js
  84. 415 0
      utils/util.js
  85. 21 0
      uview-ui/LICENSE
  86. 106 0
      uview-ui/README.md
  87. 190 0
      uview-ui/components/u-action-sheet/u-action-sheet.vue
  88. 256 0
      uview-ui/components/u-alert-tips/u-alert-tips.vue
  89. 290 0
      uview-ui/components/u-avatar-cropper/u-avatar-cropper.vue
  90. 1265 0
      uview-ui/components/u-avatar-cropper/weCropper.js
  91. 24 0
      uview-ui/components/u-avatar/u-avatar.vue
  92. 153 0
      uview-ui/components/u-back-top/u-back-top.vue
  93. 216 0
      uview-ui/components/u-badge/u-badge.vue
  94. 596 0
      uview-ui/components/u-button/u-button.vue
  95. 639 0
      uview-ui/components/u-calendar/u-calendar.vue
  96. 257 0
      uview-ui/components/u-car-keyboard/u-car-keyboard.vue
  97. 299 0
      uview-ui/components/u-card/u-card.vue
  98. 70 0
      uview-ui/components/u-cell-group/u-cell-group.vue
  99. 316 0
      uview-ui/components/u-cell-item/u-cell-item.vue
  100. 123 0
      uview-ui/components/u-checkbox-group/u-checkbox-group.vue

+ 21 - 0
App.vue

@@ -0,0 +1,21 @@
+<script>
+	export default {
+		onLaunch: function() {
+			console.log('App Launch')
+		},
+		onShow: function() {
+			console.log('App Show')
+		},
+		onHide: function() {
+			console.log('App Hide')
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import "uview-ui/index.scss";
+	
+	@import "@/assets/colorui/main.css";
+	@import "@/assets/colorui/icon.css";
+	@import "@/assets/colorui/app.css";
+</style>

+ 205 - 0
assets/colorui/app.css

@@ -0,0 +1,205 @@
+/* 新邻园区 */
+.base-bg-color{
+	background-color: #59a5f0;
+	color: #FFFFFF;
+}
+
+/* ===========padding=========== */
+.padding-10,.padding-sm{
+	padding: 10rpx;
+}
+.padding-20,.padding-df{
+	padding: 20rpx;
+}
+.padding-30,.padding-lg{
+	padding: 30rpx;
+}
+.padding-40{
+	padding: 40rpx;
+}
+.padding-50{
+	padding: 50rpx;
+}
+.padding-left-10,.padding-left-sm{
+	padding-left: 10rpx;
+}
+.padding-left-20,.padding-left-df{
+	padding-left: 20rpx;
+}
+.padding-left-30,.padding-left-lg{
+	padding-left: 30rpx;
+}
+.padding-left-40{
+	padding-left: 40rpx;
+}
+.padding-left-50{
+	padding-left: 50rpx;
+}
+
+.padding-right-10,.padding-right-sm{
+	padding-right: 10rpx;
+}
+.padding-right-20,.padding-right-df{
+	padding-right: 20rpx;
+}
+.padding-right-30,.padding-right-lg{
+	padding-right: 30rpx;
+}
+.padding-right-40{
+	padding-right: 40rpx;
+}
+.padding-right-50{
+	padding-right: 50rpx;
+}
+
+.padding-top-10,.padding-top-sm{
+	padding-top: 10rpx;
+}
+.padding-top-20,.padding-top-df{
+	padding-top: 20rpx;
+}
+.padding-top-30,.padding-top-lg{
+	padding-top: 30rpx;
+}
+.padding-top-40{
+	padding-top: 40rpx;
+}
+.padding-top-50{
+	padding-top: 50rpx;
+}
+
+.padding-bottom-10,.padding-bottom-sm{
+	padding-bottom: 10rpx;
+}
+.padding-bottom-20,.padding-bottom-df{
+	padding-bottom: 20rpx;
+}
+.padding-bottom-30,.padding-bottom-lg{
+	padding-bottom: 30rpx;
+}
+.padding-bottom-40{
+	padding-bottom: 40rpx;
+}
+.padding-bottom-50{
+	padding-bottom: 50rpx;
+}
+
+/* ===========margin=========== */
+.margin-10,.margin-sm{
+	margin: 10rpx;
+}
+.margin-20,.margin-df{
+	margin: 20rpx;
+}
+.margin-30,.margin-lg{
+	margin: 30rpx;
+}
+.margin-40{
+	margin: 40rpx;
+}
+.margin-50{
+	margin: 50rpx;
+}
+.margin-left-10,.margin-left-sm{
+	margin-left: 10rpx;
+}
+.margin-left-20,.margin-left-df{
+	margin-left: 20rpx;
+}
+.margin-left-30,.margin-left-lg{
+	margin-left: 30rpx;
+}
+.margin-left-40{
+	margin-left: 40rpx;
+}
+.margin-left-50{
+	margin-left: 50rpx;
+}
+
+.margin-right-10,.margin-right-sm{
+	margin-right: 10rpx;
+}
+.margin-right-20,.margin-right-df{
+	margin-right: 20rpx;
+}
+.margin-right-30,.margin-right-lg{
+	margin-right: 30rpx;
+}
+.margin-right-40{
+	margin-right: 40rpx;
+}
+.margin-right-50{
+	margin-right: 50rpx;
+}
+
+.margin-top-10,.margin-top-sm{
+	margin-top: 10rpx;
+}
+.margin-top-20,.margin-top-df{
+	margin-top: 20rpx;
+}
+.margin-top-30,.margin-top-lg{
+	margin-top: 30rpx;
+}
+.margin-top-40{
+	margin-top: 40rpx;
+}
+.margin-top-50{
+	margin-top: 50rpx;
+}
+
+.margin-bottom-10,.margin-bottom-sm{
+	margin-bottom: 10rpx;
+}
+.margin-bottom-20,.margin-bottom-df{
+	margin-bottom: 20rpx;
+}
+.margin-bottom-30,.margin-bottom-lg{
+	margin-bottom: 30rpx;
+}
+.margin-bottom-40{
+	margin-bottom: 40rpx;
+}
+.margin-bottom-50{
+	margin-bottom: 50rpx;
+}
+
+/* ==========text-cut=========== */
+
+
+
+.text-cut-1 {
+	overflow: hidden;
+	text-overflow: ellipsis;
+	display: -webkit-box;
+	-webkit-line-clamp: 1;
+	-webkit-box-orient: vertical;
+}
+
+.text-cut-2 {
+	overflow: hidden;
+	text-overflow: ellipsis;
+	display: -webkit-box;
+	-webkit-line-clamp: 2;
+	-webkit-box-orient: vertical;
+}
+
+.text-cut {
+		overflow: hidden;
+		text-overflow: ellipsis;
+		white-space: nowrap;
+		display: block;
+}
+
+.bg-gradual-black {
+	background-image: linear-gradient(45deg, #26272f, #414244);
+	color: #f7ebd2;
+}
+
+.footer-fixed {
+	position: fixed;
+	z-index: 99999;
+	width: 100%;
+	bottom: 0;
+	left: 0;
+}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 36 - 0
assets/colorui/icon.css


+ 3914 - 0
assets/colorui/main.css

@@ -0,0 +1,3914 @@
+/* ==================
+        初始化
+ ==================== */
+body {
+	background-color: #f1f1f1;
+	font-size: 28upx;
+	color: #333333;
+	font-family: Helvetica Neue, Helvetica, sans-serif;
+}
+
+view,
+scroll-view,
+swiper,
+button,
+input,
+textarea,
+label,
+navigator,
+image {
+	box-sizing: border-box;
+}
+
+.round {
+	border-radius: 5000upx;
+}
+
+.radius {
+	border-radius: 6upx;
+}
+
+/* ==================
+          图片
+ ==================== */
+
+image {
+	max-width: 100%;
+	display: inline-block;
+	position: relative;
+	z-index: 0;
+}
+
+image.loading::before {
+	content: "";
+	background-color: #f5f5f5;
+	display: block;
+	position: absolute;
+	width: 100%;
+	height: 100%;
+	z-index: -2;
+}
+
+image.loading::after {
+	content: "\e7f1";
+	font-family: "cuIcon";
+	position: absolute;
+	top: 0;
+	left: 0;
+	width: 32upx;
+	height: 32upx;
+	line-height: 32upx;
+	right: 0;
+	bottom: 0;
+	z-index: -1;
+	font-size: 32upx;
+	margin: auto;
+	color: #ccc;
+	-webkit-animation: cuIcon-spin 2s infinite linear;
+	animation: cuIcon-spin 2s infinite linear;
+	display: block;
+}
+
+.response {
+	width: 100%;
+}
+
+/* ==================
+         开关
+ ==================== */
+
+switch,
+checkbox,
+radio {
+	position: relative;
+}
+
+switch::after,
+switch::before {
+	font-family: "cuIcon";
+	content: "\e645";
+	position: absolute;
+	color: #ffffff !important;
+	top: 0%;
+	left: 0upx;
+	font-size: 26upx;
+	line-height: 26px;
+	width: 50%;
+	text-align: center;
+	pointer-events: none;
+	transform: scale(0, 0);
+	transition: all 0.3s ease-in-out 0s;
+	z-index: 9;
+	bottom: 0;
+	height: 26px;
+	margin: auto;
+}
+
+switch::before {
+	content: "\e646";
+	right: 0;
+	transform: scale(1, 1);
+	left: auto;
+}
+
+switch[checked]::after,
+switch.checked::after {
+	transform: scale(1, 1);
+}
+
+switch[checked]::before,
+switch.checked::before {
+	transform: scale(0, 0);
+}
+
+/* #ifndef MP-ALIPAY */
+radio::before,
+checkbox::before {
+	font-family: "cuIcon";
+	content: "\e645";
+	position: absolute;
+	color: #ffffff !important;
+	top: 50%;
+	margin-top: -8px;
+	right: 5px;
+	font-size: 32upx;
+	line-height: 16px;
+	pointer-events: none;
+	transform: scale(1, 1);
+	transition: all 0.3s ease-in-out 0s;
+	z-index: 9;
+}
+
+radio .wx-radio-input,
+checkbox .wx-checkbox-input,
+radio .uni-radio-input,
+checkbox .uni-checkbox-input {
+	margin: 0;
+	width: 24px;
+	height: 24px;
+}
+
+checkbox.round .wx-checkbox-input,
+checkbox.round .uni-checkbox-input {
+	border-radius: 100upx;
+}
+
+/* #endif */
+
+switch[checked]::before {
+	transform: scale(0, 0);
+}
+
+switch .wx-switch-input,
+switch .uni-switch-input {
+	border: none;
+	padding: 0 24px;
+	width: 48px;
+	height: 26px;
+	margin: 0;
+	border-radius: 100upx;
+}
+
+switch .wx-switch-input:not([class*="bg-"]),
+switch .uni-switch-input:not([class*="bg-"]) {
+	background: #8799a3 !important;
+}
+
+switch .wx-switch-input::after,
+switch .uni-switch-input::after {
+	margin: auto;
+	width: 26px;
+	height: 26px;
+	border-radius: 100upx;
+	left: 0upx;
+	top: 0upx;
+	bottom: 0upx;
+	position: absolute;
+	transform: scale(0.9, 0.9);
+	transition: all 0.1s ease-in-out 0s;
+}
+
+switch .wx-switch-input.wx-switch-input-checked::after,
+switch .uni-switch-input.uni-switch-input-checked::after {
+	margin: auto;
+	left: 22px;
+	box-shadow: none;
+	transform: scale(0.9, 0.9);
+}
+
+radio-group {
+	display: inline-block;
+}
+
+
+
+switch.radius .wx-switch-input::after,
+switch.radius .wx-switch-input,
+switch.radius .wx-switch-input::before,
+switch.radius .uni-switch-input::after,
+switch.radius .uni-switch-input,
+switch.radius .uni-switch-input::before {
+	border-radius: 10upx;
+}
+
+switch .wx-switch-input::before,
+radio.radio::before,
+checkbox .wx-checkbox-input::before,
+radio .wx-radio-input::before,
+switch .uni-switch-input::before,
+radio.radio::before,
+checkbox .uni-checkbox-input::before,
+radio .uni-radio-input::before {
+	display: none;
+}
+
+radio.radio[checked]::after,
+radio.radio .uni-radio-input-checked::after {
+	content: "";
+	background-color: transparent;
+	display: block;
+	position: absolute;
+	width: 8px;
+	height: 8px;
+	z-index: 999;
+	top: 0upx;
+	left: 0upx;
+	right: 0;
+	bottom: 0;
+	margin: auto;
+	border-radius: 200upx;
+	/* #ifndef MP */
+	border: 7px solid #ffffff !important;
+	/* #endif */
+
+	/* #ifdef MP */
+	border: 8px solid #ffffff !important;
+	/* #endif */
+}
+
+.switch-sex::after {
+	content: "\e71c";
+}
+
+.switch-sex::before {
+	content: "\e71a";
+}
+
+.switch-sex .wx-switch-input,
+.switch-sex .uni-switch-input {
+	background: #e54d42 !important;
+	border-color: #e54d42 !important;
+}
+
+.switch-sex[checked] .wx-switch-input,
+.switch-sex.checked .uni-switch-input {
+	background: #0081ff !important;
+	border-color: #0081ff !important;
+}
+
+switch.red[checked] .wx-switch-input.wx-switch-input-checked,
+checkbox.red[checked] .wx-checkbox-input,
+radio.red[checked] .wx-radio-input,
+switch.red.checked .uni-switch-input.uni-switch-input-checked,
+checkbox.red.checked .uni-checkbox-input,
+radio.red.checked .uni-radio-input {
+	background-color: #e54d42 !important;
+	border-color: #e54d42 !important;
+	color: #ffffff !important;
+}
+
+switch.orange[checked] .wx-switch-input,
+checkbox.orange[checked] .wx-checkbox-input,
+radio.orange[checked] .wx-radio-input,
+switch.orange.checked .uni-switch-input,
+checkbox.orange.checked .uni-checkbox-input,
+radio.orange.checked .uni-radio-input {
+	background-color: #f37b1d !important;
+	border-color: #f37b1d !important;
+	color: #ffffff !important;
+}
+
+switch.yellow[checked] .wx-switch-input,
+checkbox.yellow[checked] .wx-checkbox-input,
+radio.yellow[checked] .wx-radio-input,
+switch.yellow.checked .uni-switch-input,
+checkbox.yellow.checked .uni-checkbox-input,
+radio.yellow.checked .uni-radio-input {
+	background-color: #fbbd08 !important;
+	border-color: #fbbd08 !important;
+	color: #333333 !important;
+}
+
+switch.olive[checked] .wx-switch-input,
+checkbox.olive[checked] .wx-checkbox-input,
+radio.olive[checked] .wx-radio-input,
+switch.olive.checked .uni-switch-input,
+checkbox.olive.checked .uni-checkbox-input,
+radio.olive.checked .uni-radio-input {
+	background-color: #8dc63f !important;
+	border-color: #8dc63f !important;
+	color: #ffffff !important;
+}
+
+switch.green[checked] .wx-switch-input,
+switch[checked] .wx-switch-input,
+checkbox.green[checked] .wx-checkbox-input,
+checkbox[checked] .wx-checkbox-input,
+radio.green[checked] .wx-radio-input,
+radio[checked] .wx-radio-input,
+switch.green.checked .uni-switch-input,
+switch.checked .uni-switch-input,
+checkbox.green.checked .uni-checkbox-input,
+checkbox.checked .uni-checkbox-input,
+radio.green.checked .uni-radio-input,
+radio.checked .uni-radio-input {
+	background-color: #39b54a !important;
+	border-color: #39b54a !important;
+	color: #ffffff !important;
+	border-color: #39B54A !important;
+}
+
+switch.cyan[checked] .wx-switch-input,
+checkbox.cyan[checked] .wx-checkbox-input,
+radio.cyan[checked] .wx-radio-input,
+switch.cyan.checked .uni-switch-input,
+checkbox.cyan.checked .uni-checkbox-input,
+radio.cyan.checked .uni-radio-input {
+	background-color: #1cbbb4 !important;
+	border-color: #1cbbb4 !important;
+	color: #ffffff !important;
+}
+
+switch.blue[checked] .wx-switch-input,
+checkbox.blue[checked] .wx-checkbox-input,
+radio.blue[checked] .wx-radio-input,
+switch.blue.checked .uni-switch-input,
+checkbox.blue.checked .uni-checkbox-input,
+radio.blue.checked .uni-radio-input {
+	background-color: #0081ff !important;
+	border-color: #0081ff !important;
+	color: #ffffff !important;
+}
+
+switch.purple[checked] .wx-switch-input,
+checkbox.purple[checked] .wx-checkbox-input,
+radio.purple[checked] .wx-radio-input,
+switch.purple.checked .uni-switch-input,
+checkbox.purple.checked .uni-checkbox-input,
+radio.purple.checked .uni-radio-input {
+	background-color: #6739b6 !important;
+	border-color: #6739b6 !important;
+	color: #ffffff !important;
+}
+
+switch.mauve[checked] .wx-switch-input,
+checkbox.mauve[checked] .wx-checkbox-input,
+radio.mauve[checked] .wx-radio-input,
+switch.mauve.checked .uni-switch-input,
+checkbox.mauve.checked .uni-checkbox-input,
+radio.mauve.checked .uni-radio-input {
+	background-color: #9c26b0 !important;
+	border-color: #9c26b0 !important;
+	color: #ffffff !important;
+}
+
+switch.pink[checked] .wx-switch-input,
+checkbox.pink[checked] .wx-checkbox-input,
+radio.pink[checked] .wx-radio-input,
+switch.pink.checked .uni-switch-input,
+checkbox.pink.checked .uni-checkbox-input,
+radio.pink.checked .uni-radio-input {
+	background-color: #e03997 !important;
+	border-color: #e03997 !important;
+	color: #ffffff !important;
+}
+
+switch.brown[checked] .wx-switch-input,
+checkbox.brown[checked] .wx-checkbox-input,
+radio.brown[checked] .wx-radio-input,
+switch.brown.checked .uni-switch-input,
+checkbox.brown.checked .uni-checkbox-input,
+radio.brown.checked .uni-radio-input {
+	background-color: #a5673f !important;
+	border-color: #a5673f !important;
+	color: #ffffff !important;
+}
+
+switch.grey[checked] .wx-switch-input,
+checkbox.grey[checked] .wx-checkbox-input,
+radio.grey[checked] .wx-radio-input,
+switch.grey.checked .uni-switch-input,
+checkbox.grey.checked .uni-checkbox-input,
+radio.grey.checked .uni-radio-input {
+	background-color: #8799a3 !important;
+	border-color: #8799a3 !important;
+	color: #ffffff !important;
+}
+
+switch.gray[checked] .wx-switch-input,
+checkbox.gray[checked] .wx-checkbox-input,
+radio.gray[checked] .wx-radio-input,
+switch.gray.checked .uni-switch-input,
+checkbox.gray.checked .uni-checkbox-input,
+radio.gray.checked .uni-radio-input {
+	background-color: #f0f0f0 !important;
+	border-color: #f0f0f0 !important;
+	color: #333333 !important;
+}
+
+switch.black[checked] .wx-switch-input,
+checkbox.black[checked] .wx-checkbox-input,
+radio.black[checked] .wx-radio-input,
+switch.black.checked .uni-switch-input,
+checkbox.black.checked .uni-checkbox-input,
+radio.black.checked .uni-radio-input {
+	background-color: #333333 !important;
+	border-color: #333333 !important;
+	color: #ffffff !important;
+}
+
+switch.white[checked] .wx-switch-input,
+checkbox.white[checked] .wx-checkbox-input,
+radio.white[checked] .wx-radio-input,
+switch.white.checked .uni-switch-input,
+checkbox.white.checked .uni-checkbox-input,
+radio.white.checked .uni-radio-input {
+	background-color: #ffffff !important;
+	border-color: #ffffff !important;
+	color: #333333 !important;
+}
+
+/* ==================
+          边框
+ ==================== */
+
+/* -- 实线 -- */
+
+.solid,
+.solid-top,
+.solid-right,
+.solid-bottom,
+.solid-left,
+.solids,
+.solids-top,
+.solids-right,
+.solids-bottom,
+.solids-left,
+.dashed,
+.dashed-top,
+.dashed-right,
+.dashed-bottom,
+.dashed-left {
+	position: relative;
+}
+
+.solid::after,
+.solid-top::after,
+.solid-right::after,
+.solid-bottom::after,
+.solid-left::after,
+.solids::after,
+.solids-top::after,
+.solids-right::after,
+.solids-bottom::after,
+.solids-left::after,
+.dashed::after,
+.dashed-top::after,
+.dashed-right::after,
+.dashed-bottom::after,
+.dashed-left::after {
+	content: " ";
+	width: 200%;
+	height: 200%;
+	position: absolute;
+	top: 0;
+	left: 0;
+	border-radius: inherit;
+	transform: scale(0.5);
+	transform-origin: 0 0;
+	pointer-events: none;
+	box-sizing: border-box;
+}
+
+.solid::after {
+	border: 1upx solid rgba(0, 0, 0, 0.1);
+}
+
+.solid-top::after {
+	border-top: 1upx solid rgba(0, 0, 0, 0.1);
+}
+
+.solid-right::after {
+	border-right: 1upx solid rgba(0, 0, 0, 0.1);
+}
+
+.solid-bottom::after {
+	border-bottom: 1upx solid rgba(0, 0, 0, 0.1);
+}
+
+.solid-left::after {
+	border-left: 1upx solid rgba(0, 0, 0, 0.1);
+}
+
+.solids::after {
+	border: 8upx solid #eee;
+}
+
+.solids-top::after {
+	border-top: 8upx solid #eee;
+}
+
+.solids-right::after {
+	border-right: 8upx solid #eee;
+}
+
+.solids-bottom::after {
+	border-bottom: 8upx solid #eee;
+}
+
+.solids-left::after {
+	border-left: 8upx solid #eee;
+}
+
+/* -- 虚线 -- */
+
+.dashed::after {
+	border: 1upx dashed #ddd;
+}
+
+.dashed-top::after {
+	border-top: 1upx dashed #ddd;
+}
+
+.dashed-right::after {
+	border-right: 1upx dashed #ddd;
+}
+
+.dashed-bottom::after {
+	border-bottom: 1upx dashed #ddd;
+}
+
+.dashed-left::after {
+	border-left: 1upx dashed #ddd;
+}
+
+/* -- 阴影 -- */
+
+.shadow[class*='white'] {
+	--ShadowSize: 0 1upx 6upx;
+}
+
+.shadow-lg {
+	--ShadowSize: 0upx 40upx 100upx 0upx;
+}
+
+.shadow-warp {
+	position: relative;
+	box-shadow: 0 0 10upx rgba(0, 0, 0, 0.1);
+}
+
+.shadow-warp:before,
+.shadow-warp:after {
+	position: absolute;
+	content: "";
+	top: 20upx;
+	bottom: 30upx;
+	left: 20upx;
+	width: 50%;
+	box-shadow: 0 30upx 20upx rgba(0, 0, 0, 0.2);
+	transform: rotate(-3deg);
+	z-index: -1;
+}
+
+.shadow-warp:after {
+	right: 20upx;
+	left: auto;
+	transform: rotate(3deg);
+}
+
+.shadow-blur {
+	position: relative;
+}
+
+.shadow-blur::before {
+	content: "";
+	display: block;
+	background: inherit;
+	filter: blur(10upx);
+	position: absolute;
+	width: 100%;
+	height: 100%;
+	top: 10upx;
+	left: 10upx;
+	z-index: -1;
+	opacity: 0.4;
+	transform-origin: 0 0;
+	border-radius: inherit;
+	transform: scale(1, 1);
+}
+
+/* ==================
+          按钮
+ ==================== */
+
+.cu-btn {
+	position: relative;
+	border: 0upx;
+	display: inline-flex;
+	align-items: center;
+	justify-content: center;
+	box-sizing: border-box;
+	padding: 0 30upx;
+	font-size: 28upx;
+	height: 64upx;
+	line-height: 1;
+	text-align: center;
+	text-decoration: none;
+	overflow: visible;
+	margin-left: initial;
+	transform: translate(0upx, 0upx);
+	margin-right: initial;
+}
+
+.cu-btn::after {
+	display: none;
+}
+
+.cu-btn:not([class*="bg-"]) {
+	background-color: #f0f0f0;
+}
+
+.cu-btn[class*="line"] {
+	background-color: transparent;
+}
+
+.cu-btn[class*="line"]::after {
+	content: " ";
+	display: block;
+	width: 200%;
+	height: 200%;
+	position: absolute;
+	top: 0;
+	left: 0;
+	border: 1upx solid currentColor;
+	transform: scale(0.5);
+	transform-origin: 0 0;
+	box-sizing: border-box;
+	border-radius: 12upx;
+	z-index: 1;
+	pointer-events: none;
+}
+
+.cu-btn.round[class*="line"]::after {
+	border-radius: 1000upx;
+}
+
+.cu-btn[class*="lines"]::after {
+	border: 6upx solid currentColor;
+}
+
+.cu-btn[class*="bg-"]::after {
+	display: none;
+}
+
+.cu-btn.sm {
+	padding: 0 20upx;
+	font-size: 20upx;
+	height: 48upx;
+}
+
+.cu-btn.df {
+	padding: 0 24upx;
+	font-size: 26upx;
+	height: 54upx;
+}
+
+.cu-btn.lg {
+	padding: 0 40upx;
+	font-size: 32upx;
+	height: 80upx;
+}
+
+.cu-btn.cuIcon.sm {
+	width: 48upx;
+	height: 48upx;
+}
+
+.cu-btn.cuIcon {
+	width: 64upx;
+	height: 64upx;
+	border-radius: 500upx;
+	padding: 0;
+}
+
+button.cuIcon.lg {
+	width: 80upx;
+	height: 80upx;
+}
+
+.cu-btn.shadow-blur::before {
+	top: 4upx;
+	left: 4upx;
+	filter: blur(6upx);
+	opacity: 0.6;
+}
+
+.cu-btn.button-hover {
+	transform: translate(1upx, 1upx);
+}
+
+.block {
+	display: block;
+}
+
+.cu-btn.block {
+	display: flex;
+}
+
+.cu-btn[disabled] {
+	opacity: 0.6;
+	color: #ffffff;
+}
+
+/* ==================
+          徽章
+ ==================== */
+
+.cu-tag {
+	font-size: 24upx;
+	vertical-align: middle;
+	position: relative;
+	display: inline-flex;
+	align-items: center;
+	justify-content: center;
+	box-sizing: border-box;
+	padding: 0upx 16upx;
+	height: 48upx;
+	font-family: Helvetica Neue, Helvetica, sans-serif;
+	white-space: nowrap;
+}
+
+.cu-tag:not([class*="bg"]):not([class*="line"]) {
+	background-color: #f1f1f1;
+}
+
+.cu-tag[class*="line-"]::after {
+	content: " ";
+	width: 200%;
+	height: 200%;
+	position: absolute;
+	top: 0;
+	left: 0;
+	border: 1upx solid currentColor;
+	transform: scale(0.5);
+	transform-origin: 0 0;
+	box-sizing: border-box;
+	border-radius: inherit;
+	z-index: 1;
+	pointer-events: none;
+}
+
+.cu-tag.radius[class*="line"]::after {
+	border-radius: 12upx;
+}
+
+.cu-tag.round[class*="line"]::after {
+	border-radius: 1000upx;
+}
+
+.cu-tag[class*="line-"]::after {
+	border-radius: 0;
+}
+
+.cu-tag+.cu-tag {
+	margin-left: 10upx;
+}
+
+.cu-tag.sm {
+	font-size: 20upx;
+	padding: 0upx 12upx;
+	height: 32upx;
+}
+
+.cu-capsule {
+	display: inline-flex;
+	vertical-align: middle;
+}
+
+.cu-capsule+.cu-capsule {
+	margin-left: 10upx;
+}
+
+.cu-capsule .cu-tag {
+	margin: 0;
+}
+
+.cu-capsule .cu-tag[class*="line-"]:last-child::after {
+	border-left: 0upx solid transparent;
+}
+
+.cu-capsule .cu-tag[class*="line-"]:first-child::after {
+	border-right: 0upx solid transparent;
+}
+
+.cu-capsule.radius .cu-tag:first-child {
+	border-top-left-radius: 6upx;
+	border-bottom-left-radius: 6upx;
+}
+
+.cu-capsule.radius .cu-tag:last-child::after,
+.cu-capsule.radius .cu-tag[class*="line-"] {
+	border-top-right-radius: 12upx;
+	border-bottom-right-radius: 12upx;
+}
+
+.cu-capsule.round .cu-tag:first-child {
+	border-top-left-radius: 200upx;
+	border-bottom-left-radius: 200upx;
+	text-indent: 4upx;
+}
+
+.cu-capsule.round .cu-tag:last-child::after,
+.cu-capsule.round .cu-tag:last-child {
+	border-top-right-radius: 200upx;
+	border-bottom-right-radius: 200upx;
+	text-indent: -4upx;
+}
+
+.cu-tag.badge {
+	border-radius: 200upx;
+	position: absolute;
+	top:4upx;
+	right: -10upx;
+	font-size: 20upx;
+	padding: 0upx 10upx;
+	height: 28upx;
+	color: #ffffff;
+}
+
+.cu-tag.badge:not([class*="bg-"]) {
+	background-color: #dd514c;
+}
+
+.cu-tag:empty:not([class*="cuIcon-"]) {
+	padding: 0upx;
+	width: 16upx;
+	height: 16upx;
+	top: -4upx;
+	right: -4upx;
+}
+
+.cu-tag[class*="cuIcon-"] {
+	width: 32upx;
+	height: 32upx;
+	top: -4upx;
+	right: -4upx;
+}
+
+/* ==================
+          头像
+ ==================== */
+
+.cu-avatar {
+	font-variant: small-caps;
+	margin: 0;
+	padding: 0;
+	display: inline-flex;
+	text-align: center;
+	justify-content: center;
+	align-items: center;
+	background-color: #ccc;
+	color: #ffffff;
+	white-space: nowrap;
+	position: relative;
+	width: 64upx;
+	height: 64upx;
+	background-size: cover;
+	background-position: center;
+	vertical-align: middle;
+	font-size: 1.5em;
+}
+
+.cu-avatar.sm {
+	width: 48upx;
+	height: 48upx;
+	font-size: 1em;
+}
+
+.cu-avatar.lg {
+	width: 96upx;
+	height: 96upx;
+	font-size: 2em;
+}
+
+.cu-avatar.xl {
+	width: 128upx;
+	height: 128upx;
+	font-size: 2.5em;
+}
+
+.cu-avatar .avatar-text {
+	font-size: 0.4em;
+}
+
+.cu-avatar-group {
+	direction: rtl;
+	unicode-bidi: bidi-override;
+	padding: 0 10upx 0 40upx;
+	display: inline-block;
+}
+
+.cu-avatar-group .cu-avatar {
+	margin-left: -30upx;
+	border: 4upx solid #f1f1f1;
+	vertical-align: middle;
+}
+
+.cu-avatar-group .cu-avatar.sm {
+	margin-left: -20upx;
+	border: 1upx solid #f1f1f1;
+}
+
+/* ==================
+         进度条
+ ==================== */
+
+.cu-progress {
+	overflow: hidden;
+	height: 28upx;
+	background-color: #ebeef5;
+	display: inline-flex;
+	align-items: center;
+	width: 100%;
+}
+
+.cu-progress+view,
+.cu-progress+text {
+	line-height: 1;
+}
+
+.cu-progress.xs {
+	height: 10upx;
+}
+
+.cu-progress.sm {
+	height: 20upx;
+}
+
+.cu-progress view {
+	width: 0;
+	height: 100%;
+	align-items: center;
+	display: flex;
+	justify-items: flex-end;
+	justify-content: space-around;
+	font-size: 20upx;
+	color: #ffffff;
+	transition: width 0.6s ease;
+}
+
+.cu-progress text {
+	align-items: center;
+	display: flex;
+	font-size: 20upx;
+	color: #333333;
+	text-indent: 10upx;
+}
+
+.cu-progress.text-progress {
+	padding-right: 60upx;
+}
+
+.cu-progress.striped view {
+	background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+	background-size: 72upx 72upx;
+}
+
+.cu-progress.active view {
+	animation: progress-stripes 2s linear infinite;
+}
+
+@keyframes progress-stripes {
+	from {
+		background-position: 72upx 0;
+	}
+
+	to {
+		background-position: 0 0;
+	}
+}
+
+/* ==================
+          加载
+ ==================== */
+
+.cu-load {
+	display: block;
+	line-height: 3em;
+	text-align: center;
+}
+
+.cu-load::before {
+	font-family: "cuIcon";
+	display: inline-block;
+	margin-right: 6upx;
+}
+
+.cu-load.loading::before {
+	content: "\e67a";
+	animation: cuIcon-spin 2s infinite linear;
+}
+
+.cu-load.loading::after {
+	content: "加载中...";
+}
+
+.cu-load.over::before {
+	content: "\e64a";
+}
+
+.cu-load.over::after {
+	content: "没有更多了";
+}
+
+.cu-load.erro::before {
+	content: "\e658";
+}
+
+.cu-load.erro::after {
+	content: "加载失败";
+}
+
+.cu-load.load-cuIcon::before {
+	font-size: 32upx;
+}
+
+.cu-load.load-cuIcon::after {
+	display: none;
+}
+
+.cu-load.load-cuIcon.over {
+	display: none;
+}
+
+.cu-load.load-modal {
+	position: fixed;
+	top: 0;
+	right: 0;
+	bottom: 140upx;
+	left: 0;
+	margin: auto;
+	width: 260upx;
+	height: 260upx;
+	background-color: #ffffff;
+	border-radius: 10upx;
+	box-shadow: 0 0 0upx 2000upx rgba(0, 0, 0, 0.5);
+	display: flex;
+	align-items: center;
+	flex-direction: column;
+	justify-content: center;
+	font-size: 28upx;
+	z-index: 9999;
+	line-height: 2.4em;
+}
+
+.cu-load.load-modal [class*="cuIcon-"] {
+	font-size: 60upx;
+}
+
+.cu-load.load-modal image {
+	width: 70upx;
+	height: 70upx;
+}
+
+.cu-load.load-modal::after {
+	content: "";
+	position: absolute;
+	background-color: #ffffff;
+	border-radius: 50%;
+	width: 200upx;
+	height: 200upx;
+	font-size: 10px;
+	border-top: 6upx solid rgba(0, 0, 0, 0.05);
+	border-right: 6upx solid rgba(0, 0, 0, 0.05);
+	border-bottom: 6upx solid rgba(0, 0, 0, 0.05);
+	border-left: 6upx solid #f37b1d;
+	animation: cuIcon-spin 1s infinite linear;
+	z-index: -1;
+}
+
+.load-progress {
+	pointer-events: none;
+	top: 0;
+	position: fixed;
+	width: 100%;
+	left: 0;
+	z-index: 2000;
+}
+
+.load-progress.hide {
+	display: none;
+}
+
+.load-progress .load-progress-bar {
+	position: relative;
+	width: 100%;
+	height: 4upx;
+	overflow: hidden;
+	transition: all 200ms ease 0s;
+}
+
+.load-progress .load-progress-spinner {
+	position: absolute;
+	top: 10upx;
+	right: 10upx;
+	z-index: 2000;
+	display: block;
+}
+
+.load-progress .load-progress-spinner::after {
+	content: "";
+	display: block;
+	width: 24upx;
+	height: 24upx;
+	-webkit-box-sizing: border-box;
+	box-sizing: border-box;
+	border: solid 4upx transparent;
+	border-top-color: inherit;
+	border-left-color: inherit;
+	border-radius: 50%;
+	-webkit-animation: load-progress-spinner 0.4s linear infinite;
+	animation: load-progress-spinner 0.4s linear infinite;
+}
+
+@-webkit-keyframes load-progress-spinner {
+	0% {
+		-webkit-transform: rotate(0);
+		transform: rotate(0);
+	}
+
+	100% {
+		-webkit-transform: rotate(360deg);
+		transform: rotate(360deg);
+	}
+}
+
+@keyframes load-progress-spinner {
+	0% {
+		-webkit-transform: rotate(0);
+		transform: rotate(0);
+	}
+
+	100% {
+		-webkit-transform: rotate(360deg);
+		transform: rotate(360deg);
+	}
+}
+
+/* ==================
+          列表
+ ==================== */
+.grayscale {
+	filter: grayscale(1);
+}
+
+.cu-list+.cu-list {
+	margin-top: 30upx
+}
+
+.cu-list>.cu-item {
+	transition: all .6s ease-in-out 0s;
+	transform: translateX(0upx)
+}
+
+.cu-list>.cu-item.move-cur {
+	transform: translateX(-260upx)
+}
+
+.cu-list>.cu-item .move {
+	position: absolute;
+	right: 0;
+	display: flex;
+	width: 260upx;
+	height: 100%;
+	transform: translateX(100%)
+}
+
+.cu-list>.cu-item .move view {
+	display: flex;
+	flex: 1;
+	justify-content: center;
+	align-items: center
+}
+
+.cu-list.menu-avatar {
+	overflow: hidden;
+}
+
+.cu-list.menu-avatar>.cu-item {
+	position: relative;
+	display: flex;
+	padding-right: 10upx;
+	height: 140upx;
+	background-color: #ffffff;
+	justify-content: flex-end;
+	align-items: center
+}
+
+.cu-list.menu-avatar>.cu-item>.cu-avatar {
+	position: absolute;
+	left: 30upx
+}
+
+.cu-list.menu-avatar>.cu-item .flex .text-cut {
+	max-width: 510upx
+}
+
+.cu-list.menu-avatar>.cu-item .content {
+	position: absolute;
+	left: 146upx;
+	width: calc(100% - 96upx - 60upx - 120upx - 20upx);
+	line-height: 1.6em;
+}
+
+.cu-list.menu-avatar>.cu-item .content.flex-sub {
+	width: calc(100% - 96upx - 60upx - 20upx);
+}
+
+.cu-list.menu-avatar>.cu-item .content>view:first-child {
+	font-size: 30upx;
+	display: flex;
+	align-items: center
+}
+
+.cu-list.menu-avatar>.cu-item .content .cu-tag.sm {
+	display: inline-block;
+	margin-left: 10upx;
+	height: 28upx;
+	font-size: 16upx;
+	line-height: 32upx
+}
+
+.cu-list.menu-avatar>.cu-item .action {
+	width: 100upx;
+	text-align: center
+}
+
+.cu-list.menu-avatar>.cu-item .action view+view {
+	margin-top: 10upx
+}
+
+.cu-list.menu-avatar.comment>.cu-item .content {
+	position: relative;
+	left: 0;
+	width: auto;
+	flex: 1;
+}
+
+.cu-list.menu-avatar.comment>.cu-item {
+	padding: 30upx 30upx 30upx 120upx;
+	height: auto
+}
+
+.cu-list.menu-avatar.comment .cu-avatar {
+	align-self: flex-start
+}
+
+.cu-list.menu>.cu-item {
+	position: relative;
+	display: flex;
+	padding: 0 30upx;
+	min-height: 100upx;
+	background-color: #ffffff;
+	justify-content: space-between;
+	align-items: center
+}
+
+.cu-list.menu>.cu-item:last-child:after {
+	border: none
+}
+
+.cu-list.menu-avatar>.cu-item:after,
+.cu-list.menu>.cu-item:after {
+	position: absolute;
+	top: 0;
+	left: 0;
+	box-sizing: border-box;
+	width: 200%;
+	height: 200%;
+	border-bottom: 1upx solid #ddd;
+	border-radius: inherit;
+	content: " ";
+	transform: scale(.5);
+	transform-origin: 0 0;
+	pointer-events: none
+}
+
+.cu-list.menu>.cu-item.grayscale {
+	background-color: #f5f5f5
+}
+
+.cu-list.menu>.cu-item.cur {
+	background-color: #fcf7e9
+}
+
+.cu-list.menu>.cu-item.arrow {
+	padding-right: 90upx
+}
+
+.cu-list.menu>.cu-item.arrow:before {
+	position: absolute;
+	top: 0;
+	right: 30upx;
+	bottom: 0;
+	display: block;
+	margin: auto;
+	width: 30upx;
+	height: 30upx;
+	color: #8799a3;
+	content: "\e6a3";
+	text-align: center;
+	font-size: 34upx;
+	font-family: cuIcon;
+	line-height: 30upx
+}
+
+.cu-list.menu>.cu-item button.content {
+	padding: 0;
+	background-color: transparent;
+	justify-content: flex-start
+}
+
+.cu-list.menu>.cu-item button.content:after {
+	display: none
+}
+
+.cu-list.menu>.cu-item .cu-avatar-group .cu-avatar {
+	border-color: #ffffff
+}
+
+.cu-list.menu>.cu-item .content>view:first-child {
+	display: flex;
+	align-items: center
+}
+
+.cu-list.menu>.cu-item .content>text[class*=cuIcon] {
+	display: inline-block;
+	margin-right: 10upx;
+	width: 1.6em;
+	text-align: center
+}
+
+.cu-list.menu>.cu-item .content>image {
+	display: inline-block;
+	margin-right: 10upx;
+	width: 1.6em;
+	height: 1.6em;
+	vertical-align: middle
+}
+
+.cu-list.menu>.cu-item .content {
+	font-size: 30upx;
+	line-height: 1.6em;
+	flex: 1
+}
+
+.cu-list.menu>.cu-item .content .cu-tag.sm {
+	display: inline-block;
+	margin-left: 10upx;
+	height: 28upx;
+	font-size: 16upx;
+	line-height: 32upx
+}
+
+.cu-list.menu>.cu-item .action .cu-tag:empty {
+	right: 10upx
+}
+
+.cu-list.menu {
+	display: block;
+	overflow: hidden
+}
+
+.cu-list.menu.sm-border>.cu-item:after {
+	left: 30upx;
+	width: calc(200% - 120upx)
+}
+
+.cu-list.grid>.cu-item {
+	position: relative;
+	display: flex;
+	padding: 20upx 0 30upx;
+	transition-duration: 0s;
+	flex-direction: column
+}
+
+.cu-list.grid>.cu-item:after {
+	position: absolute;
+	top: 0;
+	left: 0;
+	box-sizing: border-box;
+	width: 200%;
+	height: 200%;
+	border-right: 1px solid rgba(0, 0, 0, .1);
+	border-bottom: 1px solid rgba(0, 0, 0, .1);
+	border-radius: inherit;
+	content: " ";
+	transform: scale(.5);
+	transform-origin: 0 0;
+	pointer-events: none
+}
+
+.cu-list.grid>.cu-item text {
+	display: block;
+	margin-top: 10upx;
+	color: #888;
+	font-size: 26upx;
+	line-height: 40upx
+}
+
+.cu-list.grid>.cu-item [class*=cuIcon] {
+	position: relative;
+	display: block;
+	margin-top: 20upx;
+	width: 100%;
+	font-size: 48upx
+}
+
+.cu-list.grid>.cu-item .cu-tag {
+	right: auto;
+	left: 50%;
+	margin-left: 20upx
+}
+
+.cu-list.grid {
+	background-color: #ffffff;
+	text-align: center
+}
+
+.cu-list.grid.no-border>.cu-item {
+	padding-top: 10upx;
+	padding-bottom: 20upx
+}
+
+.cu-list.grid.no-border>.cu-item:after {
+	border: none
+}
+
+.cu-list.grid.no-border {
+	padding: 20upx 10upx
+}
+
+.cu-list.grid.col-3>.cu-item:nth-child(3n):after,
+.cu-list.grid.col-4>.cu-item:nth-child(4n):after,
+.cu-list.grid.col-5>.cu-item:nth-child(5n):after {
+	border-right-width: 0
+}
+
+.cu-list.card-menu {
+	overflow: hidden;
+	margin-right: 30upx;
+	margin-left: 30upx;
+	border-radius: 20upx
+}
+
+
+/* ==================
+          操作条
+ ==================== */
+
+.cu-bar {
+	display: flex;
+	position: relative;
+	align-items: center;
+	min-height: 100upx;
+	justify-content: space-between;
+}
+
+.cu-bar .action {
+	display: flex;
+	align-items: center;
+	height: 100%;
+	justify-content: center;
+	max-width: 100%;
+}
+
+.cu-bar .action.border-title {
+	position: relative;
+	top: -10upx;
+}
+
+.cu-bar .action.border-title text[class*="bg-"]:last-child {
+	position: absolute;
+	bottom: -0.5rem;
+	min-width: 2rem;
+	height: 6upx;
+	left: 0;
+}
+
+.cu-bar .action.sub-title {
+	position: relative;
+	top: -0.2rem;
+}
+
+.cu-bar .action.sub-title text {
+	position: relative;
+	z-index: 1;
+}
+
+.cu-bar .action.sub-title text[class*="bg-"]:last-child {
+	position: absolute;
+	display: inline-block;
+	bottom: -0.2rem;
+	border-radius: 6upx;
+	width: 100%;
+	height: 0.6rem;
+	left: 0.6rem;
+	opacity: 0.3;
+	z-index: 0;
+}
+
+.cu-bar .action.sub-title text[class*="text-"]:last-child {
+	position: absolute;
+	display: inline-block;
+	bottom: -0.7rem;
+	left: 0.5rem;
+	opacity: 0.2;
+	z-index: 0;
+	text-align: right;
+	font-weight: 900;
+	font-size: 36upx;
+}
+
+.cu-bar.justify-center .action.border-title text:last-child,
+.cu-bar.justify-center .action.sub-title text:last-child {
+	left: 0;
+	right: 0;
+	margin: auto;
+	text-align: center;
+}
+
+.cu-bar .action:first-child {
+	margin-left: 30upx;
+	font-size: 30upx;
+}
+
+.cu-bar .action text.text-cut {
+	text-align: left;
+	width: 100%;
+}
+
+.cu-bar .cu-avatar:first-child {
+	margin-left: 20upx;
+}
+
+.cu-bar .action:first-child>text[class*="cuIcon-"] {
+	margin-left: -0.3em;
+	margin-right: 0.3em;
+}
+
+.cu-bar .action:last-child {
+	margin-right: 30upx;
+}
+
+.cu-bar .action>text[class*="cuIcon-"],
+.cu-bar .action>view[class*="cuIcon-"] {
+	font-size: 36upx;
+}
+
+.cu-bar .action>text[class*="cuIcon-"]+text[class*="cuIcon-"] {
+	margin-left: 0.5em;
+}
+
+.cu-bar .content {
+	position: absolute;
+	text-align: center;
+	width: calc(100% - 340upx);
+	left: 0;
+	right: 0;
+	bottom: 0;
+	top: 0;
+	margin: auto;
+	height: 60upx;
+	font-size: 32upx;
+	line-height: 60upx;
+	cursor: none;
+	pointer-events: none;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+	overflow: hidden;
+}
+
+.cu-bar.ios .content {
+	bottom: 7px;
+	height: 30px;
+	font-size: 32upx;
+	line-height: 30px;
+}
+
+.cu-bar.btn-group {
+	justify-content: space-around;
+}
+
+.cu-bar.btn-group button {
+	padding: 20upx 32upx;
+}
+
+.cu-bar.btn-group button {
+	flex: 1;
+	margin: 0 20upx;
+	max-width: 50%;
+}
+
+.cu-bar .search-form {
+	background-color: #f5f5f5;
+	line-height: 64upx;
+	height: 64upx;
+	font-size: 24upx;
+	color: #333333;
+	flex: 1;
+	display: flex;
+	align-items: center;
+	margin: 0 30upx;
+}
+
+.cu-bar .search-form+.action {
+	margin-right: 30upx;
+}
+
+.cu-bar .search-form input {
+	flex: 1;
+	padding-right: 30upx;
+	height: 64upx;
+	line-height: 64upx;
+	font-size: 26upx;
+	background-color: transparent;
+}
+
+.cu-bar .search-form [class*="cuIcon-"] {
+	margin: 0 0.5em 0 0.8em;
+}
+
+.cu-bar .search-form [class*="cuIcon-"]::before {
+	top: 0upx;
+}
+
+.cu-bar.fixed,
+.nav.fixed {
+	position: fixed;
+	width: 100%;
+	top: 0;
+	z-index: 1024;
+	box-shadow: 0 1upx 6upx rgba(0, 0, 0, 0.1);
+}
+
+.cu-bar.foot {
+	position: fixed;
+	width: 100%;
+	bottom: 0;
+	z-index: 1024;
+	box-shadow: 0 -1upx 6upx rgba(0, 0, 0, 0.1);
+}
+
+.cu-bar.tabbar {
+	padding: 0;
+	height: calc(100upx + env(safe-area-inset-bottom) / 2);
+	padding-bottom: calc(env(safe-area-inset-bottom) / 2);
+}
+
+.cu-tabbar-height {
+	min-height: 100upx;
+	height: calc(100upx + env(safe-area-inset-bottom) / 2);
+}
+
+.cu-bar.tabbar.shadow {
+	box-shadow: 0 -1upx 6upx rgba(0, 0, 0, 0.1);
+}
+
+.cu-bar.tabbar .action {
+	font-size: 22upx;
+	position: relative;
+	flex: 1;
+	text-align: center;
+	padding: 0;
+	display: block;
+	height: auto;
+	line-height: 1;
+	margin: 0;
+	background-color: inherit;
+	overflow: initial;
+}
+
+.cu-bar.tabbar.shop .action {
+	width: 140upx;
+	flex: initial;
+}
+
+.cu-bar.tabbar .action.add-action {
+	position: relative;
+	z-index: 2;
+	padding-top: 50upx;
+}
+
+.cu-bar.tabbar .action.add-action [class*="cuIcon-"] {
+	position: absolute;
+	width: 70upx;
+	z-index: 2;
+	height: 70upx;
+	border-radius: 50%;
+	line-height: 70upx;
+	font-size: 50upx;
+	top: -35upx;
+	left: 0;
+	right: 0;
+	margin: auto;
+	padding: 0;
+}
+
+.cu-bar.tabbar .action.add-action::after {
+	content: "";
+	position: absolute;
+	width: 100upx;
+	height: 100upx;
+	top: -50upx;
+	left: 0;
+	right: 0;
+	margin: auto;
+	box-shadow: 0 -3upx 8upx rgba(0, 0, 0, 0.08);
+	border-radius: 50upx;
+	background-color: inherit;
+	z-index: 0;
+}
+
+.cu-bar.tabbar .action.add-action::before {
+	content: "";
+	position: absolute;
+	width: 100upx;
+	height: 30upx;
+	bottom: 30upx;
+	left: 0;
+	right: 0;
+	margin: auto;
+	background-color: inherit;
+	z-index: 1;
+}
+
+.cu-bar.tabbar .btn-group {
+	flex: 1;
+	display: flex;
+	justify-content: space-around;
+	align-items: center;
+	padding: 0 10upx;
+}
+
+.cu-bar.tabbar button.action::after {
+	border: 0;
+}
+
+.cu-bar.tabbar .action [class*="cuIcon-"] {
+	width: 100upx;
+	position: relative;
+	display: block;
+	height: auto;
+	margin: 0 auto 10upx;
+	text-align: center;
+	font-size: 40upx;
+}
+
+.cu-bar.tabbar .action .cuIcon-cu-image {
+	margin: 0 auto;
+}
+
+.cu-bar.tabbar .action .cuIcon-cu-image image {
+	width: 50upx;
+	height: 50upx;
+	display: inline-block;
+}
+
+.cu-bar.tabbar .submit {
+	align-items: center;
+	display: flex;
+	justify-content: center;
+	text-align: center;
+	position: relative;
+	flex: 2;
+	align-self: stretch;
+}
+
+.cu-bar.tabbar .submit:last-child {
+	flex: 2.6;
+}
+
+.cu-bar.tabbar .submit+.submit {
+	flex: 2;
+}
+
+.cu-bar.tabbar.border .action::before {
+	content: " ";
+	width: 200%;
+	height: 200%;
+	position: absolute;
+	top: 0;
+	left: 0;
+	transform: scale(0.5);
+	transform-origin: 0 0;
+	border-right: 1upx solid rgba(0, 0, 0, 0.1);
+	z-index: 3;
+}
+
+.cu-bar.tabbar.border .action:last-child:before {
+	display: none;
+}
+
+.cu-bar.input {
+	padding-right: 20upx;
+	background-color: #ffffff;
+}
+
+.cu-bar.input input {
+	overflow: initial;
+	line-height: 64upx;
+	height: 64upx;
+	min-height: 64upx;
+	flex: 1;
+	font-size: 30upx;
+	margin: 0 20upx;
+}
+
+.cu-bar.input .action {
+	margin-left: 20upx;
+}
+
+.cu-bar.input .action [class*="cuIcon-"] {
+	font-size: 48upx;
+}
+
+.cu-bar.input input+.action {
+	margin-right: 20upx;
+	margin-left: 0upx;
+}
+
+.cu-bar.input .action:first-child [class*="cuIcon-"] {
+	margin-left: 0upx;
+}
+
+.cu-custom {
+	display: block;
+	position: relative;
+}
+
+.cu-custom .cu-bar .content {
+	width: calc(100% - 440upx);
+}
+
+/* #ifdef MP-ALIPAY */
+.cu-custom .cu-bar .action .cuIcon-back {
+	opacity: 0;
+}
+
+/* #endif */
+
+.cu-custom .cu-bar .content image {
+	height: 60upx;
+	width: 240upx;
+}
+
+.cu-custom .cu-bar {
+	min-height: 0px;
+	/* #ifdef MP-WEIXIN */
+	padding-right: 220upx;
+	/* #endif */
+	/* #ifdef MP-ALIPAY */
+	padding-right: 150upx;
+	/* #endif */
+	box-shadow: 0upx 0upx 0upx;
+	z-index: 9999;
+}
+
+.cu-custom .cu-bar .border-custom {
+	position: relative;
+	background: rgba(0, 0, 0, 0.15);
+	border-radius: 1000upx;
+	height: 30px;
+}
+
+.cu-custom .cu-bar .border-custom::after {
+	content: " ";
+	width: 200%;
+	height: 200%;
+	position: absolute;
+	top: 0;
+	left: 0;
+	border-radius: inherit;
+	transform: scale(0.5);
+	transform-origin: 0 0;
+	pointer-events: none;
+	box-sizing: border-box;
+	border: 1upx solid #ffffff;
+	opacity: 0.5;
+}
+
+.cu-custom .cu-bar .border-custom::before {
+	content: " ";
+	width: 1upx;
+	height: 110%;
+	position: absolute;
+	top: 22.5%;
+	left: 0;
+	right: 0;
+	margin: auto;
+	transform: scale(0.5);
+	transform-origin: 0 0;
+	pointer-events: none;
+	box-sizing: border-box;
+	opacity: 0.6;
+	background-color: #ffffff;
+}
+
+.cu-custom .cu-bar .border-custom text {
+	display: block;
+	flex: 1;
+	margin: auto !important;
+	text-align: center;
+	font-size: 34upx;
+}
+
+/* ==================
+         导航栏
+ ==================== */
+
+.nav {
+	white-space: nowrap;
+}
+
+::-webkit-scrollbar {
+	display: none;
+}
+
+.nav .cu-item {
+	height: 90upx;
+	display: inline-block;
+	line-height: 90upx;
+	margin: 0 10upx;
+	padding: 0 20upx;
+}
+
+.nav .cu-item.cur {
+	border-bottom: 4upx solid;
+}
+
+/* ==================
+         时间轴
+ ==================== */
+
+.cu-timeline {
+	display: block;
+	background-color: #ffffff;
+}
+
+.cu-timeline .cu-time {
+	width: 120upx;
+	text-align: center;
+	padding: 20upx 0;
+	font-size: 26upx;
+	color: #888;
+	display: block;
+}
+
+.cu-timeline>.cu-item {
+	padding: 30upx 30upx 30upx 120upx;
+	position: relative;
+	display: block;
+	z-index: 0;
+}
+
+.cu-timeline>.cu-item:not([class*="text-"]) {
+	color: #ccc;
+}
+
+.cu-timeline>.cu-item::after {
+	content: "";
+	display: block;
+	position: absolute;
+	width: 1upx;
+	background-color: #ddd;
+	left: 60upx;
+	height: 100%;
+	top: 0;
+	z-index: 8;
+}
+
+.cu-timeline>.cu-item::before {
+	font-family: "cuIcon";
+	display: block;
+	position: absolute;
+	top: 36upx;
+	z-index: 9;
+	background-color: #ffffff;
+	width: 50upx;
+	height: 50upx;
+	text-align: center;
+	border: none;
+	line-height: 50upx;
+	left: 36upx;
+}
+
+.cu-timeline>.cu-item:not([class*="cuIcon-"])::before {
+	content: "\e763";
+}
+
+.cu-timeline>.cu-item[class*="cuIcon-"]::before {
+	background-color: #ffffff;
+	width: 50upx;
+	height: 50upx;
+	text-align: center;
+	border: none;
+	line-height: 50upx;
+	left: 36upx;
+}
+
+.cu-timeline>.cu-item>.content {
+	padding: 30upx;
+	border-radius: 6upx;
+	display: block;
+	line-height: 1.6;
+}
+
+.cu-timeline>.cu-item>.content:not([class*="bg-"]) {
+	background-color: #f1f1f1;
+	color: #333333;
+}
+
+.cu-timeline>.cu-item>.content+.content {
+	margin-top: 20upx;
+}
+
+/* ==================
+         聊天
+ ==================== */
+
+.cu-chat {
+	display: flex;
+	flex-direction: column;
+}
+
+.cu-chat .cu-item {
+	display: flex;
+	padding: 30upx 30upx 70upx;
+	position: relative;
+}
+
+.cu-chat .cu-item>.cu-avatar {
+	width: 80upx;
+	height: 80upx;
+}
+
+.cu-chat .cu-item>.main {
+	max-width: calc(100% - 260upx);
+	margin: 0 40upx;
+	display: flex;
+	align-items: center;
+}
+
+.cu-chat .cu-item>image {
+	height: 320upx;
+}
+
+.cu-chat .cu-item>.main .content {
+	padding: 20upx;
+	border-radius: 6upx;
+	display: inline-flex;
+	max-width: 100%;
+	align-items: center;
+	font-size: 30upx;
+	position: relative;
+	min-height: 80upx;
+	line-height: 40upx;
+	text-align: left;
+}
+
+.cu-chat .cu-item>.main .content:not([class*="bg-"]) {
+	background-color: #ffffff;
+	color: #333333;
+}
+
+.cu-chat .cu-item .date {
+	position: absolute;
+	font-size: 24upx;
+	color: #8799a3;
+	width: calc(100% - 320upx);
+	bottom: 20upx;
+	left: 160upx;
+}
+
+.cu-chat .cu-item .action {
+	padding: 0 30upx;
+	display: flex;
+	align-items: center;
+}
+
+.cu-chat .cu-item>.main .content::after {
+	content: "";
+	top: 27upx;
+	transform: rotate(45deg);
+	position: absolute;
+	z-index: 100;
+	display: inline-block;
+	overflow: hidden;
+	width: 24upx;
+	height: 24upx;
+	left: -12upx;
+	right: initial;
+	background-color: inherit;
+}
+
+.cu-chat .cu-item.self>.main .content::after {
+	left: auto;
+	right: -12upx;
+}
+
+.cu-chat .cu-item>.main .content::before {
+	content: "";
+	top: 30upx;
+	transform: rotate(45deg);
+	position: absolute;
+	z-index: -1;
+	display: inline-block;
+	overflow: hidden;
+	width: 24upx;
+	height: 24upx;
+	left: -12upx;
+	right: initial;
+	background-color: inherit;
+	filter: blur(5upx);
+	opacity: 0.3;
+}
+
+.cu-chat .cu-item>.main .content:not([class*="bg-"])::before {
+	background-color: #333333;
+	opacity: 0.1;
+}
+
+.cu-chat .cu-item.self>.main .content::before {
+	left: auto;
+	right: -12upx;
+}
+
+.cu-chat .cu-item.self {
+	justify-content: flex-end;
+	text-align: right;
+}
+
+.cu-chat .cu-info {
+	display: inline-block;
+	margin: 20upx auto;
+	font-size: 24upx;
+	padding: 8upx 12upx;
+	background-color: rgba(0, 0, 0, 0.2);
+	border-radius: 6upx;
+	color: #ffffff;
+	max-width: 400upx;
+	line-height: 1.4;
+}
+
+/* ==================
+         卡片
+ ==================== */
+
+.cu-card {
+	display: block;
+	overflow: hidden;
+}
+
+.cu-card>.cu-item {
+	display: block;
+	background-color: #ffffff;
+	overflow: hidden;
+	border-radius: 10upx;
+	margin: 30upx;
+}
+
+.cu-card>.cu-item.shadow-blur {
+	overflow: initial;
+}
+
+.cu-card.no-card>.cu-item {
+	margin: 0upx;
+	border-radius: 0upx;
+}
+
+.cu-card .grid.grid-square {
+	margin-bottom: -20upx;
+}
+
+.cu-card.case .image {
+	position: relative;
+}
+
+.cu-card.case .image image {
+	width: 100%;
+}
+
+.cu-card.case .image .cu-tag {
+	position: absolute;
+	right: 0;
+	top: 0;
+}
+
+.cu-card.case .image .cu-bar {
+	position: absolute;
+	bottom: 0;
+	width: 100%;
+	background-color: transparent;
+	padding: 0upx 30upx;
+}
+
+.cu-card.case.no-card .image {
+	margin: 30upx 30upx 0;
+	overflow: hidden;
+	border-radius: 10upx;
+}
+
+.cu-card.dynamic {
+	display: block;
+}
+
+.cu-card.dynamic>.cu-item {
+	display: block;
+	background-color: #ffffff;
+	overflow: hidden;
+}
+
+.cu-card.dynamic>.cu-item>.text-content {
+	padding: 0 30upx 0;
+	max-height: 6.4em;
+	overflow: hidden;
+	font-size: 30upx;
+	margin-bottom: 20upx;
+}
+
+.cu-card.dynamic>.cu-item .square-img {
+	width: 100%;
+	height: 200upx;
+	border-radius: 6upx;
+}
+
+.cu-card.dynamic>.cu-item .only-img {
+	width: 100%;
+	height: 320upx;
+	border-radius: 6upx;
+}
+
+/* card.dynamic>.cu-item .comment {
+  padding: 20upx;
+  background-color: #f1f1f1;
+  margin: 0 30upx 30upx;
+  border-radius: 6upx;
+} */
+
+.cu-card.article {
+	display: block;
+}
+
+.cu-card.article>.cu-item {
+	padding-bottom: 30upx;
+}
+
+.cu-card.article>.cu-item .title {
+	font-size: 30upx;
+	font-weight: 900;
+	color: #333333;
+	line-height: 100upx;
+	padding: 0 30upx;
+}
+
+.cu-card.article>.cu-item .content {
+	display: flex;
+	padding: 0 30upx;
+}
+
+.cu-card.article>.cu-item .content>image {
+	width: 240upx;
+	height: 6.4em;
+	margin-right: 20upx;
+	border-radius: 6upx;
+}
+
+.cu-card.article>.cu-item .content .desc {
+	flex: 1;
+	display: flex;
+	flex-direction: column;
+	justify-content: space-between;
+}
+
+.cu-card.article>.cu-item .content .text-content {
+	font-size: 28upx;
+	color: #888;
+	height: 4.8em;
+	overflow: hidden;
+}
+
+/* ==================
+         表单
+ ==================== */
+
+.cu-form-group {
+	background-color: #ffffff;
+	padding: 1upx 30upx;
+	display: flex;
+	align-items: center;
+	min-height: 100upx;
+	justify-content: space-between;
+}
+
+.cu-form-group+.cu-form-group {
+	border-top: 1upx solid #eee;
+}
+
+.cu-form-group .title {
+	text-align: justify;
+	padding-right: 30upx;
+	font-size: 30upx;
+	position: relative;
+	height: 60upx;
+	line-height: 60upx;
+}
+
+.cu-form-group input {
+	flex: 1;
+	font-size: 30upx;
+	color: #555;
+	padding-right: 20upx;
+}
+
+.cu-form-group>text[class*="cuIcon-"] {
+	font-size: 36upx;
+	padding: 0;
+	box-sizing: border-box;
+}
+
+.cu-form-group textarea {
+	margin: 32upx 0 30upx;
+	height: 4.6em;
+	width: 100%;
+	line-height: 1.2em;
+	flex: 1;
+	font-size: 28upx;
+	padding: 0;
+}
+
+.cu-form-group.align-start .title {
+	height: 1em;
+	margin-top: 32upx;
+	line-height: 1em;
+}
+
+.cu-form-group picker {
+	flex: 1;
+	padding-right: 40upx;
+	overflow: hidden;
+	position: relative;
+}
+
+.cu-form-group picker .picker {
+	line-height: 100upx;
+	font-size: 28upx;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+	overflow: hidden;
+	width: 100%;
+	text-align: right;
+}
+
+.cu-form-group picker::after {
+	font-family: cuIcon;
+	display: block;
+	content: "\e6a3";
+	position: absolute;
+	font-size: 34upx;
+	color: #8799a3;
+	line-height: 100upx;
+	width: 60upx;
+	text-align: center;
+	top: 0;
+	bottom: 0;
+	right: -20upx;
+	margin: auto;
+}
+
+.cu-form-group textarea[disabled],
+.cu-form-group textarea[disabled] .placeholder {
+	color: transparent;
+}
+
+/* ==================
+         模态窗口
+ ==================== */
+
+.cu-modal {
+	position: fixed;
+	top: 0;
+	right: 0;
+	bottom: 0;
+	left: 0;
+	z-index: 1110;
+	opacity: 0;
+	outline: 0;
+	text-align: center;
+	-ms-transform: scale(1.185);
+	transform: scale(1.185);
+	backface-visibility: hidden;
+	perspective: 2000upx;
+	background: rgba(0, 0, 0, 0.6);
+	transition: all 0.3s ease-in-out 0s;
+	pointer-events: none;
+}
+
+.cu-modal::before {
+	content: "\200B";
+	display: inline-block;
+	height: 100%;
+	vertical-align: middle;
+}
+
+.cu-modal.show {
+	opacity: 1;
+	transition-duration: 0.3s;
+	-ms-transform: scale(1);
+	transform: scale(1);
+	overflow-x: hidden;
+	overflow-y: auto;
+	pointer-events: auto;
+}
+
+.cu-dialog {
+	position: relative;
+	display: inline-block;
+	vertical-align: middle;
+	margin-left: auto;
+	margin-right: auto;
+	width: 680upx;
+	max-width: 100%;
+	background-color: #f8f8f8;
+	border-radius: 10upx;
+	overflow: hidden;
+}
+
+.cu-modal.bottom-modal::before {
+	vertical-align: bottom;
+}
+
+.cu-modal.bottom-modal .cu-dialog {
+	width: 100%;
+	border-radius: 0;
+}
+
+.cu-modal.bottom-modal {
+	margin-bottom: -1000upx;
+}
+
+.cu-modal.bottom-modal.show {
+	margin-bottom: 0;
+}
+
+.cu-modal.drawer-modal {
+	transform: scale(1);
+	display: flex;
+}
+
+.cu-modal.drawer-modal .cu-dialog {
+	height: 100%;
+	min-width: 200upx;
+	border-radius: 0;
+	margin: initial;
+	transition-duration: 0.3s;
+}
+
+.cu-modal.drawer-modal.justify-start .cu-dialog {
+	transform: translateX(-100%);
+}
+
+.cu-modal.drawer-modal.justify-end .cu-dialog {
+	transform: translateX(100%);
+}
+
+.cu-modal.drawer-modal.show .cu-dialog {
+	transform: translateX(0%);
+}
+.cu-modal .cu-dialog>.cu-bar:first-child .action{
+  min-width: 100rpx;
+  margin-right: 0;
+  min-height: 100rpx;
+}
+/* ==================
+         轮播
+ ==================== */
+swiper .a-swiper-dot {
+	display: inline-block;
+	width: 16upx;
+	height: 16upx;
+	background: rgba(0, 0, 0, .3);
+	border-radius: 50%;
+	vertical-align: middle;
+}
+
+swiper[class*="-dot"] .wx-swiper-dots,
+swiper[class*="-dot"] .a-swiper-dots,
+swiper[class*="-dot"] .uni-swiper-dots {
+	display: flex;
+	align-items: center;
+	width: 100%;
+	justify-content: center;
+}
+
+swiper.square-dot .wx-swiper-dot,
+swiper.square-dot .a-swiper-dot,
+swiper.square-dot .uni-swiper-dot {
+	background-color: #ffffff;
+	opacity: 0.4;
+	width: 10upx;
+	height: 10upx;
+	border-radius: 20upx;
+	margin: 0 8upx !important;
+}
+
+swiper.square-dot .wx-swiper-dot.wx-swiper-dot-active,
+swiper.square-dot .a-swiper-dot.a-swiper-dot-active,
+swiper.square-dot .uni-swiper-dot.uni-swiper-dot-active {
+	opacity: 1;
+	width: 30upx;
+}
+
+swiper.round-dot .wx-swiper-dot,
+swiper.round-dot .a-swiper-dot,
+swiper.round-dot .uni-swiper-dot {
+	width: 10upx;
+	height: 10upx;
+	position: relative;
+	margin: 4upx 8upx !important;
+}
+
+swiper.round-dot .wx-swiper-dot.wx-swiper-dot-active::after,
+swiper.round-dot .a-swiper-dot.a-swiper-dot-active::after,
+swiper.round-dot .uni-swiper-dot.uni-swiper-dot-active::after {
+	content: "";
+	position: absolute;
+	width: 10upx;
+	height: 10upx;
+	top: 0upx;
+	left: 0upx;
+	right: 0;
+	bottom: 0;
+	margin: auto;
+	background-color: #ffffff;
+	border-radius: 20upx;
+}
+
+swiper.round-dot .wx-swiper-dot.wx-swiper-dot-active,
+swiper.round-dot .a-swiper-dot.a-swiper-dot-active,
+swiper.round-dot .uni-swiper-dot.uni-swiper-dot-active {
+	width: 18upx;
+	height: 18upx;
+}
+
+.screen-swiper {
+	min-height: 375upx;
+}
+
+.screen-swiper image,
+.screen-swiper video,
+.swiper-item image,
+.swiper-item video {
+	width: 100%;
+	display: block;
+	height: 100%;
+	margin: 0;
+	pointer-events: none;
+}
+
+.card-swiper {
+	height: 420upx !important;
+}
+
+.card-swiper swiper-item {
+	width: 610upx !important;
+	left: 70upx;
+	box-sizing: border-box;
+	padding: 40upx 0upx 70upx;
+	overflow: initial;
+}
+
+.card-swiper swiper-item .swiper-item {
+	width: 100%;
+	display: block;
+	height: 100%;
+	border-radius: 10upx;
+	transform: scale(0.9);
+	transition: all 0.2s ease-in 0s;
+	overflow: hidden;
+}
+
+.card-swiper swiper-item.cur .swiper-item {
+	transform: none;
+	transition: all 0.2s ease-in 0s;
+}
+
+
+.tower-swiper {
+	height: 420upx;
+	position: relative;
+	max-width: 750upx;
+	overflow: hidden;
+}
+
+.tower-swiper .tower-item {
+	position: absolute;
+	width: 300upx;
+	height: 380upx;
+	top: 0;
+	bottom: 0;
+	left: 50%;
+	margin: auto;
+	transition: all 0.2s ease-in 0s;
+	opacity: 1;
+}
+
+.tower-swiper .tower-item.none {
+	opacity: 0;
+}
+
+.tower-swiper .tower-item .swiper-item {
+	width: 100%;
+	height: 100%;
+	border-radius: 6upx;
+	overflow: hidden;
+}
+
+/* ==================
+          步骤条
+ ==================== */
+
+.cu-steps {
+	display: flex;
+}
+
+scroll-view.cu-steps {
+	display: block;
+	white-space: nowrap;
+}
+
+scroll-view.cu-steps .cu-item {
+	display: inline-block;
+}
+
+.cu-steps .cu-item {
+	flex: 1;
+	text-align: center;
+	position: relative;
+	min-width: 100upx;
+}
+
+.cu-steps .cu-item:not([class*="text-"]) {
+	color: #8799a3;
+}
+
+.cu-steps .cu-item [class*="cuIcon-"],
+.cu-steps .cu-item .num {
+	display: block;
+	font-size: 40upx;
+	line-height: 80upx;
+}
+
+.cu-steps .cu-item::before,
+.cu-steps .cu-item::after,
+.cu-steps.steps-arrow .cu-item::before,
+.cu-steps.steps-arrow .cu-item::after {
+	content: "";
+	display: block;
+	position: absolute;
+	height: 0px;
+	width: calc(100% - 80upx);
+	border-bottom: 1px solid #ccc;
+	left: calc(0px - (100% - 80upx) / 2);
+	top: 40upx;
+	z-index: 0;
+}
+
+.cu-steps.steps-arrow .cu-item::before,
+.cu-steps.steps-arrow .cu-item::after {
+	content: "\e6a3";
+	font-family: 'cuIcon';
+	height: 30upx;
+	border-bottom-width: 0px;
+	line-height: 30upx;
+	top: 0;
+	bottom: 0;
+	margin: auto;
+	color: #ccc;
+}
+
+.cu-steps.steps-bottom .cu-item::before,
+.cu-steps.steps-bottom .cu-item::after {
+	bottom: 40upx;
+	top: initial;
+}
+
+.cu-steps .cu-item::after {
+	border-bottom: 1px solid currentColor;
+	width: 0px;
+	transition: all 0.3s ease-in-out 0s;
+}
+
+.cu-steps .cu-item[class*="text-"]::after {
+	width: calc(100% - 80upx);
+	color: currentColor;
+}
+
+.cu-steps .cu-item:first-child::before,
+.cu-steps .cu-item:first-child::after {
+	display: none;
+}
+
+.cu-steps .cu-item .num {
+	width: 40upx;
+	height: 40upx;
+	border-radius: 50%;
+	line-height: 40upx;
+	margin: 20upx auto;
+	font-size: 24upx;
+	border: 1px solid currentColor;
+	position: relative;
+	overflow: hidden;
+}
+
+.cu-steps .cu-item[class*="text-"] .num {
+	background-color: currentColor;
+}
+
+.cu-steps .cu-item .num::before,
+.cu-steps .cu-item .num::after {
+	content: attr(data-index);
+	position: absolute;
+	left: 0;
+	right: 0;
+	top: 0;
+	bottom: 0;
+	margin: auto;
+	transition: all 0.3s ease-in-out 0s;
+	transform: translateY(0upx);
+}
+
+.cu-steps .cu-item[class*="text-"] .num::before {
+	transform: translateY(-40upx);
+	color: #ffffff;
+}
+
+.cu-steps .cu-item .num::after {
+	transform: translateY(40upx);
+	color: #ffffff;
+	transition: all 0.3s ease-in-out 0s;
+}
+
+.cu-steps .cu-item[class*="text-"] .num::after {
+	content: "\e645";
+	font-family: 'cuIcon';
+	color: #ffffff;
+	transform: translateY(0upx);
+}
+
+.cu-steps .cu-item[class*="text-"] .num.err::after {
+	content: "\e646";
+}
+
+/* ==================
+          布局
+ ==================== */
+
+/*  -- flex弹性布局 -- */
+
+.flex {
+	display: flex;
+}
+
+.basis-xs {
+	flex-basis: 20%;
+}
+
+.basis-sm {
+	flex-basis: 40%;
+}
+
+.basis-df {
+	flex-basis: 50%;
+}
+
+.basis-lg {
+	flex-basis: 60%;
+}
+
+.basis-xl {
+	flex-basis: 80%;
+}
+
+.flex-sub {
+	flex: 1;
+}
+
+.flex-twice {
+	flex: 2;
+}
+
+.flex-treble {
+	flex: 3;
+}
+
+.flex-direction {
+	flex-direction: column;
+}
+
+.flex-wrap {
+	flex-wrap: wrap;
+}
+
+.align-start {
+	align-items: flex-start;
+}
+
+.align-end {
+	align-items: flex-end;
+}
+
+.align-center {
+	align-items: center;
+}
+
+.align-stretch {
+	align-items: stretch;
+}
+
+.self-start {
+	align-self: flex-start;
+}
+
+.self-center {
+	align-self: flex-center;
+}
+
+.self-end {
+	align-self: flex-end;
+}
+
+.self-stretch {
+	align-self: stretch;
+}
+
+.align-stretch {
+	align-items: stretch;
+}
+
+.justify-start {
+	justify-content: flex-start;
+}
+
+.justify-end {
+	justify-content: flex-end;
+}
+
+.justify-center {
+	justify-content: center;
+}
+
+.justify-between {
+	justify-content: space-between;
+}
+
+.justify-around {
+	justify-content: space-around;
+}
+
+/* grid布局 */
+
+.grid {
+	display: flex;
+	flex-wrap: wrap;
+}
+
+.grid.grid-square {
+	overflow: hidden;
+}
+
+.grid.grid-square .cu-tag {
+	position: absolute;
+	right: 0;
+	top: 0;
+	border-bottom-left-radius: 6upx;
+	padding: 6upx 12upx;
+	height: auto;
+	background-color: rgba(0, 0, 0, 0.5);
+}
+
+.grid.grid-square>view>text[class*="cuIcon-"] {
+	font-size: 52upx;
+	position: absolute;
+	color: #8799a3;
+	margin: auto;
+	top: 0;
+	bottom: 0;
+	left: 0;
+	right: 0;
+	display: flex;
+	justify-content: center;
+	align-items: center;
+	flex-direction: column;
+}
+
+.grid.grid-square>view {
+	margin-right: 20upx;
+	margin-bottom: 20upx;
+	border-radius: 6upx;
+	position: relative;
+	overflow: hidden;
+}
+.grid.grid-square>view.bg-img image {
+	width: 100%;
+	height: 100%;
+	position: absolute;
+}
+.grid.col-1.grid-square>view {
+	padding-bottom: 100%;
+	height: 0;
+	margin-right: 0;
+}
+
+.grid.col-2.grid-square>view {
+	padding-bottom: calc((100% - 20upx)/2);
+	height: 0;
+	width: calc((100% - 20upx)/2);
+}
+
+.grid.col-3.grid-square>view {
+	padding-bottom: calc((100% - 40upx)/3);
+	height: 0;
+	width: calc((100% - 40upx)/3);
+}
+
+.grid.col-4.grid-square>view {
+	padding-bottom: calc((100% - 60upx)/4);
+	height: 0;
+	width: calc((100% - 60upx)/4);
+}
+
+.grid.col-5.grid-square>view {
+	padding-bottom: calc((100% - 80upx)/5);
+	height: 0;
+	width: calc((100% - 80upx)/5);
+}
+
+.grid.col-2.grid-square>view:nth-child(2n),
+.grid.col-3.grid-square>view:nth-child(3n),
+.grid.col-4.grid-square>view:nth-child(4n),
+.grid.col-5.grid-square>view:nth-child(5n) {
+	margin-right: 0;
+}
+
+.grid.col-1>view {
+	width: 100%;
+}
+
+.grid.col-2>view {
+	width: 50%;
+}
+
+.grid.col-3>view {
+	width: 33.33%;
+}
+
+.grid.col-4>view {
+	width: 25%;
+}
+
+.grid.col-5>view {
+	width: 20%;
+}
+
+/*  -- 内外边距 -- */
+
+.margin-0 {
+	margin: 0;
+}
+
+.margin-xs {
+	margin: 10upx;
+}
+
+.margin-sm {
+	margin: 20upx;
+}
+
+.margin {
+	margin: 30upx;
+}
+
+.margin-lg {
+	margin: 40upx;
+}
+
+.margin-xl {
+	margin: 50upx;
+}
+
+.margin-top-xs {
+	margin-top: 10upx;
+}
+
+.margin-top-sm {
+	margin-top: 20upx;
+}
+
+.margin-top {
+	margin-top: 30upx;
+}
+
+.margin-top-lg {
+	margin-top: 40upx;
+}
+
+.margin-top-xl {
+	margin-top: 50upx;
+}
+
+.margin-right-xs {
+	margin-right: 10upx;
+}
+
+.margin-right-sm {
+	margin-right: 20upx;
+}
+
+.margin-right {
+	margin-right: 30upx;
+}
+
+.margin-right-lg {
+	margin-right: 40upx;
+}
+
+.margin-right-xl {
+	margin-right: 50upx;
+}
+
+.margin-bottom-xs {
+	margin-bottom: 10upx;
+}
+
+.margin-bottom-sm {
+	margin-bottom: 20upx;
+}
+
+.margin-bottom {
+	margin-bottom: 30upx;
+}
+
+.margin-bottom-lg {
+	margin-bottom: 40upx;
+}
+
+.margin-bottom-xl {
+	margin-bottom: 50upx;
+}
+
+.margin-left-xs {
+	margin-left: 10upx;
+}
+
+.margin-left-sm {
+	margin-left: 20upx;
+}
+
+.margin-left {
+	margin-left: 30upx;
+}
+
+.margin-left-lg {
+	margin-left: 40upx;
+}
+
+.margin-left-xl {
+	margin-left: 50upx;
+}
+
+.margin-lr-xs {
+	margin-left: 10upx;
+	margin-right: 10upx;
+}
+
+.margin-lr-sm {
+	margin-left: 20upx;
+	margin-right: 20upx;
+}
+
+.margin-lr {
+	margin-left: 30upx;
+	margin-right: 30upx;
+}
+
+.margin-lr-lg {
+	margin-left: 40upx;
+	margin-right: 40upx;
+}
+
+.margin-lr-xl {
+	margin-left: 50upx;
+	margin-right: 50upx;
+}
+
+.margin-tb-xs {
+	margin-top: 10upx;
+	margin-bottom: 10upx;
+}
+
+.margin-tb-sm {
+	margin-top: 20upx;
+	margin-bottom: 20upx;
+}
+
+.margin-tb {
+	margin-top: 30upx;
+	margin-bottom: 30upx;
+}
+
+.margin-tb-lg {
+	margin-top: 40upx;
+	margin-bottom: 40upx;
+}
+
+.margin-tb-xl {
+	margin-top: 50upx;
+	margin-bottom: 50upx;
+}
+
+.padding-0 {
+	padding: 0;
+}
+
+.padding-xs {
+	padding: 10upx;
+}
+
+.padding-sm {
+	padding: 20upx;
+}
+
+.padding {
+	padding: 30upx;
+}
+
+.padding-lg {
+	padding: 40upx;
+}
+
+.padding-xl {
+	padding: 50upx;
+}
+
+.padding-top-xs {
+	padding-top: 10upx;
+}
+
+.padding-top-sm {
+	padding-top: 20upx;
+}
+
+.padding-top {
+	padding-top: 30upx;
+}
+
+.padding-top-lg {
+	padding-top: 40upx;
+}
+
+.padding-top-xl {
+	padding-top: 50upx;
+}
+
+.padding-right-xs {
+	padding-right: 10upx;
+}
+
+.padding-right-sm {
+	padding-right: 20upx;
+}
+
+.padding-right {
+	padding-right: 30upx;
+}
+
+.padding-right-lg {
+	padding-right: 40upx;
+}
+
+.padding-right-xl {
+	padding-right: 50upx;
+}
+
+.padding-bottom-xs {
+	padding-bottom: 10upx;
+}
+
+.padding-bottom-sm {
+	padding-bottom: 20upx;
+}
+
+.padding-bottom {
+	padding-bottom: 30upx;
+}
+
+.padding-bottom-lg {
+	padding-bottom: 40upx;
+}
+
+.padding-bottom-xl {
+	padding-bottom: 50upx;
+}
+
+.padding-left-xs {
+	padding-left: 10upx;
+}
+
+.padding-left-sm {
+	padding-left: 20upx;
+}
+
+.padding-left {
+	padding-left: 30upx;
+}
+
+.padding-left-lg {
+	padding-left: 40upx;
+}
+
+.padding-left-xl {
+	padding-left: 50upx;
+}
+
+.padding-lr-xs {
+	padding-left: 10upx;
+	padding-right: 10upx;
+}
+
+.padding-lr-sm {
+	padding-left: 20upx;
+	padding-right: 20upx;
+}
+
+.padding-lr {
+	padding-left: 30upx;
+	padding-right: 30upx;
+}
+
+.padding-lr-lg {
+	padding-left: 40upx;
+	padding-right: 40upx;
+}
+
+.padding-lr-xl {
+	padding-left: 50upx;
+	padding-right: 50upx;
+}
+
+.padding-tb-xs {
+	padding-top: 10upx;
+	padding-bottom: 10upx;
+}
+
+.padding-tb-sm {
+	padding-top: 20upx;
+	padding-bottom: 20upx;
+}
+
+.padding-tb {
+	padding-top: 30upx;
+	padding-bottom: 30upx;
+}
+
+.padding-tb-lg {
+	padding-top: 40upx;
+	padding-bottom: 40upx;
+}
+
+.padding-tb-xl {
+	padding-top: 50upx;
+	padding-bottom: 50upx;
+}
+
+/* -- 浮动 --  */
+
+.cf::after,
+.cf::before {
+	content: " ";
+	display: table;
+}
+
+.cf::after {
+	clear: both;
+}
+
+.fl {
+	float: left;
+}
+
+.fr {
+	float: right;
+}
+
+/* ==================
+          背景
+ ==================== */
+
+.line-red::after,
+.lines-red::after {
+	border-color: #e54d42;
+}
+
+.line-orange::after,
+.lines-orange::after {
+	border-color: #f37b1d;
+}
+
+.line-yellow::after,
+.lines-yellow::after {
+	border-color: #fbbd08;
+}
+
+.line-olive::after,
+.lines-olive::after {
+	border-color: #8dc63f;
+}
+
+.line-green::after,
+.lines-green::after {
+	border-color: #39b54a;
+}
+
+.line-cyan::after,
+.lines-cyan::after {
+	border-color: #1cbbb4;
+}
+
+.line-blue::after,
+.lines-blue::after {
+	border-color: #0081ff;
+}
+
+.line-purple::after,
+.lines-purple::after {
+	border-color: #6739b6;
+}
+
+.line-mauve::after,
+.lines-mauve::after {
+	border-color: #9c26b0;
+}
+
+.line-pink::after,
+.lines-pink::after {
+	border-color: #e03997;
+}
+
+.line-brown::after,
+.lines-brown::after {
+	border-color: #a5673f;
+}
+
+.line-grey::after,
+.lines-grey::after {
+	border-color: #8799a3;
+}
+
+.line-gray::after,
+.lines-gray::after {
+	border-color: #aaaaaa;
+}
+
+.line-black::after,
+.lines-black::after {
+	border-color: #333333;
+}
+
+.line-white::after,
+.lines-white::after {
+	border-color: #ffffff;
+}
+
+.bg-red {
+	background-color: #e54d42;
+	color: #ffffff;
+}
+
+.bg-orange {
+	background-color: #f37b1d;
+	color: #ffffff;
+}
+
+.bg-yellow {
+	background-color: #fbbd08;
+	color: #333333;
+}
+
+.bg-olive {
+	background-color: #8dc63f;
+	color: #ffffff;
+}
+
+.bg-green {
+	background-color: #39b54a;
+	color: #ffffff;
+}
+
+.bg-cyan {
+	background-color: #1cbbb4;
+	color: #ffffff;
+}
+
+.bg-blue {
+	background-color: #0081ff;
+	color: #ffffff;
+}
+
+.bg-purple {
+	background-color: #6739b6;
+	color: #ffffff;
+}
+
+.bg-mauve {
+	background-color: #9c26b0;
+	color: #ffffff;
+}
+
+.bg-pink {
+	background-color: #e03997;
+	color: #ffffff;
+}
+
+.bg-brown {
+	background-color: #a5673f;
+	color: #ffffff;
+}
+
+.bg-grey {
+	background-color: #8799a3;
+	color: #ffffff;
+}
+
+.bg-gray {
+	background-color: #f0f0f0;
+	color: #333333;
+}
+
+.bg-black {
+	background-color: #333333;
+	color: #ffffff;
+}
+
+.bg-white {
+	background-color: #ffffff;
+	color: #666666;
+}
+
+.bg-shadeTop {
+	background-image: linear-gradient(rgba(0, 0, 0, 1), rgba(0, 0, 0, 0.01));
+	color: #ffffff;
+}
+
+.bg-shadeBottom {
+	background-image: linear-gradient(rgba(0, 0, 0, 0.01), rgba(0, 0, 0, 1));
+	color: #ffffff;
+}
+
+.bg-red.light {
+	color: #e54d42;
+	background-color: #fadbd9;
+}
+
+.bg-orange.light {
+	color: #f37b1d;
+	background-color: #fde6d2;
+}
+
+.bg-yellow.light {
+	color: #fbbd08;
+	background-color: #fef2ced2;
+}
+
+.bg-olive.light {
+	color: #8dc63f;
+	background-color: #e8f4d9;
+}
+
+.bg-green.light {
+	color: #39b54a;
+	background-color: #d7f0dbff;
+}
+
+.bg-cyan.light {
+	color: #1cbbb4;
+	background-color: #d2f1f0;
+}
+
+.bg-blue.light {
+	color: #0081ff;
+	background-color: #cce6ff;
+}
+
+.bg-purple.light {
+	color: #6739b6;
+	background-color: #e1d7f0;
+}
+
+.bg-mauve.light {
+	color: #9c26b0;
+	background-color: #ebd4ef;
+}
+
+.bg-pink.light {
+	color: #e03997;
+	background-color: #f9d7ea;
+}
+
+.bg-brown.light {
+	color: #a5673f;
+	background-color: #ede1d9;
+}
+
+.bg-grey.light {
+	color: #8799a3;
+	background-color: #e7ebed;
+}
+
+.bg-gradual-red {
+	background-image: linear-gradient(45deg, #f43f3b, #ec008c);
+	color: #ffffff;
+}
+
+.bg-gradual-black {
+	background-image: linear-gradient(45deg, #26272f, #414244);
+	color: #f7ebd2;
+}
+
+.bg-gradual-orange {
+	background-image: linear-gradient(45deg, #ff9700, #ed1c24);
+	color: #ffffff;
+}
+
+.bg-gradual-green {
+	background-image: linear-gradient(45deg, #39b54a, #8dc63f);
+	color: #ffffff;
+}
+
+.bg-gradual-purple {
+	background-image: linear-gradient(45deg, #9000ff, #5e00ff);
+	color: #ffffff;
+}
+
+.bg-gradual-pink {
+	background-image: linear-gradient(45deg, #ec008c, #6739b6);
+	color: #ffffff;
+}
+
+.bg-gradual-blue {
+	background-image: linear-gradient(45deg, #0081ff, #1cbbb4);
+	color: #ffffff;
+}
+
+.shadow[class*="-red"] {
+	box-shadow: 6upx 6upx 8upx rgba(204, 69, 59, 0.2);
+}
+
+.shadow[class*="-orange"] {
+	box-shadow: 6upx 6upx 8upx rgba(217, 109, 26, 0.2);
+}
+
+.shadow[class*="-yellow"] {
+	box-shadow: 6upx 6upx 8upx rgba(224, 170, 7, 0.2);
+}
+
+.shadow[class*="-olive"] {
+	box-shadow: 6upx 6upx 8upx rgba(124, 173, 55, 0.2);
+}
+
+.shadow[class*="-green"] {
+	box-shadow: 6upx 6upx 8upx rgba(48, 156, 63, 0.2);
+}
+
+.shadow[class*="-cyan"] {
+	box-shadow: 6upx 6upx 8upx rgba(28, 187, 180, 0.2);
+}
+
+.shadow[class*="-blue"] {
+	box-shadow: 6upx 6upx 8upx rgba(0, 102, 204, 0.2);
+}
+
+.shadow[class*="-purple"] {
+	box-shadow: 6upx 6upx 8upx rgba(88, 48, 156, 0.2);
+}
+
+.shadow[class*="-mauve"] {
+	box-shadow: 6upx 6upx 8upx rgba(133, 33, 150, 0.2);
+}
+
+.shadow[class*="-pink"] {
+	box-shadow: 6upx 6upx 8upx rgba(199, 50, 134, 0.2);
+}
+
+.shadow[class*="-brown"] {
+	box-shadow: 6upx 6upx 8upx rgba(140, 88, 53, 0.2);
+}
+
+.shadow[class*="-grey"] {
+	box-shadow: 6upx 6upx 8upx rgba(114, 130, 138, 0.2);
+}
+
+.shadow[class*="-gray"] {
+	box-shadow: 6upx 6upx 8upx rgba(114, 130, 138, 0.2);
+}
+
+.shadow[class*="-black"] {
+	box-shadow: 6upx 6upx 8upx rgba(26, 26, 26, 0.2);
+}
+
+.shadow[class*="-white"] {
+	box-shadow: 6upx 6upx 8upx rgba(26, 26, 26, 0.2);
+}
+
+.text-shadow[class*="-red"] {
+	text-shadow: 6upx 6upx 8upx rgba(204, 69, 59, 0.2);
+}
+
+.text-shadow[class*="-orange"] {
+	text-shadow: 6upx 6upx 8upx rgba(217, 109, 26, 0.2);
+}
+
+.text-shadow[class*="-yellow"] {
+	text-shadow: 6upx 6upx 8upx rgba(224, 170, 7, 0.2);
+}
+
+.text-shadow[class*="-olive"] {
+	text-shadow: 6upx 6upx 8upx rgba(124, 173, 55, 0.2);
+}
+
+.text-shadow[class*="-green"] {
+	text-shadow: 6upx 6upx 8upx rgba(48, 156, 63, 0.2);
+}
+
+.text-shadow[class*="-cyan"] {
+	text-shadow: 6upx 6upx 8upx rgba(28, 187, 180, 0.2);
+}
+
+.text-shadow[class*="-blue"] {
+	text-shadow: 6upx 6upx 8upx rgba(0, 102, 204, 0.2);
+}
+
+.text-shadow[class*="-purple"] {
+	text-shadow: 6upx 6upx 8upx rgba(88, 48, 156, 0.2);
+}
+
+.text-shadow[class*="-mauve"] {
+	text-shadow: 6upx 6upx 8upx rgba(133, 33, 150, 0.2);
+}
+
+.text-shadow[class*="-pink"] {
+	text-shadow: 6upx 6upx 8upx rgba(199, 50, 134, 0.2);
+}
+
+.text-shadow[class*="-brown"] {
+	text-shadow: 6upx 6upx 8upx rgba(140, 88, 53, 0.2);
+}
+
+.text-shadow[class*="-grey"] {
+	text-shadow: 6upx 6upx 8upx rgba(114, 130, 138, 0.2);
+}
+
+.text-shadow[class*="-gray"] {
+	text-shadow: 6upx 6upx 8upx rgba(114, 130, 138, 0.2);
+}
+
+.text-shadow[class*="-black"] {
+	text-shadow: 6upx 6upx 8upx rgba(26, 26, 26, 0.2);
+}
+
+.bg-img {
+	background-size: cover;
+	background-position: center;
+	background-repeat: no-repeat;
+}
+
+.bg-mask {
+	background-color: #333333;
+	position: relative;
+}
+
+.bg-mask::after {
+	content: "";
+	border-radius: inherit;
+	width: 100%;
+	height: 100%;
+	display: block;
+	background-color: rgba(0, 0, 0, 0.4);
+	position: absolute;
+	left: 0;
+	right: 0;
+	bottom: 0;
+	top: 0;
+}
+
+.bg-mask view,
+.bg-mask cover-view {
+	z-index: 5;
+	position: relative;
+}
+
+.bg-video {
+	position: relative;
+}
+
+.bg-video video {
+	display: block;
+	height: 100%;
+	width: 100%;
+	-o-object-fit: cover;
+	object-fit: cover;
+	position: absolute;
+	top: 0;
+	z-index: 0;
+	pointer-events: none;
+}
+
+/* ==================
+          文本
+ ==================== */
+
+.text-xs {
+	font-size: 20upx;
+}
+
+.text-sm {
+	font-size: 24upx;
+}
+
+.text-df {
+	font-size: 28upx;
+}
+
+.text-lg {
+	font-size: 32upx;
+}
+
+.text-xl {
+	font-size: 36upx;
+}
+
+.text-xxl {
+	font-size: 44upx;
+}
+
+.text-sl {
+	font-size: 80upx;
+}
+
+.text-xsl {
+	font-size: 120upx;
+}
+
+.text-Abc {
+	text-transform: Capitalize;
+}
+
+.text-ABC {
+	text-transform: Uppercase;
+}
+
+.text-abc {
+	text-transform: Lowercase;
+}
+
+.text-price::before {
+	content: "¥";
+	font-size: 80%;
+	margin-right: 4upx;
+}
+
+.text-cut {
+	text-overflow: ellipsis;
+	white-space: nowrap;
+	overflow: hidden;
+}
+
+.text-bold {
+	font-weight: bold;
+}
+
+.text-center {
+	text-align: center;
+}
+
+.text-content {
+	line-height: 1.6;
+}
+
+.text-left {
+	text-align: left;
+}
+
+.text-right {
+	text-align: right;
+}
+
+.text-red,
+.line-red,
+.lines-red {
+	color: #e54d42;
+}
+
+.text-orange,
+.line-orange,
+.lines-orange {
+	color: #f37b1d;
+}
+
+.text-yellow,
+.line-yellow,
+.lines-yellow {
+	color: #fbbd08;
+}
+
+.text-olive,
+.line-olive,
+.lines-olive {
+	color: #8dc63f;
+}
+
+.text-green,
+.line-green,
+.lines-green {
+	color: #39b54a;
+}
+
+.text-cyan,
+.line-cyan,
+.lines-cyan {
+	color: #1cbbb4;
+}
+
+.text-blue,
+.line-blue,
+.lines-blue {
+	color: #0081ff;
+}
+
+.text-purple,
+.line-purple,
+.lines-purple {
+	color: #6739b6;
+}
+
+.text-mauve,
+.line-mauve,
+.lines-mauve {
+	color: #9c26b0;
+}
+
+.text-pink,
+.line-pink,
+.lines-pink {
+	color: #e03997;
+}
+
+.text-brown,
+.line-brown,
+.lines-brown {
+	color: #a5673f;
+}
+
+.text-grey,
+.line-grey,
+.lines-grey {
+	color: #8799a3;
+}
+
+.text-gray,
+.line-gray,
+.lines-gray {
+	color: #aaaaaa;
+}
+
+.text-black,
+.line-black,
+.lines-black {
+	color: #333333;
+}
+
+.text-white,
+.line-white,
+.lines-white {
+	color: #ffffff;
+}

+ 13 - 0
assets/http/api.js

@@ -0,0 +1,13 @@
+import {http} from './service.js'
+
+let liveUrl={
+	page:'/blade-live-broadcast-type/livebroadcasttype/page'
+}
+
+const live = {
+	page:p => http.get(liveUrl.page, {params:p}),
+}
+
+export const api={
+	live
+}

+ 80 - 0
assets/http/service.js

@@ -0,0 +1,80 @@
+import Request from '../../utils/my-request/index.js'
+
+let tokenUrl="https://cms.gzhylwh.com/api/blade-auth/oauth/token?tenantId=000000&password=21232f297a57a5a743894a0e4a801fc3&username=admin"
+let baseURL='https://cms.gzhylwh.com/api'
+const getTokenStorage = () => {
+  let token = ''
+  try {
+    token = uni.getStorageSync('token')
+  } catch (e) {
+    //TODO handle the exception
+  }
+  return token
+}
+const http = new Request()
+http.setConfig((config) => { /* 设置全局配置 */
+  config.baseURL = baseURL  /* 根域名不同 */
+  config.header = {
+    ...config.header,
+  }
+  return config
+})
+http.interceptors.request.use((config) => { /* 请求之前拦截器。可以使用async await 做异步操作 */
+  config.header = {
+    ...config.header,
+    "Blade-Auth": getTokenStorage()
+  }
+  return config
+}, (config) => {
+  return Promise.reject(config)
+})
+// 是否正在刷新的标记
+let isRefreshing = false
+// 重试队列,每一项将是一个待执行的函数形式
+let requests = []
+http.interceptors.response.use(async (response) => { /* 请求之后拦截器。可以使用async await 做异步操作  */
+  //toekn过期处理 
+      if (response.data.code == 401) {
+          let {config} = response
+          if (!isRefreshing) {
+              isRefreshing = true
+              let token = uni.getStorageSync('token')
+              let [,res] = await uni.request({
+                  url: tokenUrl,
+                  method: 'POST',
+                  header:{
+                  	Authorization:"Basic d3hhcHA6d3hhcHBfc2Vja2V0"
+                  },
+              })
+              //否则保存新的token
+              token=res.data.token_type+" "+res.data.access_token
+              uni.setStorageSync('token', token)
+              requests.forEach(cb => cb())
+              // 重试完了清空这个队列
+              requests = []
+              isRefreshing = false
+              return http.request(config)
+          } else {
+              return new Promise((resolve) => {
+                  // 将resolve放进队列,用一个函数形式来保存,等token刷新后直接执行
+                  requests.push(() => {
+                      resolve(http.request(config))
+                  })
+              })
+          }
+      }
+      if (response.data.code != 200) { // 服务端返回的状态码不等于200,则reject()
+        return Promise.reject(response)
+      }
+      return response.data
+  }, (err) => { // 请求错误做点什么
+      uni.showToast({
+          icon: 'none',
+          position: 'bottom',
+          title: '网络异常'
+      })
+      return err
+  })
+export {
+  http
+}

+ 123 - 0
components/dt_custom_bar.vue

@@ -0,0 +1,123 @@
+<template>
+  <view>
+    <view :style="{ background: background }" class="custom-header-container">
+      <view :style="{height:getStausBarHeight + 'px'}" class="custom-header-status-bar"></view>
+      <view :class="{'ios-center': isIos }" class="custom-header-top-container">
+        <view :style="{color: color}" :class="{isIos: isIos}" class="custom-back-btn iconfont" v-if="showBack" @tap="backTap">
+			<image v-if="color!='#ffffff'" src="http://139.9.103.171:1888/img/image/ic_back_black.png" mode="widthFix" style="width: 20px;"></image>
+			<image v-if="color=='#ffffff'" src="http://139.9.103.171:1888/img/image/ic_back_white.png" mode="widthFix" style="width: 20px;"></image>
+		</view>
+        <view :style="{color: color}" :class="[{'ios-center': isIos },{'android-left-30':!isIos&&!showBack},{'android-left-80':!isIos&&showBack}]" class="custom-header-title" >{{ title }}</view></view>
+    </view>
+    <view :style="{ height: getStausBarHeight + (isIos ? 45 : 48) + 'px' }" class="custom-header-height"></view>
+  </view>
+</template>
+<script>
+export default {
+    props: {
+      title:{
+        type:String,
+		default:''
+	  },
+      background: {
+        type: String,
+		default:'transparent'
+      },
+      color: {
+        type: String,
+		default:'#ffffff'
+      },
+      showBack: {
+        type: Boolean,
+		default:false
+      },
+    },
+    computed: {
+      getStausBarHeight() {
+        try {
+          const res = uni.getSystemInfoSync();
+          return res.statusBarHeight;
+        } catch(e) {}
+      },
+      isIos() {
+        return uni.getSystemInfoSync().system.indexOf('iOS') > -1
+      }
+    },
+    methods: {
+      backTap() {
+		uni.navigateBack({
+			delta:1
+		})
+      }
+    }
+  }
+</script>
+<style scoped lang="scss">
+	.custom-header-top-container {
+		display:flex;
+		flex-flow:row nowrap;
+		justify-content:flex-start;
+		width:100%;
+		align-items:center;
+		&.ios-center {
+		 justify-content:center;
+	  }
+	}
+	.custom-header-container {
+		z-index:9;
+		width:750upx;
+		display:flex;
+		flex-direction:column;
+		align-items:center;
+		position:fixed;
+		top:0;
+	}
+	.custom-back-btn {
+		height:48px;
+		line-height:48px;
+		width:40px;
+		margin:0;
+		padding:0;
+		border-radius:0 !important;
+		display:flex;
+		align-items:center;
+		justify-content:center;
+		position:absolute;
+		left:0upx;
+		font-size:18px;
+		border-radius:5px;
+		font-weight:500;
+		color:#FFFFFF;
+		&:active {
+		 background:#0D72DF;
+	   }
+	  &.isIos {
+		line-height:45px;
+		height:45px;
+	 }
+	}
+	.custom-header-status-bar {
+		width:100%;
+		top:0;
+		position:sticky;
+		z-index:100;
+	}
+	.custom-header-title {
+		height:48px;
+		line-height:48px;
+		font-size:16px;
+		color:#FFFFFF;
+		&.ios-center {
+			margin-left: 0;
+			line-height:45px;
+			height:45px;
+		}
+		&.android-left-30{
+			margin-left: 30upx;
+		}
+		&.android-left-80{
+			margin-left: 80upx;
+		}
+			
+	}
+</style>

+ 69 - 0
components/hot-consult/hot-consult.vue

@@ -0,0 +1,69 @@
+<template>
+	<view>
+		<view class="container">
+			<view class="flex justify-between" >
+				<block>
+					<view class="cu-avatar text-font"  style="background-image:url(http://139.9.103.171:1888/miniofile/app/notice.png);"></view>
+					<view class="margin-top-xs" style="width: 680rpx">
+						<swiper :circular="true" class="swiper" autoplay="true" vertical="true" interval="5000" next-margin="46rpx">
+							<swiper-item v-for="(item, index) in swiperTexts" :key="index" @click="detailTap(item.id)">
+								<view class="swiper-item" > 
+									<text class="text-orange cuIcon-title padding-right-sm"></text>
+									<text>{{item.title}}</text>
+								</view>
+							</swiper-item>
+						</swiper>
+					</view>
+				</block>
+				<view class="flex align-center justify-center" style="width: 100rpx;" @click="onTap">
+					<text class="cuIcon-right"></text>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			swiperTexts: {
+				type: Array,
+				default: () => {
+					return []
+				}
+			},
+		},
+		methods: {
+			onTap() {
+				this.$emit('onTap');
+			},
+			detailTap(id) {
+				this.$emit('detailTap',id);
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+.container {
+	background-color: #ffffff;
+	height: 110rpx;
+}
+.swiper {
+	height: 90rpx;
+}
+.swiper-item {
+	font-size: 24rpx;
+	color: #323232;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+	overflow: hidden;
+	height: 40rpx; 
+	margin: 6rpx 0rpx;
+}
+.text-font {
+	width: 100rpx;
+	height: 100rpx;
+	margin: 10rpx 10rpx 10rpx 20rpx;
+}
+</style>

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 69 - 0
components/uploadimg/uploadImg.vue


+ 51 - 0
main.js

@@ -0,0 +1,51 @@
+import Vue from 'vue'
+import App from './App'
+
+import uView from 'uview-ui';
+Vue.use(uView);
+
+//封装api
+import { api } from 'assets/http/api.js' 
+Vue.prototype.$api = api
+
+//引入util.js
+import Util from 'utils/util.js'
+Vue.prototype.$util = Util
+
+//封装缓存
+import simpleCache from "@/utils/cache.js"
+Vue.prototype.$cache = simpleCache
+
+//封装判空函数
+Vue.prototype.$isEmpty=function(value){
+	switch (typeof value) {
+		case 'undefined':
+			return true;
+		case 'string':
+			if(value=='undefined') return true
+			if (value.replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '').length == 0) return true;
+			break;
+		case 'boolean':
+			if (!value) return true;
+			break;
+		case 'number':
+			if (0 === value || isNaN(value)) return true;
+			break;
+		case 'object':
+			if (null === value || value.length === 0) return true;
+			for (var i in value) {
+				return false;
+			}
+			return true;
+	}
+	return false;
+}
+
+Vue.config.productionTip = false
+
+App.mpType = 'app'
+
+const app = new Vue({
+    ...App
+})
+app.$mount()

+ 78 - 0
manifest.json

@@ -0,0 +1,78 @@
+{
+    "name" : "garden-wxapp",
+    "appid" : "__UNI__EB99808",
+    "description" : "",
+    "versionName" : "1.0.0",
+    "versionCode" : "100",
+    "transformPx" : false,
+    /* 5+App特有相关 */
+    "app-plus" : {
+        "usingComponents" : true,
+        "nvueCompiler" : "uni-app",
+        "compilerVersion" : 3,
+        "splashscreen" : {
+            "alwaysShowBeforeRender" : true,
+            "waiting" : true,
+            "autoclose" : true,
+            "delay" : 0
+        },
+        /* 模块配置 */
+        "modules" : {},
+        /* 应用发布信息 */
+        "distribute" : {
+            /* android打包配置 */
+            "android" : {
+                "permissions" : [
+                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
+                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
+                    "<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
+                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
+                    "<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
+                    "<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
+                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
+                ]
+            },
+            /* ios打包配置 */
+            "ios" : {},
+            /* SDK配置 */
+            "sdkConfigs" : {}
+        }
+    },
+    /* 快应用特有相关 */
+    "quickapp" : {},
+    /* 小程序特有相关 */
+    "mp-weixin" : {
+        "appid" : "wx4d345bcdef6d1c36",
+        "setting" : {
+            "urlCheck" : false
+        },
+        "usingComponents" : true
+    },
+    "mp-alipay" : {
+        "usingComponents" : true
+    },
+    "mp-baidu" : {
+        "usingComponents" : true
+    },
+    "mp-toutiao" : {
+        "usingComponents" : true
+    },
+    "uniStatistics" : {
+        "enable" : false
+    }
+}

+ 190 - 0
pages.json

@@ -0,0 +1,190 @@
+{
+	"easycom": {
+		"^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
+	},
+	"pages": [ 
+		{
+		    "path" : "pages/login/login",
+		    "style" :                                                                                    
+		    {
+		        "navigationBarTitleText": "登陆",
+		        "enablePullDownRefresh": false
+		    }
+		    
+		},
+		{
+			"path": "pages/index/index",
+			"style": {
+				"navigationStyle":"custom"
+			}
+		}
+	    ,{
+            "path" : "pages/news/news",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "园区动态",
+                "enablePullDownRefresh": false
+            }
+            
+        }
+        ,{
+            "path" : "pages/mine/mine",
+            "style" :                                                                                    
+            {
+				"navigationBarTitleText":"个人中心",
+                "enablePullDownRefresh": false
+            }
+            
+        }
+        
+        ,{
+            "path" : "pages/company/company",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "我的企业",
+                "enablePullDownRefresh": false
+            }
+            
+        }
+        ,{
+            "path" : "pages/auth/auth",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "认证信息",
+                "enablePullDownRefresh": false
+            }
+            
+        }
+        ,{
+            "path" : "pages/test/test",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "",
+                "enablePullDownRefresh": false
+            }
+            
+        }
+        ,{
+            "path" : "pages/test/test1",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "",
+                "enablePullDownRefresh": false
+            }
+            
+        }
+        ,{
+            "path" : "pages/mine/setting/setting",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "",
+                "enablePullDownRefresh": false
+            }
+            
+        }
+        ,{
+            "path" : "pages/mine/mine-info/mine-info",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "个人信息",
+                "enablePullDownRefresh": false
+            }
+            
+        }
+        ,{
+            "path" : "pages/news/detail",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "文章详情",
+                "enablePullDownRefresh": false
+            }
+            
+        }
+        ,{
+            "path" : "pages/my-camera/my-camera",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "",
+                "enablePullDownRefresh": false
+            }
+            
+        }
+        ,{
+            "path" : "pages/index/my-temperature/my-temperature",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "我的测温",
+                "enablePullDownRefresh": false
+            }
+            
+        }
+        ,{
+            "path" : "pages/index/my-temperature/deatil",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "测温详情",
+                "enablePullDownRefresh": false
+            }
+            
+        }
+        ,{
+            "path" : "pages/index/access-record/access-record",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "通行详情",
+                "enablePullDownRefresh": false
+            }
+            
+        }
+        ,{
+            "path" : "pages/mine/feedback/feedback",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "问题反馈",
+                "enablePullDownRefresh": false
+            }
+            
+        }
+        ,{
+            "path" : "pages/mine/protocol/protocol",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "暂未开发",
+                "enablePullDownRefresh": false
+            }
+            
+        }
+    ],
+	"tabBar": {
+		  "color":"#8a8a8a",
+		  "backgroundColor":"#FFFFFF",
+		  "borderStyle":"white",
+		  "selectedColor":"#59a5f0",
+		  "list": [
+			{
+			  "pagePath": "pages/index/index",
+			  "text": "园区",
+			  "selectedIconPath":"static/tarbar/home.png",
+			  "iconPath":"static/tarbar/home0.png"
+			},
+			{
+			  "pagePath":"pages/news/news",
+			  "text": "园区动态",
+			  "selectedIconPath":"static/tarbar/news.png",
+			  "iconPath":"static/tarbar/news0.png"
+			},
+			{
+			  "pagePath": "pages/mine/mine",
+			  "text": "个人中心",
+			  "selectedIconPath":"static/tarbar/my.png",
+			  "iconPath":"static/tarbar/my0.png"
+			}
+		  ]
+	 },
+	"globalStyle": {
+		"navigationBarTextStyle": "black",
+		"navigationBarTitleText": "uni-app",
+		"navigationBarBackgroundColor": "#FFFFFF",
+		"backgroundColor": "#F8F8F8"
+	}
+}

+ 223 - 0
pages/auth/auth.vue

@@ -0,0 +1,223 @@
+<template>
+	<view class="padding-20">
+		<view class="auth">
+			<text class="cuIcon-titles text-blue padding-right-10"></text>
+			<text>个人信息认证</text>
+			<view class="card">
+				<u-form :model="model"  ref="uForm" >
+					<u-form-item  :label-width="labelWidth"  label="姓名" >
+						<u-input  placeholder="请输入姓名" v-model="model.name" type="text"></u-input>
+					</u-form-item>
+					<u-form-item  :label-width="labelWidth"   label="性别" >
+						<u-input  type="select" :select-open="sexSelectShow" v-model="model.sex" placeholder="请选择性别" @click="sexSelectShow = true"></u-input>
+					</u-form-item>
+					<u-form-item   label="身份证号"  :label-width="labelWidth">
+						<u-input  placeholder="请输入身份证号" v-model="model.idcard" type="idcard"></u-input>
+					</u-form-item>
+					<u-form-item   label="手机号码"  :label-width="labelWidth">
+						<u-input  placeholder="请输入手机号" v-model="model.phone" type="number"></u-input>
+					</u-form-item>
+					<u-form-item :border-bottom="false"  label="面部信息采集"  :label-width="labelWidth"></u-form-item>
+				</u-form>
+				
+				<view @click="faceSelectShow=true" class="flex justify-center padding-bottom-50">
+					<view class=" ">
+						<upload-img
+						   :width="$isEmpty(face_url)?350:560"
+						   :height="$isEmpty(face_url)?350:420"
+						  :currentImage="face_url"
+						  bgsrc="http://139.9.103.171:1888/miniofile/xlyq/face1.png"
+						  >
+						</upload-img>
+						<view class="text-center padding-top-20" style="color: #59a5f0;">
+						 <text class="cuIcon-camera padding-right-sm" style="font-size: 30rpx;"></text>
+						 <text v-if="$isEmpty(face_url)">点击上传人脸</text>
+						 <text style="margin-top: 40rpx;display: inline-block;" v-else>点击重新上传</text>
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+		<view class="auth">
+			<text class="cuIcon-titles text-blue padding-right-10"></text>
+			<text>企业信息认证</text>
+			<view class="card">
+				<u-form :model="model"  ref="uForm" >
+					<u-form-item  :label-width="labelWidth"   label="公司园区" >
+						<u-input  type="select" :select-open="ganderSelectShow" v-model="model.gander" placeholder="请选择工作园区" @click="ganderSelectShow = true"></u-input>
+					</u-form-item>
+					<u-form-item  :label-width="labelWidth"   label="所属企业" >
+						<u-input  type="select" :select-open="companySelectShow" v-model="model.company" placeholder="请选择所属企业" @click="companySelectShow = true"></u-input>
+					</u-form-item>
+				</u-form>
+			</view>
+		</view>
+		<view class="auth">
+			<text class="cuIcon-titles text-blue padding-right-10"></text>
+			<text>其他信息</text>
+			<view class="card">
+				<u-form :model="model"  ref="uForm" >
+					<u-form-item :border-bottom="false" :label-width="labelWidth"   label="备注(可选)" ></u-form-item>
+					<textarea value="" v-model="model.remark" placeholder="填写备注信息" />
+				</u-form>
+			</view>
+		</view>
+		
+		
+		<view class="cu-btn bg-blue round flex" style="padding: 40rpx 0;margin-top: 40rpx;">
+			提交
+		</view>
+		<u-action-sheet :list="sexSelectList" v-model="sexSelectShow" @click="sexSelectCallback"></u-action-sheet>
+		<u-action-sheet :list="ganderSelectList" v-model="ganderSelectShow" @click="ganderSelectCallback"></u-action-sheet>
+		<u-action-sheet :list="companySelectList" v-model="companySelectShow" @click="companySelectCallback"></u-action-sheet>
+		<u-action-sheet @click="faceSelectCallback"  z-index="999999" :list="faceSelectList" v-model="faceSelectShow"></u-action-sheet>
+	</view>
+</template>
+
+<script>
+	import uploadImg from '@/components/uploadimg/uploadImg.vue'
+	let that = this;
+	export default {
+		components:{
+		   uploadImg
+		},
+		data() {
+			return {
+				labelWidth:'200',
+				model: {
+					name: '',
+					sex: '',
+					phone: '',
+					idcard:'',
+					gander:'',
+					company:'',
+					face_image:''
+				},
+				//图片回显
+				face_url:'',
+				//性别
+				sexSelectList: [{text: '男'},{text: '女'}],
+				sexSelectShow: false,
+				//园区
+				ganderSelectList: [],
+				ganderSelectShow: false,
+				//企业
+				companySelectList: [],
+				companySelectShow: false,
+				//上传人脸的方式
+				faceSelectList: [{
+					text: '相册上传',
+				}, {
+					text: '拍照上传'
+				}],
+				faceSelectShow:false,
+				//验证码
+				codeTips: '',
+				
+			}
+		},
+		onLoad() {
+			this.fetchStaticData()
+			this.initData()
+		},
+		methods: {
+			initData(){
+				if (!this.$isEmpty(this.$cache.get('phone'))) {
+					this.model.phone=this.$cache.get('phone')
+				}
+			},
+			//性别
+			sexSelectCallback(index) {
+				uni.hideKeyboard();
+				this.model.sex = this.sexSelectList[index].text;
+			},
+			//园区
+			ganderSelectCallback(index) {
+				uni.hideKeyboard();
+				this.model.gander = this.ganderSelectList[index].text;
+			},
+			//公司
+			companySelectCallback(index) {
+				uni.hideKeyboard();
+				this.model.company = this.companySelectList[index].text;
+			},
+			faceSelectCallback(index){
+				if (index==0) {
+					//图片上传
+					this.chooseImage()
+				} else if(index==1){
+					//拍照上传
+					uni.navigateTo({
+						url:"../my-camera/my-camera"
+					})
+				}
+			},
+			//点击上传图片事件
+			chooseImage: function () {
+			  uni.chooseImage({
+			    count: 1,
+			    //最多可以选择的图片张数,默认9
+			    sourceType: ['album', 'camera'],
+			    sizeType: ['compressed'],
+			    //可选择原图或压缩后的图片
+			    success: res => {
+			      that.handelImg(res.tempFilePaths[0])
+			    }
+			  });
+			},
+			//处理照片,拍照上传和相册上传的共同处理方法
+			handelImg(imgUrl){
+				that.face_url=imgUrl
+				uni.getFileSystemManager().readFile({
+				  filePath: imgUrl,
+				  //选择图片返回的相对路径
+				  encoding: 'base64',
+				  //编码格式
+				  success: res => {
+					  //图片的base64字符串
+					  that.face_image='data:image/jpeg;base64,' + res.data
+				  }
+				});
+			},
+			fetchStaticData(){
+				this.ganderSelectList=[
+					{
+						text: '新邻园区1'
+					},
+					{
+						text: '新邻园区2'
+					}
+				]
+				this.companySelectList=[
+					{
+						text: '新邻企业1'
+					},
+					{
+						text: '新邻企业2'
+					}
+				]
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	page{
+		background-color: #FFFFFF;
+	}
+	.auth{
+		padding: 40rpx 10rpx;
+		.card{
+			margin-top: 20rpx;
+			padding: 0 30rpx;
+			box-sizing: border-box;
+			border-radius: 12rpx;
+			box-shadow: 0 -10rpx rgba(248, 248, 248,.9) ,0 10rpx rgba(248, 248, 248,.9) , -10rpx 0rpx rgba(248, 248, 248,.9) ,10rpx 0rpx rgba(248, 248, 248,.9);
+			.item{
+				padding:30rpx 0;
+				display: flex;
+				justify-content: space-between;
+			}
+		}
+	}
+</style>

+ 190 - 0
pages/company/company.vue

@@ -0,0 +1,190 @@
+<template>
+	<view>
+		<swiper   class="screen-swiper square-dot "  :indicator-dots="true" :circular="true"
+		 :autoplay="true" interval="5000" duration="500">
+			<swiper-item v-for="(item,index) in bannerList" :key="index">
+				<image   :src="item.image" mode="aspectFill" ></image>
+			</swiper-item>
+		</swiper>
+		
+		<view class="card">
+			<image src="http://139.9.103.171:1888/miniofile/xlyq/del/logo.jpg"></image>
+			<view class="flex flex-direction justify-center padding-left-30">
+				<text class="text-bold  text-lg" style="padding-bottom: 12rpx;">鹏鼎控股</text>
+				<text class="text-sm">电子技术/半导体/集成电路</text>
+			</view>
+		</view>
+		
+		<view class="desc">
+			<text class="text-lg text-bold">公司简介</text>
+			<view class="sub-title">
+				<text style="padding-left: 60rpx;">鹏鼎控股成立于1999年,于2018年9月18日在深交所上市,股票简称“鹏鼎控股”。公司主要从事各类印制电路板的设计、研发、制造与销售业务。专注于为行业领先客户提供全方位PCB产品及服务。
+				公司的制造基地分布于深圳、秦皇岛、淮安,服务半径覆盖中国大陆、中国香港、中国台湾、日本、韩国等地,可以为全球客户提供高速、高质、低成本及高附加值的PCB设计、开发、制造及销售服务,已成为业内极具影响力的重要厂商之一。
+				</text>
+			</view>
+		</view>
+		
+		<view class="history">
+			<view class="top u-border-bottom margin-bottom-40">
+				<text class="text-bold text-lg">发展历程</text>
+				<view class="text-sm padding-top-10 text-gray">
+					<text>更多</text>
+					<text class="cuIcon-right padding-left-10"></text>
+				</view>
+			</view>
+			<u-time-line>
+				<u-time-line-item nodeTop="2" v-for="(item,index) in historyList" :key="index">
+					<template v-slot:node>
+						<view class="u-node" style="background-color: rgba(200, 217, 243,.6);">
+							<u-icon name="clock-fill" color="#093c8f" :size="28"></u-icon>
+						</view>
+					</template>
+					<template v-slot:content>
+						<view>
+							<view class="u-order-title">{{item.time}}</view>
+							<view class="u-order-desc">{{item.content}}</view>
+						</view>
+					</template>
+				</u-time-line-item>
+			</u-time-line>
+		</view>
+		
+		<view class="address">
+			<view class="top u-border-bottom">
+				<text class="text-bold text-lg">公司地址</text>
+			</view>
+			
+			<view class="item" v-for="(item,index) in 3" :key="index">
+				<view class="flex">
+					<u-icon name="map" size="50"></u-icon>
+					<text class="padding-left-20 text-lg">鹏鼎控股深圳园区</text>
+				</view>
+				<text class="sub-address">广东省深圳市宝安区燕罗街道松罗路</text>
+			</view>
+			
+			<view class="padding-top-50">
+				<u-divider>没有更多了</u-divider>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				bannerList: [],
+				historyList:[]
+			}
+		},
+		onLoad() {
+			this.fetchStaticData()
+		},
+		methods: {
+			fetchStaticData(){
+				this.bannerList=[
+					{
+					  'image': "http://139.9.103.171:1888/miniofile/xlyq/banner01.jpg"
+					},
+				]
+				
+				this.historyList=[
+					{
+						time:'2020',
+						content:'荣获国家环保部2020年度「中国环境社会责任企业J淮安园区高端HDI及先进SLP类载板智能制造工厂项目“云签约”,鹏鼎控股在深圳特区40周年“最受尊敬40家上市公司及人物”评选活动中,鹏鼎控股荣获“最受尊敬40家上市公司”、董事长沈庆芳荣获“最受尊敬40位企业家”'
+					},
+					{
+						time:'2019',
+						content:'建设印度园区举行全球合作伙伴大会鹏鼎控股荣获2019中国上市公司品牌价值榜《第十八届(2018)中国电子电路行业排行榜》中位列PCB企业第一位'
+					},
+				]
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	page{
+	}
+	
+	.card{
+		padding: 20rpx;
+		background-color: #FFFFFF;
+		margin: 10rpx;
+		border-radius: 10rpx;
+		display: flex;
+		box-shadow: 0 10rpx rgba(248, 248, 248,.9) , -10rpx 0rpx rgba(248, 248, 248,.9) ,10rpx 0rpx rgba(248, 248, 248,.9);
+		image{
+			border: 1rpx solid #f1f1f1;
+			width:120rpx;
+			height: 120rpx;
+			border-radius: 50%;
+		}
+	}
+	
+	.desc{
+		background-color: #FFFFFF;
+		padding:40rpx 30rpx;
+		.sub-title{
+			padding-top: 40rpx;
+			font-size: 28rpx;
+			line-height: 50rpx;
+		}
+	}
+	
+	.history{
+		background-color: #FFFFFF;
+		margin-top: 20rpx;
+		padding: 40rpx 20rpx 20rpx 50rpx;
+	}
+	
+	.top{
+		padding-bottom: 30rpx;
+		display: flex;
+		justify-content: space-between;
+	}
+	
+	.address{
+		margin-top: 20rpx;
+		background-color: #FFFFFF;
+		padding: 30rpx;
+		
+		
+		.item{
+			padding-top: 40rpx;
+			.sub-address{
+				padding-left: 70rpx;font-size: 26rpx;color: #bababa;
+			}
+		}
+	}
+	
+	
+	.u-node {
+			width: 44rpx;
+			height: 44rpx;
+			border-radius: 100rpx;
+			display: flex;
+			justify-content: center;
+			align-items: center;
+			background: #d0d0d0;
+		}
+		
+		.u-order-title {
+			color: #333333;
+			font-weight: bold;
+			font-size: 32rpx;
+		}
+		
+		.u-order-desc {
+			padding-top: 20rpx;
+			color: #8d8d8d;
+			font-size: 26rpx;
+			line-height: 48rpx;
+			margin-bottom: 6rpx;
+		}
+		
+		.u-order-time {
+			color: rgb(200, 200, 200);
+			font-size: 26rpx;
+		}
+</style>

+ 24 - 0
pages/index/access-record/access-record.vue

@@ -0,0 +1,24 @@
+<template>
+	<view>
+		<u-empty  marginTop="300"  icon-size="400" text="暂无记录" src="http://139.9.103.171:1888/miniofile/xlyq/empty/empty.png"></u-empty>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				
+			}
+		},
+		methods: {
+			
+		}
+	}
+</script>
+
+<style lang="scss">
+page{
+	background-color: #FFFFFF;
+}
+</style>

+ 301 - 0
pages/index/index.vue

@@ -0,0 +1,301 @@
+<template>
+	<view class="">
+		<!-- 头部 -->
+		<u-navbar :border-bottom="false" :is-back="false" title=" ">
+			<view class="slot-wrap">
+				<picker @change="ganderChange" range-key="name" :value="ganderIndex" :range="ganderArray">
+				  <view class="padding-left-40 ">
+				  	<text class="padding-right-10" style="font-size: 34rpx;">{{gander?gander:'暂无园区信息'}}</text>
+					<u-icon  name="arrow-down-fill" top="-5" size="20" color="#7f7f7f"></u-icon>
+				  </view>
+				</picker>
+			</view>
+		</u-navbar>
+		<!-- banner -->
+		<swiper   class="screen-swiper square-dot "  :indicator-dots="true" :circular="true"
+		 :autoplay="true" interval="5000" duration="500">
+			<swiper-item v-for="(item,index) in bannerList" :key="index">
+				<image   :src="item.image" mode="aspectFill" ></image>
+			</swiper-item>
+		</swiper>
+		<!-- 公告 -->
+		<view class="">
+			<view class="bg-white" style="height: 10rpx;"></view>
+			<hotConsult   :swiperTexts="noticeList"></hotConsult>
+		</view>
+		
+		<!-- 园区服务 -->
+		<view class="bg-white">
+			<view  style="padding: 30rpx 30rpx 0 30rpx; ">
+				<text class="cuIcon-titles text-blue"></text>
+				<text class="text-bold text-lg">园区服务</text>
+			</view>
+			<view class="nav-list  padding-top-30" >
+				<view hover-class="none"
+					@click="jump(item.index)"
+					class="nav-li light"  :style="{backgroundColor:item.color}" 
+					v-for="(item,index) in elements" :key="index">
+					<view class="nav-title" style="color: #000000;font-size: 28rpx;">{{item.title}}</view>
+					<view class="" style="padding-top: 10rpx;font-size: 24rpx;color: #acacac;">{{item.name}}</view>
+					<image :src="item.icon" mode=""></image>
+				</view>
+			</view>
+		</view>
+		<view class="bg-white">
+			<view  style="padding: 30rpx 30rpx 0 30rpx; ">
+				<text class="cuIcon-titles text-blue"></text>
+				<text class="text-bold text-lg">消防服务</text>
+			</view>
+			<view class="nav-list  padding-top-30" >
+				<view hover-class="none"
+					@click="jump(item.index)"
+					class="nav-li light" navigateTo :style="{backgroundColor:item.color}" 
+					v-for="(item,index) in fireList" :key="index">
+					<view class="nav-title" style="color: #000000;font-size: 28rpx;">{{item.title}}</view>
+					<view class="" style="padding-top: 10rpx;font-size: 24rpx;color: #acacac;">{{item.name}}</view>
+					<image :src="item.icon" mode=""></image>
+				</view>
+			</view>
+		</view>
+		<!-- <u-divider bg-color="#f1f1f1" color="#62a3dc" border-color="#62a3dc"  height="100">查看更多</u-divider> -->
+	</view>
+</template>
+
+<script>
+import hotConsult from "@/components/hot-consult/hot-consult.vue"
+export default {
+	components:{
+		hotConsult
+	},
+	data() {
+		return {
+		
+			//园区 label
+			gander:'新邻产业园',
+			//默认选中下标
+			ganderIndex:0, 
+			//园区列表
+			ganderArray:[], 
+			
+			//banner
+			bannerList: [],
+			// 公告
+			noticeList:[],
+			//消防服务
+			fireList:[],
+			//园区服务
+		    elements: [],
+			
+		};
+	},
+	onLoad() {
+		this.fetchStaticData()
+	},
+	methods:{
+		ganderChange(e){
+			console.log(e);
+		},
+		jump(index){
+			if (index==1) {
+				//我的企业
+				uni.navigateTo({
+					url:"../company/company"
+				})
+			}else if(index==2){
+				//人员认证
+				uni.navigateTo({
+					url:"../auth/auth"
+				})
+			}else if (index==3) {
+				//我的测温
+				uni.navigateTo({
+					url:"my-temperature/my-temperature"
+				})
+			}else if (index==4) {
+				//通行记录
+				uni.navigateTo({
+					url:"./access-record/access-record"
+				})
+			}
+		},
+		fetchStaticData(){
+			this.bannerList=[
+				{
+				  'image': "http://139.9.103.171:1888/miniofile/xlyq/banner01.jpg"
+				},
+			]
+			
+			this.ganderArray=[
+				{
+					name:'新邻产业园',
+					value:'1'
+				},
+				{
+					name:'新邻工业园',
+					value:'2'
+				}
+			]
+			this.noticeList=[
+				{
+					title:'疫情期间,出入小区请佩戴好口罩,配合门卫大叔做好测温登记工作。谢谢大家的配合。'
+				},
+				{
+					title:'停水停电通知。市政通水设施突发性故障抢修,本小区供水压力暂受影响,敬请做好储水准备,预约影响时间2020年11月28号22时至11月29号16时,由此给您带来不便,敬请谅解。'
+				},
+				{
+					title:'2020年10月1日-2020年10月8日,中秋 国庆节放假,假期间需注意,祝国庆节玩的开心。'
+				},
+				{
+					title:'疫情期间,出入小区请佩戴好口罩,配合门卫大叔做好测温登记工作。谢谢大家的配合。'
+				}
+			]
+			
+			this.elements=[
+				{
+					title: '我的企业',
+					name: 'My business',
+					color: '#f9f4f1',
+					icon: '../../static/index/gander/qiye.png',
+					index:1
+				},
+				{
+					title: '人员认证',
+					name: 'Personnel certification',
+					color: '#ecf3f9',
+					icon: '../../static/index/gander/renzheng.png',
+					index:2
+				}, 
+				{
+					title: '我的测温',
+					name: 'My temperature',
+					color: '#f0f3ff',
+					icon: '../../static/index/gander/cewen1.png',
+					index:3
+				}, 
+				{
+					title: '通行记录',
+					name: 'Access records',
+					color: '#f7f7f5',
+					icon: '../../static/index/gander/tongxing.png',
+					index:4
+				}
+			]
+			this.fireList=[
+				{
+					title: '烟感报警',
+					name: 'Smoke alarm',
+					color: '#f2f0fd',
+					icon: '../../static/index/fire/yangan.png',
+					index:5
+				},
+				{
+					title: '燃气告警',
+					name: 'Gas alarm',
+					color: '#fffaf8',
+					icon: '../../static/index/fire/ranqi.png',
+					index:6
+				}, 
+				{
+					title: '消防水压',
+					name: 'Fire water pressure',
+					color: '#ecf3f9',
+					icon: '../../static/index/fire/xiaofang.png',
+					index:7
+				}, 
+				{
+					
+				},
+			]
+		}
+	}
+};
+</script>
+
+<style lang="scss" scoped>
+	
+	
+	//四宫格 begin
+	.nav-list {
+		display: flex;
+		flex-wrap: wrap;
+		justify-content: center;
+	}
+	.nav-li {
+		padding: 30upx 30rpx;
+		border-radius: 12upx;
+		width: 44%;
+		margin: 10rpx 2% 10upx;
+		background-size: cover;
+		background-position: center;
+		position: relative;
+		z-index: 1;
+	}
+	.nav-li::after {
+		content: "";
+		position: absolute;
+		z-index: -1;
+		background-color: inherit;
+		width: 100%;
+		height: 100%;
+		left: 0;
+		bottom: -10%;
+		border-radius: 10upx;
+		opacity: 0.2;
+		transform: scale(0.9, 0.9);
+	}
+	.nav-li.cur {
+		color: #fff;
+		background: rgb(94, 185, 94);
+		box-shadow: 4upx 4upx 6upx rgba(94, 185, 94, 0.4);
+	}
+	.nav-title {
+		font-size: 32upx;
+		font-weight: 300;
+	}
+	.nav-title::first-letter {
+		font-size: 40upx;
+		margin-right: 4upx;
+	}
+	.nav-name {
+		font-size: 28upx;
+		text-transform: Capitalize;
+		margin-top: 20upx;
+		position: relative;
+	}
+	.nav-name::before {
+		content: "";
+		position: absolute;
+		display: block;
+		width: 40upx;
+		height: 6upx;
+		background: #fff;
+		bottom: 0;
+		right: 0;
+		opacity: 0.5;
+	}
+	.nav-name::after {
+		content: "";
+		position: absolute;
+		display: block;
+		width: 100upx;
+		height: 1px;
+		background: #fff;
+		bottom: 0;
+		right: 40upx;
+		opacity: 0.3;
+	}
+	.nav-name::first-letter {
+		font-weight: bold;
+		font-size: 36upx;
+		margin-right: 1px;
+	}
+	.nav-li image {
+		position: absolute;
+		right: 30upx;
+		top: 22upx;
+		width: 66upx;
+		height: 66upx;
+	}
+	//四宫格 end
+	
+</style>

+ 85 - 0
pages/index/my-temperature/deatil.vue

@@ -0,0 +1,85 @@
+<template>
+	<view class="content ">
+		<view class="flex flex-direction ">
+			<view class="flex justify-between">
+				<view class="">
+					<view class="item">
+						<text class="cuIcon-people text-blue margin-right-10"></text>
+						<text class="text-bold padding-right-10">姓名:</text>
+						<text >{{dataDetail.name}}</text>
+					</view>
+					<view class="item">
+						<text class="cuIcon-male text-blue margin-right-10"></text>
+						<text class="text-bold padding-right-10">性别:</text>
+						<text>{{dataDetail.sex}}</text>
+					</view>
+					<view class="item">
+						<text class="cuIcon-hot text-blue margin-right-10"></text>
+						<text class="text-bold padding-right-10">体温:</text>
+						<text>{{dataDetail.temperature}} ℃</text>
+					</view>
+					<view class="item">
+						<text class="cuIcon-activity text-blue margin-right-10"></text>
+						<text class="text-bold padding-right-10">所属企业:</text>
+						<text>{{dataDetail.enterprise}}</text>
+					</view>
+				</view>
+				<view class="padding-top-20">
+					<image @click="previewImg(dataDetail.image)"  style="width: 220rpx;height: 250rpx;border-radius: 12rpx;"  :src="dataDetail.image"></image>
+				</view>
+			</view>
+			<view class="item">
+				<text class="cuIcon-news text-blue margin-right-10"></text>
+				<text class="text-bold padding-right-10">身份证号:</text>
+				<text>{{dataDetail.idCard}}</text>
+			</view>
+			<view class="item">
+				<text class="cuIcon-time text-blue margin-right-10"></text>
+				<text class="text-bold padding-right-10">测温时间:</text>
+				<text>{{dataDetail.time}}</text>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	var app=getApp()
+	export default {
+		data() {
+			return {
+				dataDetail:{
+					'name':'李德希',
+					'sex':'男',
+					'enterprise':'新邻企业',
+					'temperature':'36.4',
+					'image':'http://139.9.103.171:1888/miniofile/xlyq/del/ldx.png',
+					'idCard':'440881199604264598',
+					'time':'2020-12-15 14:18:56'
+				}
+			}
+		},
+		onShow() {
+		},
+		methods: {
+			previewImg(img){
+				let imgs=[]
+				imgs.push(img)
+				uni.previewImage({
+					urls:imgs
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	page{
+		background-color: #FFFFFF;
+	}
+	.content{
+		padding:60rpx;
+		.item{
+			padding: 22rpx 0;
+		}
+	}
+</style>

+ 60 - 0
pages/index/my-temperature/my-temperature.vue

@@ -0,0 +1,60 @@
+<template>
+	<view class="">
+		<navigator url="./deatil" class="mine_order_statue" v-for="(item,index) in 6" :key="index">
+			<view class="flex justify-between" style="padding: 10rpx 0 10rpx 10rpx ;">
+				<view class="flex">
+					<image mode="heightFix" src="http://139.9.103.171:1888/miniofile/xlyq/del/ldx.png"  ></image>
+					<view  class="flex flex-direction justify-around padding-left-30">
+						<view class="">
+							<text class="text-bold">姓名:</text>
+							<text>李德希</text>
+						</view>
+						<view class="">
+							<text class="text-bold">温度:</text>
+							<text>36.5 ℃</text>
+						</view>
+						<view class="">
+							<text class="text-bold">测温时间:</text>
+							<text>2020-12-15 14:18:56</text>
+						</view>
+					</view>
+				</view>
+				<view class="flex align-center justify-center">
+					<text class="cuIcon-right"></text>
+				</view>
+			</view>
+		</navigator>
+		<u-divider bg-color="#f1f1f1" height="100">没有更多了</u-divider>
+	</view>
+</template>
+
+<script>
+export default {
+	name: '',
+	data() {
+		return {
+			
+		};
+	},
+	onLoad() {
+		
+	},
+	methods:{
+		
+	}
+};
+</script>
+
+<style lang="scss" scoped>
+	.mine_order_statue {
+		margin: 18upx 14upx 0;
+		background: #fff;
+		padding: 10upx 20upx;
+		border-radius: 20rpx;
+		image{
+			background-color: #FFFFFF;
+			width: 160rpx;
+			height: 160rpx;
+		}
+	}
+</style>

+ 291 - 0
pages/login/login.vue

@@ -0,0 +1,291 @@
+<!-- 蓝色简洁登录页面 -->
+<template>
+	<view class="">
+		<view class="t-login">
+			<u-top-tips ref="uTips"></u-top-tips>
+			<u-toast ref="uToast"></u-toast>
+			<!-- 页面装饰图片 -->
+			<!-- <image class="img-a" src="@/static/login/2.png"></image> -->
+			<!-- <image class="img-b" src="@/static/login/3.png"></image> -->
+			<!-- 标题 -->
+			<view class="t-b">{{ title }}</view>
+			<form class="cl">
+				<view class="t-a">
+					<image   src="@/static/login/sj.png"></image>
+					<input  type="number" name="phone" placeholder="请输入手机号" maxlength="11" v-model="phone" />
+				</view>
+				<view class="t-a">
+					<image  src="@/static/login/yz.png"></image>
+					<input type="number" name="code" maxlength="6" placeholder="请输入验证码" v-model="yzm" />
+					<view :style="showText?'':'background-color: #A7A7A7;'"  class="t-c" @click="getCode()">{{tips}}</view>
+				</view>
+				<view @click="typeShow=true" class="flex padding-bottom-50" style="text-align: left">
+					<view style="border: 1px solid #e9e9e9;background-color: #f8f7fc;" class="cu-btn   df  round">
+						<text class="text-black">{{typeList[typeIndex].text}}登陆</text>
+						<text class="text-black cuIcon-triangledownfill " style="font-size: 40rpx;padding-left: 4rpx;"></text>
+					</view>
+				</view>
+				
+				<view class="checkbox">
+					<u-checkbox 
+					@change="checkboxChange" 
+					v-model="checked" 
+					>七天内免登录</u-checkbox>
+				</view>
+				<button @tap="login()">登 录</button>
+			</form>
+			<view v-if="typeIndex==0">
+				<view class="t-f">
+					<u-divider color="#aaa" border-color="#aaa">微信快速登陆</u-divider>
+				</view>
+				<!-- <view class="t-f"><text>————— 微信快速登录 —————</text></view> -->
+				<view style="display: flex;justify-content: center;padding-top: 50rpx;">
+					<view  @tap="wxLogin()"><image style="width: 88rpx;height: 88rpx;" src="@/static/login/wx.png"></image></view>
+				</view>
+			</view>
+			<u-action-sheet @click="typeClick" :list="typeList" v-model="typeShow"></u-action-sheet>
+			<u-verification-code seconds="60" @end="end" @start="start" ref="uCode" @change="codeChange"></u-verification-code>
+		</view>
+	</view>
+</template>
+<script>
+let that
+export default {
+	data() {
+		return {
+			typeList:[{text:'员工',value:'0'},{text:'企业',value:'1'}],
+			typeShow:false,
+			typeIndex:0,
+			checked:false,//七天免登录
+			title: '欢迎回来!', 
+			tips: '', 
+			showText:true,
+			phone: '', //手机号码
+			yzm: '' //验证码
+		};
+	},
+	onLoad() {
+		if (this.$cache.get('phone')) {
+			//免登录
+			uni.switchTab({
+				url:"../index/index"
+			})
+		}
+	},
+	methods: {
+		wxLogin(){
+			this.$refs.uTips.show({
+				title: '完成员工认证的用户才可以使用微信快速登陆',
+				type: 'primary',
+				duration: '2500'
+			})
+		},
+		typeClick(index){
+			this.typeIndex=index
+		},
+		getCode() {
+			if(this.$refs.uCode.canGetCode) {
+				// 模拟向后端请求验证码
+				uni.showLoading({
+					title: '正在获取验证码'
+				})
+				setTimeout(() => {
+					uni.hideLoading();
+					// 这里此提示会被this.start()方法中的提示覆盖
+					this.$u.toast('验证码已发送');
+					// 通知验证码组件内部开始倒计时
+					this.$refs.uCode.start();
+				}, 3000);
+			} else {
+				this.$u.toast('倒计时结束后再发送');
+			}
+		},
+		checkboxChange(e){
+			this.checked=e.value
+		},
+		codeChange(text) {
+			this.tips = text;
+		},
+		end() {
+			this.showText=true
+		},
+		start() {
+			this.showText=false
+		},
+		//当前登录按钮操作
+		login() {
+			var that = this;
+			if (!that.phone) {
+				uni.showToast({ title: '请输入手机号', icon: 'none' });
+				return;
+			}
+			if (!/^[1][3,4,5,7,8,9][0-9]{9}$/.test(that.phone)) {
+				uni.showToast({ title: '请输入正确手机号', icon: 'none' });
+				return;
+			}
+			if (!that.yzm) {
+				uni.showToast({ title: '请输入验证码', icon: 'none' });
+				return;
+			}
+			if (that.checked) {
+				//七天内免登录
+				that.$cache.put("phone",that.phone,1*24*60*60*7) 
+			}else{
+				//三十分内钟免登录
+				that.$cache.put("phone",that.phone,1*60*30)
+			}
+			//存储登陆的用户类型
+			if (that.typeIndex==0) {
+				//员工登陆
+				that.$cache.put('loginType','employees')
+			}else if(that.typeIndex==1){
+				//企业登陆
+				that.$cache.put('loginType','enterprise')
+			}
+			uni.showLoading({
				title: '登陆中...'
			})
+			setTimeout(()=>{
+				uni.hideLoading()
+				uni.switchTab({
+					url:"../index/index"
+				})
+			},1500)
+		},
+		
+	}
+};
+</script>
+<style lang="scss" >
+page{
+	background-color: #FFFFFF;
+}
+.checkbox{
+	padding-bottom: 50rpx;
+	padding-left: 20rpx;
+	margin-top: -10rpx;
+}
+
+.img-a {
+	position: absolute;
+	width: 100%;
+	top: -300rpx;
+	right: -100rpx;
+}
+.img-b {
+	position: absolute;
+	width: 50%;
+	bottom: 0;
+	left: -50rpx;
+	margin-bottom: -200rpx;
+}
+.t-login {
+	width: 600rpx;
+	margin: -200rpx auto;
+	font-size: 28rpx;
+	color: #000;
+}
+
+.t-login button {
+	font-size: 28rpx;
+	background: #5677fc;
+	color: #fff;
+	height: 90rpx;
+	line-height: 90rpx;
+	border-radius: 50rpx;
+	box-shadow: 0 5px 7px 0 rgba(86, 119, 252, 0.2);
+}
+
+.t-login input {
+	padding: 0 20rpx 0 120rpx;
+	height: 90rpx;
+	line-height: 90rpx;
+	margin-bottom: 50rpx;
+	background: #f8f7fc;
+	border: 1px solid #e9e9e9;
+	font-size: 28rpx;
+	border-radius: 50rpx;
+}
+
+.t-login .t-a {
+	position: relative;
+}
+
+.t-login .t-a image {
+	width: 40rpx;
+	height: 42rpx;
+	position: absolute;
+	left: 20rpx;
+	top: 28rpx;
+	padding-right:4rpx;
+}
+
+.t-login .t-b {
+	text-align: left;
+	font-size: 46rpx;
+	color: #000;
+	padding: 300rpx 0 120rpx 0;
+	font-weight: bold;
+}
+.t-login .t-c {
+	position: absolute;
+	right: 22rpx;
+	top: 22rpx;
+	background: #5677fc;
+	color: #fff;
+	font-size: 24rpx;
+	border-radius: 50rpx;
+	height: 50rpx;
+	line-height: 50rpx;
+	padding: 0 25rpx;
+	z-index: 99999;
+}
+
+.t-login .t-d {
+	text-align: center;
+	color: #999;
+	margin: 80rpx 0;
+}
+
+.t-login .t-e {
+	text-align: center;
+	width: 250rpx;
+	margin: 80rpx auto;
+}
+
+.t-login .t-g {
+	float: left;
+	width: 50%;
+}
+
+.t-login .t-e image {
+	width: 50rpx;
+	height: 50rpx;
+}
+
+.t-login .t-f {
+	text-align: center;
+	margin: 100rpx 0 0 0;
+	color: #666;
+}
+
+.t-login .t-f text {
+	margin-left: 20rpx;
+	color: #aaaaaa;
+	font-size: 27rpx;
+}
+
+.t-login .uni-input-placeholder {
+	color: #000;
+}
+
+.cl {
+	zoom: 1;
+}
+
+.cl:after {
+	clear: both;
+	display: block;
+	visibility: hidden;
+	height: 0;
+	content: '\20';
+}
+</style>

+ 49 - 0
pages/login/login1.vue

@@ -0,0 +1,49 @@
+<template>
+	<view class="flex bg-white flex-direction justify-center align-center " style="padding-top: 100rpx;">
+		<u-avatar  size="130" src="http://pic2.sc.chinaz.com/Files/pic/pic9/202002/hpic2119_s.jpg"></u-avatar>
+		<text  style="margin:30rpx 0 100rpx 0rpx;color: #333333;font-size: 26rpx;font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;">Hi~登陆玩转新邻园区吧</text>
+		<view class="cu-btn round wx-btn ">
+			<view class="text-center"  style="position: relative;left: -100rpx;">
+				<text class="cuIcon-weixin icon"></text>
+			</view>
+			<view style="position: relative;left: -16rpx;">
+				<text class="text-center text-lg">微信快速登陆</text>
+			</view>
+		</view>
+		<view class="cu-btn round line-gray " style="width: 200rpx;margin-top: 80rpx;">
+			暂不登陆
+		</view>
+	</view>
+</template>
+<script>
+export default {
+	name: '',
+	data() {
+		return {
+			
+		};
+	},
+	onLoad() {
+		
+	},
+	methods:{
+		
+	}
+};
+</script>
+
+<style lang="scss" scoped>
+	page{
+		background-color: #FFFFFF;
+	}
+	
+	.wx-btn{
+		background-color: #2ba246;
+		color: #FFFFFF;
+		padding: 40rpx 180rpx;
+		.icon{
+			color: #216a21;
+			font-size: 42rpx;
+		}
+	}
+</style>

+ 250 - 0
pages/mine/feedback/feedback.vue

@@ -0,0 +1,250 @@
+<template>
+	<view class="page">
+		<view class="content">
+			<view style="padding: 30rpx 0;">
+				<text>请选择您要反馈的问题类型:</text>
+			</view>
+
+			<radio-group  class="block" @change="RadioChange">
+				<view class="radioBox">
+					<view class="radioItem" :class="data.type==item.type?'checkBorder':'defalutBorder'" v-for="(item,index) in typeList" :key="index">
+						<label class="flex" >
+							<view class="">
+								<radio  style="transform: scale(.7);"  class="round blue" :class="data.type===item.type?'checked':''" :checked="data.type==item.type?true:false"
+								 :value="item.type"></radio>
+							</view>
+							<view class="text-left padding-left-20 flex" style="flex-direction: column;justify-content: center;">
+								{{item.title}}
+							</view>
+						</label>
+					</view>
+				</view>
+			</radio-group>
+			<view class="area">
+				<view >
+					<textarea @input="input" :value="data.question"  maxlength="120"  placeholder="请描述您的问题,以便我们尽快为您处理"></textarea>
+					<view  class="text-right text-df text-gray padding-bottom-10">
+						{{data.question.length}} / 120
+					</view>
+				</view>
+				<view class="imgArea">
+					<view class="padding-bottom-20">
+						<text class="">请提供相关问题的截图或照片(最多四张)</text>
+					</view>
+					<view class="cu-form-group" style="padding: 20rpx 0 0 0;">
+						<view class="grid col-3 grid-square flex-sub">
+							<view class="bg-img" v-for="(item,index) in imgList" :key="index" @click="viewImage(index)" >
+							 <image :src="imgList[index]" mode="aspectFill"></image>
+								<view class="cu-tag bg-red" @click.stop="DelImg(index)" >
+									<text class='cuIcon-close'></text>
+								</view>
+							</view>
+							<view class="solids" @click="chooseImage" v-if="imgList.length<4">
+								<text class='cuIcon-add ' style="font-size: 60rpx;color: #c9c9c9;"></text>
+							</view>
+						</view>
+					</view>
+					<!-- <u-upload @on-choose-complete="chooseImage" :auto-upload="false" width="194" height="194" :action="action" max-count="4" :file-list="fileList" ></u-upload> -->
+				</view>
+				
+			</view>
+			<view class="bg-white" style="height: 150rpx;">
+				
+			</view>
+		</view>
+		<view class="bg-white margin-top-20 footer-fixed" @click="sumit">
+			<view class="flex flex-direction padding-sm">
+				<button class="radius cu-btn bg-blue" style="padding: 45rpx;">提交反馈</button>
+			</view>
+		</view>
+		
+	</view>
+</template>
+
+<script>
+	var app = getApp();
+	export default {
+		data() {
+			return {
+				//图片回显
+				imgList:[],
+				data:{
+					member_id:'',
+					question:'',
+					image_base64:[],
+					type:"1",
+				},
+				//选择项列表
+				typeList:[
+					{
+						title:'功能异常:功能故障或不可用',
+						type:'1'
+					},
+					{
+						title:'产品建议:用的不爽,我有建议',
+						type:'2'
+					},
+					{
+						title:'安全密码:密码,故障等',
+						type:'3'
+					},
+					{
+						title:'其他问题',
+						type:'4'
+					},
+				],
+			}
+		},
+		methods: {
+			//选择反馈类型
+			RadioChange(e){
+				this.data.type=e.detail.value
+			},
+			/**输入问题描述
+			 * @param {Object} e
+			 */
+			input(e){
+				this.data.question=e.detail.value
+			},
+			sumit(){
+				if (this.$isEmpty(this.data.question)) {
+					uni.showToast({
+						title:"问题描述不能为空",
+						icon:"none"
+					})
+					return
+				}
+				if (this.data.question.length<3) {
+					uni.showToast({
+						title:"问题描述不能少于三个字",
+						icon:"none"
+					})
+					return
+				}
+				if (this.$isEmpty(this.data.image_base64)) {
+					uni.showToast({
+						title:"请提供相关截图",
+						icon:"none"
+					})
+					return
+				}
+				this.data.member_id='19478'
+				console.log(this.data)
+			},
+			/**
+			 * 上传问题截图
+			 */
+			chooseImage() {
+				let that=this
+				uni.chooseImage({
+					count: 4-this.imgList.length, 
+					sizeType: ['original', 'compressed'], 
+					sourceType: ['album'],
+					success: (res) => {
+						const tempFilePaths = res.tempFilePaths;
+						for (let index in tempFilePaths) {
+							//图片回显
+							that.imgList.push(tempFilePaths[index])
+							//图片转为base64的图片
+							uni.getFileSystemManager().readFile({
+							  filePath: tempFilePaths[index],
+							  //选择图片返回的相对路径
+							  encoding: 'base64',
+							  //编码格式
+							  success: res => {
+							    //成功的回调
+							    that.data.image_base64.push('data:image/jpeg;base64,' + res.data)
+							  }
+							});
+						}
+					
+					}
+				});
+			},
+			/*预览图片*/
+			viewImage(index) {
+				uni.previewImage({
+					urls: this.imgList,
+					current: index
+				});
+			},
+			/*删除图片*/
+			DelImg(index) {
+				uni.showModal({
+					title: '提示',
+					content: '确定要删除这张照片吗?',
+					cancelText: '取消',
+					confirmText: '确定',
+					success: res => {
+						if (res.confirm) {
+							this.imgList.splice(index, 1)
+						}
+					}
+				})
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+	.page{
+		background-color: #FFFFFF;
+		min-height: 100vh;
+	}
+	view{
+		box-sizing: border-box;
+	}
+	.commit{
+		color: #fff;
+		font-size: 28upx;
+		text-align: center;
+		line-height: 88upx;
+		margin: 0 20upx;
+		width: 690upx;
+		height:88upx;
+		background:#59a5f0;
+		border-radius:25px;
+		margin-bottom: 50upx;
+		position: absolute;
+		left: 0;
+		right: 0;
+		bottom: 0;
+		
+	}
+	.content{
+		margin: 0 26rpx;
+		.radioBox{
+			padding-top: 10rpx;
+			.radioItem{
+				padding: 18rpx;
+				margin-bottom: 15rpx;
+				border-radius: 10rpx;
+			}
+			.defalutBorder{
+				border: 1rpx solid #d1d1d1;
+			}
+			.checkBorder{
+				border: 1rpx solid #59a5f0;
+				color: #59a5f0;
+			}
+			
+		}
+		.area{
+			margin-top: 20rpx;
+			padding: 20rpx;
+			border-radius: 12rpx;
+			border: 1rpx solid #d1d1d1;
+			
+			textarea{
+				width: 100%;
+				line-height: 50rpx;
+			}
+			.imgArea{
+				border-top: 1rpx solid #d1d1d1;
+				padding-top: 30rpx;
+			}
+			
+		}
+	}
+	
+</style>

+ 111 - 0
pages/mine/mine-info/mine-info.vue

@@ -0,0 +1,111 @@
+<template>
+	<view>
+		<button class="item bg-white btn" style="padding: 10rpx 20rpx;">
+			<view class="flex align-center justify-center">
+				<text style="font-size: 28rpx;font-weight: 500;">头像:</text>
+			</view>
+			<view class="flex padding-top-20 ">
+				<u-avatar  size="88" :src="wxUserInfo.avatarUrl"></u-avatar>
+				<text class="cuIcon-right padding-left-20 "></text>
+			</view>
+		</button>
+		
+		<button class="item btn" style="padding: 6rpx 20rpx;">
+			<view class="flex align-center justify-center">
+				<text style="font-size: 28rpx;font-weight: 500;">昵称:</text>
+			</view>
+			<view class="flex align-center justify-center">
+				<text>{{wxUserInfo.nickName}}</text>
+				<text class="cuIcon-right padding-left-20"></text>
+			</view>
+		</button>
+		
+		<view class="item" @click="sexShow=true">
+			<view class="">
+				<text>性别:</text>
+			</view>
+			<view class="" >
+				<text v-text="wxUserInfo.gender==2?'女':'男'"></text>
+				<text class="cuIcon-right padding-left-10"></text>
+			</view>
+		</view>
+		
+		<view class="item">
+			<view class="">
+				<text>手机号:</text>
+			</view>
+			<view class="">
+				<text >{{phone}}</text>
+				<text class="cuIcon-right padding-left-10"></text>
+			</view>
+		</view>
+		
+		<view v-if="!$isEmpty(phone)" @click="loginOut" class="flex bg-blue cu-btn round" style="margin: 80rpx 20rpx;padding: 40rpx 0;">
+			退出登陆
+		</view>
+		<u-action-sheet :list="sexList" v-model="sexShow"></u-action-sheet>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				wxUserInfo:'',
+				phone:'',
+				sexList:[
+					{
+						text:'男',
+						value:1
+					},
+					{
+						text:'女',
+						value:2
+					},
+				],
+				sexShow:false
+			}
+		},
+		onLoad() {
+			this.wxUserInfo=this.$cache.get('userInfo')
+			console.log(this.wxUserInfo);
+			this.phone=this.$cache.get('phone')
+		},
+		methods: {
+			loginOut(){
+				try {
+				     uni.clearStorageSync();
+					 uni.showModal({
+					 	showCancel:false,
+						confirmText:"确认",
+						content:"退出成功",
+						success() {
+							uni.reLaunch({
+								url:"../../login/login"
+							})
+						}
+					 })
+				} catch (e) {
+					uni.showToast({
+						title:"退出失败",
+						icon:"none"
+					})
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.item{
+		display: flex;
+		justify-content: space-between;
+		background-color: #FFFFFF;
+		padding:26rpx 20rpx;
+		border-bottom: 1rpx solid #f4f4f4;
+	}
+	
+	.btn::after {
+		border: none;
+	}
+</style>

+ 365 - 0
pages/mine/mine.vue

@@ -0,0 +1,365 @@
+<template>
+<view class="">
+	<view class="pageBg">
+		<view class="mine_order_statue">
+			<view class="flex justify-between" style="padding: 20rpx;">
+				<view class="flex">
+					<image :src="userInfo.avatarUrl?userInfo.avatarUrl:'http://139.9.103.171:8888/group1/M00/00/01/iwlnq1_AYZqAb30pAAAQNvkj3Wk302.png'"  style="background-color: #FFFFFF;width: 110rpx;height: 110rpx;border-radius: 50%;" ></image>
+					<view  class="flex flex-direction padding-left-30">
+						<text class="text-lg text-bold" v-text="userInfo.nickName?userInfo.nickName:'暂无昵称'"></text>
+						<button v-if="$isEmpty(userInfo)" open-type="getUserInfo" @getuserinfo="getUserInfo" class="cu-btn  bg-white text-blue margin-top-20 df" style="margin-left: -20rpx;">
+							点击获取微信昵称和头像
+						</button>
+						<view v-else class="padding-20" >
+							<text  class="margin-top-30 text-df">{{phone}}</text>
+						</view>
+					</view>
+				</view>
+				<view @click="goUserInfo" class="flex align-center justify-center">
+					<text class="cuIcon-right"></text>
+				</view>
+			</view>
+		</view>
+		
+		<view class="item_list">
+			<view class=" flex justify-between" style="padding: 40rpx 20rpx;">
+				<view class="text-bold">所属公司</view>
+				<view class="text-gray">
+					<text>暂无公司信息</text>
+					<text class="cuIcon-playfill  padding-left-20" style="font-size: 28rpx;"></text>
+				</view>
+			</view>
+		</view>
+		
+		<view class="item_list" >
+			<view class="item" v-for="(item, index) in systemItemList" :key="index" @tap="tapToMenu(item.name)">
+				<view class="item_content">
+					<image :src="item.itemIcon"></image>
+					<text>{{ item.itemName }}</text>
+				</view>
+				<view class="">
+					<image src="http://139.9.103.171:1888/img/image/arrow.png"></image>
+				</view>
+			</view>
+		</view>
+	</view>
+</view>
+</template>
+
+<script>
+var app=getApp()
+import DtCustomBar from '@/components/dt_custom_bar.vue'
+let that
+export default {
+	components: {
+		DtCustomBar
+	},
+	data() {
+		return {
+			background: {
+				backgroundColor: '#f5f6f8',
+			},
+			phone:'',
+			userInfo:{},
+			systemItemList:[
+				// {
+				// 	itemName: '物业报修',
+				// 	itemIcon: '/static/index/blue/wuye.png',
+				// 	index:10
+				// },
+				// {
+				// 	itemName: '人员认证',
+				// 	itemIcon: '/static/index/blue/shenfen.png',
+				// 	index:10
+				// },
+				{
+					itemName: '我的消息',
+					itemIcon: '/static/index/blue/msg.png',
+					name:'msg'
+				},
+				{
+					itemName: '问题反馈',
+					itemIcon: '/static/index/blue/fankui.png',
+					name:'feedback'
+				},
+				{
+					itemName: '帮助中心',
+					itemIcon: '/static/index/blue/shuoming.png',
+					name:'help'
+				},
+				{
+					itemName: '用户协议',
+					itemIcon: '/static/index/blue/xieyi1.png',
+					name:'protocol'
+				}
+			],
+			memberId: '',
+			dataDetail: {},
+			orderStatusNum: {},
+			userDetail: {},
+			isLogin: false,
+		};
+	},
+	onShow() {
+		this.apiGetUserInfo()
+	},
+	onLoad() {
+		that=this
+	},
+	computed: {
+		
+	},
+	methods: {
+		//功能跳转
+		tapToMenu(name){
+			let url="protocol/protocol"
+			switch (name){
+				case 'feedback':
+					url="feedback/feedback"
+					break;
+				default:
+					break;
+			}
+			if (!this.$isEmpty(url)) {
+				uni.navigateTo({
+					url:url
+				})
+			}
+		},
+		
+		//获取微信昵称和头像
+		getUserInfo(e){
+			this.userInfo=e.detail.userInfo
+			console.log(this.userInfo.avatarUrl)
+			this.$cache.put('userInfo',this.userInfo)
+		},
+		//从缓存中获取用户信息
+		apiGetUserInfo(){
+			this.phone=this.$cache.get('phone') || ''
+			this.userInfo= this.$cache.get('userInfo') || {}
+		},
+		//跳转到用户信息
+		goUserInfo(){
+			uni.navigateTo({
+				url:"./mine-info/mine-info"
+			})
+		}
+	},
+
+};
+</script>
+<style lang="scss" scoped>
+page{
+	min-height: 100vh;
+	background-color: #f5f6f8;
+}
+button::after {
+	  border: none;
+	}
+.header {
+	// border-bottom-right-radius: 100rpx;
+	// border-bottom-left-radius: 100rpx;
+	//todo
+	height: 260upx;
+	background-repeat: no-repeat;
+	background-size: 100% 100%;
+	.member_head_img {
+		margin-right: 30upx;
+		image {
+			//todo
+			width: 110upx;
+			height:110upx;
+			border-radius: 59rpx;
+		}
+
+		.avatar-wrap {
+			display: inline-flex;
+			border: 0;
+			background-color: transparent;
+		}
+	}
+
+	.no_login {
+		display: flex;
+		flex-direction: column;
+		.no_login_btn {
+			border-radius: 25px;
+			//todo
+			font-size: 32upx;
+			color: #fff;
+			width: fit-content;
+			padding: 0 15upx;
+			height: 60upx;
+			line-height: 60upx;
+			background: transparent;
+		}
+	}
+
+	.member_info {
+		display: flex;
+		flex-direction: column;
+		.member_name_box {
+			display: flex;
+			flex-direction: row;
+			align-items: center;
+			.member_name { 
+				font-size: 40upx;
+				color: #fff;
+				font-weight: bold;
+			}
+			.member_level {
+				background: #ffc600;
+				color: #fff;
+				font-size: 22upx;
+				border-radius: 4upx;
+				padding: 5upx 10upx;
+				margin-left: 10upx;
+			}
+		}
+
+		.member_phone_box {
+			display: flex;
+			flex-direction: row;
+			align-items: center;
+			.member_phone { 
+				font-size: 24upx;
+				color: #FFFFFF;
+			}
+
+			image {
+				width: 19upx;
+				height: 19upx;
+				padding: 20upx;
+			}
+		}
+	}
+
+	.member_benefits {
+		background: #fff;
+		width: 180upx;
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+		text-align: center;
+		border-radius: 27upx 0px 0px 27upx;
+		height: 54upx;
+		text-align: center;
+		position: absolute;
+		right: 0;
+
+		image {
+			width: 26upx;
+			height: 23upx;
+			padding: 0 10upx 0 30upx;
+		}
+
+		.member_benefits_text {
+			font-size: 24upx;
+			color: #2f7ff5;
+			letter-spacing: 2upx;
+		}
+	}
+
+	button::after {
+		border: none;
+	}
+}
+
+.coupon_point {
+	display: flex;
+	flex-direction: row;
+	align-items: center;
+	height: 110upx;
+	background: #fff;
+	justify-content: space-around;
+
+	.item {
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		width: 50%;
+
+		.item_box {
+			display: flex;
+			flex-direction: row;
+			align-items: center;
+			letter-spacing: 2upx;
+
+			.item_content {
+				color: #2f7ff5;
+				font-size: 34upx;
+			}
+
+			.item_unit {
+				color: #2f7ff5;
+				font-size: 22upx;
+				margin-top: 6upx;
+			}
+		}
+
+		.item_text {
+			color: #333333;
+			font-size: 22upx;
+		}
+	}
+
+	.line {
+		width: 1upx;
+		height: 50upx;
+		background: #e5e5e5;
+	}
+}
+
+.mine_order_statue {
+	//todo
+	box-shadow: 0 10rpx #e7f1fd ;
+	margin: 20upx 20upx 0;
+	background: #fff;
+	padding: 10upx 20upx;
+	border-radius: 20rpx;
+}
+
+.item_list {
+	display: flex;
+	flex-direction: column;
+	background: #fff;
+	margin-top: 20upx;
+    margin-left: 20rpx;
+	margin-right: 20rpx;
+	border-radius: 10rpx;
+	.item {
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+		justify-content: space-between;
+		padding: 0 30upx;
+		height: 90upx;
+		border-bottom: 1upx solid #f1f1f1;
+
+		.item_content {
+			display: flex;
+			flex-direction: row;
+			align-items: center;
+
+			image {
+				width: 42upx;
+				height: 42upx;
+			}
+
+			text {
+				font-size: 28upx;
+				color: #333333;
+				margin-left: 20upx;
+			}
+		}
+
+		image {
+			width: 10upx;
+			height: 18upx;
+		}
+	}
+	.item:last-child {
+		border: none;
+	}
+}
+</style>

+ 24 - 0
pages/mine/protocol/protocol.vue

@@ -0,0 +1,24 @@
+<template>
+	<view>
+		<u-empty  marginTop="300"  icon-size="400" text="暂未开发" src="http://139.9.103.171:1888/miniofile/xlyq/empty/empty.png"></u-empty>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				
+			}
+		},
+		methods: {
+			
+		}
+	}
+</script>
+
+<style lang="scss">
+page{
+	background-color: #FFFFFF;
+}
+</style>

+ 35 - 0
pages/mine/setting/setting.vue

@@ -0,0 +1,35 @@
+<template>
+	<view>
+		<view class="item margin-top-20">
+			<text>用户协议</text>
+			<text class="cuIcon-right"></text>
+		</view>
+		<view class="item ">
+			<text></text>
+			<text class="cuIcon-right"></text>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				
+			}
+		},
+		methods: {
+			
+		}
+	}
+</script>
+
+<style lang="scss">
+	.item{
+		background-color: #FFFFFF;
+		display: flex;
+		justify-content: space-between;
+		padding: 24rpx 30rpx;
+		border-bottom: 1rpx solid #f5f5f5;
+	}
+</style>

+ 194 - 0
pages/my-camera/my-camera.vue

@@ -0,0 +1,194 @@
+<template>
+	<view class="warp">
+		<view class="center">
+			<image class="content" v-if="src!=null" :src="src" ></image>
+			<camera class="content" v-else :device-position="position" flash="auto" @error="error" >
+				<cover-image :class="type==1?'coverImg-type1':'coverImg-type0'"  :src="type==1?'../../static/camera/card.png':'http://139.9.103.171:1888/miniofile/xlyq/face2.png'"></cover-image>
+			</camera>
+		</view>
+		<view class="bottom">
+			<!-- 取消拍摄 -->
+			<image class="cancel"  @click="cancel" src="../../static/camera/back.png" ></image>
+			<!-- 确认选择照片 -->
+			<image class="confirm" @click="confirm" v-if="src!=null"  src="../../static/camera/confirm1.png" ></image>
+			<!-- 确认拍摄 -->
+			<image class="confirm" v-else @click="takePhoto" src="../../static/camera/takephoto.png" ></image>
+			<!-- 切换摄像头 -->
+			<image class="change" v-if="src==null"   @click="change" src="../../static/camera/change.png"  ></image>
+			<!-- 重新拍摄 -->
+			<image class="change" v-else  @click="rephoto" src="../../static/camera/rephoto.png"  ></image>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				//0 人面 1 证件
+				type:0,
+				
+				flash:'off',
+				position:'front',
+				src: null
+			}
+		},
+		onLoad(options) {
+			this.type=options.type || 0
+		},
+		methods: {
+			//确认
+			confirm(){
+				console.log(this.src)
+				/* 返回调用页面并把图片URL传递过去 */
+				let that=this
+				let pages = getCurrentPages();
+				let prevPage = pages[pages.length - 2]; 
+				prevPage.setData({
+					"image":that.src
+				})
+				uni.navigateBack();
+			},
+			//闪光灯切换
+			tapLight(){
+				if (this.src==null) {
+					this.flash=this.flash=='on'?'off':'on'
+				}
+			},
+			//切换镜头
+			change(){
+				if (this.src==null) {
+					this.position=this.position=='back'?'front':'back'
+				}
+			},
+			//重新拍摄
+			rephoto(){
+				let that=this
+				uni.showModal({
+					title:"提示",
+					content:"确定重新拍摄?",
+					success: (res) => {
+						if (res.confirm) {
+							that.src=null
+						}
+					}
+				})
+			},
+			//取消拍照
+			cancel(){
+				uni.showModal({
+					title:"提示",
+					content:"确定取消拍摄?",
+					success: (res) => {
+						if (res.confirm) {
+							uni.navigateBack()
+						}
+					}
+				})
+			},
+			//拍照
+			takePhoto() {
+				let that=this
+				const ctx = uni.createCameraContext();
+				ctx.takePhoto({
+					quality: 'high',
+					success: (res) => {
+						that.src = res.tempImagePath
+					},
+					fail: (err) => {
+						console.log(err)
+					}
+				});
+			},
+			//打印错误日志
+			error(e) {
+				console.log(e.detail);
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.warp{
+		height: 100vh;
+		background-color: #fff;
+	}
+	.top{
+		display: flex;
+		justify-content: space-between;
+		box-sizing: border-box;
+		image{
+			width: 50rpx;
+		}
+		//闪光灯
+		.light{
+			margin-left: 50rpx;
+			padding: 10rpx 0;
+		}
+		.rephoto{
+			margin-right: 30rpx;
+			padding: 6rpx 0;
+		}
+	}
+	
+	.center{
+		.content{
+			height: 80vh;
+			width: 100vw;
+			.coverImg-type0{
+				height: 75vh;
+				margin-top: -20rpx;
+				margin-bottom: 20rpx;
+				opacity: 0.3;
+			}
+			.coverImg-type1{
+				height: 80vh;
+				opacity: 0.6;
+			}
+		}
+	}
+	
+
+	
+	
+	// 底部功能按钮
+	.bottom{
+		height: 19vh;
+		display: flex;
+		justify-content:space-around;
+		align-items: center;
+		//切换镜头
+		.change{
+			height: 88rpx;
+			width: 88rpx;
+			margin-left: 40rpx;
+			opacity: 0.7;
+		}
+		//确认拍摄
+		.confirm{
+			height: 150rpx;
+			width: 150rpx
+		}
+		
+		//取消上传
+		.cancel{
+			height: 88rpx;
+			width: 88rpx;
+			margin-right: 40rpx;
+			opacity: .7;
+		}
+	}
+	
+	//重新拍摄按钮
+	.button {
+		font-size: 20rpx;
+	    background-color: #59a5f0; /* Green */
+	    border: none;
+	    color: white;
+	    padding: 2rpx 32rpx;
+	    text-align: center;
+	    text-decoration: none;
+	    display: inline-block;
+	    cursor: pointer;
+	}
+</style>

+ 74 - 0
pages/news/detail.vue

@@ -0,0 +1,74 @@
+<template>
+	<view>
+		<!--文章标题-->
+		<view class="title" >{{dataDetail.title}}</view>
+		<view class="text-gray " style="padding: 0 0 30rpx 30rpx;">
+			<text class="cuIcon-time padding-right-10"></text>
+			<text style="font-size: 28rpx;color: #999999;text-align: left;">{{dataDetail.time}}</text>
+		</view>
+		<view class="content-view-box">
+			<view class="font-view">
+				<u-parse :html="dataDetail.content"></u-parse>
+			</view>
+		</view>
+		<u-divider height="80">到底了</u-divider>
+	</view>
+</template>
+
+<script>
+	var app=getApp()
+	export default {
+		components: {
+		},
+		data() {
+			return {
+				dataDetail:{
+					title:'银川经开区以技术创新推动行业发展',
+					time:'2020-11-22 12:14:56',
+					content:`原标题:银川经开区:以技术创新推动行业发展
+
+实时进行监控、全自动采集数据、提前发出设备故障报警提示……在银川经济技术开发区(以下简称“银川经开区”)宁夏希望信息产业股份有限公司(以下简称“希望信息产业”)的“智慧冷库云管理APP”上,这些基本功能一应俱全,只需要轻轻点击一下手机,就可以随时“操作”冷库设备,这帮助工业企业提供了减少能耗的安全运行方案,提高了工作效率和智能化水平,加快了企业实现转型升级的步伐。
+
+据悉,“智慧冷库云管理APP”利用“互联网、大数据、云计算”等新兴技术,来实现数据采集在线监控、历史查询、业务报表、监控调取、数据接口等基本功能,快速提升制冷能源系统管理效率,以实现对制冷能源系统在线化、实时化、移动化、智能化管理,改变传统人工管理带来的设备运行效率低、能源浪费严重、设备故障率高以及制冷品质不良等问题,以工业互联网赋能,提高行业经营运维管理。
+
+“通过技术创新,让数据采集能够跨越空间,冷库中数百种参数呈现在APP里,无论从管理层的手机还是到现场工程师的电脑,随时随地一眼看尽冷库、制冷系统状态。”希望信息产业相关负责人说,同时,公司还根据企业需求,提供定制化服务模块,服务领域覆盖全国商业冷链物流、工业冷冻、大中型空调以及区域冷热联供能源站。
+
+当前,随着新一轮科技革命和产业革命加速发展,银川经开区抢抓机遇,实施工业互联网创新发展战略,引进国内外工业互联网领军人才和创业创新团队,培育了一批数字车间、智能工厂、工业互联网平台、上云标杆企业、两化融合管理体系等试点企业,园区也正以大数据智能化为引领,点燃创新“引擎”,驱动经济加快转型升级,为打造“千亿级升级版”经开区储蓄更多能量。(记者闫茜)`
+				},
+			}
+		},
+		onShow() {
+			
+		},
+		onLoad(options) {
+		},
+		methods: {
+			
+		}
+	}
+</script>
+
+
+<style lang="scss">
+	page {
+		background: #FFFFFF;
+	}
+	.title {
+		font-weight: 800;
+		font-size: 40rpx;
+		line-height: 54rpx;
+		color: #333333;
+		margin: 35rpx;
+	}
+	.content-view-box {
+		font-weight: normal;
+		vertical-align: baseline;
+		.font-view {
+			padding: 27.27rpx;
+			line-height: 2;
+		}
+		image {
+			width: 100%;
+		}
+	}
+</style>

+ 184 - 0
pages/news/news.vue

@@ -0,0 +1,184 @@
+<template>
+	<view>
+		<view class="uni-list" >
+		    <navigator url="./detail"  class="uni-list-cell"  hover-class="uni-list-cell-hover" v-for="(item,index) in newList" :key="index">
+		        <view class="uni-media-list" >
+					<!-- 左图右文 -->
+					<image   mode="aspectFill" class="uni-media-list-logo-left" :src="item.image"></image>
+		            <view class="uni-media-list-body" style="height: 180rpx;">
+		                <view class="uni-media-list-text-top text-cut-2">{{item.title}}</view>
+						<view class="text-cut-2 text-sm" style="color: #666666;">
+							<text>{{item.subTitle}}</text>
+						</view>
+		                <view class="uni-media-list-text-bottom">
+		                    <text>{{item.time}}</text>
+		                </view>
+		            </view>
+		        </view>
+		    </navigator>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				newList:[]
+			}
+		},
+		onLoad() {
+			this.fetchStaticData()
+		},
+		methods: {
+			fetchStaticData(){
+				this.newList=[
+					{
+						title:'银川综保区举行重大项目签约首发仪式',
+						subTitle:'原标题:推进新通道建设扩大对外开放——银川综保区举行重大项目签约暨“一带一路”国际卡车班列首发仪式',
+						time:'2020-11-15 18:51:56',
+						image:'http://139.9.103.171:1888/miniofile/xlyq/news.jpg'
+					},
+					{
+						title:'为新产业新业态发展提供一片沃土',
+						subTitle:'原标题:为新产业新业态发展提供一片沃土,为避免产业发展不好人才少,人才不够制约产业发展的恶性循环发生,我们更应该营造良好的创新环境,为新产业新业态发展提供一片沃土,为新职业创造更多的就业空间。',
+						time:'2020-11-15 18:51:56',
+						image:'http://139.9.103.171:1888/miniofile/xlyq/news1.jpg'
+					},
+					{
+						title:'银川育新机开新局推动工业高质量发展',
+						subTitle:'原标题:银川育新机开新局推动工业高质量发展坚持不懈推动高质量发展,加快转变经济发展方式,加快产业转型升级,加快新旧动能转换,推动经济发展实现量的合理增长和',
+						time:'2020-11-15 18:51:56',
+						image:'http://139.9.103.171:1888/miniofile/xlyq/news2.jpg'
+					},
+					{
+						title:'宁夏银川入选全国营商环境标杆城市',
+						subTitle:'原标题:银川入选全国营商环境标杆城市11月15日,记者从银川市审批服务管理局获悉,近日国家发改委组织召开了《中国营商环境报告2020》发布暨全国优化营商环境工作推',
+						time:'2020-11-22 11:38:22',
+						image:'http://139.9.103.171:1888/miniofile/xlyq/news3.jpg'
+					}
+				]
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.uni-list {
+	    background-color: #FFFFFF;
+	    position: relative;
+	    width: 100%;
+	    display: flex;
+	    flex-direction: column;
+	}
+	
+	.uni-list:after {
+	    position: absolute;
+	    z-index: 10;
+	    right: 0;
+	    bottom: 0;
+	    left: 0;
+	    height: 1px;
+	    content: '';
+	    -webkit-transform: scaleY(.5);
+	    transform: scaleY(.5);
+	    // background-color: #c8c7cc;
+	}
+	
+	.uni-list::before {
+	    position: absolute;
+	    z-index: 10;
+	    right: 0;
+	    top: 0;
+	    left: 0;
+	    height: 1px;
+	    content: '';
+	    -webkit-transform: scaleY(.5);
+	    transform: scaleY(.5);
+	}
+	
+	.uni-list-cell {
+	    position: relative;
+	    display: flex;
+	    flex-direction: row;
+	    justify-content: space-between;
+	    align-items: center;
+	}
+	
+	.uni-list-cell-hover {
+	    background-color: #eee;
+	}
+	
+	.uni-list-cell::after {
+	    position: absolute;
+	    z-index: 3;
+	    right: 0;
+	    bottom: 0;
+	    left: 30upx;
+	    height: 1px;
+	    content: '';
+	    -webkit-transform: scaleY(.5);
+	    transform: scaleY(.5);
+	    background-color: #c8c7cc;
+	}
+	
+	.uni-list .uni-list-cell:last-child::after {
+	    height: 0upx;
+	}
+	
+	/* 图文列表 */
+	.uni-media-list {
+	    padding: 22upx 20upx;
+	    box-sizing: border-box;
+	    display: flex;
+	    width: 100%;
+	    flex-direction: row;
+	}
+	
+	.uni-navigate-right.uni-media-list {
+	    padding-right: 74upx;
+	}
+	.uni-media-list-text-bottom {
+	    line-height: 30upx;
+	    font-size: 26upx;
+	    color: #8f8f94;
+	}
+	
+	.uni-media-list-logo-left {
+		border-radius: 10rpx;
+	    width: 230upx;
+	    height: 180upx;
+		margin-right: 20upx
+	}
+	
+	.uni-media-list-logo-right {
+	    width: 180upx;
+	    height: 140upx;
+		margin-left: 20upx
+	}
+	
+	.uni-media-list-body {
+	    display: flex;
+	    flex: 1;
+	    flex-direction: column;
+	    justify-content: space-between;
+	    align-items: flex-start;
+	    overflow: hidden;
+	    height: auto;
+	}
+	
+	.uni-media-list-text-top {
+	    width: 100%;
+	    line-height: 36upx;
+	    height: 50upx;
+	    font-size: 26upx;
+		font-weight: 800;
+	    overflow: hidden;
+	}
+	
+	.uni-media-list-text-bottom {
+	    display: flex;
+	    flex-direction: row;
+	    justify-content: space-between;
+	}
+</style>

+ 219 - 0
pages/test/test.vue

@@ -0,0 +1,219 @@
+<template>
+	<view class="padding-20">
+		<view class="auth">
+			<text class="cuIcon-titles text-blue padding-right-10"></text>
+			<text>个人信息认证</text>
+			<view class="card">
+				<u-form :model="model"  ref="uForm" >
+					<u-form-item  :label-width="labelWidth"  label="姓名" >
+						<u-input  placeholder="请输入姓名" v-model="model.name" type="text"></u-input>
+					</u-form-item>
+					<u-form-item  :label-width="labelWidth"   label="性别" >
+						<u-input  type="select" :select-open="sexSelectShow" v-model="model.sex" placeholder="请选择性别" @click="sexSelectShow = true"></u-input>
+					</u-form-item>
+					<u-form-item   label="身份证号"  :label-width="labelWidth">
+						<u-input  placeholder="请输入身份证号" v-model="model.idcard" type="idcard"></u-input>
+					</u-form-item>
+					<u-form-item   label="手机号码"  :label-width="labelWidth">
+						<u-input  placeholder="请输入手机号" v-model="model.phone" type="number"></u-input>
+					</u-form-item>
+					<u-form-item :border-bottom="false"  label="面部信息采集"  :label-width="labelWidth"></u-form-item>
+				</u-form>
+				
+				<view @click="" class="flex justify-center padding-bottom-50">
+					<view class=" ">
+						<upload-img
+						   :width="$isEmpty(face_url)?300:560"
+						   :height="$isEmpty(face_url)?300:420"
+						  :currentImage="face_url"
+						  bgsrc="http://139.9.103.171:1888/img/image/camera1.png"
+						  >
+						</upload-img>
+						<view class="text-center padding-top-20" style="color: #59a5f0;">
+						 <text class="cuIcon-camera padding-right-sm" style="font-size: 30rpx;"></text>
+						 <text v-if="$isEmpty(face_url)">点击上传人脸</text>
+						 <text style="margin-top: 40rpx;display: inline-block;" v-else>点击重新上传</text>
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+		<view class="auth">
+			<text class="cuIcon-titles text-blue padding-right-10"></text>
+			<text>企业认证信息</text>
+			<view class="card">
+				<u-form :model="model"  ref="uForm" >
+					<u-form-item  :label-width="labelWidth"   label="公司园区" >
+						<u-input  type="select" :select-open="ganderSelectShow" v-model="model.gander" placeholder="请选择工作园区" @click="ganderSelectShow = true"></u-input>
+					</u-form-item>
+					<u-form-item  :label-width="labelWidth"   label="所属企业" >
+						<u-input  type="select" :select-open="companySelectShow" v-model="model.company" placeholder="请选择所属企业" @click="companySelectShow = true"></u-input>
+					</u-form-item>
+					<u-form-item  :label-width="labelWidth"  label="工作岗位" >
+						<u-input  placeholder="请输入工作岗位" v-model="model.jobs" type="text"></u-input>
+					</u-form-item>
+					<u-form-item  :label-width="labelWidth"  label="企业联系人" >
+						<u-input  placeholder="请输入企业联系人" v-model="model.contact" type="text"></u-input>
+					</u-form-item>
+				</u-form>
+			</view>
+		</view>
+		<view class="cu-btn bg-blue round flex" style="padding: 40rpx 0;margin-top: 40rpx;">
+			提交
+		</view>
+		<u-action-sheet :list="sexSelectList" v-model="sexSelectShow" @click="sexSelectCallback"></u-action-sheet>
+		<u-action-sheet :list="ganderSelectList" v-model="ganderSelectShow" @click="ganderSelectCallback"></u-action-sheet>
+		<u-action-sheet :list="companySelectList" v-model="companySelectShow" @click="companySelectCallback"></u-action-sheet>
+		<u-action-sheet @click="faceSelectCallback"  z-index="999999" :list="faceSelectList" v-model="faceSelectShow"></u-action-sheet>
+	</view>
+</template>
+
+<script>
+	import uploadImg from '@/components/uploadimg/uploadImg.vue'
+	let that = this;
+	export default {
+		components:{
+		   uploadImg
+		},
+		data() {
+			return {
+				labelWidth:'200',
+				model: {
+					name: '',
+					sex: '',
+					phone: '',
+					idcard:'',
+					gander:'',
+					company:'',
+					jobs:'',
+					contact:'',
+					face_image:''
+				},
+				//图片回显
+				face_url:'',
+				//性别
+				sexSelectList: [{text: '男'},{text: '女'}],
+				sexSelectShow: false,
+				//园区
+				ganderSelectList: [],
+				ganderSelectShow: false,
+				//企业
+				companySelectList: [],
+				companySelectShow: false,
+				//上传人脸的方式
+				faceSelectList: [{
+					text: '相册上传',
+				}, {
+					text: '拍照上传'
+				}],
+				faceSelectShow:false,
+				//验证码
+				codeTips: '',
+				
+			}
+		},
+		onLoad() {
+			this.fetchStaticData()
+			this.initData()
+		},
+		methods: {
+			initData(){
+				if (!this.$isEmpty(this.$cache.get('phone'))) {
+					this.model.phone=this.$cache.get('phone')
+				}
+			},
+			//性别
+			sexSelectCallback(index) {
+				uni.hideKeyboard();
+				this.model.sex = this.sexSelectList[index].text;
+			},
+			//园区
+			ganderSelectCallback(index) {
+				uni.hideKeyboard();
+				this.model.gander = this.ganderSelectList[index].text;
+			},
+			//公司
+			companySelectCallback(index) {
+				uni.hideKeyboard();
+				this.model.company = this.companySelectList[index].text;
+			},
+			faceSelectCallback(index){
+				if (index==0) {
+					//图片上传
+					this.chooseImage()
+				} else if(index==1){
+					//拍照上传
+					uni.navigateTo({
+						url:"../my-camera/my-camera"
+					})
+				}
+			},
+			//点击上传图片事件
+			chooseImage: function () {
+			  uni.chooseImage({
+			    count: 1,
+			    //最多可以选择的图片张数,默认9
+			    sourceType: ['album', 'camera'],
+			    sizeType: ['compressed'],
+			    //可选择原图或压缩后的图片
+			    success: res => {
+			      that.handelImg(res.tempFilePaths[0])
+			    }
+			  });
+			},
+			//处理照片,拍照上传和相册上传的共同处理方法
+			handelImg(imgUrl){
+				that.face_url=imgUrl
+				uni.getFileSystemManager().readFile({
+				  filePath: imgUrl,
+				  //选择图片返回的相对路径
+				  encoding: 'base64',
+				  //编码格式
+				  success: res => {
+					  //图片的base64字符串
+					  that.face_image='data:image/jpeg;base64,' + res.data
+				  }
+				});
+			},
+			fetchStaticData(){
+				this.ganderSelectList=[
+					{
+						text: '新邻园区1'
+					},
+					{
+						text: '新邻园区2'
+					}
+				]
+				this.companySelectList=[
+					{
+						text: '新邻企业1'
+					},
+					{
+						text: '新邻企业2'
+					}
+				]
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	page{
+		background-color: #FFFFFF;
+	}
+	.auth{
+		padding: 40rpx 10rpx;
+		.card{
+			margin-top: 20rpx;
+			padding: 0 30rpx;
+			box-sizing: border-box;
+			border-radius: 12rpx;
+			box-shadow: 0 -10rpx rgba(248, 248, 248,.9) ,0 10rpx rgba(248, 248, 248,.9) , -10rpx 0rpx rgba(248, 248, 248,.9) ,10rpx 0rpx rgba(248, 248, 248,.9);
+			.item{
+				padding:30rpx 0;
+				display: flex;
+				justify-content: space-between;
+			}
+		}
+	}
+</style>

+ 24 - 0
pages/test/test1.vue

@@ -0,0 +1,24 @@
+<template>
+	
+</template>
+
+<script>
+export default {
+	name: '',
+	data() {
+		return {
+			
+		};
+	},
+	onLoad() {
+		
+	},
+	methods:{
+		
+	}
+};
+</script>
+
+<style lang="scss" scoped>
+	
+</style>

BIN
static/camera/back.png


BIN
static/camera/card.png


BIN
static/camera/change.png


BIN
static/camera/confirm1.png


BIN
static/camera/rephoto.png


BIN
static/camera/takephoto.png


BIN
static/index/blue/avatar1.png


BIN
static/index/blue/contact.png


BIN
static/index/blue/face.png


BIN
static/index/blue/fankui.png


BIN
static/index/blue/msg.png


BIN
static/index/blue/setting.png


BIN
static/index/blue/shenfen.png


BIN
static/index/blue/shuoming.png


BIN
static/index/blue/touxiang.png


BIN
static/index/blue/wuye.png


BIN
static/index/blue/xieyi1.png


BIN
static/index/fire/more.png


BIN
static/index/fire/ranqi.png


BIN
static/index/fire/xiaofang.png


BIN
static/index/fire/yangan.png


BIN
static/index/gander/cewen.png


BIN
static/index/gander/cewen1.png


BIN
static/index/gander/qiye.png


BIN
static/index/gander/renzheng.png


BIN
static/index/gander/renzheng1.png


BIN
static/index/gander/tongxing.png


BIN
static/login/2.png


BIN
static/login/3.png


BIN
static/login/sj.png


BIN
static/login/wx.png


BIN
static/login/yz.png


BIN
static/tarbar/home.png


BIN
static/tarbar/home0.png


BIN
static/tarbar/my.png


BIN
static/tarbar/my0.png


BIN
static/tarbar/news.png


BIN
static/tarbar/news0.png


+ 76 - 0
uni.scss

@@ -0,0 +1,76 @@
+/**
+ * 这里是uni-app内置的常用样式变量
+ *
+ * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
+ * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
+ *
+ */
+
+/**
+ * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
+ *
+ * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
+ */
+
+/* 颜色变量 */
+@import "uview-ui/theme.scss";
+/* 行为相关颜色 */
+$uni-color-primary: #007aff;
+$uni-color-success: #4cd964;
+$uni-color-warning: #f0ad4e;
+$uni-color-error: #dd524d;
+
+/* 文字基本颜色 */
+$uni-text-color:#333;//基本色
+$uni-text-color-inverse:#fff;//反色
+$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
+$uni-text-color-placeholder: #808080;
+$uni-text-color-disable:#c0c0c0;
+
+/* 背景颜色 */
+$uni-bg-color:#ffffff;
+$uni-bg-color-grey:#f8f8f8;
+$uni-bg-color-hover:#f1f1f1;//点击状态颜色
+$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
+
+/* 边框颜色 */
+$uni-border-color:#c8c7cc;
+
+/* 尺寸变量 */
+
+/* 文字尺寸 */
+$uni-font-size-sm:24rpx;
+$uni-font-size-base:28rpx;
+$uni-font-size-lg:32rpx;
+
+/* 图片尺寸 */
+$uni-img-size-sm:40rpx;
+$uni-img-size-base:52rpx;
+$uni-img-size-lg:80rpx;
+
+/* Border Radius */
+$uni-border-radius-sm: 4rpx;
+$uni-border-radius-base: 6rpx;
+$uni-border-radius-lg: 12rpx;
+$uni-border-radius-circle: 50%;
+
+/* 水平间距 */
+$uni-spacing-row-sm: 10px;
+$uni-spacing-row-base: 20rpx;
+$uni-spacing-row-lg: 30rpx;
+
+/* 垂直间距 */
+$uni-spacing-col-sm: 8rpx;
+$uni-spacing-col-base: 16rpx;
+$uni-spacing-col-lg: 24rpx;
+
+/* 透明度 */
+$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
+
+/* 文章场景相关 */
+$uni-color-title: #2C405A; // 文章标题颜色
+$uni-font-size-title:40rpx;
+$uni-color-subtitle: #555555; // 二级标题颜色
+$uni-font-size-subtitle:36rpx;
+$uni-color-paragraph: #3F536E; // 文章段落颜色
+$uni-font-size-paragraph:30rpx;

+ 114 - 0
utils/cache.js

@@ -0,0 +1,114 @@
+const postfix = '_cache_time'; // 缓存前缀
+
+const simpleCache = {
+	postfix: postfix,
+}
+
+
+/**
+ * 写入缓存
+ * @param {String} key 本地缓存中的指定的key
+ * @param {Any} data 需要存储的内容,只支持原生类型、及能够通过 JSON.stringify 序列化的对象
+ * @param {Number} time 保存的时间, 数字类型,单位秒 为空则永久有效.
+ */
+simpleCache.put = function(key, data, time) {
+	uni.setStorageSync(key, data)
+	var seconds = parseInt(time);
+	if (seconds > 0) {
+		var timestamp = Date.parse(new Date());
+		timestamp = timestamp / 1000 + seconds;
+		uni.setStorageSync(key + postfix, timestamp + "")
+	} else {
+		uni.removeStorageSync(key + postfix)
+	}
+}
+
+/**
+ * 从本地缓存中同步获取指定 key 对应的内容。
+ * @param {String} key 本地缓存中的指定的 key
+ * @param def 获取失败时的默认内容,可以为空.
+ */
+simpleCache.get = function(key, def) {
+	var deadtime = parseInt(uni.getStorageSync(key + postfix))
+	if (deadtime) {
+		if (parseInt(deadtime) < Date.parse(new Date()) / 1000) {
+			//已过期
+			if (def) {
+				return def;
+			} else {
+				//清除过期时间
+				uni.removeStorageSync(key + postfix)
+				//移除缓存
+				uni.removeStorageSync(key)
+				return false;
+			}
+		}
+	}
+	var res = uni.getStorageSync(key);
+	if (res) {
+		return res;
+	} else {
+		if (def == undefined || def == "") {
+			def = false;
+			uni.removeStorageSync(key)
+		}
+		return def;
+	}
+}
+
+/**
+ * 从本地缓存中同步移除指定 key。
+ * @param {String} key 本地缓存中的指定的 key
+ */
+simpleCache.remove = function(key) {
+	uni.removeStorageSync(key);
+	uni.removeStorageSync(key + postfix);
+}
+
+/**
+ * 同步清理本地数据缓存。
+ */
+simpleCache.clear = function() {
+	// 这里面其实可以扩展你不想清理的缓存,比如你保存的用户登录状态. 在清理之前先获取一次.
+	// var user = simpleCache.get("user_info"); 
+	uni.clearStorageSync();
+	// simpleCache.put("user_info",user); // 等 其它的自行扩展.
+}
+
+simpleCache.image_cache=function(id_key,image_url,isError,time=3*24*60*60) {
+	let imgTemp= simpleCache.get(id_key)
+	if(!imgTemp){
+		//本地没有缓存,需要下载
+		uni.downloadFile({
+		    url: image_url, 
+		    success: (res) => {
+		        if (res.statusCode === 200) {
+					let temp=res.tempFilePath
+					simpleCache.put(id_key,temp,time)
+		        }
+		    }
+		});
+		console.log("我来自网络")
+		return image_url
+	}else{
+		if(isError){
+			console.log("我发生错误了")
+			return imgTemp
+		}else{
+			console.log("我没有发生错误")
+			return image_url
+		}
+	}
+}
+
+
+
+// export default simpleCache
+
+module.exports = {
+	put:simpleCache.put,
+	get:simpleCache.get,
+	remove:simpleCache.remove,
+	clear:simpleCache.clear,
+	cacheImg:simpleCache.image_cache
+}

+ 88 - 0
utils/my-request/adapters/index.js

@@ -0,0 +1,88 @@
+import buildURL from '../helpers/buildURL'
+import buildFullPath from '../core/buildFullPath'
+import settle from '../core/settle'
+
+/**
+ * 返回可选值存在的配置
+ * @param {Array} keys - 可选值数组
+ * @param {Object} config2 - 配置
+ * @return {{}} - 存在的配置项
+ */
+const mergeKeys = (keys, config2) => {
+  let config = {}
+  keys.forEach(prop => {
+    if (typeof config2[prop] !== 'undefined') {
+      config[prop] = config2[prop]
+    }
+  })
+  return config
+}
+export default (config) => {
+  return new Promise((resolve, reject) => {
+    const _config = {
+      url: buildURL(buildFullPath(config.baseURL, config.url), config.params),
+      header: config.header,
+      complete: (response) => {
+        response.config = config
+        try {
+          // 对可能字符串不是json 的情况容错
+          if (typeof response.data === 'string') {
+            response.data = JSON.parse(response.data)
+          }
+          // eslint-disable-next-line no-empty
+        } catch (e) {
+        }
+        settle(resolve, reject, response)
+      }
+    }
+    let requestTask
+    if (config.method === 'UPLOAD') {
+      delete _config.header['content-type']
+      delete _config.header['Content-Type']
+      let otherConfig = {
+        // #ifdef MP-ALIPAY
+        fileType: config.fileType,
+        // #endif
+        filePath: config.filePath,
+        name: config.name
+      }
+      const optionalKeys = [
+        // #ifdef APP-PLUS || H5
+        'files',
+        // #endif
+        // #ifdef H5
+        'file',
+        // #endif
+        'formData'
+      ]
+      requestTask = uni.uploadFile({..._config, ...otherConfig, ...mergeKeys(optionalKeys, config)})
+    } else if (config.method === 'DOWNLOAD') {
+      requestTask = uni.downloadFile(_config)
+    } else {
+      const optionalKeys = [
+        'data',
+        'method',
+        // #ifdef MP-ALIPAY || MP-WEIXIN
+        'timeout',
+        // #endif
+        'dataType',
+        // #ifndef MP-ALIPAY || APP-PLUS
+        'responseType',
+        // #endif
+        // #ifdef APP-PLUS
+        'sslVerify',
+        // #endif
+        // #ifdef H5
+        'withCredentials',
+        // #endif
+        // #ifdef APP-PLUS
+        'firstIpv4',
+        // #endif
+      ]
+      requestTask = uni.request({..._config,...mergeKeys(optionalKeys, config)})
+    }
+    if (config.getTask) {
+      config.getTask(requestTask, config)
+    }
+  })
+}

+ 51 - 0
utils/my-request/core/InterceptorManager.js

@@ -0,0 +1,51 @@
+'use strict'
+
+
+function InterceptorManager() {
+  this.handlers = []
+}
+
+/**
+ * Add a new interceptor to the stack
+ *
+ * @param {Function} fulfilled The function to handle `then` for a `Promise`
+ * @param {Function} rejected The function to handle `reject` for a `Promise`
+ *
+ * @return {Number} An ID used to remove interceptor later
+ */
+InterceptorManager.prototype.use = function use(fulfilled, rejected) {
+  this.handlers.push({
+    fulfilled: fulfilled,
+    rejected: rejected
+  })
+  return this.handlers.length - 1
+}
+
+/**
+ * Remove an interceptor from the stack
+ *
+ * @param {Number} id The ID that was returned by `use`
+ */
+InterceptorManager.prototype.eject = function eject(id) {
+  if (this.handlers[id]) {
+    this.handlers[id] = null
+  }
+}
+
+/**
+ * Iterate over all the registered interceptors
+ *
+ * This method is particularly useful for skipping over any
+ * interceptors that may have become `null` calling `eject`.
+ *
+ * @param {Function} fn The function to call for each interceptor
+ */
+InterceptorManager.prototype.forEach = function forEach(fn) {
+  this.handlers.forEach(h => {
+    if (h !== null) {
+      fn(h)
+    }
+  })
+}
+
+export default InterceptorManager

+ 199 - 0
utils/my-request/core/Request.js

@@ -0,0 +1,199 @@
+/**
+ * @Class Request
+ * @description luch-request http请求插件
+ * @version 3.0.4
+ * @Author lu-ch
+ * @Date 2020-07-05
+ * @Email webwork.s@qq.com
+ * 文档: https://www.quanzhan.co/luch-request/
+ * github: https://github.com/lei-mu/luch-request
+ * DCloud: http://ext.dcloud.net.cn/plugin?id=392
+ * HBuilderX: beat-2.7.14 alpha-2.8.0
+ */
+
+
+import dispatchRequest from './dispatchRequest'
+import InterceptorManager from './InterceptorManager'
+import mergeConfig from './mergeConfig'
+import defaults from './defaults'
+import { isPlainObject } from '../utils'
+
+export default class Request {
+  /**
+   * @param {Object} arg - 全局配置
+   * @param {String} arg.baseURL - 全局根路径
+   * @param {Object} arg.header - 全局header
+   * @param {String} arg.method = [GET|POST|PUT|DELETE|CONNECT|HEAD|OPTIONS|TRACE] - 全局默认请求方式
+   * @param {String} arg.dataType = [json] - 全局默认的dataType
+   * @param {String} arg.responseType = [text|arraybuffer] - 全局默认的responseType。App和支付宝小程序不支持
+   * @param {Object} arg.custom - 全局默认的自定义参数
+   * @param {Number} arg.timeout - 全局默认的超时时间,单位 ms。默认30000。仅微信小程序(2.10.0)、支付宝小程序支持
+   * @param {Boolean} arg.sslVerify - 全局默认的是否验证 ssl 证书。默认true.仅App安卓端支持(HBuilderX 2.3.3+)
+   * @param {Boolean} arg.withCredentials - 全局默认的跨域请求时是否携带凭证(cookies)。默认false。仅H5支持(HBuilderX 2.6.15+)
+   * @param {Boolean} arg.firstIpv4 - 全DNS解析时优先使用ipv4。默认false。仅 App-Android 支持 (HBuilderX 2.8.0+)
+   * @param {Function(statusCode):Boolean} arg.validateStatus - 全局默认的自定义验证器。默认statusCode >= 200 && statusCode < 300
+   */
+  constructor(arg = {}) {
+    if (!isPlainObject(arg)) {
+      arg = {}
+      console.warn('设置全局参数必须接收一个Object')
+    }
+    this.config = {...defaults, ...arg}
+    this.interceptors = {
+      request: new InterceptorManager(),
+      response: new InterceptorManager()
+    }
+  }
+
+  /**
+   * @Function
+   * @param {Request~setConfigCallback} f - 设置全局默认配置
+   */
+  setConfig(f) {
+    this.config = f(this.config)
+  }
+
+  middleware(config) {
+    config = mergeConfig(this.config, config)
+    let chain = [dispatchRequest, undefined]
+    let promise = Promise.resolve(config)
+
+    this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
+      chain.unshift(interceptor.fulfilled, interceptor.rejected)
+    })
+
+    this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
+      chain.push(interceptor.fulfilled, interceptor.rejected)
+    })
+
+    while (chain.length) {
+      promise = promise.then(chain.shift(), chain.shift())
+    }
+
+    return promise
+  }
+
+  /**
+   * @Function
+   * @param {Object} config - 请求配置项
+   * @prop {String} options.url - 请求路径
+   * @prop {Object} options.data - 请求参数
+   * @prop {Object} [options.responseType = config.responseType] [text|arraybuffer] - 响应的数据类型
+   * @prop {Object} [options.dataType = config.dataType] - 如果设为 json,会尝试对返回的数据做一次 JSON.parse
+   * @prop {Object} [options.header = config.header] - 请求header
+   * @prop {Object} [options.method = config.method] - 请求方法
+   * @returns {Promise<unknown>}
+   */
+  request(config = {}) {
+    return this.middleware(config)
+  }
+
+  get(url, options = {}) {
+    return this.middleware({
+      url,
+      method: 'GET',
+      ...options
+    })
+  }
+
+  post(url, data, options = {}) {
+    return this.middleware({
+      url,
+      data,
+      method: 'POST',
+      ...options
+    })
+  }
+
+  // #ifndef MP-ALIPAY
+  put(url, data, options = {}) {
+    return this.middleware({
+      url,
+      data,
+      method: 'PUT',
+      ...options
+    })
+  }
+
+  // #endif
+
+  // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU
+  delete(url, data, options = {}) {
+    return this.middleware({
+      url,
+      data,
+      method: 'DELETE',
+      ...options
+    })
+  }
+
+  // #endif
+
+  // #ifdef APP-PLUS || H5 || MP-WEIXIN
+  connect(url, data, options = {}) {
+    return this.middleware({
+      url,
+      data,
+      method: 'CONNECT',
+      ...options
+    })
+  }
+
+  // #endif
+
+  // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU
+  head(url, data, options = {}) {
+    return this.middleware({
+      url,
+      data,
+      method: 'HEAD',
+      ...options
+    })
+  }
+
+  // #endif
+
+  // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU
+  options(url, data, options = {}) {
+    return this.middleware({
+      url,
+      data,
+      method: 'OPTIONS',
+      ...options
+    })
+  }
+
+  // #endif
+
+  // #ifdef APP-PLUS || H5 || MP-WEIXIN
+  trace(url, data, options = {}) {
+    return this.middleware({
+      url,
+      data,
+      method: 'TRACE',
+      ...options
+    })
+  }
+
+  // #endif
+
+  upload(url, config = {}) {
+    config.url = url
+    config.method = 'UPLOAD'
+    return this.middleware(config)
+  }
+
+  download(url, config = {}) {
+    config.url = url
+    config.method = 'DOWNLOAD'
+    return this.middleware(config)
+  }
+}
+
+
+/**
+ * setConfig回调
+ * @return {Object} - 返回操作后的config
+ * @callback Request~setConfigCallback
+ * @param {Object} config - 全局默认config
+ */

+ 20 - 0
utils/my-request/core/buildFullPath.js

@@ -0,0 +1,20 @@
+'use strict'
+
+import isAbsoluteURL from '../helpers/isAbsoluteURL'
+import combineURLs from '../helpers/combineURLs'
+
+/**
+ * Creates a new URL by combining the baseURL with the requestedURL,
+ * only when the requestedURL is not already an absolute URL.
+ * If the requestURL is absolute, this function returns the requestedURL untouched.
+ *
+ * @param {string} baseURL The base URL
+ * @param {string} requestedURL Absolute or relative URL to combine
+ * @returns {string} The combined full path
+ */
+export default function buildFullPath(baseURL, requestedURL) {
+  if (baseURL && !isAbsoluteURL(requestedURL)) {
+    return combineURLs(baseURL, requestedURL)
+  }
+  return requestedURL
+}

+ 30 - 0
utils/my-request/core/defaults.js

@@ -0,0 +1,30 @@
+/**
+ * 默认的全局配置
+ */
+
+
+export default {
+  baseURL: '',
+  header: {},
+  method: 'GET',
+  dataType: 'json',
+  // #ifndef MP-ALIPAY || APP-PLUS
+  responseType: 'text',
+  // #endif
+  custom: {},
+  // #ifdef MP-ALIPAY || MP-WEIXIN
+  timeout: 30000,
+  // #endif
+  // #ifdef APP-PLUS
+  sslVerify: true,
+  // #endif
+  // #ifdef H5
+  withCredentials: false,
+  // #endif
+  // #ifdef APP-PLUS
+  firstIpv4: false,
+  // #endif
+  validateStatus: function validateStatus(status) {
+    return status >= 200 && status < 300
+  }
+}

+ 6 - 0
utils/my-request/core/dispatchRequest.js

@@ -0,0 +1,6 @@
+import adapter from '../adapters/index'
+
+
+export default (config) => {
+  return adapter(config)
+}

+ 89 - 0
utils/my-request/core/mergeConfig.js

@@ -0,0 +1,89 @@
+import {deepMerge} from '../utils'
+
+/**
+ * 合并局部配置优先的配置,如果局部有该配置项则用局部,如果全局有该配置项则用全局
+ * @param {Array} keys - 配置项
+ * @param {Object} globalsConfig - 当前的全局配置
+ * @param {Object} config2 - 局部配置
+ * @return {{}}
+ */
+const mergeKeys = (keys, globalsConfig, config2) => {
+  let config = {}
+  keys.forEach(prop => {
+    if (typeof config2[prop] !== 'undefined') {
+      config[prop] = config2[prop]
+    } else if (typeof globalsConfig[prop] !== 'undefined') {
+      config[prop] = globalsConfig[prop]
+    }
+  })
+  return config
+}
+/**
+ *
+ * @param globalsConfig - 当前实例的全局配置
+ * @param config2 - 当前的局部配置
+ * @return - 合并后的配置
+ */
+export default (globalsConfig, config2 = {}) => {
+  const method = config2.method || globalsConfig.method || 'GET'
+  let config = {
+    baseURL: globalsConfig.baseURL || '',
+    method: method,
+    url: config2.url || '',
+    params: config2.params || {},
+    custom: {...(globalsConfig.custom || {}), ...(config2.custom || {})},
+    header: deepMerge(globalsConfig.header || {}, config2.header || {})
+  }
+  const defaultToConfig2Keys = ['getTask', 'validateStatus']
+  config = {...config, ...mergeKeys(defaultToConfig2Keys, globalsConfig, config2)}
+
+  // eslint-disable-next-line no-empty
+  if (method === 'DOWNLOAD') {
+
+  } else if (method === 'UPLOAD') {
+    delete config.header['content-type']
+    delete config.header['Content-Type']
+    const uploadKeys = [
+      // #ifdef APP-PLUS || H5
+      'files',
+      // #endif
+      // #ifdef MP-ALIPAY
+      'fileType',
+      // #endif
+      // #ifdef H5
+      'file',
+      // #endif
+      'filePath',
+      'name',
+      'formData',
+    ]
+    uploadKeys.forEach(prop => {
+      if (typeof config2[prop] !== 'undefined') {
+        config[prop] = config2[prop]
+      }
+    })
+  } else {
+    const defaultsKeys = [
+      'data',
+      // #ifdef MP-ALIPAY || MP-WEIXIN
+      'timeout',
+      // #endif
+      'dataType',
+      // #ifndef MP-ALIPAY || APP-PLUS
+      'responseType',
+      // #endif
+      // #ifdef APP-PLUS
+      'sslVerify',
+      // #endif
+      // #ifdef H5
+      'withCredentials',
+      // #endif
+      // #ifdef APP-PLUS
+      'firstIpv4',
+      // #endif
+    ]
+    config = {...config, ...mergeKeys(defaultsKeys, globalsConfig, config2)}
+  }
+
+  return config
+}

+ 16 - 0
utils/my-request/core/settle.js

@@ -0,0 +1,16 @@
+/**
+ * Resolve or reject a Promise based on response status.
+ *
+ * @param {Function} resolve A function that resolves the promise.
+ * @param {Function} reject A function that rejects the promise.
+ * @param {object} response The response.
+ */
+export default function settle(resolve, reject, response) {
+  const validateStatus = response.config.validateStatus
+  const status = response.statusCode
+  if (status && (!validateStatus || validateStatus(status))) {
+    resolve(response)
+  } else {
+    reject(response)
+  }
+}

+ 69 - 0
utils/my-request/helpers/buildURL.js

@@ -0,0 +1,69 @@
+'use strict'
+
+import * as utils from './../utils'
+
+function encode(val) {
+  return encodeURIComponent(val).
+    replace(/%40/gi, '@').
+    replace(/%3A/gi, ':').
+    replace(/%24/g, '$').
+    replace(/%2C/gi, ',').
+    replace(/%20/g, '+').
+    replace(/%5B/gi, '[').
+    replace(/%5D/gi, ']')
+}
+
+/**
+ * Build a URL by appending params to the end
+ *
+ * @param {string} url The base of the url (e.g., http://www.google.com)
+ * @param {object} [params] The params to be appended
+ * @returns {string} The formatted url
+ */
+export default function buildURL(url, params) {
+  /*eslint no-param-reassign:0*/
+  if (!params) {
+    return url
+  }
+
+  var serializedParams
+  if (utils.isURLSearchParams(params)) {
+    serializedParams = params.toString()
+  } else {
+    var parts = []
+
+    utils.forEach(params, function serialize(val, key) {
+      if (val === null || typeof val === 'undefined') {
+        return
+      }
+
+      if (utils.isArray(val)) {
+        key = key + '[]'
+      } else {
+        val = [val]
+      }
+
+      utils.forEach(val, function parseValue(v) {
+        if (utils.isDate(v)) {
+          v = v.toISOString()
+        } else if (utils.isObject(v)) {
+          v = JSON.stringify(v)
+        }
+        parts.push(encode(key) + '=' + encode(v))
+      })
+    })
+
+    serializedParams = parts.join('&')
+  }
+
+  if (serializedParams) {
+    var hashmarkIndex = url.indexOf('#')
+    if (hashmarkIndex !== -1) {
+      url = url.slice(0, hashmarkIndex)
+    }
+
+    url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams
+  }
+
+  return url
+}

+ 14 - 0
utils/my-request/helpers/combineURLs.js

@@ -0,0 +1,14 @@
+'use strict'
+
+/**
+ * Creates a new URL by combining the specified URLs
+ *
+ * @param {string} baseURL The base URL
+ * @param {string} relativeURL The relative URL
+ * @returns {string} The combined URL
+ */
+export default function combineURLs(baseURL, relativeURL) {
+  return relativeURL
+    ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '')
+    : baseURL
+}

+ 14 - 0
utils/my-request/helpers/isAbsoluteURL.js

@@ -0,0 +1,14 @@
+'use strict'
+
+/**
+ * Determines whether the specified URL is absolute
+ *
+ * @param {string} url The URL to test
+ * @returns {boolean} True if the specified URL is absolute, otherwise false
+ */
+export default function isAbsoluteURL(url) {
+  // A URL is considered absolute if it begins with "<scheme>://" or "//" (protocol-relative URL).
+  // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed
+  // by any combination of letters, digits, plus, period, or hyphen.
+  return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url)
+}

+ 2 - 0
utils/my-request/index.js

@@ -0,0 +1,2 @@
+import Request from './core/Request'
+export default Request

+ 131 - 0
utils/my-request/utils.js

@@ -0,0 +1,131 @@
+'use strict'
+
+// utils is a library of generic helper functions non-specific to axios
+
+var toString = Object.prototype.toString
+
+/**
+ * Determine if a value is an Array
+ *
+ * @param {Object} val The value to test
+ * @returns {boolean} True if value is an Array, otherwise false
+ */
+export function isArray (val) {
+  return toString.call(val) === '[object Array]'
+}
+
+
+/**
+ * Determine if a value is an Object
+ *
+ * @param {Object} val The value to test
+ * @returns {boolean} True if value is an Object, otherwise false
+ */
+export function isObject (val) {
+  return val !== null && typeof val === 'object'
+}
+
+/**
+ * Determine if a value is a Date
+ *
+ * @param {Object} val The value to test
+ * @returns {boolean} True if value is a Date, otherwise false
+ */
+export function isDate (val) {
+  return toString.call(val) === '[object Date]'
+}
+
+/**
+ * Determine if a value is a URLSearchParams object
+ *
+ * @param {Object} val The value to test
+ * @returns {boolean} True if value is a URLSearchParams object, otherwise false
+ */
+export function isURLSearchParams (val) {
+  return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams
+}
+
+
+/**
+ * Iterate over an Array or an Object invoking a function for each item.
+ *
+ * If `obj` is an Array callback will be called passing
+ * the value, index, and complete array for each item.
+ *
+ * If 'obj' is an Object callback will be called passing
+ * the value, key, and complete object for each property.
+ *
+ * @param {Object|Array} obj The object to iterate
+ * @param {Function} fn The callback to invoke for each item
+ */
+export function forEach (obj, fn) {
+  // Don't bother if no value provided
+  if (obj === null || typeof obj === 'undefined') {
+    return
+  }
+
+  // Force an array if not already something iterable
+  if (typeof obj !== 'object') {
+    /*eslint no-param-reassign:0*/
+    obj = [obj]
+  }
+
+  if (isArray(obj)) {
+    // Iterate over array values
+    for (var i = 0, l = obj.length; i < l; i++) {
+      fn.call(null, obj[i], i, obj)
+    }
+  } else {
+    // Iterate over object keys
+    for (var key in obj) {
+      if (Object.prototype.hasOwnProperty.call(obj, key)) {
+        fn.call(null, obj[key], key, obj)
+      }
+    }
+  }
+}
+
+/**
+ * 是否为boolean 值
+ * @param val
+ * @returns {boolean}
+ */
+export function isBoolean(val) {
+  return typeof val === 'boolean'
+}
+
+/**
+ * 是否为真正的对象{} new Object
+ * @param {any} obj - 检测的对象
+ * @returns {boolean}
+ */
+export function isPlainObject(obj) {
+  return Object.prototype.toString.call(obj) === '[object Object]'
+}
+
+
+
+/**
+ * Function equal to merge with the difference being that no reference
+ * to original objects is kept.
+ *
+ * @see merge
+ * @param {Object} obj1 Object to merge
+ * @returns {Object} Result of all merge properties
+ */
+export function deepMerge(/* obj1, obj2, obj3, ... */) {
+  let result = {}
+  function assignValue(val, key) {
+    if (typeof result[key] === 'object' && typeof val === 'object') {
+      result[key] = deepMerge(result[key], val)
+    } else if (typeof val === 'object') {
+      result[key] = deepMerge({}, val)
+    } else {
+      result[key] = val
+    }
+  }
+  for (let i = 0, l = arguments.length; i < l; i++) {
+    forEach(arguments[i], assignValue)
+  }
+  return result
+}

+ 415 - 0
utils/util.js

@@ -0,0 +1,415 @@
+//工具类
+let util = {}
+
+
+//复制
+util.copy=content=>{
+	uni.setClipboardData({ data: content });
+}
+
+
+// 图片缓存
+
+
+//拨打电话
+util.callPhone=phone=>{
+	uni.showModal({
+	    title: '提示',
+	    content: `确定要拨打电话:${phone}吗?`,
+	    success: function (res) {
+	        if (res.confirm) {
+				uni.makePhoneCall({
+				    phoneNumber: phone //仅为示例
+				});
+	        } 
+	    }
+	});
+}
+util.showModel=(content,title='提示')=>{
+    return new Promise((resolve,reject)=>{
+        uni.showModal({
+            title: title,
+            content: content,
+            success: (res)=>{
+                resolve(res)
+            }
+        });
+    })
+}
+//是否为手机号码
+util.isPhone = phone => {
+  let pat = /^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\d{8}$/
+  return pat.test(phone)
+}
+
+//去除两边空格
+util.trim = value => {
+  if (value) {
+    return value.replace(/^\s+|\s+$/gm, '')
+  }
+  return ''
+}
+
+//根据QueryString参数名称获取值
+util.getQueryStringByName = (url, name) => {
+  var result = url.match(new RegExp('[?&]' + name + '=([^&]+)', 'i'))
+  if (result == null || result.length < 1) {
+    return ''
+  }
+  return result[1]
+}
+
+//四舍五入保留2位小数(不够位数,则用0替补)
+util.keepTwoDecimalFull = num => {
+  var result = parseFloat(num)
+  if (isNaN(result)) {
+    return false
+  }
+  result = Math.round(num * 100) / 100
+  var s_x = result.toString()
+  var pos_decimal = s_x.indexOf('.')
+  if (pos_decimal < 0) {
+    pos_decimal = s_x.length
+    s_x += '.'
+  }
+  while (s_x.length <= pos_decimal + 2) {
+    s_x += '0'
+  }
+  return s_x
+}
+
+/**
+ * 数组去重
+ * @param {Array} arr 源数组
+ * 
+ * @return {Array} newArr 去重后的数组
+ */
+util.uniqueArray = (arr)=>{
+  let newArr = []
+  arr.forEach(item => {
+    return newArr.includes(item) ? '' : newArr.push(item)
+  })
+  return newArr
+}
+
+util.checkMobile = phoneStr => {
+  if (phoneStr.length < 11) {
+    return false
+  } else if (!/^1[3|4|5|6|7|8][0-9]\d{4,8}$/.test(phoneStr)) {
+    return false
+  } else {
+    return true
+  }
+}
+
+/**
+ * 序列化对象
+ * @param {Object} data 标准JS对象 { key:value,... }
+ */
+util.serialize = (data, isEncode = false) => {
+  if (!data) return ''
+  var pairs = []
+  for (var name in data) {
+    if (!data.hasOwnProperty(name)) continue
+    if (typeof data[name] === 'function') continue
+    var value =
+      data[name] != null && typeof data[name] != 'undefined'
+        ? data[name].toString()
+        : ''
+    if (isEncode) {
+      name = encodeURIComponent(name)
+      value = encodeURIComponent(value)
+    }
+    pairs.push(name + '=' + value)
+  }
+  return pairs.join('&')
+}
+
+
+
+//获取某一个页面上下文 context
+util.getPageCtx = (idx = 0) => {
+  let pages = getCurrentPages()
+  if (pages.length > 0) {
+    return pages[pages.length - 1 - idx] || {}
+  }
+  return {}
+}
+
+//获取当前页面路由
+util.getCurrentRoute = () => {
+  let page = util.getPageCtx()
+  if (page.route) {
+    return page.route
+  }
+  return ''
+}
+
+
+/* ======================== 时间日期 begin ========================== */
+
+
+//日期转字符串
+util.dateToString = (date)=>{
+	var year = date.getFullYear();
+	var month =(date.getMonth() + 1).toString(); 
+	var day = (date.getDate()).toString();  
+	if (month.length == 1) { 
+	    month = "0" + month; 
+	} 
+	if (day.length == 1) { 
+	    day = "0" + day; 
+	}
+	var dateTime = year + "-" + month + "-" + day;
+	return dateTime; 
+}
+//字符串转日期
+util.stringToDate = (dateStr,separator)=>{
+	if(!separator){
+	       separator="-";
+	}
+	var dateArr = dateStr.split(separator);
+	var year = parseInt(dateArr[0]);
+	var month;                     
+	if(dateArr[1].indexOf("0") == 0){
+	    month = parseInt(dateArr[1].substring(1));
+	}else{
+	     month = parseInt(dateArr[1]);
+	}
+	var day = parseInt(dateArr[2]);
+	var date = new Date(year,month -1,day);
+	return date;
+}
+
+/**
+ * 天数加减
+ * date传入你需要的日期,格式"xxxx-xx-xx"。addDays传要加减的日期数,往前传正数,往后传负数
+ */
+util.addDay=(date,addDays)=>{
+	var Dates = new Date(date);
+	Dates.setDate(Dates.getDate() + addDays);
+	var mon = Dates.getMonth() + 1,
+	    day = Dates.getDate();
+	if(mon < 10){
+	    mon = "0" + mon;//月份小于10,在前面补充0
+	}
+	if(day < 10){
+	    day = "0" + day;//日小于10,在前面补充0
+	}
+	return Dates.getFullYear() + "-" + mon + "-" +day;
+}
+
+
+// 时间函数-tian=0(获取当前时间)-accuracy=1(获取年月日)
+util.getTime = (tian, accuracy) => {
+  //获取当前时间戳
+  var timestamp = Date.parse(new Date())
+
+  timestamp = timestamp / 1000
+  var tomorrow_timetamp = timestamp - tian * 24 * 60 * 60
+
+  var date = new Date(tomorrow_timetamp * 1000)
+  //年
+  var Y = date.getFullYear()
+  //月
+  var M =
+    date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
+  //日
+  var D = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
+  //时
+  var h = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
+
+  //分
+  var m = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
+
+  //秒
+  var s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
+
+  var Time = Y + '-' + M + '-' + D
+  var Time2 = Y + '-' + M + '-' + D + ' ' + h + ':' + m + ':' + s
+  if (accuracy == '1') {
+    return Time
+  } else {
+    return Time2
+  }
+}
+
+// 格式化日期 2019-01-01 TT(WW)
+util.dateFormat = (
+  value = new Date(),
+  format = 'yyyy-MM-dd',
+  isInit = false
+) => {
+  if (value) {
+    var date = typeof value == 'string' ? value.replace(/\-/g, '/') : value
+    var d = new Date(date)
+    var week = ''
+    var label = ''
+    if (isInit) {
+      var cdt = new Date()
+      var cur = new Date(
+        cdt.getFullYear() + '/' + (cdt.getMonth() + 1) + '/' + cdt.getDate()
+      )
+      var diffTime = d.getTime() - cur.getTime()
+      var oneDayTime = 24 * 60 * 60 * 1000
+      var twoDayTime = 48 * 60 * 60 * 1000
+      var threeDayTime = 72 * 60 * 60 * 1000
+      let weeks = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
+      if (diffTime > 0) {
+        if (diffTime <= oneDayTime) {
+          label = '今天'
+        } else if (diffTime <= twoDayTime) {
+          label = '明天'
+        } else if (diffTime <= threeDayTime) {
+          label = '后天'
+        }
+      }
+      week = weeks[d.getDay()]
+    }
+
+    var o = {
+      'T+': label,
+      'W+': week,
+      'M+': d.getMonth() + 1, //month
+      'd+': d.getDate(), //day
+      'h+': d.getHours(), //hour
+      'm+': d.getMinutes(), //minute
+      's+': d.getSeconds(), //second
+      'q+': Math.floor((d.getMonth() + 3) / 3), //quarter
+      S: d.getMilliseconds() //millisecond
+    }
+
+    if (/(y+)/.test(format)) {
+      format = format.replace(
+        RegExp.$1,
+        (d.getFullYear() + '').substr(4 - RegExp.$1.length)
+      )
+    }
+    for (var k in o) {
+      if (k == 'T+' && !label) continue
+
+      if (new RegExp('(' + k + ')').test(format)) {
+        format = format.replace(
+          RegExp.$1,
+          RegExp.$1.length == 1
+            ? o[k]
+            : ('00' + o[k]).substr(('' + o[k]).length)
+        )
+      }
+    }
+    return format
+  }
+  return value
+}
+
+// 活动倒计时  需要在外面调用 如:setInterval("countDown()",1000);
+util.countDown = (day, hour, minute, second) => {
+  var flag = false
+  second -= 1
+  if (second == 0) {
+    minute = minute - 1
+    second = 60
+    if (minute < 0) {
+      hour = hour - 1
+      minute = 59
+      if (hour < 0) {
+        day -= 1
+        hour = 23
+        if (day < 0) {
+          flag = true
+        }
+      }
+    }
+  }
+  if (flag) {
+    return '活动结束'
+  } else {
+    return day + '天' + hour + '小时' + minute + '分' + second + '秒'
+  }
+}
+// 两个时间相差 天 小时 分钟 秒 date1、date2格式:'2019-06-29 14:36:10'或'2019/06/29 14:36:10'
+util.timeComparison = (date1, date2) => {
+  // var date1 = '2019-06-29 14:36:10';  //开始时间
+  // var date2 = new Date();    //结束时间
+  var date3 = date2.getTime() - date1.getTime() //时间差的毫秒数
+
+  //------------------------------
+
+  //计算出相差天数
+  var days = Math.floor(date3 / (24 * 3600 * 1000))
+
+  //计算出小时数
+  var leave1 = date3 % (24 * 3600 * 1000) //计算天数后剩余的毫秒数
+  var hours = Math.floor(leave1 / (3600 * 1000))
+  //计算相差分钟数
+  var leave2 = leave1 % (3600 * 1000) //计算小时数后剩余的毫秒数
+  var minutes = Math.floor(leave2 / (60 * 1000))
+  //计算相差秒数
+  var leave3 = leave2 % (60 * 1000) //计算分钟数后剩余的毫秒数
+  var seconds = (leave3 / 1000).toFixed(1)
+
+  return (
+    ' 相差 ' +
+    days +
+    '天 ' +
+    hours +
+    '小时 ' +
+    minutes +
+    ' 分钟' +
+    seconds +
+    ' 秒'
+  )
+}
+util.timeComparisonActive = (date1, date2, isNeedMillSecond = true) => {
+  // var date1 = '2019-06-29 14:36:10';  //开始时间
+  // var date2 = new Date();    //结束时间
+  var date3 = date2.getTime() - date1.getTime() //时间差的毫秒数
+  if (parseInt(date3) <= 0) {
+    date3 = 0
+  }
+  //------------------------------
+
+  //计算出相差天数
+  var days = Math.floor(date3 / (24 * 3600 * 1000))
+
+  //计算出小时数
+  var leave1 = date3 % (24 * 3600 * 1000) //计算天数后剩余的毫秒数
+  var hours = Math.floor(leave1 / (3600 * 1000))
+  //计算相差分钟数
+  var leave2 = leave1 % (3600 * 1000) //计算小时数后剩余的毫秒数
+  var minutes = Math.floor(leave2 / (60 * 1000))
+  //计算相差秒数
+  var leave3 = leave2 % (60 * 1000) //计算分钟数后剩余的毫秒数
+  if (isNeedMillSecond) {
+    var seconds = (leave3 / 1000).toFixed(1)
+  } else {
+    var seconds = Math.floor(leave3 / 1000)
+  }
+  var allSeconds =
+    days * 24 * 60 * 60 + hours * 60 * 60 + minutes * 60 + seconds
+  hours = days * 24 + hours < 10 ? '0' + (days * 24 + hours) : days * 24 + hours
+  minutes = minutes < 10 ? '0' + minutes : minutes
+  seconds = seconds < 10 ? '0' + seconds : seconds
+  days = days < 10 ? '0' + days : days
+
+  var isEnd = allSeconds > 0 ? false : true
+
+  return { days, hours, minutes, seconds, isEnd }
+}
+
+
+/**
+ * 生成日期对象
+ * @param {String,Number} value 日期 字符串 或者 毫秒数字
+ * @return {Date} [date = new Date()] 日期对象
+ */ 
+util.createDate = (value)=>{
+  let date = typeof (value) == 'string' ? value.replace(/\-/g, '/') : value
+  return new Date(date)
+} 
+/* ======================== 时间日期 end ========================== */
+
+
+
+
+export default util

+ 21 - 0
uview-ui/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 www.uviewui.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 106 - 0
uview-ui/README.md

@@ -0,0 +1,106 @@
+<p align="center">
+    <img alt="logo" src="https://uviewui.com/common/logo.png" width="120" height="120" style="margin-bottom: 10px;">
+</p>
+<h3 align="center" style="margin: 30px 0 30px;font-weight: bold;font-size:40px;">uView</h3>
+<h3 align="center">多平台快速开发的UI框架</h3>
+
+
+## 说明
+
+uView UI,是[uni-app](https://uniapp.dcloud.io/)生态优秀的UI框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水
+
+## 特性
+
+- 兼容安卓,iOS,微信小程序,H5,QQ小程序,百度小程序,支付宝小程序,头条小程序
+- 60+精选组件,功能丰富,多端兼容,让您快速集成,开箱即用
+- 众多贴心的JS利器,让您飞镖在手,召之即来,百步穿杨
+- 众多的常用页面和布局,让您专注逻辑,事半功倍
+- 详尽的文档支持,现代化的演示效果
+- 按需引入,精简打包体积
+
+
+## 安装
+
+```bash
+# npm方式安装
+npm i uview-ui
+```
+
+## 快速上手
+
+1. `main.js`引入uView库
+```js
+// main.js
+import uView from 'uview-ui';
+Vue.use(uView);
+```
+
+2. `App.vue`引入基础样式(注意style标签需声明scss属性支持)
+```css
+/* App.vue */
+<style lang="scss">
+@import "uview-ui/index.scss";
+</style>
+```
+
+3. `uni.scss`引入全局scss变量文件
+```css
+/* uni.scss */
+@import "uview-ui/theme.scss";
+```
+
+4. `pages.json`配置easycom规则(按需引入)
+
+```js
+// pages.json
+{
+	"easycom": {
+		// npm安装的方式不需要前面的"@/",下载安装的方式需要"@/"
+		// npm安装方式
+		"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
+		// 下载安装方式
+		// "^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
+	},
+	// 此为本身已有的内容
+	"pages": [
+		// ......
+	]
+}
+```
+
+请通过[快速上手](https://uviewui.com/components/quickstart.html)了解更详细的内容 
+
+## 使用方法
+配置easycom规则后,自动按需引入,无需`import`组件,直接引用即可。
+
+```html
+<template>
+	<u-button>按钮</u-button>
+</template>
+```
+
+请通过[快速上手](https://uviewui.com/components/quickstart.html)了解更详细的内容 
+
+## 链接
+
+- [官方文档](https://uviewui.com/)
+- [更新日志](https://uviewui.com/components/changelog.html)
+- [升级指南](https://uviewui.com/components/changelog.html)
+- [关于我们](https://uviewui.com/cooperation/about.html)
+
+## 预览
+
+您可以通过**微信**扫码,查看最佳的演示效果。
+<br>
+<br>
+<img src="https://uviewui.com/common/weixin_mini_qrcode.png" width="220" height="220" >
+
+<!-- ## 捐赠uView的研发
+
+uView文档和源码全部开源免费,如果您认为uView帮到了您的开发工作,您可以捐赠uView的研发工作,捐赠无门槛,哪怕是一杯可乐也好(相信这比打赏主播更有意义)。
+
+<img src="https://uviewui.com/common/wechat.png" width="220" >
+<img style="margin-left: 100px;" src="https://uviewui.com/common/alipay.png" width="220" >
+ -->
+## 版权信息
+uView遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议,意味着您无需支付任何费用,也无需授权,即可将uView应用到您的产品中。

+ 190 - 0
uview-ui/components/u-action-sheet/u-action-sheet.vue

@@ -0,0 +1,190 @@
+<template>
+	<u-popup mode="bottom" :border-radius="borderRadius" :popup="false" v-model="value" :maskCloseAble="maskCloseAble"
+	    length="auto" :safeAreaInsetBottom="safeAreaInsetBottom" @close="popupClose" :z-index="uZIndex">
+		<view class="u-tips u-border-bottom" v-if="tips.text" :style="[tipsStyle]">
+			{{tips.text}}
+		</view>
+		<block v-for="(item, index) in list" :key="index">
+			<view 
+				@touchmove.stop.prevent 
+				@tap="itemClick(index)" 
+				:style="[itemStyle(index)]" 
+				class="u-action-sheet-item u-line-1" 
+				:class="[index < list.length - 1 ? 'u-border-bottom' : '']"
+				:hover-stay-time="150"
+			>
+				<text>{{item.text}}</text>
+				<text class="u-action-sheet-item__subtext u-line-1" v-if="item.subText">{{item.subText}}</text>
+			</view>
+		</block>
+		<view class="u-gab" v-if="cancelBtn">
+		</view>
+		<view @touchmove.stop.prevent class="u-actionsheet-cancel u-action-sheet-item" hover-class="u-hover-class"
+		    :hover-stay-time="150" v-if="cancelBtn" @tap="close">{{cancelText}}</view>
+	</u-popup>
+</template>
+
+<script>
+	/**
+	 * actionSheet 操作菜单
+	 * @description 本组件用于从底部弹出一个操作菜单,供用户选择并返回结果。本组件功能类似于uni的uni.showActionSheetAPI,配置更加灵活,所有平台都表现一致。
+	 * @tutorial https://www.uviewui.com/components/actionSheet.html
+	 * @property {Array<Object>} list 按钮的文字数组,见官方文档示例
+	 * @property {Object} tips 顶部的提示文字,见官方文档示例
+	 * @property {String} cancel-text 取消按钮的提示文字
+	 * @property {Boolean} cancel-btn 是否显示底部的取消按钮(默认true)
+	 * @property {Number String} border-radius 弹出部分顶部左右的圆角值,单位rpx(默认0)
+	 * @property {Boolean} mask-close-able 点击遮罩是否可以关闭(默认true)
+	 * @property {Boolean} safe-area-inset-bottom 是否开启底部安全区适配(默认false)
+	 * @property {Number String} z-index z-index值(默认1075)
+	 * @property {String} cancel-text 取消按钮的提示文字
+	 * @event {Function} click 点击ActionSheet列表项时触发
+	 * @event {Function} close 点击取消按钮时触发
+	 * @example <u-action-sheet :list="list" @click="click" v-model="show"></u-action-sheet>
+	 */
+	export default {
+		name: "u-action-sheet",
+		props: {
+			// 点击遮罩是否可以关闭actionsheet
+			maskCloseAble: {
+				type: Boolean,
+				default: true
+			},
+			// 按钮的文字数组,可以自定义颜色和字体大小,字体单位为rpx
+			list: {
+				type: Array,
+				default () {
+					// 如下
+					// return [{
+					// 	text: '确定',
+					// 	color: '',
+					// 	fontSize: ''
+					// }]
+					return [];
+				}
+			},
+			// 顶部的提示文字
+			tips: {
+				type: Object,
+				default () {
+					return {
+						text: '',
+						color: '',
+						fontSize: '26'
+					}
+				}
+			},
+			// 底部的取消按钮
+			cancelBtn: {
+				type: Boolean,
+				default: true
+			},
+			// 是否开启底部安全区适配,开启的话,会在iPhoneX机型底部添加一定的内边距
+			safeAreaInsetBottom: {
+				type: Boolean,
+				default: false
+			},
+			// 通过双向绑定控制组件的弹出与收起
+			value: {
+				type: Boolean,
+				default: false
+			},
+			// 弹出的顶部圆角值
+			borderRadius: {
+				type: [String, Number],
+				default: 0
+			},
+			// 弹出的z-index值
+			zIndex: {
+				type: [String, Number],
+				default: 0
+			},
+			// 取消按钮的文字提示
+			cancelText: {
+				type: String,
+				default: '取消'
+			}
+		},
+		computed: {
+			// 顶部提示的样式
+			tipsStyle() {
+				let style = {};
+				if (this.tips.color) style.color = this.tips.color;
+				if (this.tips.fontSize) style.fontSize = this.tips.fontSize + 'rpx';
+				return style;
+			},
+			// 操作项目的样式
+			itemStyle() {
+				return (index) => {
+					let style = {};
+					if (this.list[index].color) style.color = this.list[index].color;
+					if (this.list[index].fontSize) style.fontSize = this.list[index].fontSize + 'rpx';
+					// 选项被禁用的样式
+					if (this.list[index].disabled) style.color = '#c0c4cc';
+					return style;
+				}
+			},
+			uZIndex() {
+				// 如果用户有传递z-index值,优先使用
+				return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
+			}
+		},
+		methods: {
+			// 点击取消按钮
+			close() {
+				// 发送input事件,并不会作用于父组件,而是要设置组件内部通过props传递的value参数
+				// 这是一个vue发送事件的特殊用法
+				this.popupClose();
+				this.$emit('close');
+			},
+			// 弹窗关闭
+			popupClose() {
+				this.$emit('input', false);
+			},
+			// 点击某一个item
+			itemClick(index) {
+				// disabled的项禁止点击
+				if(this.list[index].disabled) return;
+				this.$emit('click', index);
+				this.$emit('input', false);
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	@import "../../libs/css/style.components.scss";
+
+	.u-tips {
+		font-size: 26rpx;
+		text-align: center;
+		padding: 34rpx 0;
+		line-height: 1;
+		color: $u-tips-color;
+	}
+
+	.u-action-sheet-item {
+		@include vue-flex;;
+		line-height: 1;
+		justify-content: center;
+		align-items: center;
+		font-size: 32rpx;
+		padding: 34rpx 0;
+		flex-direction: column;
+	}
+	
+	.u-action-sheet-item__subtext {
+		font-size: 24rpx;
+		color: $u-tips-color;
+		margin-top: 20rpx;
+	}
+
+	.u-gab {
+		height: 12rpx;
+		background-color: rgb(234, 234, 236);
+	}
+
+	.u-actionsheet-cancel {
+		color: $u-main-color;
+	}
+</style>

+ 256 - 0
uview-ui/components/u-alert-tips/u-alert-tips.vue

@@ -0,0 +1,256 @@
+<template>
+	<view class="u-alert-tips" v-if="show" :class="[
+		!show ? 'u-close-alert-tips': '',
+		type ? 'u-alert-tips--bg--' + type + '-light' : '',
+		type ? 'u-alert-tips--border--' + type + '-disabled' : '',
+	]" :style="{
+		backgroundColor: bgColor,
+		borderColor: borderColor
+	}">
+		<view class="u-icon-wrap">
+			<u-icon v-if="showIcon" :name="uIcon" :size="description ? 40 : 32" class="u-icon" :color="uIconType" :custom-style="iconStyle"></u-icon>
+		</view>
+		<view class="u-alert-content" @tap.stop="click">
+			<view class="u-alert-title" :style="[uTitleStyle]">
+				{{title}}
+			</view>
+			<view v-if="description" class="u-alert-desc" :style="[descStyle]">
+				{{description}}
+			</view>
+		</view>
+		<view class="u-icon-wrap">
+			<u-icon @click="close" v-if="closeAble && !closeText" hoverClass="u-type-error-hover-color" name="close" color="#c0c4cc"
+			 :size="22" class="u-close-icon" :style="{
+				top: description ? '18rpx' : '24rpx'
+			}"></u-icon>
+		</view>
+		<text v-if="closeAble && closeText" class="u-close-text" :style="{
+			top: description ? '18rpx' : '24rpx'
+		}">{{closeText}}</text>
+	</view>
+</template>
+
+<script>
+	/**
+	 * alertTips 警告提示
+	 * @description 警告提示,展现需要关注的信息
+	 * @tutorial https://uviewui.com/components/alertTips.html
+	 * @property {String} title 显示的标题文字
+	 * @property {String} description 辅助性文字,颜色比title浅一点,字号也小一点,可选
+	 * @property {String} type 关闭按钮(默认为叉号icon图标)
+	 * @property {String} icon 图标名称
+	 * @property {Object} icon-style 图标的样式,对象形式
+	 * @property {Object} title-style 标题的样式,对象形式
+	 * @property {Object} desc-style 描述的样式,对象形式
+	 * @property {String} close-able 用文字替代关闭图标,close-able为true时有效
+	 * @property {Boolean} show-icon 是否显示左边的辅助图标
+	 * @property {Boolean} show 显示或隐藏组件
+	 * @event {Function} click 点击组件时触发
+	 * @event {Function} close 点击关闭按钮时触发
+	 */
+	export default {
+		name: 'u-alert-tips',
+		props: {
+			// 显示文字
+			title: {
+				type: String,
+				default: ''
+			},
+			// 主题,success/warning/info/error
+			type: {
+				type: String,
+				default: 'warning'
+			},
+			// 辅助性文字
+			description: {
+				type: String,
+				default: ''
+			},
+			// 是否可关闭
+			closeAble: {
+				type: Boolean,
+				default: false
+			},
+			// 关闭按钮自定义文本
+			closeText: {
+				type: String,
+				default: ''
+			},
+			// 是否显示图标
+			showIcon: {
+				type: Boolean,
+				default: false
+			},
+			// 文字颜色,如果定义了color值,icon会失效
+			color: {
+				type: String,
+				default: ''
+			},
+			// 背景颜色
+			bgColor: {
+				type: String,
+				default: ''
+			},
+			// 边框颜色
+			borderColor: {
+				type: String,
+				default: ''
+			},
+			// 是否显示
+			show: {
+				type: Boolean,
+				default: true
+			},
+			// 左边显示的icon
+			icon: {
+				type: String,
+				default: ''
+			},
+			// icon的样式
+			iconStyle: {
+				type: Object,
+				default() {
+					return {}
+				}
+			},
+			// 标题的样式
+			titleStyle: {
+				type: Object,
+				default() {
+					return {}
+				}
+			},
+			// 描述文字的样式
+			descStyle: {
+				type: Object,
+				default() {
+					return {}
+				}
+			},
+		},
+		data() {
+			return {
+			}
+		},
+		computed: {
+			uTitleStyle() {
+				let style = {};
+				// 如果有描述文字的话,标题进行加粗
+				style.fontWeight = this.description ? 500 : 'normal';
+				// 将用户传入样式对象和style合并,传入的优先级比style高,同属性会被覆盖
+				return this.$u.deepMerge(style, this.titleStyle);
+			},
+			uIcon() {
+				// 如果有设置icon名称就使用,否则根据type主题,推定一个默认的图标
+				return this.icon ? this.icon : this.$u.type2icon(this.type);
+			},
+			uIconType() {
+				// 如果有设置图标的样式,优先使用,没有的话,则用type的样式
+				return Object.keys(this.iconStyle).length ? '' : this.type;
+			}
+		},
+		methods: {
+			// 点击内容
+			click() {
+				this.$emit('click');
+			},
+			// 点击关闭按钮
+			close() {
+				this.$emit('close');
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	@import "../../libs/css/style.components.scss";
+	
+	.u-alert-tips {
+		@include vue-flex;
+		align-items: center;
+		padding: 16rpx 30rpx;
+		border-radius: 8rpx;
+		position: relative;
+		transition: all 0.3s linear;
+		border: 1px solid #fff;
+		
+		&--bg--primary-light {
+			background-color: $u-type-primary-light;
+		}
+		
+		&--bg--info-light {
+			background-color: $u-type-info-light;
+		}
+		
+		&--bg--success-light {
+			background-color: $u-type-success-light;
+		}
+		
+		&--bg--warning-light {
+			background-color: $u-type-warning-light;
+		}
+		
+		&--bg--error-light {
+			background-color: $u-type-error-light;
+		}
+		
+		&--border--primary-disabled {
+			border-color: $u-type-primary-disabled;
+		}
+		
+		&--border--success-disabled {
+			border-color: $u-type-success-disabled;
+		}
+		
+		&--border--error-disabled {
+			border-color: $u-type-error-disabled;
+		}
+		
+		&--border--warning-disabled {
+			border-color: $u-type-warning-disabled;
+		}
+		
+		&--border--info-disabled {
+			border-color: $u-type-info-disabled;
+		}
+	}
+
+	.u-close-alert-tips {
+		opacity: 0;
+		visibility: hidden;
+	}
+
+	.u-icon {
+		margin-right: 16rpx;
+	}
+
+	.u-alert-title {
+		font-size: 28rpx;
+		color: $u-main-color;
+	}
+
+	.u-alert-desc {
+		font-size: 26rpx;
+		text-align: left;
+		color: $u-content-color;
+	}
+
+	.u-close-icon {
+		position: absolute;
+		top: 20rpx;
+		right: 20rpx;
+	}
+
+	.u-close-hover {
+		color: red;
+	}
+	
+	.u-close-text {
+		font-size: 24rpx;
+		color: $u-tips-color;
+		position: absolute;
+		top: 20rpx;
+		right: 20rpx;
+		line-height: 1;
+	}
+</style>

+ 290 - 0
uview-ui/components/u-avatar-cropper/u-avatar-cropper.vue

@@ -0,0 +1,290 @@
+<template>
+	<view class="content">
+		<view class="cropper-wrapper" :style="{ height: cropperOpt.height + 'px' }">
+			<canvas
+				class="cropper"
+				:disable-scroll="true"
+				@touchstart="touchStart"
+				@touchmove="touchMove"
+				@touchend="touchEnd"
+				:style="{ width: cropperOpt.width, height: cropperOpt.height, backgroundColor: 'rgba(0, 0, 0, 0.8)' }"
+				canvas-id="cropper"
+				id="cropper"
+			></canvas>
+			<canvas
+				class="cropper"
+				:disable-scroll="true"
+				:style="{
+					position: 'fixed',
+					top: `-${cropperOpt.width * cropperOpt.pixelRatio}px`,
+					left: `-${cropperOpt.height * cropperOpt.pixelRatio}px`,
+					width: `${cropperOpt.width * cropperOpt.pixelRatio}px`,
+					height: `${cropperOpt.height * cropperOpt.pixelRatio}`
+				}"
+				canvas-id="targetId"
+				id="targetId"
+			></canvas>
+		</view>
+		<view class="cropper-buttons safe-area-padding" :style="{ height: bottomNavHeight + 'px' }">
+			<!-- #ifdef H5 -->
+			<view class="upload" @tap="uploadTap">选择图片</view>
+			<!-- #endif -->
+			<!-- #ifndef H5 -->
+			<view class="upload" @tap="uploadTap">重新选择</view>
+			<!-- #endif -->
+			<view class="getCropperImage" @tap="getCropperImage(false)">确定</view>
+		</view>
+	</view>
+</template>
+
+<script>
+import WeCropper from './weCropper.js';
+export default {
+	props: {
+		// 裁剪矩形框的样式,其中可包含的属性为lineWidth-边框宽度(单位rpx),color: 边框颜色,
+		// mask-遮罩颜色,一般设置为一个rgba的透明度,如"rgba(0, 0, 0, 0.35)"
+		boundStyle: {
+			type: Object,
+			default() {
+				return {
+					lineWidth: 4,
+					borderColor: 'rgb(245, 245, 245)',
+					mask: 'rgba(0, 0, 0, 0.35)'
+				};
+			}
+		}
+		// // 裁剪框宽度,单位rpx
+		// rectWidth: {
+		// 	type: [String, Number],
+		// 	default: 400
+		// },
+		// // 裁剪框高度,单位rpx
+		// rectHeight: {
+		// 	type: [String, Number],
+		// 	default: 400
+		// },
+		// // 输出图片宽度,单位rpx
+		// destWidth: {
+		// 	type: [String, Number],
+		// 	default: 400
+		// },
+		// // 输出图片高度,单位rpx
+		// destHeight: {
+		// 	type: [String, Number],
+		// 	default: 400
+		// },
+		// // 输出的图片类型,如果发现裁剪的图片很大,可能是因为设置为了"png",改成"jpg"即可
+		// fileType: {
+		// 	type: String,
+		// 	default: 'jpg',
+		// },
+		// // 生成的图片质量
+		// // H5上无效,目前不考虑使用此参数
+		// quality: {
+		// 	type: [Number, String],
+		// 	default: 1
+		// }
+	},
+	data() {
+		return {
+			// 底部导航的高度
+			bottomNavHeight: 50,
+			originWidth: 200,
+			width: 0,
+			height: 0,
+			cropperOpt: {
+				id: 'cropper',
+				targetId: 'targetCropper',
+				pixelRatio: 1,
+				width: 0,
+				height: 0,
+				scale: 2.5,
+				zoom: 8,
+				cut: {
+					x: (this.width - this.originWidth) / 2,
+					y: (this.height - this.originWidth) / 2,
+					width: this.originWidth,
+					height: this.originWidth
+				},
+				boundStyle: {
+					lineWidth: uni.upx2px(this.boundStyle.lineWidth),
+					mask: this.boundStyle.mask,
+					color: this.boundStyle.borderColor
+				}
+			},
+			// 裁剪框和输出图片的尺寸,高度默认等于宽度
+			// 输出图片宽度,单位px
+			destWidth: 200,
+			// 裁剪框宽度,单位px
+			rectWidth: 200,
+			// 输出的图片类型,如果'png'类型发现裁剪的图片太大,改成"jpg"即可
+			fileType: 'jpg',
+			src: '', // 选择的图片路径,用于在点击确定时,判断是否选择了图片
+		};
+	},
+	onLoad(option) {
+		let rectInfo = uni.getSystemInfoSync();
+		this.width = rectInfo.windowWidth;
+		this.height = rectInfo.windowHeight - this.bottomNavHeight;
+		this.cropperOpt.width = this.width;
+		this.cropperOpt.height = this.height;
+		this.cropperOpt.pixelRatio = rectInfo.pixelRatio;
+
+		if (option.destWidth) this.destWidth = option.destWidth;
+		if (option.rectWidth) {
+			let rectWidth = Number(option.rectWidth);
+			this.cropperOpt.cut = {
+				x: (this.width - rectWidth) / 2,
+				y: (this.height - rectWidth) / 2,
+				width: rectWidth,
+				height: rectWidth
+			};
+		}
+		this.rectWidth = option.rectWidth;
+		if (option.fileType) this.fileType = option.fileType;
+		// 初始化
+		this.cropper = new WeCropper(this.cropperOpt)
+			.on('ready', ctx => {
+				// wecropper is ready for work!
+			})
+			.on('beforeImageLoad', ctx => {
+				// before picture loaded, i can do something
+			})
+			.on('imageLoad', ctx => {
+				// picture loaded
+			})
+			.on('beforeDraw', (ctx, instance) => {
+				// before canvas draw,i can do something
+			});
+		// 设置导航栏样式,以免用户在page.json中没有设置为黑色背景
+		uni.setNavigationBarColor({
+			frontColor: '#ffffff',
+			backgroundColor: '#000000'
+		});
+		uni.chooseImage({
+			count: 1, // 默认9
+			sizeType: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有
+			sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
+			success: res => {
+				this.src = res.tempFilePaths[0];
+				//  获取裁剪图片资源后,给data添加src属性及其值
+				this.cropper.pushOrign(this.src);
+			}
+		});
+	},
+	methods: {
+		touchStart(e) {
+			this.cropper.touchStart(e);
+		},
+		touchMove(e) {
+			this.cropper.touchMove(e);
+		},
+		touchEnd(e) {
+			this.cropper.touchEnd(e);
+		},
+		getCropperImage(isPre = false) {
+			if(!this.src) return this.$u.toast('请先选择图片再裁剪');
+
+			let cropper_opt = {
+				destHeight: Number(this.destWidth), // uni.canvasToTempFilePath要求这些参数为数值
+				destWidth: Number(this.destWidth),
+				fileType: this.fileType
+			};
+			this.cropper.getCropperImage(cropper_opt, (path, err) => {
+				if (err) {
+					uni.showModal({
+						title: '温馨提示',
+						content: err.message
+					});
+				} else {
+					if (isPre) {
+						uni.previewImage({
+							current: '', // 当前显示图片的 http 链接
+							urls: [path] // 需要预览的图片 http 链接列表
+						});
+					} else {
+						uni.$emit('uAvatarCropper', path);
+						this.$u.route({
+							type: 'back'
+						});
+					}
+				}
+			});
+		},
+		uploadTap() {
+			const self = this;
+			uni.chooseImage({
+				count: 1, // 默认9
+				sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
+				sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
+				success: (res) => {
+					self.src = res.tempFilePaths[0];
+					//  获取裁剪图片资源后,给data添加src属性及其值
+
+					self.cropper.pushOrign(this.src);
+				}
+			});
+		}
+	}
+};
+</script>
+
+<style scoped lang="scss">
+@import '../../libs/css/style.components.scss';
+
+.content {
+	background: rgba(255, 255, 255, 1);
+}
+
+.cropper {
+	position: absolute;
+	top: 0;
+	left: 0;
+	width: 100%;
+	height: 100%;
+	z-index: 11;
+}
+
+.cropper-buttons {
+	background-color: #000000;
+	color: #eee;
+}
+
+.cropper-wrapper {
+	position: relative;
+	@include vue-flex;
+	flex-direction: row;
+	justify-content: space-between;
+	align-items: center;
+	width: 100%;
+	background-color: #000;
+}
+
+.cropper-buttons {
+	width: 100vw;
+	@include vue-flex;
+	flex-direction: row;
+	justify-content: space-between;
+	align-items: center;
+	position: fixed;
+	bottom: 0;
+	left: 0;
+	font-size: 28rpx;
+}
+
+.cropper-buttons .upload,
+.cropper-buttons .getCropperImage {
+	width: 50%;
+	text-align: center;
+}
+
+.cropper-buttons .upload {
+	text-align: left;
+	padding-left: 50rpx;
+}
+
+.cropper-buttons .getCropperImage {
+	text-align: right;
+	padding-right: 50rpx;
+}
+</style>

+ 1265 - 0
uview-ui/components/u-avatar-cropper/weCropper.js

@@ -0,0 +1,1265 @@
+/**
+ * we-cropper v1.3.9
+ * (c) 2020 dlhandsome
+ * @license MIT
+ */
+(function(global, factory) {
+	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+		typeof define === 'function' && define.amd ? define(factory) :
+		(global.WeCropper = factory());
+}(this, (function() {
+	'use strict';
+
+	var device = void 0;
+	var TOUCH_STATE = ['touchstarted', 'touchmoved', 'touchended'];
+
+	function firstLetterUpper(str) {
+		return str.charAt(0).toUpperCase() + str.slice(1)
+	}
+
+	function setTouchState(instance) {
+		var arg = [],
+			len = arguments.length - 1;
+		while (len-- > 0) arg[len] = arguments[len + 1];
+
+		TOUCH_STATE.forEach(function(key, i) {
+			if (arg[i] !== undefined) {
+				instance[key] = arg[i];
+			}
+		});
+	}
+
+	function validator(instance, o) {
+		Object.defineProperties(instance, o);
+	}
+
+	function getDevice() {
+		if (!device) {
+			device = uni.getSystemInfoSync();
+		}
+		return device
+	}
+
+	var tmp = {};
+
+	var ref = getDevice();
+	var pixelRatio = ref.pixelRatio;
+
+	var DEFAULT = {
+		id: {
+			default: 'cropper',
+			get: function get() {
+				return tmp.id
+			},
+			set: function set(value) {
+				if (typeof(value) !== 'string') {
+					console.error(("id:" + value + " is invalid"));
+				}
+				tmp.id = value;
+			}
+		},
+		width: {
+			default: 750,
+			get: function get() {
+				return tmp.width
+			},
+			set: function set(value) {
+				if (typeof(value) !== 'number') {
+					console.error(("width:" + value + " is invalid"));
+				}
+				tmp.width = value;
+			}
+		},
+		height: {
+			default: 750,
+			get: function get() {
+				return tmp.height
+			},
+			set: function set(value) {
+				if (typeof(value) !== 'number') {
+					console.error(("height:" + value + " is invalid"));
+				}
+				tmp.height = value;
+			}
+		},
+		pixelRatio: {
+			default: pixelRatio,
+			get: function get() {
+				return tmp.pixelRatio
+			},
+			set: function set(value) {
+				if (typeof(value) !== 'number') {
+					console.error(("pixelRatio:" + value + " is invalid"));
+				}
+				tmp.pixelRatio = value;
+			}
+		},
+		scale: {
+			default: 2.5,
+			get: function get() {
+				return tmp.scale
+			},
+			set: function set(value) {
+				if (typeof(value) !== 'number') {
+					console.error(("scale:" + value + " is invalid"));
+				}
+				tmp.scale = value;
+			}
+		},
+		zoom: {
+			default: 5,
+			get: function get() {
+				return tmp.zoom
+			},
+			set: function set(value) {
+				if (typeof(value) !== 'number') {
+					console.error(("zoom:" + value + " is invalid"));
+				} else if (value < 0 || value > 10) {
+					console.error("zoom should be ranged in 0 ~ 10");
+				}
+				tmp.zoom = value;
+			}
+		},
+		src: {
+			default: '',
+			get: function get() {
+				return tmp.src
+			},
+			set: function set(value) {
+				if (typeof(value) !== 'string') {
+					console.error(("src:" + value + " is invalid"));
+				}
+				tmp.src = value;
+			}
+		},
+		cut: {
+			default: {},
+			get: function get() {
+				return tmp.cut
+			},
+			set: function set(value) {
+				if (typeof(value) !== 'object') {
+					console.error(("cut:" + value + " is invalid"));
+				}
+				tmp.cut = value;
+			}
+		},
+		boundStyle: {
+			default: {},
+			get: function get() {
+				return tmp.boundStyle
+			},
+			set: function set(value) {
+				if (typeof(value) !== 'object') {
+					console.error(("boundStyle:" + value + " is invalid"));
+				}
+				tmp.boundStyle = value;
+			}
+		},
+		onReady: {
+			default: null,
+			get: function get() {
+				return tmp.ready
+			},
+			set: function set(value) {
+				tmp.ready = value;
+			}
+		},
+		onBeforeImageLoad: {
+			default: null,
+			get: function get() {
+				return tmp.beforeImageLoad
+			},
+			set: function set(value) {
+				tmp.beforeImageLoad = value;
+			}
+		},
+		onImageLoad: {
+			default: null,
+			get: function get() {
+				return tmp.imageLoad
+			},
+			set: function set(value) {
+				tmp.imageLoad = value;
+			}
+		},
+		onBeforeDraw: {
+			default: null,
+			get: function get() {
+				return tmp.beforeDraw
+			},
+			set: function set(value) {
+				tmp.beforeDraw = value;
+			}
+		}
+	};
+
+	var ref$1 = getDevice();
+	var windowWidth = ref$1.windowWidth;
+
+	function prepare() {
+		var self = this;
+
+		// v1.4.0 版本中将不再自动绑定we-cropper实例
+		self.attachPage = function() {
+			var pages = getCurrentPages();
+			// 获取到当前page上下文
+			var pageContext = pages[pages.length - 1];
+			// 把this依附在Page上下文的wecropper属性上,便于在page钩子函数中访问
+			Object.defineProperty(pageContext, 'wecropper', {
+				get: function get() {
+					console.warn(
+						'Instance will not be automatically bound to the page after v1.4.0\n\n' +
+						'Please use a custom instance name instead\n\n' +
+						'Example: \n' +
+						'this.mycropper = new WeCropper(options)\n\n' +
+						'// ...\n' +
+						'this.mycropper.getCropperImage()'
+					);
+					return self
+				},
+				configurable: true
+			});
+		};
+
+		self.createCtx = function() {
+			var id = self.id;
+			var targetId = self.targetId;
+
+			if (id) {
+				self.ctx = self.ctx || uni.createCanvasContext(id);
+				self.targetCtx = self.targetCtx || uni.createCanvasContext(targetId);
+			} else {
+				console.error("constructor: create canvas context failed, 'id' must be valuable");
+			}
+		};
+
+		self.deviceRadio = windowWidth / 750;
+	}
+
+	var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !==
+		'undefined' ? self : {};
+
+
+
+
+
+	function createCommonjsModule(fn, module) {
+		return module = {
+			exports: {}
+		}, fn(module, module.exports), module.exports;
+	}
+
+	var tools = createCommonjsModule(function(module, exports) {
+		/**
+		 * String type check
+		 */
+		exports.isStr = function(v) {
+			return typeof v === 'string';
+		};
+		/**
+		 * Number type check
+		 */
+		exports.isNum = function(v) {
+			return typeof v === 'number';
+		};
+		/**
+		 * Array type check
+		 */
+		exports.isArr = Array.isArray;
+		/**
+		 * undefined type check
+		 */
+		exports.isUndef = function(v) {
+			return v === undefined;
+		};
+
+		exports.isTrue = function(v) {
+			return v === true;
+		};
+
+		exports.isFalse = function(v) {
+			return v === false;
+		};
+		/**
+		 * Function type check
+		 */
+		exports.isFunc = function(v) {
+			return typeof v === 'function';
+		};
+		/**
+		 * Quick object check - this is primarily used to tell
+		 * Objects from primitive values when we know the value
+		 * is a JSON-compliant type.
+		 */
+		exports.isObj = exports.isObject = function(obj) {
+			return obj !== null && typeof obj === 'object'
+		};
+
+		/**
+		 * Strict object type check. Only returns true
+		 * for plain JavaScript objects.
+		 */
+		var _toString = Object.prototype.toString;
+		exports.isPlainObject = function(obj) {
+			return _toString.call(obj) === '[object Object]'
+		};
+
+		/**
+		 * Check whether the object has the property.
+		 */
+		var hasOwnProperty = Object.prototype.hasOwnProperty;
+		exports.hasOwn = function(obj, key) {
+			return hasOwnProperty.call(obj, key)
+		};
+
+		/**
+		 * Perform no operation.
+		 * Stubbing args to make Flow happy without leaving useless transpiled code
+		 * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/)
+		 */
+		exports.noop = function(a, b, c) {};
+
+		/**
+		 * Check if val is a valid array index.
+		 */
+		exports.isValidArrayIndex = function(val) {
+			var n = parseFloat(String(val));
+			return n >= 0 && Math.floor(n) === n && isFinite(val)
+		};
+	});
+
+	var tools_7 = tools.isFunc;
+	var tools_10 = tools.isPlainObject;
+
+	var EVENT_TYPE = ['ready', 'beforeImageLoad', 'beforeDraw', 'imageLoad'];
+
+	function observer() {
+		var self = this;
+
+		self.on = function(event, fn) {
+			if (EVENT_TYPE.indexOf(event) > -1) {
+				if (tools_7(fn)) {
+					event === 'ready' ?
+						fn(self) :
+						self[("on" + (firstLetterUpper(event)))] = fn;
+				}
+			} else {
+				console.error(("event: " + event + " is invalid"));
+			}
+			return self
+		};
+	}
+
+	function wxPromise(fn) {
+		return function(obj) {
+			var args = [],
+				len = arguments.length - 1;
+			while (len-- > 0) args[len] = arguments[len + 1];
+
+			if (obj === void 0) obj = {};
+			return new Promise(function(resolve, reject) {
+				obj.success = function(res) {
+					resolve(res);
+				};
+				obj.fail = function(err) {
+					reject(err);
+				};
+				fn.apply(void 0, [obj].concat(args));
+			})
+		}
+	}
+
+	function draw(ctx, reserve) {
+		if (reserve === void 0) reserve = false;
+
+		return new Promise(function(resolve) {
+			ctx.draw(reserve, resolve);
+		})
+	}
+
+	var getImageInfo = wxPromise(uni.getImageInfo);
+
+	var canvasToTempFilePath = wxPromise(uni.canvasToTempFilePath);
+
+	var base64 = createCommonjsModule(function(module, exports) {
+		/*! http://mths.be/base64 v0.1.0 by @mathias | MIT license */
+		(function(root) {
+
+			// Detect free variables `exports`.
+			var freeExports = 'object' == 'object' && exports;
+
+			// Detect free variable `module`.
+			var freeModule = 'object' == 'object' && module &&
+				module.exports == freeExports && module;
+
+			// Detect free variable `global`, from Node.js or Browserified code, and use
+			// it as `root`.
+			var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal;
+			if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
+				root = freeGlobal;
+			}
+
+			/*--------------------------------------------------------------------------*/
+
+			var InvalidCharacterError = function(message) {
+				this.message = message;
+			};
+			InvalidCharacterError.prototype = new Error;
+			InvalidCharacterError.prototype.name = 'InvalidCharacterError';
+
+			var error = function(message) {
+				// Note: the error messages used throughout this file match those used by
+				// the native `atob`/`btoa` implementation in Chromium.
+				throw new InvalidCharacterError(message);
+			};
+
+			var TABLE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+			// http://whatwg.org/html/common-microsyntaxes.html#space-character
+			var REGEX_SPACE_CHARACTERS = /[\t\n\f\r ]/g;
+
+			// `decode` is designed to be fully compatible with `atob` as described in the
+			// HTML Standard. http://whatwg.org/html/webappapis.html#dom-windowbase64-atob
+			// The optimized base64-decoding algorithm used is based on @atk’s excellent
+			// implementation. https://gist.github.com/atk/1020396
+			var decode = function(input) {
+				input = String(input)
+					.replace(REGEX_SPACE_CHARACTERS, '');
+				var length = input.length;
+				if (length % 4 == 0) {
+					input = input.replace(/==?$/, '');
+					length = input.length;
+				}
+				if (
+					length % 4 == 1 ||
+					// http://whatwg.org/C#alphanumeric-ascii-characters
+					/[^+a-zA-Z0-9/]/.test(input)
+				) {
+					error(
+						'Invalid character: the string to be decoded is not correctly encoded.'
+					);
+				}
+				var bitCounter = 0;
+				var bitStorage;
+				var buffer;
+				var output = '';
+				var position = -1;
+				while (++position < length) {
+					buffer = TABLE.indexOf(input.charAt(position));
+					bitStorage = bitCounter % 4 ? bitStorage * 64 + buffer : buffer;
+					// Unless this is the first of a group of 4 characters…
+					if (bitCounter++ % 4) {
+						// …convert the first 8 bits to a single ASCII character.
+						output += String.fromCharCode(
+							0xFF & bitStorage >> (-2 * bitCounter & 6)
+						);
+					}
+				}
+				return output;
+			};
+
+			// `encode` is designed to be fully compatible with `btoa` as described in the
+			// HTML Standard: http://whatwg.org/html/webappapis.html#dom-windowbase64-btoa
+			var encode = function(input) {
+				input = String(input);
+				if (/[^\0-\xFF]/.test(input)) {
+					// Note: no need to special-case astral symbols here, as surrogates are
+					// matched, and the input is supposed to only contain ASCII anyway.
+					error(
+						'The string to be encoded contains characters outside of the ' +
+						'Latin1 range.'
+					);
+				}
+				var padding = input.length % 3;
+				var output = '';
+				var position = -1;
+				var a;
+				var b;
+				var c;
+				var buffer;
+				// Make sure any padding is handled outside of the loop.
+				var length = input.length - padding;
+
+				while (++position < length) {
+					// Read three bytes, i.e. 24 bits.
+					a = input.charCodeAt(position) << 16;
+					b = input.charCodeAt(++position) << 8;
+					c = input.charCodeAt(++position);
+					buffer = a + b + c;
+					// Turn the 24 bits into four chunks of 6 bits each, and append the
+					// matching character for each of them to the output.
+					output += (
+						TABLE.charAt(buffer >> 18 & 0x3F) +
+						TABLE.charAt(buffer >> 12 & 0x3F) +
+						TABLE.charAt(buffer >> 6 & 0x3F) +
+						TABLE.charAt(buffer & 0x3F)
+					);
+				}
+
+				if (padding == 2) {
+					a = input.charCodeAt(position) << 8;
+					b = input.charCodeAt(++position);
+					buffer = a + b;
+					output += (
+						TABLE.charAt(buffer >> 10) +
+						TABLE.charAt((buffer >> 4) & 0x3F) +
+						TABLE.charAt((buffer << 2) & 0x3F) +
+						'='
+					);
+				} else if (padding == 1) {
+					buffer = input.charCodeAt(position);
+					output += (
+						TABLE.charAt(buffer >> 2) +
+						TABLE.charAt((buffer << 4) & 0x3F) +
+						'=='
+					);
+				}
+
+				return output;
+			};
+
+			var base64 = {
+				'encode': encode,
+				'decode': decode,
+				'version': '0.1.0'
+			};
+
+			// Some AMD build optimizers, like r.js, check for specific condition patterns
+			// like the following:
+			if (
+				typeof undefined == 'function' &&
+				typeof undefined.amd == 'object' &&
+				undefined.amd
+			) {
+				undefined(function() {
+					return base64;
+				});
+			} else if (freeExports && !freeExports.nodeType) {
+				if (freeModule) { // in Node.js or RingoJS v0.8.0+
+					freeModule.exports = base64;
+				} else { // in Narwhal or RingoJS v0.7.0-
+					for (var key in base64) {
+						base64.hasOwnProperty(key) && (freeExports[key] = base64[key]);
+					}
+				}
+			} else { // in Rhino or a web browser
+				root.base64 = base64;
+			}
+
+		}(commonjsGlobal));
+	});
+
+	function makeURI(strData, type) {
+		return 'data:' + type + ';base64,' + strData
+	}
+
+	function fixType(type) {
+		type = type.toLowerCase().replace(/jpg/i, 'jpeg');
+		var r = type.match(/png|jpeg|bmp|gif/)[0];
+		return 'image/' + r
+	}
+
+	function encodeData(data) {
+		var str = '';
+		if (typeof data === 'string') {
+			str = data;
+		} else {
+			for (var i = 0; i < data.length; i++) {
+				str += String.fromCharCode(data[i]);
+			}
+		}
+		return base64.encode(str)
+	}
+
+	/**
+	 * 获取图像区域隐含的像素数据
+	 * @param canvasId canvas标识
+	 * @param x 将要被提取的图像数据矩形区域的左上角 x 坐标
+	 * @param y 将要被提取的图像数据矩形区域的左上角 y 坐标
+	 * @param width 将要被提取的图像数据矩形区域的宽度
+	 * @param height 将要被提取的图像数据矩形区域的高度
+	 * @param done 完成回调
+	 */
+	function getImageData(canvasId, x, y, width, height, done) {
+		uni.canvasGetImageData({
+			canvasId: canvasId,
+			x: x,
+			y: y,
+			width: width,
+			height: height,
+			success: function success(res) {
+				done(res, null);
+			},
+			fail: function fail(res) {
+				done(null, res);
+			}
+		});
+	}
+
+	/**
+	 * 生成bmp格式图片
+	 * 按照规则生成图片响应头和响应体
+	 * @param oData 用来描述 canvas 区域隐含的像素数据 { data, width, height } = oData
+	 * @returns {*} base64字符串
+	 */
+	function genBitmapImage(oData) {
+		//
+		// BITMAPFILEHEADER: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183374(v=vs.85).aspx
+		// BITMAPINFOHEADER: http://msdn.microsoft.com/en-us/library/dd183376.aspx
+		//
+		var biWidth = oData.width;
+		var biHeight = oData.height;
+		var biSizeImage = biWidth * biHeight * 3;
+		var bfSize = biSizeImage + 54; // total header size = 54 bytes
+
+		//
+		//  typedef struct tagBITMAPFILEHEADER {
+		//  	WORD bfType;
+		//  	DWORD bfSize;
+		//  	WORD bfReserved1;
+		//  	WORD bfReserved2;
+		//  	DWORD bfOffBits;
+		//  } BITMAPFILEHEADER;
+		//
+		var BITMAPFILEHEADER = [
+			// WORD bfType -- The file type signature; must be "BM"
+			0x42, 0x4D,
+			// DWORD bfSize -- The size, in bytes, of the bitmap file
+			bfSize & 0xff, bfSize >> 8 & 0xff, bfSize >> 16 & 0xff, bfSize >> 24 & 0xff,
+			// WORD bfReserved1 -- Reserved; must be zero
+			0, 0,
+			// WORD bfReserved2 -- Reserved; must be zero
+			0, 0,
+			// DWORD bfOffBits -- The offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to the bitmap bits.
+			54, 0, 0, 0
+		];
+
+		//
+		//  typedef struct tagBITMAPINFOHEADER {
+		//  	DWORD biSize;
+		//  	LONG  biWidth;
+		//  	LONG  biHeight;
+		//  	WORD  biPlanes;
+		//  	WORD  biBitCount;
+		//  	DWORD biCompression;
+		//  	DWORD biSizeImage;
+		//  	LONG  biXPelsPerMeter;
+		//  	LONG  biYPelsPerMeter;
+		//  	DWORD biClrUsed;
+		//  	DWORD biClrImportant;
+		//  } BITMAPINFOHEADER, *PBITMAPINFOHEADER;
+		//
+		var BITMAPINFOHEADER = [
+			// DWORD biSize -- The number of bytes required by the structure
+			40, 0, 0, 0,
+			// LONG biWidth -- The width of the bitmap, in pixels
+			biWidth & 0xff, biWidth >> 8 & 0xff, biWidth >> 16 & 0xff, biWidth >> 24 & 0xff,
+			// LONG biHeight -- The height of the bitmap, in pixels
+			biHeight & 0xff, biHeight >> 8 & 0xff, biHeight >> 16 & 0xff, biHeight >> 24 & 0xff,
+			// WORD biPlanes -- The number of planes for the target device. This value must be set to 1
+			1, 0,
+			// WORD biBitCount -- The number of bits-per-pixel, 24 bits-per-pixel -- the bitmap
+			// has a maximum of 2^24 colors (16777216, Truecolor)
+			24, 0,
+			// DWORD biCompression -- The type of compression, BI_RGB (code 0) -- uncompressed
+			0, 0, 0, 0,
+			// DWORD biSizeImage -- The size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps
+			biSizeImage & 0xff, biSizeImage >> 8 & 0xff, biSizeImage >> 16 & 0xff, biSizeImage >> 24 & 0xff,
+			// LONG biXPelsPerMeter, unused
+			0, 0, 0, 0,
+			// LONG biYPelsPerMeter, unused
+			0, 0, 0, 0,
+			// DWORD biClrUsed, the number of color indexes of palette, unused
+			0, 0, 0, 0,
+			// DWORD biClrImportant, unused
+			0, 0, 0, 0
+		];
+
+		var iPadding = (4 - ((biWidth * 3) % 4)) % 4;
+
+		var aImgData = oData.data;
+
+		var strPixelData = '';
+		var biWidth4 = biWidth << 2;
+		var y = biHeight;
+		var fromCharCode = String.fromCharCode;
+
+		do {
+			var iOffsetY = biWidth4 * (y - 1);
+			var strPixelRow = '';
+			for (var x = 0; x < biWidth; x++) {
+				var iOffsetX = x << 2;
+				strPixelRow += fromCharCode(aImgData[iOffsetY + iOffsetX + 2]) +
+					fromCharCode(aImgData[iOffsetY + iOffsetX + 1]) +
+					fromCharCode(aImgData[iOffsetY + iOffsetX]);
+			}
+
+			for (var c = 0; c < iPadding; c++) {
+				strPixelRow += String.fromCharCode(0);
+			}
+
+			strPixelData += strPixelRow;
+		} while (--y)
+
+		var strEncoded = encodeData(BITMAPFILEHEADER.concat(BITMAPINFOHEADER)) + encodeData(strPixelData);
+
+		return strEncoded
+	}
+
+	/**
+	 * 转换为图片base64
+	 * @param canvasId canvas标识
+	 * @param x 将要被提取的图像数据矩形区域的左上角 x 坐标
+	 * @param y 将要被提取的图像数据矩形区域的左上角 y 坐标
+	 * @param width 将要被提取的图像数据矩形区域的宽度
+	 * @param height 将要被提取的图像数据矩形区域的高度
+	 * @param type 转换图片类型
+	 * @param done 完成回调
+	 */
+	function convertToImage(canvasId, x, y, width, height, type, done) {
+		if (done === void 0) done = function() {};
+
+		if (type === undefined) {
+			type = 'png';
+		}
+		type = fixType(type);
+		if (/bmp/.test(type)) {
+			getImageData(canvasId, x, y, width, height, function(data, err) {
+				var strData = genBitmapImage(data);
+				tools_7(done) && done(makeURI(strData, 'image/' + type), err);
+			});
+		} else {
+			console.error('暂不支持生成\'' + type + '\'类型的base64图片');
+		}
+	}
+
+	var CanvasToBase64 = {
+		convertToImage: convertToImage,
+		// convertToPNG: function (width, height, done) {
+		//   return convertToImage(width, height, 'png', done)
+		// },
+		// convertToJPEG: function (width, height, done) {
+		//   return convertToImage(width, height, 'jpeg', done)
+		// },
+		// convertToGIF: function (width, height, done) {
+		//   return convertToImage(width, height, 'gif', done)
+		// },
+		convertToBMP: function(ref, done) {
+			if (ref === void 0) ref = {};
+			var canvasId = ref.canvasId;
+			var x = ref.x;
+			var y = ref.y;
+			var width = ref.width;
+			var height = ref.height;
+			if (done === void 0) done = function() {};
+
+			return convertToImage(canvasId, x, y, width, height, 'bmp', done)
+		}
+	};
+
+	function methods() {
+		var self = this;
+
+		var boundWidth = self.width; // 裁剪框默认宽度,即整个画布宽度
+		var boundHeight = self.height; // 裁剪框默认高度,即整个画布高度
+
+		var id = self.id;
+		var targetId = self.targetId;
+		var pixelRatio = self.pixelRatio;
+
+		var ref = self.cut;
+		var x = ref.x;
+		if (x === void 0) x = 0;
+		var y = ref.y;
+		if (y === void 0) y = 0;
+		var width = ref.width;
+		if (width === void 0) width = boundWidth;
+		var height = ref.height;
+		if (height === void 0) height = boundHeight;
+
+		self.updateCanvas = function(done) {
+			if (self.croperTarget) {
+				//  画布绘制图片
+				self.ctx.drawImage(
+					self.croperTarget,
+					self.imgLeft,
+					self.imgTop,
+					self.scaleWidth,
+					self.scaleHeight
+				);
+			}
+			tools_7(self.onBeforeDraw) && self.onBeforeDraw(self.ctx, self);
+
+			self.setBoundStyle(self.boundStyle); //	设置边界样式
+
+			self.ctx.draw(false, done);
+			return self
+		};
+
+		self.pushOrigin = self.pushOrign = function(src) {
+			self.src = src;
+
+			tools_7(self.onBeforeImageLoad) && self.onBeforeImageLoad(self.ctx, self);
+
+			return getImageInfo({
+					src: src
+				})
+				.then(function(res) {
+					var innerAspectRadio = res.width / res.height;
+					var customAspectRadio = width / height;
+
+					self.croperTarget = res.path;
+
+					if (innerAspectRadio < customAspectRadio) {
+						self.rectX = x;
+						self.baseWidth = width;
+						self.baseHeight = width / innerAspectRadio;
+						self.rectY = y - Math.abs((height - self.baseHeight) / 2);
+					} else {
+						self.rectY = y;
+						self.baseWidth = height * innerAspectRadio;
+						self.baseHeight = height;
+						self.rectX = x - Math.abs((width - self.baseWidth) / 2);
+					}
+
+					self.imgLeft = self.rectX;
+					self.imgTop = self.rectY;
+					self.scaleWidth = self.baseWidth;
+					self.scaleHeight = self.baseHeight;
+
+					self.update();
+
+					return new Promise(function(resolve) {
+						self.updateCanvas(resolve);
+					})
+				})
+				.then(function() {
+					tools_7(self.onImageLoad) && self.onImageLoad(self.ctx, self);
+				})
+		};
+
+		self.removeImage = function() {
+			self.src = '';
+			self.croperTarget = '';
+			return draw(self.ctx)
+		};
+
+		self.getCropperBase64 = function(done) {
+			if (done === void 0) done = function() {};
+
+			CanvasToBase64.convertToBMP({
+				canvasId: id,
+				x: x,
+				y: y,
+				width: width,
+				height: height
+			}, done);
+		};
+
+		self.getCropperImage = function(opt, fn) {
+			var customOptions = opt;
+
+			var canvasOptions = {
+				canvasId: id,
+				x: x,
+				y: y,
+				width: width,
+				height: height
+			};
+
+			var task = function() {
+				return Promise.resolve();
+			};
+
+			if (
+				tools_10(customOptions) &&
+				customOptions.original
+			) {
+				// original mode
+				task = function() {
+					self.targetCtx.drawImage(
+						self.croperTarget,
+						self.imgLeft * pixelRatio,
+						self.imgTop * pixelRatio,
+						self.scaleWidth * pixelRatio,
+						self.scaleHeight * pixelRatio
+					);
+
+					canvasOptions = {
+						canvasId: targetId,
+						x: x * pixelRatio,
+						y: y * pixelRatio,
+						width: width * pixelRatio,
+						height: height * pixelRatio
+					};
+
+					return draw(self.targetCtx)
+				};
+			}
+
+			return task()
+				.then(function() {
+					if (tools_10(customOptions)) {
+						canvasOptions = Object.assign({}, canvasOptions, customOptions);
+					}
+
+					if (tools_7(customOptions)) {
+						fn = customOptions;
+					}
+
+					var arg = canvasOptions.componentContext ?
+						[canvasOptions, canvasOptions.componentContext] :
+						[canvasOptions];
+
+					return canvasToTempFilePath.apply(null, arg)
+				})
+				.then(function(res) {
+					var tempFilePath = res.tempFilePath;
+
+					return tools_7(fn) ?
+						fn.call(self, tempFilePath, null) :
+						tempFilePath
+				})
+				.catch(function(err) {
+					if (tools_7(fn)) {
+						fn.call(self, null, err);
+					} else {
+						throw err
+					}
+				})
+		};
+	}
+
+	/**
+	 * 获取最新缩放值
+	 * @param oldScale 上一次触摸结束后的缩放值
+	 * @param oldDistance 上一次触摸结束后的双指距离
+	 * @param zoom 缩放系数
+	 * @param touch0 第一指touch对象
+	 * @param touch1 第二指touch对象
+	 * @returns {*}
+	 */
+	var getNewScale = function(oldScale, oldDistance, zoom, touch0, touch1) {
+		var xMove, yMove, newDistance;
+		// 计算二指最新距离
+		xMove = Math.round(touch1.x - touch0.x);
+		yMove = Math.round(touch1.y - touch0.y);
+		newDistance = Math.round(Math.sqrt(xMove * xMove + yMove * yMove));
+
+		return oldScale + 0.001 * zoom * (newDistance - oldDistance)
+	};
+
+	function update() {
+		var self = this;
+
+		if (!self.src) {
+			return
+		}
+
+		self.__oneTouchStart = function(touch) {
+			self.touchX0 = Math.round(touch.x);
+			self.touchY0 = Math.round(touch.y);
+		};
+
+		self.__oneTouchMove = function(touch) {
+			var xMove, yMove;
+			// 计算单指移动的距离
+			if (self.touchended) {
+				return self.updateCanvas()
+			}
+			xMove = Math.round(touch.x - self.touchX0);
+			yMove = Math.round(touch.y - self.touchY0);
+
+			var imgLeft = Math.round(self.rectX + xMove);
+			var imgTop = Math.round(self.rectY + yMove);
+
+			self.outsideBound(imgLeft, imgTop);
+
+			self.updateCanvas();
+		};
+
+		self.__twoTouchStart = function(touch0, touch1) {
+			var xMove, yMove, oldDistance;
+
+			self.touchX1 = Math.round(self.rectX + self.scaleWidth / 2);
+			self.touchY1 = Math.round(self.rectY + self.scaleHeight / 2);
+
+			// 计算两指距离
+			xMove = Math.round(touch1.x - touch0.x);
+			yMove = Math.round(touch1.y - touch0.y);
+			oldDistance = Math.round(Math.sqrt(xMove * xMove + yMove * yMove));
+
+			self.oldDistance = oldDistance;
+		};
+
+		self.__twoTouchMove = function(touch0, touch1) {
+			var oldScale = self.oldScale;
+			var oldDistance = self.oldDistance;
+			var scale = self.scale;
+			var zoom = self.zoom;
+
+			self.newScale = getNewScale(oldScale, oldDistance, zoom, touch0, touch1);
+
+			//  设定缩放范围
+			self.newScale <= 1 && (self.newScale = 1);
+			self.newScale >= scale && (self.newScale = scale);
+
+			self.scaleWidth = Math.round(self.newScale * self.baseWidth);
+			self.scaleHeight = Math.round(self.newScale * self.baseHeight);
+			var imgLeft = Math.round(self.touchX1 - self.scaleWidth / 2);
+			var imgTop = Math.round(self.touchY1 - self.scaleHeight / 2);
+
+			self.outsideBound(imgLeft, imgTop);
+
+			self.updateCanvas();
+		};
+
+		self.__xtouchEnd = function() {
+			self.oldScale = self.newScale;
+			self.rectX = self.imgLeft;
+			self.rectY = self.imgTop;
+		};
+	}
+
+	var handle = {
+		//  图片手势初始监测
+		touchStart: function touchStart(e) {
+			var self = this;
+			var ref = e.touches;
+			var touch0 = ref[0];
+			var touch1 = ref[1];
+
+			if (!self.src) {
+				return
+			}
+
+			setTouchState(self, true, null, null);
+
+			// 计算第一个触摸点的位置,并参照改点进行缩放
+			self.__oneTouchStart(touch0);
+
+			// 两指手势触发
+			if (e.touches.length >= 2) {
+				self.__twoTouchStart(touch0, touch1);
+			}
+		},
+
+		//  图片手势动态缩放
+		touchMove: function touchMove(e) {
+			var self = this;
+			var ref = e.touches;
+			var touch0 = ref[0];
+			var touch1 = ref[1];
+
+			if (!self.src) {
+				return
+			}
+
+			setTouchState(self, null, true);
+
+			// 单指手势时触发
+			if (e.touches.length === 1) {
+				self.__oneTouchMove(touch0);
+			}
+			// 两指手势触发
+			if (e.touches.length >= 2) {
+				self.__twoTouchMove(touch0, touch1);
+			}
+		},
+
+		touchEnd: function touchEnd(e) {
+			var self = this;
+
+			if (!self.src) {
+				return
+			}
+
+			setTouchState(self, false, false, true);
+			self.__xtouchEnd();
+		}
+	};
+
+	function cut() {
+		var self = this;
+		var boundWidth = self.width; // 裁剪框默认宽度,即整个画布宽度
+		var boundHeight = self.height;
+		// 裁剪框默认高度,即整个画布高度
+		var ref = self.cut;
+		var x = ref.x;
+		if (x === void 0) x = 0;
+		var y = ref.y;
+		if (y === void 0) y = 0;
+		var width = ref.width;
+		if (width === void 0) width = boundWidth;
+		var height = ref.height;
+		if (height === void 0) height = boundHeight;
+
+		/**
+		 * 设置边界
+		 * @param imgLeft 图片左上角横坐标值
+		 * @param imgTop 图片左上角纵坐标值
+		 */
+		self.outsideBound = function(imgLeft, imgTop) {
+			self.imgLeft = imgLeft >= x ?
+				x :
+				self.scaleWidth + imgLeft - x <= width ?
+				x + width - self.scaleWidth :
+				imgLeft;
+
+			self.imgTop = imgTop >= y ?
+				y :
+				self.scaleHeight + imgTop - y <= height ?
+				y + height - self.scaleHeight :
+				imgTop;
+		};
+
+		/**
+		 * 设置边界样式
+		 * @param color	边界颜色
+		 */
+		self.setBoundStyle = function(ref) {
+			if (ref === void 0) ref = {};
+			var color = ref.color;
+			if (color === void 0) color = '#04b00f';
+			var mask = ref.mask;
+			if (mask === void 0) mask = 'rgba(0, 0, 0, 0.3)';
+			var lineWidth = ref.lineWidth;
+			if (lineWidth === void 0) lineWidth = 1;
+
+			var half = lineWidth / 2;
+			var boundOption = [{
+					start: {
+						x: x - half,
+						y: y + 10 - half
+					},
+					step1: {
+						x: x - half,
+						y: y - half
+					},
+					step2: {
+						x: x + 10 - half,
+						y: y - half
+					}
+				},
+				{
+					start: {
+						x: x - half,
+						y: y + height - 10 + half
+					},
+					step1: {
+						x: x - half,
+						y: y + height + half
+					},
+					step2: {
+						x: x + 10 - half,
+						y: y + height + half
+					}
+				},
+				{
+					start: {
+						x: x + width - 10 + half,
+						y: y - half
+					},
+					step1: {
+						x: x + width + half,
+						y: y - half
+					},
+					step2: {
+						x: x + width + half,
+						y: y + 10 - half
+					}
+				},
+				{
+					start: {
+						x: x + width + half,
+						y: y + height - 10 + half
+					},
+					step1: {
+						x: x + width + half,
+						y: y + height + half
+					},
+					step2: {
+						x: x + width - 10 + half,
+						y: y + height + half
+					}
+				}
+			];
+
+			// 绘制半透明层
+			self.ctx.beginPath();
+			self.ctx.setFillStyle(mask);
+			self.ctx.fillRect(0, 0, x, boundHeight);
+			self.ctx.fillRect(x, 0, width, y);
+			self.ctx.fillRect(x, y + height, width, boundHeight - y - height);
+			self.ctx.fillRect(x + width, 0, boundWidth - x - width, boundHeight);
+			self.ctx.fill();
+
+			boundOption.forEach(function(op) {
+				self.ctx.beginPath();
+				self.ctx.setStrokeStyle(color);
+				self.ctx.setLineWidth(lineWidth);
+				self.ctx.moveTo(op.start.x, op.start.y);
+				self.ctx.lineTo(op.step1.x, op.step1.y);
+				self.ctx.lineTo(op.step2.x, op.step2.y);
+				self.ctx.stroke();
+			});
+		};
+	}
+
+	var version = "1.3.9";
+
+	var WeCropper = function WeCropper(params) {
+		var self = this;
+		var _default = {};
+
+		validator(self, DEFAULT);
+
+		Object.keys(DEFAULT).forEach(function(key) {
+			_default[key] = DEFAULT[key].default;
+		});
+		Object.assign(self, _default, params);
+
+		self.prepare();
+		self.attachPage();
+		self.createCtx();
+		self.observer();
+		self.cutt();
+		self.methods();
+		self.init();
+		self.update();
+
+		return self
+	};
+
+	WeCropper.prototype.init = function init() {
+		var self = this;
+		var src = self.src;
+
+		self.version = version;
+
+		typeof self.onReady === 'function' && self.onReady(self.ctx, self);
+
+		if (src) {
+			self.pushOrign(src);
+		} else {
+			self.updateCanvas();
+		}
+		setTouchState(self, false, false, false);
+
+		self.oldScale = 1;
+		self.newScale = 1;
+
+		return self
+	};
+
+	Object.assign(WeCropper.prototype, handle);
+
+	WeCropper.prototype.prepare = prepare;
+	WeCropper.prototype.observer = observer;
+	WeCropper.prototype.methods = methods;
+	WeCropper.prototype.cutt = cut;
+	WeCropper.prototype.update = update;
+
+	return WeCropper;
+
+})));

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 24 - 0
uview-ui/components/u-avatar/u-avatar.vue


+ 153 - 0
uview-ui/components/u-back-top/u-back-top.vue

@@ -0,0 +1,153 @@
+<template>
+	<view @tap="backToTop" class="u-back-top" :class="['u-back-top--mode--' + mode]" :style="[{
+		bottom: bottom + 'rpx',
+		right: right + 'rpx',
+		borderRadius: mode == 'circle' ? '10000rpx' : '8rpx',
+		zIndex: uZIndex,
+		opacity: opacity
+	}, customStyle]">
+		<view class="u-back-top__content" v-if="!$slots.default && !$slots.$default">
+			<u-icon @click="backToTop" :name="icon" :custom-style="iconStyle"></u-icon>
+			<view class="u-back-top__content__tips">
+				{{tips}}
+			</view>
+		</view>
+		<slot v-else />
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'u-back-top',
+		props: {
+			// 返回顶部的形状,circle-圆形,square-方形
+			mode: {
+				type: String,
+				default: 'circle'
+			},
+			// 自定义图标
+			icon: {
+				type: String,
+				default: 'arrow-upward'
+			},
+			// 提示文字
+			tips: {
+				type: String,
+				default: ''
+			},
+			// 返回顶部滚动时间
+			duration: {
+				type: [Number, String],
+				default: 100
+			},
+			// 滚动距离
+			scrollTop: {
+				type: [Number, String],
+				default: 0
+			},
+			// 距离顶部多少距离显示,单位rpx
+			top: {
+				type: [Number, String],
+				default: 400
+			},
+			// 返回顶部按钮到底部的距离,单位rpx
+			bottom: {
+				type: [Number, String],
+				default: 200
+			},
+			// 返回顶部按钮到右边的距离,单位rpx
+			right: {
+				type: [Number, String],
+				default: 40
+			},
+			// 层级
+			zIndex: {
+				type: [Number, String],
+				default: '9'
+			},
+			// 图标的样式,对象形式
+			iconStyle: {
+				type: Object,
+				default() {
+					return {
+						color: '#909399',
+						fontSize: '38rpx'
+					}
+				}
+			},
+			// 整个组件的样式
+			customStyle: {
+				type: Object,
+				default() {
+					return {}
+				}
+			}
+		},
+		watch: {
+			showBackTop(nVal, oVal) {
+				// 当组件的显示与隐藏状态发生跳变时,修改组件的层级和不透明度
+				// 让组件有显示和消失的动画效果,如果用v-if控制组件状态,将无设置动画效果
+				if(nVal) {
+					this.uZIndex = this.zIndex;
+					this.opacity = 1;
+				} else {
+					this.uZIndex = -1;
+					this.opacity = 0;
+				}
+			}
+		},
+		computed: {
+			showBackTop() {
+				// 由于scrollTop为页面的滚动距离,默认为px单位,这里将用于传入的top(rpx)值
+				// 转为px用于比较,如果滚动条到顶的距离大于设定的距离,就显示返回顶部的按钮
+				return this.scrollTop > uni.upx2px(this.top);
+			},
+		},
+		data() {
+			return {
+				// 不透明度,为了让组件有一个显示和隐藏的过渡动画
+				opacity: 0,
+				// 组件的z-index值,隐藏时设置为-1,就会看不到
+				uZIndex: -1
+			}
+		},
+		methods: {
+			backToTop() {
+				uni.pageScrollTo({
+					scrollTop: 0,
+					duration: this.duration
+				});
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	@import "../../libs/css/style.components.scss";
+	
+	.u-back-top {
+		width: 80rpx;
+		height: 80rpx;
+		position: fixed;
+		z-index: 9;
+		@include vue-flex;
+		flex-direction: column;
+		justify-content: center;
+		background-color: #E1E1E1;
+		color: $u-content-color;
+		align-items: center;
+		transition: opacity 0.4s;
+		
+		&__content {
+			@include vue-flex;
+			flex-direction: column;
+			align-items: center;
+			
+			&__tips {
+				font-size: 24rpx;
+				transform: scale(0.8);
+				line-height: 1;
+			}
+		}
+	}
+</style>

+ 216 - 0
uview-ui/components/u-badge/u-badge.vue

@@ -0,0 +1,216 @@
+<template>
+	<view v-if="show" class="u-badge" :class="[
+			isDot ? 'u-badge-dot' : '', 
+			size == 'mini' ? 'u-badge-mini' : '',
+			type ? 'u-badge--bg--' + type : ''
+		]" :style="[{
+			top: offset[0] + 'rpx',
+			right: offset[1] + 'rpx',
+			fontSize: fontSize + 'rpx',
+			position: absolute ? 'absolute' : 'static',
+			color: color,
+			backgroundColor: bgColor
+		}, boxStyle]"
+	>
+		{{showText}}
+	</view>
+</template>
+
+<script>
+	/**
+	 * badge 角标
+	 * @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。
+	 * @tutorial https://www.uviewui.com/components/badge.html
+	 * @property {String Number} count 展示的数字,大于 overflowCount 时显示为 ${overflowCount}+,为0且show-zero为false时隐藏
+	 * @property {Boolean} is-dot 不展示数字,只有一个小点(默认false)
+	 * @property {Boolean} absolute 组件是否绝对定位,为true时,offset参数才有效(默认true)
+	 * @property {String Number} overflow-count 展示封顶的数字值(默认99)
+	 * @property {String} type 使用预设的背景颜色(默认error)
+	 * @property {Boolean} show-zero 当数值为 0 时,是否展示 Badge(默认false)
+	 * @property {String} size Badge的尺寸,设为mini会得到小一号的Badge(默认default)
+	 * @property {Array} offset 设置badge的位置偏移,格式为 [x, y],也即设置的为top和right的值,单位rpx。absolute为true时有效(默认[20, 20])
+	 * @property {String} color 字体颜色(默认#ffffff)
+	 * @property {String} bgColor 背景颜色,优先级比type高,如设置,type参数会失效
+	 * @property {Boolean} is-center 组件中心点是否和父组件右上角重合,优先级比offset高,如设置,offset参数会失效(默认false)
+	 * @example <u-badge type="error" count="7"></u-badge>
+	 */
+	export default {
+		name: 'u-badge',
+		props: {
+			// primary,warning,success,error,info
+			type: {
+				type: String,
+				default: 'error'
+			},
+			// default, mini
+			size: {
+				type: String,
+				default: 'default'
+			},
+			//是否是圆点
+			isDot: {
+				type: Boolean,
+				default: false
+			},
+			// 显示的数值内容
+			count: {
+				type: [Number, String],
+			},
+			// 展示封顶的数字值
+			overflowCount: {
+				type: Number,
+				default: 99
+			},
+			// 当数值为 0 时,是否展示 Badge
+			showZero: {
+				type: Boolean,
+				default: false
+			},
+			// 位置偏移
+			offset: {
+				type: Array,
+				default: () => {
+					return [20, 20]
+				}
+			},
+			// 是否开启绝对定位,开启了offset才会起作用
+			absolute: {
+				type: Boolean,
+				default: true
+			},
+			// 字体大小
+			fontSize: {
+				type: [String, Number],
+				default: '24'
+			},
+			// 字体演示
+			color: {
+				type: String,
+				default: '#ffffff'
+			},
+			// badge的背景颜色
+			bgColor: {
+				type: String,
+				default: ''
+			},
+			// 是否让badge组件的中心点和父组件右上角重合,配置的话,offset将会失效
+			isCenter: {
+				type: Boolean,
+				default: false
+			}
+		},
+		computed: {
+			// 是否将badge中心与父组件右上角重合
+			boxStyle() {
+				let style = {};
+				if(this.isCenter) {
+					style.top = 0;
+					style.right = 0;
+					// Y轴-50%,意味着badge向上移动了badge自身高度一半,X轴50%,意味着向右移动了自身宽度一半
+					style.transform = "translateY(-50%) translateX(50%)";
+				} else {
+					style.top = this.offset[0] + 'rpx';
+					style.right = this.offset[1] + 'rpx';
+					style.transform = "translateY(0) translateX(0)";
+				}
+				// 如果尺寸为mini,后接上scal()
+				if(this.size == 'mini') {
+					style.transform = style.transform + " scale(0.8)";
+				}
+				return style;
+			},
+			// isDot类型时,不显示文字
+			showText() {
+				if(this.isDot) return '';
+				else {
+					if(this.count > this.overflowCount) return `${this.overflowCount}+`;
+					else return this.count;
+				}
+			},
+			// 是否显示组件
+			show() {
+				// 如果count的值为0,并且showZero设置为false,不显示组件
+				if(this.count == 0 && this.showZero == false) return false;
+				else return true;
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	@import "../../libs/css/style.components.scss";
+	
+	.u-badge {
+		/* #ifndef APP-NVUE */
+		display: inline-flex;
+		/* #endif */
+		justify-content: center;
+		align-items: center;
+		line-height: 24rpx;
+		padding: 4rpx 8rpx;
+		border-radius: 100rpx;
+		z-index: 9;
+		
+		&--bg--primary {
+			background-color: $u-type-primary;
+		}
+		
+		&--bg--error {
+			background-color: $u-type-error;
+		}
+		
+		&--bg--success {
+			background-color: $u-type-success;
+		}
+		
+		&--bg--info {
+			background-color: $u-type-info;
+		}
+		
+		&--bg--warning {
+			background-color: $u-type-warning;
+		}
+	}
+	
+	.u-badge-dot {
+		height: 16rpx;
+		width: 16rpx;
+		border-radius: 100rpx;
+		line-height: 1;
+	}
+	
+	.u-badge-mini {
+		transform: scale(0.8);
+		transform-origin: center center;
+	}
+	
+	// .u-primary {
+	// 	background: $u-type-primary;
+	// 	color: #fff;
+	// }
+	
+	// .u-error {
+	// 	background: $u-type-error;
+	// 	color: #fff;
+	// }
+	
+	// .u-warning {
+	// 	background: $u-type-warning;
+	// 	color: #fff;
+	// }
+	
+	// .u-success {
+	// 	background: $u-type-success;
+	// 	color: #fff;
+	// }
+	
+	// .u-black {
+	// 	background: #585858;
+	// 	color: #fff;
+	// }
+	
+	.u-info {
+		background-color: $u-type-info;
+		color: #fff;
+	}
+</style>

+ 596 - 0
uview-ui/components/u-button/u-button.vue

@@ -0,0 +1,596 @@
+<template>
+	<button
+		id="u-wave-btn"
+		class="u-btn u-line-1 u-fix-ios-appearance"
+		:class="[
+			'u-size-' + size,
+			plain ? 'u-btn--' + type + '--plain' : '',
+			loading ? 'u-loading' : '',
+			shape == 'circle' ? 'u-round-circle' : '',
+			hairLine ? showHairLineBorder : 'u-btn--bold-border',
+			'u-btn--' + type,
+			disabled ? `u-btn--${type}--disabled` : '',
+		]"
+		:hover-start-time="Number(hoverStartTime)"
+		:hover-stay-time="Number(hoverStayTime)"
+		:disabled="disabled"
+		:form-type="formType"
+		:open-type="openType"
+		:app-parameter="appParameter"
+		:hover-stop-propagation="hoverStopPropagation"
+		:send-message-title="sendMessageTitle"
+		send-message-path="sendMessagePath"
+		:lang="lang"
+		:data-name="dataName"
+		:session-from="sessionFrom"
+		:send-message-img="sendMessageImg"
+		:show-message-card="showMessageCard"
+		@getphonenumber="getphonenumber"
+		@getuserinfo="getuserinfo"
+		@error="error"
+		@opensetting="opensetting"
+		@launchapp="launchapp"
+		:style="[customStyle, {
+			overflow: ripple ? 'hidden' : 'visible'
+		}]"
+		@tap.stop="click($event)"
+		:hover-class="getHoverClass"
+		:loading="loading"
+	>
+		<slot></slot>
+		<view
+			v-if="ripple"
+			class="u-wave-ripple"
+			:class="[waveActive ? 'u-wave-active' : '']"
+			:style="{
+				top: rippleTop + 'px',
+				left: rippleLeft + 'px',
+				width: fields.targetWidth + 'px',
+				height: fields.targetWidth + 'px',
+				'background-color': rippleBgColor || 'rgba(0, 0, 0, 0.15)'
+			}"
+		></view>
+	</button>
+</template>
+
+<script>
+/**
+ * button 按钮
+ * @description Button 按钮
+ * @tutorial https://www.uviewui.com/components/button.html
+ * @property {String} size 按钮的大小
+ * @property {Boolean} ripple 是否开启点击水波纹效果
+ * @property {String} ripple-bg-color 水波纹的背景色,ripple为true时有效
+ * @property {String} type 按钮的样式类型
+ * @property {Boolean} plain 按钮是否镂空,背景色透明
+ * @property {Boolean} disabled 是否禁用
+ * @property {Boolean} hair-line 是否显示按钮的细边框(默认true)
+ * @property {Boolean} shape 按钮外观形状,见文档说明
+ * @property {Boolean} loading 按钮名称前是否带 loading 图标(App-nvue 平台,在 ios 上为雪花,Android上为圆圈)
+ * @property {String} form-type 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
+ * @property {String} open-type 开放能力
+ * @property {String} data-name 额外传参参数,用于小程序的data-xxx属性,通过target.dataset.name获取
+ * @property {String} hover-class 指定按钮按下去的样式类。当 hover-class="none" 时,没有点击态效果(App-nvue 平台暂不支持)
+ * @property {Number} hover-start-time 按住后多久出现点击态,单位毫秒
+ * @property {Number} hover-stay-time 手指松开后点击态保留时间,单位毫秒
+ * @property {Object} custom-style 对按钮的自定义样式,对象形式,见文档说明
+ * @event {Function} click 按钮点击
+ * @event {Function} getphonenumber open-type="getPhoneNumber"时有效
+ * @event {Function} getuserinfo 用户点击该按钮时,会返回获取到的用户信息,从返回参数的detail中获取到的值同uni.getUserInfo
+ * @event {Function} error 当使用开放能力时,发生错误的回调
+ * @event {Function} opensetting 在打开授权设置页并关闭后回调
+ * @event {Function} launchapp 打开 APP 成功的回调
+ * @example <u-button>月落</u-button>
+ */
+export default {
+	name: 'u-button',
+	props: {
+		// 是否细边框
+		hairLine: {
+			type: Boolean,
+			default: true
+		},
+		// 按钮的预置样式,default,primary,error,warning,success
+		type: {
+			type: String,
+			default: 'default'
+		},
+		// 按钮尺寸,default,medium,mini
+		size: {
+			type: String,
+			default: 'default'
+		},
+		// 按钮形状,circle(两边为半圆),square(带圆角)
+		shape: {
+			type: String,
+			default: 'square'
+		},
+		// 按钮是否镂空
+		plain: {
+			type: Boolean,
+			default: false
+		},
+		// 是否禁止状态
+		disabled: {
+			type: Boolean,
+			default: false
+		},
+		// 是否加载中
+		loading: {
+			type: Boolean,
+			default: false
+		},
+		// 开放能力,具体请看uniapp稳定关于button组件部分说明
+		// https://uniapp.dcloud.io/component/button
+		openType: {
+			type: String,
+			default: ''
+		},
+		// 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
+		// 取值为submit(提交表单),reset(重置表单)
+		formType: {
+			type: String,
+			default: ''
+		},
+		// 打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效
+		// 只微信小程序、QQ小程序有效
+		appParameter: {
+			type: String,
+			default: ''
+		},
+		// 指定是否阻止本节点的祖先节点出现点击态,微信小程序有效
+		hoverStopPropagation: {
+			type: Boolean,
+			default: false
+		},
+		// 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文。只微信小程序有效
+		lang: {
+			type: String,
+			default: 'en'
+		},
+		// 会话来源,open-type="contact"时有效。只微信小程序有效
+		sessionFrom: {
+			type: String,
+			default: ''
+		},
+		// 会话内消息卡片标题,open-type="contact"时有效
+		// 默认当前标题,只微信小程序有效
+		sendMessageTitle: {
+			type: String,
+			default: ''
+		},
+		// 会话内消息卡片点击跳转小程序路径,open-type="contact"时有效
+		// 默认当前分享路径,只微信小程序有效
+		sendMessagePath: {
+			type: String,
+			default: ''
+		},
+		// 会话内消息卡片图片,open-type="contact"时有效
+		// 默认当前页面截图,只微信小程序有效
+		sendMessageImg: {
+			type: String,
+			default: ''
+		},
+		// 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,
+		// 用户点击后可以快速发送小程序消息,open-type="contact"时有效
+		showMessageCard: {
+			type: Boolean,
+			default: false
+		},
+		// 手指按(触摸)按钮时按钮时的背景颜色
+		hoverBgColor: {
+			type: String,
+			default: ''
+		},
+		// 水波纹的背景颜色
+		rippleBgColor: {
+			type: String,
+			default: ''
+		},
+		// 是否开启水波纹效果
+		ripple: {
+			type: Boolean,
+			default: false
+		},
+		// 按下的类名
+		hoverClass: {
+			type: String,
+			default: ''
+		},
+		// 自定义样式,对象形式
+		customStyle: {
+			type: Object,
+			default() {
+				return {};
+			}
+		},
+		// 额外传参参数,用于小程序的data-xxx属性,通过target.dataset.name获取
+		dataName: {
+			type: String,
+			default: ''
+		},
+		// 节流,一定时间内只能触发一次
+		throttleTime: {
+			type: [String, Number],
+			default: 1000
+		},
+		// 按住后多久出现点击态,单位毫秒
+		hoverStartTime: {
+			type: [String, Number],
+			default: 20
+		},
+		// 手指松开后点击态保留时间,单位毫秒
+		hoverStayTime: {
+			type: [String, Number],
+			default: 150
+		},
+	},
+	computed: {
+		// 当没有传bgColor变量时,按钮按下去的颜色类名
+		getHoverClass() {
+			// 如果开启水波纹效果,则不启用hover-class效果
+			if (this.loading || this.disabled || this.ripple || this.hoverClass) return '';
+			let hoverClass = '';
+			hoverClass = this.plain ? 'u-' + this.type + '-plain-hover' : 'u-' + this.type + '-hover';
+			return hoverClass;
+		},
+		// 在'primary', 'success', 'error', 'warning'类型下,不显示边框,否则会造成四角有毛刺现象
+		showHairLineBorder() {
+			if (['primary', 'success', 'error', 'warning'].indexOf(this.type) >= 0 && !this.plain) {
+				return '';
+			} else {
+				return 'u-hairline-border';
+			}
+		}
+	},
+	data() {
+		return {
+			rippleTop: 0, // 水波纹的起点Y坐标到按钮上边界的距离
+			rippleLeft: 0, // 水波纹起点X坐标到按钮左边界的距离
+			fields: {}, // 波纹按钮节点信息
+			waveActive: false // 激活水波纹
+		};
+	},
+	methods: {
+		// 按钮点击
+		click(e) {
+			// 进行节流控制,每this.throttle毫秒内,只在开始处执行
+			this.$u.throttle(() => {
+				// 如果按钮时disabled和loading状态,不触发水波纹效果
+				if (this.loading === true || this.disabled === true) return;
+				// 是否开启水波纹效果
+				if (this.ripple) {
+					// 每次点击时,移除上一次的类,再次添加,才能触发动画效果
+					this.waveActive = false;
+					this.$nextTick(function() {
+						this.getWaveQuery(e);
+					});
+				}
+				this.$emit('click', e);
+			}, this.throttleTime);
+		},
+		// 查询按钮的节点信息
+		getWaveQuery(e) {
+			this.getElQuery().then(res => {
+				// 查询返回的是一个数组节点
+				let data = res[0];
+				// 查询不到节点信息,不操作
+				if (!data.width || !data.width) return;
+				// 水波纹的最终形态是一个正方形(通过border-radius让其变为一个圆形),这里要保证正方形的边长等于按钮的最长边
+				// 最终的方形(变换后的圆形)才能覆盖整个按钮
+				data.targetWidth = data.height > data.width ? data.height : data.width;
+				if (!data.targetWidth) return;
+				this.fields = data;
+				let touchesX = '',
+					touchesY = '';
+				// #ifdef MP-BAIDU
+				touchesX = e.changedTouches[0].clientX;
+				touchesY = e.changedTouches[0].clientY;
+				// #endif
+				// #ifdef MP-ALIPAY
+				touchesX = e.detail.clientX;
+				touchesY = e.detail.clientY;
+				// #endif
+				// #ifndef MP-BAIDU || MP-ALIPAY
+				touchesX = e.touches[0].clientX;
+				touchesY = e.touches[0].clientY;
+				// #endif
+				// 获取触摸点相对于按钮上边和左边的x和y坐标,原理是通过屏幕的触摸点(touchesY),减去按钮的上边界data.top
+				// 但是由于`transform-origin`默认是center,所以这里再减去半径才是水波纹view应该的位置
+				// 总的来说,就是把水波纹的矩形(变换后的圆形)的中心点,移动到我们的触摸点位置
+				this.rippleTop = touchesY - data.top - data.targetWidth / 2;
+				this.rippleLeft = touchesX - data.left - data.targetWidth / 2;
+				this.$nextTick(() => {
+					this.waveActive = true;
+				});
+			});
+		},
+		// 获取节点信息
+		getElQuery() {
+			return new Promise(resolve => {
+				let queryInfo = '';
+				// 获取元素节点信息,请查看uniapp相关文档
+				// https://uniapp.dcloud.io/api/ui/nodes-info?id=nodesrefboundingclientrect
+				queryInfo = uni.createSelectorQuery().in(this);
+				//#ifdef MP-ALIPAY
+				queryInfo = uni.createSelectorQuery();
+				//#endif
+				queryInfo.select('.u-btn').boundingClientRect();
+				queryInfo.exec(data => {
+					resolve(data);
+				});
+			});
+		},
+		// 下面为对接uniapp官方按钮开放能力事件回调的对接
+		getphonenumber(res) {
+			this.$emit('getphonenumber', res);
+		},
+		getuserinfo(res) {
+			this.$emit('getuserinfo', res);
+		},
+		error(res) {
+			this.$emit('error', res);
+		},
+		opensetting(res) {
+			this.$emit('opensetting', res);
+		},
+		launchapp(res) {
+			this.$emit('launchapp', res);
+		}
+	}
+};
+</script>
+
+<style scoped lang="scss">
+@import '../../libs/css/style.components.scss';
+.u-btn::after {
+	border: none;
+}
+
+.u-btn {
+	position: relative;
+	border: 0;
+	//border-radius: 10rpx;
+	/* #ifndef APP-NVUE */
+	display: inline-flex;		
+	/* #endif */
+	// 避免边框某些场景可能被“裁剪”,不能设置为hidden
+	overflow: visible;
+	line-height: 1;
+	@include vue-flex;
+	align-items: center;
+	justify-content: center;
+	cursor: pointer;
+	padding: 0 40rpx;
+	z-index: 1;
+	box-sizing: border-box;
+	transition: all 0.15s;
+	
+	&--bold-border {
+		border: 1px solid #ffffff;
+	}
+	
+	&--default {
+		color: $u-content-color;
+		border-color: #c0c4cc;
+		background-color: #ffffff;
+	}
+	
+	&--primary {
+		color: #ffffff;
+		border-color: $u-type-primary;
+		background-color: $u-type-primary;
+	}
+	
+	&--success {
+		color: #ffffff;
+		border-color: $u-type-success;
+		background-color: $u-type-success;
+	}
+	
+	&--error {
+		color: #ffffff;
+		border-color: $u-type-error;
+		background-color: $u-type-error;
+	}
+	
+	&--warning {
+		color: #ffffff;
+		border-color: $u-type-warning;
+		background-color: $u-type-warning;
+	}
+	
+	&--default--disabled {
+		color: #ffffff;
+		border-color: #e4e7ed;
+		background-color: #ffffff;
+	}
+	
+	&--primary--disabled {
+		color: #ffffff!important;
+		border-color: $u-type-primary-disabled!important;
+		background-color: $u-type-primary-disabled!important;
+	}
+	
+	&--success--disabled {
+		color: #ffffff!important;
+		border-color: $u-type-success-disabled!important;
+		background-color: $u-type-success-disabled!important;
+	}
+	
+	&--error--disabled {
+		color: #ffffff!important;
+		border-color: $u-type-error-disabled!important;
+		background-color: $u-type-error-disabled!important;
+	}
+	
+	&--warning--disabled {
+		color: #ffffff!important;
+		border-color: $u-type-warning-disabled!important;
+		background-color: $u-type-warning-disabled!important;
+	}
+	
+	&--primary--plain {
+		color: $u-type-primary!important;
+		border-color: $u-type-primary-disabled!important;
+		background-color: $u-type-primary-light!important;
+	}
+	
+	&--success--plain {
+		color: $u-type-success!important;
+		border-color: $u-type-success-disabled!important;
+		background-color: $u-type-success-light!important;
+	}
+	
+	&--error--plain {
+		color: $u-type-error!important;
+		border-color: $u-type-error-disabled!important;
+		background-color: $u-type-error-light!important;
+	}
+	
+	&--warning--plain {
+		color: $u-type-warning!important;
+		border-color: $u-type-warning-disabled!important;
+		background-color: $u-type-warning-light!important;
+	}
+}
+
+.u-hairline-border:after {
+	content: ' ';
+	position: absolute;
+	pointer-events: none;
+	// 设置为border-box,意味着下面的scale缩小为0.5,实际上缩小的是伪元素的内容(border-box意味着内容不含border)
+	box-sizing: border-box;
+	// 中心点作为变形(scale())的原点
+	-webkit-transform-origin: 0 0;
+	transform-origin: 0 0;
+	left: 0;
+	top: 0;
+	width: 199.8%;
+	height: 199.7%;
+	-webkit-transform: scale(0.5, 0.5);
+	transform: scale(0.5, 0.5);
+	border: 1px solid currentColor;
+	z-index: 1;
+}
+
+.u-wave-ripple {
+	z-index: 0;
+	position: absolute;
+	border-radius: 100%;
+	background-clip: padding-box;
+	pointer-events: none;
+	user-select: none;
+	transform: scale(0);
+	opacity: 1;
+	transform-origin: center;
+}
+
+.u-wave-ripple.u-wave-active {
+	opacity: 0;
+	transform: scale(2);
+	transition: opacity 1s linear, transform 0.4s linear;
+}
+
+.u-round-circle {
+	border-radius: 100rpx;
+}
+
+.u-round-circle::after {
+	border-radius: 100rpx;
+}
+
+.u-loading::after {
+	background-color: hsla(0, 0%, 100%, 0.35);
+}
+
+.u-size-default {
+	font-size: 30rpx;
+	height: 80rpx;
+	line-height: 80rpx;
+}
+
+.u-size-medium {
+	/* #ifndef APP-NVUE */
+	display: inline-flex;		
+	/* #endif */
+	width: auto;
+	font-size: 26rpx;
+	height: 70rpx;
+	line-height: 70rpx;
+	padding: 0 80rpx;
+}
+
+.u-size-mini {
+	/* #ifndef APP-NVUE */
+	display: inline-flex;		
+	/* #endif */
+	width: auto;
+	font-size: 22rpx;
+	padding-top: 1px;
+	height: 50rpx;
+	line-height: 50rpx;
+	padding: 0 20rpx;
+}
+
+.u-primary-plain-hover {
+	color: #ffffff !important;
+	background: $u-type-primary-dark !important;
+}
+
+.u-default-plain-hover {
+	color: $u-type-primary-dark !important;
+	background: $u-type-primary-light !important;
+}
+
+.u-success-plain-hover {
+	color: #ffffff !important;
+	background: $u-type-success-dark !important;
+}
+
+.u-warning-plain-hover {
+	color: #ffffff !important;
+	background: $u-type-warning-dark !important;
+}
+
+.u-error-plain-hover {
+	color: #ffffff !important;
+	background: $u-type-error-dark !important;
+}
+
+.u-info-plain-hover {
+	color: #ffffff !important;
+	background: $u-type-info-dark !important;
+}
+
+.u-default-hover {
+	color: $u-type-primary-dark !important;
+	border-color: $u-type-primary-dark !important;
+	background-color: $u-type-primary-light !important;
+}
+
+.u-primary-hover {
+	background: $u-type-primary-dark !important;
+	color: #fff;
+}
+
+.u-success-hover {
+	background: $u-type-success-dark !important;
+	color: #fff;
+}
+
+.u-info-hover {
+	background: $u-type-info-dark !important;
+	color: #fff;
+}
+
+.u-warning-hover {
+	background: $u-type-warning-dark !important;
+	color: #fff;
+}
+
+.u-error-hover {
+	background: $u-type-error-dark !important;
+	color: #fff;
+}
+</style>

+ 639 - 0
uview-ui/components/u-calendar/u-calendar.vue

@@ -0,0 +1,639 @@
+<template>
+	<u-popup closeable :maskCloseAble="maskCloseAble" mode="bottom" :popup="false" v-model="value" length="auto"
+	 :safeAreaInsetBottom="safeAreaInsetBottom" @close="close" :z-index="uZIndex" :border-radius="borderRadius" :closeable="closeable">
+		<view class="u-calendar">
+			<view class="u-calendar__header">
+				<view class="u-calendar__header__text" v-if="!$slots['tooltip']">
+					{{toolTip}}
+				</view>
+				<slot v-else name="tooltip" />
+			</view>
+			<view class="u-calendar__action u-flex u-row-center">
+				<view class="u-calendar__action__icon">
+					<u-icon v-if="changeYear" name="arrow-left-double" :color="yearArrowColor" @click="changeYearHandler(0)"></u-icon>
+				</view>
+				<view class="u-calendar__action__icon">
+					<u-icon v-if="changeMonth" name="arrow-left" :color="monthArrowColor" @click="changeMonthHandler(0)"></u-icon>
+				</view>
+				<view class="u-calendar__action__text">{{ showTitle }}</view>
+				<view class="u-calendar__action__icon">
+					<u-icon v-if="changeMonth" name="arrow-right" :color="monthArrowColor" @click="changeMonthHandler(1)"></u-icon>
+				</view>
+				<view class="u-calendar__action__icon">
+					<u-icon v-if="changeYear" name="arrow-right-double" :color="yearArrowColor" @click="changeYearHandler(1)"></u-icon>
+				</view>
+			</view>
+			<view class="u-calendar__week-day">
+				<view class="u-calendar__week-day__text" v-for="(item, index) in weekDayZh" :key="index">{{item}}</view>
+			</view>
+			<view class="u-calendar__content">
+				<!-- 前置空白部分 -->
+				<block v-for="(item, index) in weekdayArr" :key="index">
+					<view class="u-calendar__content__item"></view>
+				</block>
+				<view class="u-calendar__content__item" :class="{
+					'u-hover-class':openDisAbled(year,month,index+1),
+					'u-calendar__content--start-date': (mode == 'range' && startDate==`${year}-${month}-${index+1}`) || mode== 'date',
+					'u-calendar__content--end-date':(mode== 'range' && endDate==`${year}-${month}-${index+1}`) || mode == 'date'
+				}" :style="{backgroundColor: getColor(index,1)}" v-for="(item, index) in daysArr" :key="index"
+				 @tap="dateClick(index)">
+					<view class="u-calendar__content__item__inner" :style="{color: getColor(index,2)}">
+						<view>{{ index + 1 }}</view>
+					</view>
+					<view class="u-calendar__content__item__tips" :style="{color:activeColor}" v-if="mode== 'range' && startDate==`${year}-${month}-${index+1}` && startDate!=endDate">{{startText}}</view>
+					<view class="u-calendar__content__item__tips" :style="{color:activeColor}" v-if="mode== 'range' && endDate==`${year}-${month}-${index+1}`">{{endText}}</view>
+				</view>
+				<view class="u-calendar__content__bg-month">{{month}}</view>
+			</view>
+			<view class="u-calendar__bottom">
+				<view class="u-calendar__bottom__choose">
+					<text>{{mode == 'date' ? activeDate : startDate}}</text>
+					<text v-if="endDate">至{{endDate}}</text>
+				</view>
+				<view class="u-calendar__bottom__btn">
+					<u-button :type="btnType" shape="circle" size="default" @click="btnFix(false)">确定</u-button>
+				</view>
+			</view>
+		</view>
+	</u-popup>
+</template>
+<script>
+	/**
+	 * calendar 日历
+	 * @description 此组件用于单个选择日期,范围选择日期等,日历被包裹在底部弹起的容器中。
+	 * @tutorial http://uviewui.com/components/calendar.html
+	 * @property {String} mode 选择日期的模式,date-为单个日期,range-为选择日期范围
+	 * @property {Boolean} v-model 布尔值变量,用于控制日历的弹出与收起
+	 * @property {Boolean} safe-area-inset-bottom 是否开启底部安全区适配(默认false)
+	 * @property {Boolean} change-year 是否显示顶部的切换年份方向的按钮(默认true)
+	 * @property {Boolean} change-month 是否显示顶部的切换月份方向的按钮(默认true)
+	 * @property {String Number} max-year 可切换的最大年份(默认2050)
+	 * @property {String Number} min-year 最小可选日期(默认1950)
+	 * @property {String Number} min-date 可切换的最小年份(默认1950-01-01)
+	 * @property {String Number} max-date 最大可选日期(默认当前日期)
+	 * @property {String Number} 弹窗顶部左右两边的圆角值,单位rpx(默认20)
+	 * @property {Boolean} mask-close-able 是否允许通过点击遮罩关闭日历(默认true)
+	 * @property {String} month-arrow-color 月份切换按钮箭头颜色(默认#606266)
+	 * @property {String} year-arrow-color 年份切换按钮箭头颜色(默认#909399)
+	 * @property {String} color 日期字体的默认颜色(默认#303133)
+	 * @property {String} active-bg-color 起始/结束日期按钮的背景色(默认#2979ff)
+	 * @property {String Number} z-index 弹出时的z-index值(默认10075)
+	 * @property {String} active-color 起始/结束日期按钮的字体颜色(默认#ffffff)
+	 * @property {String} range-bg-color 起始/结束日期之间的区域的背景颜色(默认rgba(41,121,255,0.13))
+	 * @property {String} range-color 选择范围内字体颜色(默认#2979ff)
+	 * @property {String} start-text 起始日期底部的提示文字(默认 '开始')
+	 * @property {String} end-text 结束日期底部的提示文字(默认 '结束')
+	 * @property {String} btn-type 底部确定按钮的主题(默认 'primary')
+	 * @property {String} toolTip 顶部提示文字,如设置名为tooltip的slot,此参数将失效(默认 '选择日期')
+	 * @property {Boolean} closeable 是否显示右上角的关闭图标(默认true)
+	 * @example <u-calendar v-model="show" :mode="mode"></u-calendar>
+	 */
+	
+	export default {
+		name: 'u-calendar',
+		props: {
+			safeAreaInsetBottom: {
+				type: Boolean,
+				default: false
+			},
+			// 是否允许通过点击遮罩关闭Picker
+			maskCloseAble: {
+				type: Boolean,
+				default: true
+			},
+			// 通过双向绑定控制组件的弹出与收起
+			value: {
+				type: Boolean,
+				default: false
+			},
+			// 弹出的z-index值
+			zIndex: {
+				type: [String, Number],
+				default: 0
+			},
+			// 是否允许切换年份
+			changeYear: {
+				type: Boolean,
+				default: true
+			},
+			// 是否允许切换月份
+			changeMonth: {
+				type: Boolean,
+				default: true
+			},
+			// date-单个日期选择,range-开始日期+结束日期选择
+			mode: {
+				type: String,
+				default: 'date'
+			},
+			// 可切换的最大年份
+			maxYear: {
+				type: [Number, String],
+				default: 2050
+			},
+			// 可切换的最小年份
+			minYear: {
+				type: [Number, String],
+				default: 1950
+			},
+			// 最小可选日期(不在范围内日期禁用不可选)
+			minDate: {
+				type: [Number, String],
+				default: '1950-01-01'
+			},
+			/**
+			 * 最大可选日期
+			 * 默认最大值为今天,之后的日期不可选
+			 * 2030-12-31
+			 * */
+			maxDate: {
+				type: [Number, String],
+				default: ''
+			},
+			// 弹窗顶部左右两边的圆角值
+			borderRadius: {
+				type: [String, Number],
+				default: 20
+			},
+			// 月份切换按钮箭头颜色
+			monthArrowColor: {
+				type: String,
+				default: '#606266'
+			},
+			// 年份切换按钮箭头颜色
+			yearArrowColor: {
+				type: String,
+				default: '#909399'
+			},
+			// 默认日期字体颜色
+			color: {
+				type: String,
+				default: '#303133'
+			},
+			// 选中|起始结束日期背景色
+			activeBgColor: {
+				type: String,
+				default: '#2979ff'
+			},
+			// 选中|起始结束日期字体颜色
+			activeColor: {
+				type: String,
+				default: '#ffffff'
+			},
+			// 范围内日期背景色
+			rangeBgColor: {
+				type: String,
+				default: 'rgba(41,121,255,0.13)'
+			}, 
+			// 范围内日期字体颜色
+			rangeColor: {
+				type: String,
+				default: '#2979ff'
+			},
+			// mode=range时生效,起始日期自定义文案
+			startText: {
+				type: String,
+				default: '开始'
+			},
+			// mode=range时生效,结束日期自定义文案
+			endText: {
+				type: String,
+				default: '结束'
+			},
+			//按钮样式类型
+			btnType: {
+				type: String,
+				default: 'primary'
+			},
+			// 当前选中日期带选中效果
+			isActiveCurrent: {
+				type: Boolean,
+				default: true
+			},
+			// 切换年月是否触发事件 mode=date时生效
+			isChange: {
+				type: Boolean,
+				default: false
+			},
+			// 是否显示右上角的关闭图标
+			closeable: {
+				type: Boolean,
+				default: true
+			},
+			// 顶部的提示文字
+			toolTip: {
+				type: String,
+				default: '选择日期'
+			}
+		},
+		data() {
+			return {
+				// 星期几,值为1-7
+				weekday: 1, 
+				weekdayArr:[],
+				// 当前月有多少天
+				days: 0, 
+				daysArr:[],
+				showTitle: '',
+				year: 2020,
+				month: 0,
+				day: 0,
+				startYear: 0,
+				startMonth: 0,
+				startDay: 0,
+				endYear: 0,
+				endMonth: 0,
+				endDay: 0,
+				today: '',
+				activeDate: '',
+				startDate: '',
+				endDate: '',
+				isStart: true,
+				min: null,
+				max: null,
+				weekDayZh: ['日', '一', '二', '三', '四', '五', '六']
+			};
+		},
+		computed: {
+			dataChange() {
+				return `${this.mode}-${this.minDate}-${this.maxDate}`;
+			},
+			uZIndex() {
+				// 如果用户有传递z-index值,优先使用
+				return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
+			}
+		},
+		watch: {
+			dataChange(val) {
+				this.init()
+			}
+		},
+		created() {
+			this.init()
+		},
+		methods: {
+			getColor(index, type) {
+				let color = type == 1 ? '' : this.color;
+				let day = index + 1
+				let date = `${this.year}-${this.month}-${day}`
+				let timestamp = new Date(date.replace(/\-/g, '/')).getTime();
+				let start = this.startDate.replace(/\-/g, '/')
+				let end = this.endDate.replace(/\-/g, '/')
+				if ((this.isActiveCurrent && this.activeDate == date) || this.startDate == date || this.endDate == date) {
+					color = type == 1 ? this.activeBgColor : this.activeColor;
+				} else if (this.endDate && timestamp > new Date(start).getTime() && timestamp < new Date(end).getTime()) {
+					color = type == 1 ? this.rangeBgColor : this.rangeColor;
+				}
+				return color;
+			},
+			init() {
+				let now = new Date();
+				this.year = now.getFullYear();
+				this.month = now.getMonth() + 1;
+				this.day = now.getDate();
+				this.today = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`;
+				this.activeDate = this.today;
+				this.min = this.initDate(this.minDate);
+				this.max = this.initDate(this.maxDate || this.today);
+				this.startDate = "";
+				this.startYear = 0;
+				this.startMonth = 0;
+				this.startDay = 0;
+				this.endYear = 0;
+				this.endMonth = 0;
+				this.endDay = 0;
+				this.endDate = "";
+				this.isStart = true;
+				this.changeData();
+			},
+			//日期处理
+			initDate(date) {
+				let fdate = date.split('-');
+				return {
+					year: Number(fdate[0] || 1920),
+					month: Number(fdate[1] || 1),
+					day: Number(fdate[2] || 1)
+				}
+			},
+			openDisAbled: function(year, month, day) {
+				let bool = true;
+				let date = `${year}/${month}/${day}`;
+				// let today = this.today.replace(/\-/g, '/');
+				let min = `${this.min.year}/${this.min.month}/${this.min.day}`;
+				let max = `${this.max.year}/${this.max.month}/${this.max.day}`;
+				let timestamp = new Date(date).getTime();
+				if (timestamp >= new Date(min).getTime() && timestamp <= new Date(max).getTime()) {
+					bool = false;
+				}
+				return bool;
+			},
+			generateArray: function(start, end) {
+				return Array.from(new Array(end + 1).keys()).slice(start);
+			},
+			formatNum: function(num) {
+				return num < 10 ? '0' + num : num + '';
+			},
+			//一个月有多少天
+			getMonthDay(year, month) {
+				let days = new Date(year, month, 0).getDate();
+				return days;
+			},
+			getWeekday(year, month) {
+				let date = new Date(`${year}/${month}/01 00:00:00`);
+				return date.getDay();
+			},
+			checkRange(year) {
+				let overstep = false;
+				if (year < this.minYear || year > this.maxYear) {
+					uni.showToast({
+						title: "日期超出范围啦~",
+						icon: 'none'
+					})
+					overstep = true;
+				}
+				return overstep;
+			},
+			changeMonthHandler(isAdd) {
+				if (isAdd) {
+					let month = this.month + 1;
+					let year = month > 12 ? this.year + 1 : this.year;
+					if (!this.checkRange(year)) {
+						this.month = month > 12 ? 1 : month;
+						this.year = year;
+						this.changeData();
+					}
+
+				} else {
+					let month = this.month - 1;
+					let year = month < 1 ? this.year - 1 : this.year;
+					if (!this.checkRange(year)) {
+						this.month = month < 1 ? 12 : month;
+						this.year = year;
+						this.changeData();
+					}
+				}
+			},
+			changeYearHandler(isAdd) {
+				let year = isAdd ? this.year + 1 : this.year - 1;
+				if (!this.checkRange(year)) {
+					this.year = year;
+					this.changeData();
+				}
+			},
+			changeData() {
+				this.days = this.getMonthDay(this.year, this.month);
+				this.daysArr=this.generateArray(1,this.days)
+				this.weekday = this.getWeekday(this.year, this.month);
+				this.weekdayArr=this.generateArray(1,this.weekday)
+				this.showTitle = `${this.year}年${this.month}月`;
+				if (this.isChange && this.mode == 'date') {
+					this.btnFix(true);
+				}
+			},
+			dateClick: function(day) {
+				day += 1;
+				if (!this.openDisAbled(this.year, this.month, day)) {
+					this.day = day;
+					let date = `${this.year}-${this.month}-${day}`;
+					if (this.mode == 'date') {
+						this.activeDate = date;
+					} else {
+						let compare = new Date(date.replace(/\-/g, '/')).getTime() < new Date(this.startDate.replace(/\-/g, '/')).getTime()
+						if (this.isStart || compare) {
+							this.startDate = date;
+							this.startYear = this.year;
+							this.startMonth = this.month;
+							this.startDay = this.day;
+							this.endYear = 0;
+							this.endMonth = 0;
+							this.endDay = 0;
+							this.endDate = "";
+							this.activeDate = "";
+							this.isStart = false;
+						} else {
+							this.endDate = date;
+							this.endYear = this.year;
+							this.endMonth = this.month;
+							this.endDay = this.day;
+							this.isStart = true;
+						}
+					}
+				}
+			},
+			close() {
+				// 修改通过v-model绑定的父组件变量的值为false,从而隐藏日历弹窗
+				this.$emit('input', false);
+			},
+			getWeekText(date) {
+				date = new Date(`${date.replace(/\-/g, '/')} 00:00:00`);
+				let week = date.getDay();
+				return '星期' + ['日', '一', '二', '三', '四', '五', '六'][week];
+			},
+			btnFix(show) {
+				if (!show) {
+					this.close();
+				}
+				if (this.mode == 'date') {
+					let arr = this.activeDate.split('-')
+					let year = this.isChange ? this.year : Number(arr[0]);
+					let month = this.isChange ? this.month : Number(arr[1]);
+					let day = this.isChange ? this.day : Number(arr[2]);
+					//当前月有多少天
+					let days = this.getMonthDay(year, month);
+					let result = `${year}-${this.formatNum(month)}-${this.formatNum(day)}`;
+					let weekText = this.getWeekText(result);
+					let isToday = false;
+					if (`${year}-${month}-${day}` == this.today) {
+						//今天
+						isToday = true;
+					}
+					this.$emit('change', {
+						year: year,
+						month: month,
+						day: day,
+						days: days,
+						result: result,
+						week: weekText,
+						isToday: isToday,
+						// switch: show //是否是切换年月操作
+					});
+				} else {
+					if (!this.startDate || !this.endDate) return;
+					let startMonth = this.formatNum(this.startMonth);
+					let startDay = this.formatNum(this.startDay);
+					let startDate = `${this.startYear}-${startMonth}-${startDay}`;
+					let startWeek = this.getWeekText(startDate)
+
+					let endMonth = this.formatNum(this.endMonth);
+					let endDay = this.formatNum(this.endDay);
+					let endDate = `${this.endYear}-${endMonth}-${endDay}`;
+					let endWeek = this.getWeekText(endDate);
+					this.$emit('change', {
+						startYear: this.startYear,
+						startMonth: this.startMonth,
+						startDay: this.startDay,
+						startDate: startDate,
+						startWeek: startWeek,
+						endYear: this.endYear,
+						endMonth: this.endMonth,
+						endDay: this.endDay,
+						endDate: endDate,
+						endWeek: endWeek
+					});
+				}
+			}
+		}
+	};
+</script>
+
+<style scoped lang="scss">
+	@import "../../libs/css/style.components.scss";
+	
+	.u-calendar {
+		color: $u-content-color;
+		
+		&__header {
+			width: 100%;
+			box-sizing: border-box;
+			font-size: 30rpx;
+			background-color: #fff;
+			color: $u-main-color;
+			
+			&__text {
+				margin-top: 30rpx;
+				padding: 0 60rpx;
+				@include vue-flex;
+				justify-content: center;
+				align-items: center;
+			}
+		}
+		
+		&__action {
+			padding: 40rpx 0 40rpx 0;
+			
+			&__icon {
+				margin: 0 16rpx;
+			}
+			
+			&__text {
+				padding: 0 16rpx;
+				color: $u-main-color;
+				font-size: 32rpx;
+				line-height: 32rpx;
+				font-weight: bold;
+			}
+		}
+	
+		&__week-day {
+			@include vue-flex;
+			align-items: center;
+			justify-content: center;
+			padding: 6px 0;
+			overflow: hidden;
+			
+			&__text {
+				flex: 1;
+				text-align: center;
+			}
+		}
+	
+		&__content {
+			width: 100%;
+			@include vue-flex;
+			flex-wrap: wrap;
+			padding: 6px 0;
+			box-sizing: border-box;
+			background-color: #fff;
+			position: relative;
+			
+			&--end-date {
+				border-top-right-radius: 8rpx;
+				border-bottom-right-radius: 8rpx;
+			}
+			
+			&--start-date {
+				border-top-left-radius: 8rpx;
+				border-bottom-left-radius: 8rpx;
+			}
+			
+			&__item {
+				width: 14.2857%;
+				@include vue-flex;
+				align-items: center;
+				justify-content: center;
+				padding: 6px 0;
+				overflow: hidden;
+				position: relative;
+				z-index: 2;
+				
+				&__inner {
+					height: 84rpx;
+					@include vue-flex;
+					align-items: center;
+					justify-content: center;
+					flex-direction: column;
+					font-size: 32rpx;
+					position: relative;
+					border-radius: 50%;
+					
+					&__desc {
+						width: 100%;
+						font-size: 24rpx;
+						line-height: 24rpx;
+						transform: scale(0.75);
+						transform-origin: center center;
+						position: absolute;
+						left: 0;
+						text-align: center;
+						bottom: 2rpx;
+					}
+				}
+				
+				&__tips {
+					width: 100%;
+					font-size: 24rpx;
+					line-height: 24rpx;
+					position: absolute;
+					left: 0;
+					transform: scale(0.8);
+					transform-origin: center center;
+					text-align: center;
+					bottom: 8rpx;
+					z-index: 2;
+				}
+			}
+			
+			&__bg-month {
+				position: absolute;
+				font-size: 130px;
+				line-height: 130px;
+				left: 50%;
+				top: 50%;
+				transform: translate(-50%, -50%);
+				color: #e4e7ed;
+				z-index: 1;
+			}
+		}
+	
+		&__bottom {
+			width: 100%;
+			@include vue-flex;
+			align-items: center;
+			justify-content: center;
+			flex-direction: column;
+			background-color: #fff;
+			padding: 0 40rpx 30rpx;
+			box-sizing: border-box;
+			font-size: 24rpx;
+			color: $u-tips-color;
+			
+			&__choose {
+				height: 50rpx;
+			}
+			
+			&__btn {
+				width: 100%;
+			}
+		}
+	}
+</style>

+ 257 - 0
uview-ui/components/u-car-keyboard/u-car-keyboard.vue

@@ -0,0 +1,257 @@
+<template>
+	<view class="u-keyboard" @touchmove.stop.prevent="() => {}">
+		<view class="u-keyboard-grids">
+			<block>
+				<view class="u-keyboard-grids-item" v-for="(group, i) in abc ? EngKeyBoardList : areaList" :key="i">
+					<view :hover-stay-time="100" @tap="carInputClick(i, j)" hover-class="u-carinput-hover" class="u-keyboard-grids-btn"
+					 v-for="(item, j) in group" :key="j">
+						{{ item }}
+					</view>
+				</view>
+				<view @touchstart="backspaceClick" @touchend="clearTimer" :hover-stay-time="100" class="u-keyboard-back"
+				 hover-class="u-hover-class">
+					<u-icon :size="38" name="backspace" :bold="true"></u-icon>
+				</view>
+				<view :hover-stay-time="100" class="u-keyboard-change" hover-class="u-carinput-hover" @tap="changeCarInputMode">
+					<text class="zh" :class="[!abc ? 'active' : 'inactive']">中</text>
+					/
+					<text class="en" :class="[abc ? 'active' : 'inactive']">英</text>
+				</view>
+			</block>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "u-keyboard",
+		props: {
+			// 是否打乱键盘按键的顺序
+			random: {
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				// 车牌输入时,abc=true为输入车牌号码,bac=false为输入省份中文简称
+				abc: false
+			};
+		},
+		computed: {
+			areaList() {
+				let data = [
+					'京',
+					'沪',
+					'粤',
+					'津',
+					'冀',
+					'豫',
+					'云',
+					'辽',
+					'黑',
+					'湘',
+					'皖',
+					'鲁',
+					'苏',
+					'浙',
+					'赣',
+					'鄂',
+					'桂',
+					'甘',
+					'晋',
+					'陕',
+					'蒙',
+					'吉',
+					'闽',
+					'贵',
+					'渝',
+					'川',
+					'青',
+					'琼',
+					'宁',
+					'挂',
+					'藏',
+					'港',
+					'澳',
+					'新',
+					'使',
+					'学'
+				];
+				let tmp = [];
+				// 打乱顺序
+				if (this.random) data = this.$u.randomArray(data);
+				// 切割成二维数组
+				tmp[0] = data.slice(0, 10);
+				tmp[1] = data.slice(10, 20);
+				tmp[2] = data.slice(20, 30);
+				tmp[3] = data.slice(30, 36);
+				return tmp;
+			},
+			EngKeyBoardList() {
+				let data = [
+					1,
+					2,
+					3,
+					4,
+					5,
+					6,
+					7,
+					8,
+					9,
+					0,
+					'Q',
+					'W',
+					'E',
+					'R',
+					'T',
+					'Y',
+					'U',
+					'I',
+					'O',
+					'P',
+					'A',
+					'S',
+					'D',
+					'F',
+					'G',
+					'H',
+					'J',
+					'K',
+					'L',
+					'Z',
+					'X',
+					'C',
+					'V',
+					'B',
+					'N',
+					'M'
+				];
+				let tmp = [];
+				if (this.random) data = this.$u.randomArray(data);
+				tmp[0] = data.slice(0, 10);
+				tmp[1] = data.slice(10, 20);
+				tmp[2] = data.slice(20, 30);
+				tmp[3] = data.slice(30, 36);
+				return tmp;
+			}
+		},
+		methods: {
+			// 点击键盘按钮
+			carInputClick(i, j) {
+				let value = '';
+				// 不同模式,获取不同数组的值
+				if (this.abc) value = this.EngKeyBoardList[i][j];
+				else value = this.areaList[i][j];
+				this.$emit('change', value);
+			},
+			// 修改汽车牌键盘的输入模式,中文|英文
+			changeCarInputMode() {
+				this.abc = !this.abc;
+			},
+			// 点击退格键
+			backspaceClick() {
+				this.$emit('backspace');
+				clearInterval(this.timer); //再次清空定时器,防止重复注册定时器
+				this.timer = null;
+				this.timer = setInterval(() => {
+					this.$emit('backspace');
+				}, 250);
+			},
+			clearTimer() {
+				clearInterval(this.timer);
+				this.timer = null;
+			},
+		}
+	};
+</script>
+
+<style lang="scss" scoped>
+	@import "../../libs/css/style.components.scss";
+
+	.u-keyboard-grids {
+		background: rgb(215, 215, 217);
+		padding: 24rpx 0;
+		position: relative;
+	}
+
+	.u-keyboard-grids-item {
+		@include vue-flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.u-keyboard-grids-btn {
+		text-decoration: none;
+		width: 62rpx;
+		flex: 0 0 64rpx;
+		height: 80rpx;
+		/* #ifndef APP-NVUE */
+		display: inline-flex;		
+		/* #endif */
+		font-size: 36rpx;
+		text-align: center;
+		line-height: 80rpx;
+		background-color: #fff;
+		margin: 8rpx 5rpx;
+		border-radius: 8rpx;
+		box-shadow: 0 2rpx 0rpx #888992;
+		font-weight: 500;
+		justify-content: center;
+	}
+
+	.u-carinput-hover {
+		background-color: rgb(185, 188, 195) !important;
+	}
+
+	.u-keyboard-back {
+		position: absolute;
+		width: 96rpx;
+		right: 22rpx;
+		bottom: 32rpx;
+		height: 80rpx;
+		background-color: rgb(185, 188, 195);
+		@include vue-flex;
+		align-items: center;
+		border-radius: 8rpx;
+		justify-content: center;
+		box-shadow: 0 2rpx 0rpx #888992;
+	}
+
+	.u-keyboard-change {
+		font-size: 24rpx;
+		box-shadow: 0 2rpx 0rpx #888992;
+		position: absolute;
+		width: 96rpx;
+		left: 22rpx;
+		line-height: 1;
+		bottom: 32rpx;
+		height: 80rpx;
+		background-color: #ffffff;
+		@include vue-flex;
+		align-items: center;
+		border-radius: 8rpx;
+		justify-content: center;
+	}
+
+	.u-keyboard-change .inactive.zh {
+		transform: scale(0.85) translateY(-10rpx);
+	}
+
+	.u-keyboard-change .inactive.en {
+		transform: scale(0.85) translateY(10rpx);
+	}
+
+	.u-keyboard-change .active {
+		color: rgb(237, 112, 64);
+		font-size: 30rpx;
+	}
+
+	.u-keyboard-change .zh {
+		transform: translateY(-10rpx);
+	}
+
+	.u-keyboard-change .en {
+		transform: translateY(10rpx);
+	}
+</style>

+ 299 - 0
uview-ui/components/u-card/u-card.vue

@@ -0,0 +1,299 @@
+<template>
+	<view
+		class="u-card"
+		@tap.stop="click"
+		:class="{ 'u-border': border, 'u-card-full': full, 'u-card--border': borderRadius > 0 }"
+		:style="{
+			borderRadius: borderRadius + 'rpx',
+			margin: margin,
+			boxShadow: boxShadow
+		}"
+	>
+		<view
+			v-if="showHead"
+			class="u-card__head"
+			:style="[{padding: padding + 'rpx'}, headStyle]"
+			:class="{
+				'u-border-bottom': headBorderBottom
+			}"
+			@tap="headClick"
+		>
+			<view v-if="!$slots.head" class="u-flex u-row-between">
+				<view class="u-card__head--left u-flex u-line-1" v-if="title">
+					<image
+						:src="thumb"
+						class="u-card__head--left__thumb"
+						mode="aspectfull"
+						v-if="thumb"
+						:style="{ 
+							height: thumbWidth + 'rpx', 
+							width: thumbWidth + 'rpx', 
+							borderRadius: thumbCircle ? '100rpx' : '6rpx' 
+						}"
+					></image>
+					<text
+						class="u-card__head--left__title u-line-1"
+						:style="{
+							fontSize: titleSize + 'rpx',
+							color: titleColor
+						}"
+					>
+						{{ title }}
+					</text>
+				</view>
+				<view class="u-card__head--right u-line-1" v-if="subTitle">
+					<text
+						class="u-card__head__title__text"
+						:style="{
+							fontSize: subTitleSize + 'rpx',
+							color: subTitleColor
+						}"
+					>
+						{{ subTitle }}
+					</text>
+				</view>
+			</view>
+			<slot name="head" v-else />
+		</view>
+		<view @tap="bodyClick" class="u-card__body" :style="[{padding: padding + 'rpx'}, bodyStyle]"><slot name="body" /></view>
+		<view
+			v-if="showFoot"
+			class="u-card__foot"
+			 @tap="footClick"
+			:style="[{padding: $slots.foot ? padding + 'rpx' : 0}, footStyle]"
+			:class="{
+				'u-border-top': footBorderTop
+			}"
+		>
+			<slot name="foot" />
+		</view>
+	</view>
+</template>
+
+<script>
+/**
+ * card 卡片
+ * @description 卡片组件一般用于多个列表条目,且风格统一的场景
+ * @tutorial https://www.uviewui.com/components/card.html
+ * @property {Boolean} full 卡片与屏幕两侧是否留空隙(默认false)
+ * @property {String} title 头部左边的标题
+ * @property {String} title-color 标题颜色(默认#303133)
+ * @property {String | Number} title-size 标题字体大小,单位rpx(默认30)
+ * @property {String} sub-title 头部右边的副标题
+ * @property {String} sub-title-color 副标题颜色(默认#909399)
+ * @property {String | Number} sub-title-size 副标题字体大小(默认26)
+ * @property {Boolean} border 是否显示边框(默认true)
+ * @property {String | Number} index 用于标识点击了第几个卡片
+ * @property {String} box-shadow 卡片外围阴影,字符串形式(默认none)
+ * @property {String} margin 卡片与屏幕两边和上下元素的间距,需带单位,如"30rpx 20rpx"(默认30rpx)
+ * @property {String | Number} border-radius 卡片整体的圆角值,单位rpx(默认16)
+ * @property {Object} head-style 头部自定义样式,对象形式
+ * @property {Object} body-style 中部自定义样式,对象形式
+ * @property {Object} foot-style 底部自定义样式,对象形式
+ * @property {Boolean} head-border-bottom 是否显示头部的下边框(默认true)
+ * @property {Boolean} foot-border-top 是否显示底部的上边框(默认true)
+ * @property {Boolean} show-head 是否显示头部(默认true)
+ * @property {Boolean} show-head 是否显示尾部(默认true)
+ * @property {String} thumb 缩略图路径,如设置将显示在标题的左边,不建议使用相对路径
+ * @property {String | Number} thumb-width 缩略图的宽度,高等于宽,单位rpx(默认60)
+ * @property {Boolean} thumb-circle 缩略图是否为圆形(默认false)
+ * @event {Function} click 整个卡片任意位置被点击时触发
+ * @event {Function} head-click 卡片头部被点击时触发
+ * @event {Function} body-click 卡片主体部分被点击时触发
+ * @event {Function} foot-click 卡片底部部分被点击时触发
+ * @example <u-card padding="30" title="card"></u-card>
+ */
+export default {
+	name: 'u-card',
+	props: {
+		// 与屏幕两侧是否留空隙
+		full: {
+			type: Boolean,
+			default: false
+		},
+		// 标题
+		title: {
+			type: String,
+			default: ''
+		},
+		// 标题颜色
+		titleColor: {
+			type: String,
+			default: '#303133'
+		},
+		// 标题字体大小,单位rpx
+		titleSize: {
+			type: [Number, String],
+			default: '30'
+		},
+		// 副标题
+		subTitle: {
+			type: String,
+			default: ''
+		},
+		// 副标题颜色
+		subTitleColor: {
+			type: String,
+			default: '#909399'
+		},
+		// 副标题字体大小,单位rpx
+		subTitleSize: {
+			type: [Number, String],
+			default: '26'
+		},
+		// 是否显示外部边框,只对full=false时有效(卡片与边框有空隙时)
+		border: {
+			type: Boolean,
+			default: true
+		},
+		// 用于标识点击了第几个
+		index: {
+			type: [Number, String, Object],
+			default: ''
+		},
+		// 用于隔开上下左右的边距,带单位的写法,如:"30rpx 30rpx","20rpx 20rpx 30rpx 30rpx"
+		margin: {
+			type: String,
+			default: '30rpx'
+		},
+		// card卡片的圆角
+		borderRadius: {
+			type: [Number, String],
+			default: '16'
+		},
+		// 头部自定义样式,对象形式
+		headStyle: {
+			type: Object,
+			default() {
+				return {};
+			}
+		},
+		// 主体自定义样式,对象形式
+		bodyStyle: {
+			type: Object,
+			default() {
+				return {};
+			}
+		},
+		// 底部自定义样式,对象形式
+		footStyle: {
+			type: Object,
+			default() {
+				return {};
+			}
+		},
+		// 头部是否下边框
+		headBorderBottom: {
+			type: Boolean,
+			default: true
+		},
+		// 底部是否有上边框
+		footBorderTop: {
+			type: Boolean,
+			default: true
+		},
+		// 标题左边的缩略图
+		thumb: {
+			type: String,
+			default: ''
+		},
+		// 缩略图宽高,单位rpx
+		thumbWidth: {
+			type: [String, Number],
+			default: '60'
+		},
+		// 缩略图是否为圆形
+		thumbCircle: {
+			type: Boolean,
+			default: false
+		},
+		// 给head,body,foot的内边距
+		padding: {
+			type: [String, Number],
+			default: '30'
+		},
+		// 是否显示头部
+		showHead: {
+			type: Boolean,
+			default: true
+		},
+		// 是否显示尾部
+		showFoot: {
+			type: Boolean,
+			default: true
+		},
+		// 卡片外围阴影,字符串形式
+		boxShadow: {
+			type: String,
+			default: 'none'
+		}
+	},
+	data() {
+		return {};
+	},
+	methods: {
+		click() {
+			this.$emit('click', this.index);
+		},
+		headClick() {
+			this.$emit('head-click', this.index);
+		},
+		bodyClick() {
+			this.$emit('body-click', this.index);
+		},
+		footClick() {
+			this.$emit('foot-click', this.index);
+		}
+	}
+};
+</script>
+
+<style lang="scss" scoped>
+@import "../../libs/css/style.components.scss";
+	
+.u-card {
+	position: relative;
+	overflow: hidden;
+	font-size: 28rpx;
+	background-color: #ffffff;
+	box-sizing: border-box;
+	
+	&-full {
+		// 如果是与屏幕之间不留空隙,应该设置左右边距为0
+		margin-left: 0 !important;
+		margin-right: 0 !important;
+		width: 100%;
+	}
+	
+	&--border:after {
+		border-radius: 16rpx;
+	}
+
+	&__head {
+		&--left {
+			color: $u-main-color;
+			
+			&__thumb {
+				margin-right: 16rpx;
+			}
+			
+			&__title {
+				max-width: 400rpx;
+			}
+		}
+
+		&--right {
+			color: $u-tips-color;
+			margin-left: 6rpx;
+		}
+	}
+
+	&__body {
+		color: $u-content-color;
+	}
+
+	&__foot {
+		color: $u-tips-color;
+	}
+}
+</style>

+ 70 - 0
uview-ui/components/u-cell-group/u-cell-group.vue

@@ -0,0 +1,70 @@
+<template>
+	<view class="u-cell-box">
+		<view class="u-cell-title" v-if="title" :style="[titleStyle]">
+			{{title}}
+		</view>
+		<view class="u-cell-item-box" :class="{'u-border-bottom u-border-top': border}">
+			<slot />
+		</view>
+	</view>
+</template>
+
+<script>
+	/**
+	 * cellGroup 单元格父组件Group
+	 * @description cell单元格一般用于一组列表的情况,比如个人中心页,设置页等。搭配u-cell-item
+	 * @tutorial https://www.uviewui.com/components/cell.html
+	 * @property {String} title 分组标题
+	 * @property {Boolean} border 是否显示外边框(默认true)
+	 * @property {Object} title-style 分组标题的的样式,对象形式,如{'font-size': '24rpx'} 或 {'fontSize': '24rpx'}
+	 * @example <u-cell-group title="设置喜好">
+	 */
+	export default {
+		name: "u-cell-group",
+		props: {
+			// 分组标题
+			title: {
+				type: String,
+				default: ''
+			},
+			// 是否显示分组list上下边框
+			border: {
+				type: Boolean,
+				default: true
+			},
+			// 分组标题的样式,对象形式,注意驼峰属性写法
+			// 类似 {'font-size': '24rpx'} 和 {'fontSize': '24rpx'}
+			titleStyle: {
+				type: Object,
+				default () {
+					return {};
+				}
+			}
+		},
+		data() {
+			return {
+				index: 0,
+			}
+		},
+	}
+</script>
+
+<style lang="scss" scoped>
+	@import "../../libs/css/style.components.scss";
+	
+	.u-cell-box {
+		width: 100%;
+	}
+
+	.u-cell-title {
+		padding: 30rpx 32rpx 10rpx 32rpx;
+		font-size: 30rpx;
+		text-align: left;
+		color: $u-tips-color;
+	}
+
+	.u-cell-item-box {
+		background-color: #FFFFFF;
+		flex-direction: row;
+	}
+</style>

+ 316 - 0
uview-ui/components/u-cell-item/u-cell-item.vue

@@ -0,0 +1,316 @@
+<template>
+	<view
+		@tap="click"
+		class="u-cell"
+		:class="{ 'u-border-bottom': borderBottom, 'u-border-top': borderTop, 'u-col-center': center, 'u-cell--required': required }"
+		hover-stay-time="150"
+		:hover-class="hoverClass"
+		:style="{
+			backgroundColor: bgColor
+		}"
+	>
+		<u-icon :size="iconSize" :name="icon" v-if="icon" :custom-style="iconStyle" class="u-cell__left-icon-wrap"></u-icon>
+		<view class="u-flex" v-else>
+			<slot name="icon"></slot>
+		</view>
+		<view
+			class="u-cell_title"
+			:style="[
+				{
+					width: titleWidth ? titleWidth + 'rpx' : 'auto'
+				},
+				titleStyle
+			]"
+		>
+			<block v-if="title">{{ title }}</block>
+			<slot name="title" v-else></slot>
+
+			<view class="u-cell__label" v-if="label || $slots.label" :style="[labelStyle]">
+				<block v-if="label">{{ label }}</block>
+				<slot name="label" v-else></slot>
+			</view>
+		</view>
+
+		<view class="u-cell__value" :style="[valueStyle]">
+			<block class="u-cell__value" v-if="value">{{ value }}</block>
+			<slot v-else></slot>
+		</view>
+		<view class="u-flex u-cell_right" v-if="$slots['right-icon']">
+			<slot name="right-icon"></slot>
+		</view>
+		<u-icon v-if="arrow" name="arrow-right" :style="[arrowStyle]" class="u-icon-wrap u-cell__right-icon-wrap"></u-icon>
+	</view>
+</template>
+
+<script>
+/**
+ * cellItem 单元格Item
+ * @description cell单元格一般用于一组列表的情况,比如个人中心页,设置页等。搭配u-cell-group使用
+ * @tutorial https://www.uviewui.com/components/cell.html
+ * @property {String} title 左侧标题
+ * @property {String} icon 左侧图标名,只支持uView内置图标,见Icon 图标
+ * @property {Object} icon-style 左边图标的样式,对象形式
+ * @property {String} value 右侧内容
+ * @property {String} label 标题下方的描述信息
+ * @property {Boolean} border-bottom 是否显示cell的下边框(默认true)
+ * @property {Boolean} border-top 是否显示cell的上边框(默认false)
+ * @property {Boolean} center 是否使内容垂直居中(默认false)
+ * @property {String} hover-class 是否开启点击反馈,none为无效果(默认true)
+ * // @property {Boolean} border-gap border-bottom为true时,Cell列表中间的条目的下边框是否与左边有一个间隔(默认true)
+ * @property {Boolean} arrow 是否显示右侧箭头(默认true)
+ * @property {Boolean} required 箭头方向,可选值(默认right)
+ * @property {Boolean} arrow-direction 是否显示左边表示必填的星号(默认false)
+ * @property {Object} title-style 标题样式,对象形式
+ * @property {Object} value-style 右侧内容样式,对象形式
+ * @property {Object} label-style 标题下方描述信息的样式,对象形式
+ * @property {String} bg-color 背景颜色(默认transparent)
+ * @property {String Number} index 用于在click事件回调中返回,标识当前是第几个Item
+ * @property {String Number} title-width 标题的宽度,单位rpx
+ * @example <u-cell-item icon="integral-fill" title="会员等级" value="新版本"></u-cell-item>
+ */
+export default {
+	name: 'u-cell-item',
+	props: {
+		// 左侧图标名称(只能uView内置图标),或者图标src
+		icon: {
+			type: String,
+			default: ''
+		},
+		// 左侧标题
+		title: {
+			type: [String, Number],
+			default: ''
+		},
+		// 右侧内容
+		value: {
+			type: [String, Number],
+			default: ''
+		},
+		// 标题下方的描述信息
+		label: {
+			type: [String, Number],
+			default: ''
+		},
+		// 是否显示下边框
+		borderBottom: {
+			type: Boolean,
+			default: true
+		},
+		// 是否显示上边框
+		borderTop: {
+			type: Boolean,
+			default: false
+		},
+		// 多个cell中,中间的cell显示下划线时,下划线是否给一个到左边的距离
+		// 1.4.0版本废除此参数,默认边框由border-top和border-bottom提供,此参数会造成干扰
+		// borderGap: {
+		// 	type: Boolean,
+		// 	default: true
+		// },
+		// 是否开启点击反馈,即点击时cell背景为灰色,none为无效果
+		hoverClass: {
+			type: String,
+			default: 'u-cell-hover'
+		},
+		// 是否显示右侧箭头
+		arrow: {
+			type: Boolean,
+			default: true
+		},
+		// 内容是否垂直居中
+		center: {
+			type: Boolean,
+			default: false
+		},
+		// 是否显示左边表示必填的星号
+		required: {
+			type: Boolean,
+			default: false
+		},
+		// 标题的宽度,单位rpx
+		titleWidth: {
+			type: [Number, String],
+			default: ''
+		},
+		// 右侧箭头方向,可选值:right|up|down,默认为right
+		arrowDirection: {
+			type: String,
+			default: 'right'
+		},
+		// 控制标题的样式
+		titleStyle: {
+			type: Object,
+			default() {
+				return {};
+			}
+		},
+		// 右侧显示内容的样式
+		valueStyle: {
+			type: Object,
+			default() {
+				return {};
+			}
+		},
+		// 描述信息的样式
+		labelStyle: {
+			type: Object,
+			default() {
+				return {};
+			}
+		},
+		// 背景颜色
+		bgColor: {
+			type: String,
+			default: 'transparent'
+		},
+		// 用于识别被点击的是第几个cell
+		index: {
+			type: [String, Number],
+			default: ''
+		},
+		// 是否使用lable插槽
+		useLabelSlot: {
+			type: Boolean,
+			default: false
+		},
+		// 左边图标的大小,单位rpx,只对传入icon字段时有效
+		iconSize: {
+			type: [Number, String],
+			default: 34
+		},
+		// 左边图标的样式,对象形式
+		iconStyle: {
+			type: Object,
+			default() {
+				return {}
+			}
+		},
+	},
+	data() {
+		return {
+
+		};
+	},
+	computed: {
+		arrowStyle() {
+			let style = {};
+			if (this.arrowDirection == 'up') style.transform = 'rotate(-90deg)';
+			else if (this.arrowDirection == 'down') style.transform = 'rotate(90deg)';
+			else style.transform = 'rotate(0deg)';
+			return style;
+		}
+	},
+	methods: {
+		click() {
+			this.$emit('click', this.index);
+		}
+	}
+};
+</script>
+
+<style lang="scss" scoped>
+@import "../../libs/css/style.components.scss";
+.u-cell {
+	@include vue-flex;
+	align-items: center;
+	position: relative;
+	/* #ifndef APP-NVUE */
+	box-sizing: border-box;
+	/* #endif */
+	width: 100%;
+	padding: 26rpx 32rpx;
+	font-size: 28rpx;
+	line-height: 54rpx;
+	color: $u-content-color;
+	background-color: #fff;
+	text-align: left;
+}
+
+.u-cell_title {
+	font-size: 28rpx;
+}
+
+.u-cell__left-icon-wrap {
+	margin-right: 10rpx;
+	font-size: 32rpx;
+}
+
+.u-cell__right-icon-wrap {
+	margin-left: 10rpx;
+	color: #969799;
+	font-size: 28rpx;
+}
+
+.u-cell__left-icon-wrap,
+.u-cell__right-icon-wrap {
+	@include vue-flex;
+	align-items: center;
+	height: 48rpx;
+}
+
+.u-cell-border:after {
+	position: absolute; 
+	/* #ifndef APP-NVUE */
+	box-sizing: border-box;
+	content: ' ';
+	pointer-events: none;
+	border-bottom: 1px solid $u-border-color;
+	/* #endif */
+	right: 0;
+	left: 0;
+	top: 0;
+	transform: scaleY(0.5);
+}
+
+.u-cell-border {
+	position: relative;
+}
+
+.u-cell__label {
+	margin-top: 6rpx;
+	font-size: 26rpx;
+	line-height: 36rpx;
+	color: $u-tips-color;
+	/* #ifndef APP-NVUE */
+	word-wrap: break-word;
+	/* #endif */
+}
+
+.u-cell__value {
+	overflow: hidden;
+	text-align: right;
+	/* #ifndef APP-NVUE */
+	vertical-align: middle;
+	/* #endif */
+	color: $u-tips-color;
+	font-size: 26rpx;
+}
+
+.u-cell__title,
+.u-cell__value {
+	flex: 1;
+}
+
+.u-cell--required {
+	/* #ifndef APP-NVUE */
+	overflow: visible;
+	/* #endif */
+	@include vue-flex;
+	align-items: center;
+}
+
+.u-cell--required:before {
+	position: absolute;
+	/* #ifndef APP-NVUE */
+	content: '*';
+	/* #endif */
+	left: 8px;
+	margin-top: 4rpx;
+	font-size: 14px;
+	color: $u-type-error;
+}
+
+.u-cell_right {
+	line-height: 1;
+}
+</style>

+ 123 - 0
uview-ui/components/u-checkbox-group/u-checkbox-group.vue

@@ -0,0 +1,123 @@
+<template>
+	<view class="u-checkbox-group u-clearfix">
+		<slot></slot>
+	</view>
+</template>
+
+<script>
+	import Emitter from '../../libs/util/emitter.js';
+	/**
+	 * checkboxGroup 开关选择器父组件Group
+	 * @description 复选框组件一般用于需要多个选择的场景,该组件功能完整,使用方便
+	 * @tutorial https://www.uviewui.com/components/checkbox.html
+	 * @property {String Number} max 最多能选中多少个checkbox(默认999)
+	 * @property {String Number} size 组件整体的大小,单位rpx(默认40)
+	 * @property {Boolean} disabled 是否禁用所有checkbox(默认false)
+	 * @property {String Number} icon-size 图标大小,单位rpx(默认20)
+	 * @property {Boolean} label-disabled 是否禁止点击文本操作checkbox(默认false)
+	 * @property {String} width 宽度,需带单位
+	 * @property {String} width 宽度,需带单位
+	 * @property {String} shape 外观形状,shape-方形,circle-圆形(默认circle)
+	 * @property {Boolean} wrap 是否每个checkbox都换行(默认false)
+	 * @property {String} active-color 选中时的颜色,应用到所有子Checkbox组件(默认#2979ff)
+	 * @event {Function} change 任一个checkbox状态发生变化时触发,回调为一个对象
+	 * @example <u-checkbox-group></u-checkbox-group>
+	 */
+	export default {
+		name: 'u-checkbox-group',
+		mixins: [Emitter],
+		props: {
+			// 最多能选中多少个checkbox
+			max: {
+				type: [Number, String],
+				default: 999
+			},
+			// 所有选中项的 name
+			// value: {
+			// 	default: Array,
+			// 	default() {
+			// 		return []
+			// 	}
+			// },
+			// 是否禁用所有复选框
+			disabled: {
+				type: Boolean,
+				default: false
+			},
+			// 在表单内提交时的标识符
+			name: {
+				type: [Boolean, String],
+				default: ''
+			},
+			// 是否禁止点击提示语选中复选框
+			labelDisabled: {
+				type: Boolean,
+				default: false
+			},
+			// 形状,square为方形,circle为原型
+			shape: {
+				type: String,
+				default: 'square'
+			},
+			// 选中状态下的颜色
+			activeColor: {
+				type: String,
+				default: '#2979ff'
+			},
+			// 组件的整体大小
+			size: {
+				type: [String, Number],
+				default: 34
+			},
+			// 每个checkbox占u-checkbox-group的宽度
+			width: {
+				type: String,
+				default: 'auto'
+			},
+			// 是否每个checkbox都换行
+			wrap: { 
+				type: Boolean,
+				default: false
+			},
+			// 图标的大小,单位rpx
+			iconSize: {
+				type: [String, Number],
+				default: 20
+			},
+		},
+		data() {
+			return {
+			}
+		},
+		created() {
+			// 如果将children定义在data中,在微信小程序会造成循环引用而报错
+			this.children = [];
+		},
+		methods: {
+			emitEvent() {
+				let values = [];
+				this.children.map(val => {
+					if(val.value) values.push(val.name);
+				})
+				this.$emit('change', values);
+				// 发出事件,用于在表单组件中嵌入checkbox的情况,进行验证
+				// 由于头条小程序执行迟钝,故需要用几十毫秒的延时
+				setTimeout(() => {
+					// 将当前的值发送到 u-form-item 进行校验
+					this.dispatch('u-form-item', 'on-form-change', values);
+				}, 60)
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	@import "../../libs/css/style.components.scss";
+
+	.u-checkbox-group {
+		/* #ifndef MP || APP-NVUE */
+		display: inline-flex;
+		flex-wrap: wrap;
+		/* #endif */
+	}
+</style>

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است