guhongwei 2 年之前
父节点
当前提交
627ce1e591
共有 100 个文件被更改,包括 38355 次插入11924 次删除
  1. 3 2
      common/api.js
  2. 2 1
      common/config.js
  3. 77 0
      common/weapp-jwt.js
  4. 2 2
      components/upload/index.vue
  5. 3 0
      main.js
  6. 24 0
      pages.json
  7. 2 3
      pages/index/index.vue
  8. 145 0
      pagesAccount/basic/index.vue
  9. 23 0
      pagesAccount/collect/index.vue
  10. 23 0
      pagesAccount/like/index.vue
  11. 62 26
      pagesAccount/login/index.vue
  12. 23 0
      pagesAccount/other/agree.vue
  13. 159 5
      pagesAccount/register/index.vue
  14. 60 29
      pagesHome/account/index.vue
  15. 45 0
      uni_modules/uni-data-checkbox/changelog.md
  16. 821 0
      uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue
  17. 84 0
      uni_modules/uni-data-checkbox/package.json
  18. 18 0
      uni_modules/uni-data-checkbox/readme.md
  19. 92 0
      uni_modules/uni-forms/changelog.md
  20. 627 0
      uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue
  21. 397 0
      uni_modules/uni-forms/components/uni-forms/uni-forms.vue
  22. 293 0
      uni_modules/uni-forms/components/uni-forms/utils.js
  23. 486 0
      uni_modules/uni-forms/components/uni-forms/validate.js
  24. 88 0
      uni_modules/uni-forms/package.json
  25. 23 0
      uni_modules/uni-forms/readme.md
  26. 19 0
      uni_modules/uni-load-more/changelog.md
  27. 5 0
      uni_modules/uni-load-more/components/uni-load-more/i18n/en.json
  28. 8 0
      uni_modules/uni-load-more/components/uni-load-more/i18n/index.js
  29. 5 0
      uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json
  30. 5 0
      uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json
  31. 399 0
      uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue
  32. 86 0
      uni_modules/uni-load-more/package.json
  33. 14 0
      uni_modules/uni-load-more/readme.md
  34. 1 1
      unpackage/dist/dev/.sourcemap/mp-weixin/common/main.js.map
  35. 1 1
      unpackage/dist/dev/.sourcemap/mp-weixin/common/runtime.js.map
  36. 1 1
      unpackage/dist/dev/.sourcemap/mp-weixin/common/vendor.js.map
  37. 1 1
      unpackage/dist/dev/.sourcemap/mp-weixin/components/upload/index.js.map
  38. 1 1
      unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/index.js.map
  39. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pagesAccount/basic/index.js.map
  40. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pagesAccount/collect/index.js.map
  41. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pagesAccount/like/index.js.map
  42. 1 1
      unpackage/dist/dev/.sourcemap/mp-weixin/pagesAccount/login/index.js.map
  43. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pagesAccount/other/agree.js.map
  44. 1 1
      unpackage/dist/dev/.sourcemap/mp-weixin/pagesAccount/register/index.js.map
  45. 1 1
      unpackage/dist/dev/.sourcemap/mp-weixin/pagesHome/account/index.js.map
  46. 1 1
      unpackage/dist/dev/.sourcemap/mp-weixin/pagesHome/app/index.js.map
  47. 1 1
      unpackage/dist/dev/.sourcemap/mp-weixin/pagesHome/components/home-frame.js.map
  48. 1 1
      unpackage/dist/dev/.sourcemap/mp-weixin/pagesHome/find/index.js.map
  49. 1 1
      unpackage/dist/dev/.sourcemap/mp-weixin/pagesHome/home/index.js.map
  50. 1 1
      unpackage/dist/dev/.sourcemap/mp-weixin/pagesHome/hot/index.js.map
  51. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.js.map
  52. 1 1
      unpackage/dist/dev/.sourcemap/mp-weixin/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.js.map
  53. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.js.map
  54. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/uni_modules/uni-forms/components/uni-forms/uni-forms.js.map
  55. 1 1
      unpackage/dist/dev/.sourcemap/mp-weixin/uni_modules/uni-icons/components/uni-icons/uni-icons.js.map
  56. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.js.map
  57. 2 2
      unpackage/dist/dev/app-plus/app-config-service.js
  58. 9968 334
      unpackage/dist/dev/app-plus/app-service.js
  59. 2603 346
      unpackage/dist/dev/app-plus/app-view.js
  60. 834 90
      unpackage/dist/dev/app-plus/pagesAccount/app-sub-service.js
  61. 1 1
      unpackage/dist/dev/app-plus/pagesCommon/app-sub-service.js
  62. 68 18
      unpackage/dist/dev/app-plus/pagesHome/app-sub-service.js
  63. 5 1
      unpackage/dist/dev/mp-weixin/app.json
  64. 4 0
      unpackage/dist/dev/mp-weixin/common/main.js
  65. 2 2
      unpackage/dist/dev/mp-weixin/common/runtime.js
  66. 19231 10920
      unpackage/dist/dev/mp-weixin/common/vendor.js
  67. 17 17
      unpackage/dist/dev/mp-weixin/components/upload/index.js
  68. 2 2
      unpackage/dist/dev/mp-weixin/pages/index/index.js
  69. 376 0
      unpackage/dist/dev/mp-weixin/pagesAccount/basic/index.js
  70. 11 0
      unpackage/dist/dev/mp-weixin/pagesAccount/basic/index.json
  71. 1 0
      unpackage/dist/dev/mp-weixin/pagesAccount/basic/index.wxml
  72. 23 0
      unpackage/dist/dev/mp-weixin/pagesAccount/basic/index.wxss
  73. 192 0
      unpackage/dist/dev/mp-weixin/pagesAccount/collect/index.js
  74. 5 0
      unpackage/dist/dev/mp-weixin/pagesAccount/collect/index.json
  75. 1 0
      unpackage/dist/dev/mp-weixin/pagesAccount/collect/index.wxml
  76. 12 0
      unpackage/dist/dev/mp-weixin/pagesAccount/collect/index.wxss
  77. 192 0
      unpackage/dist/dev/mp-weixin/pagesAccount/like/index.js
  78. 5 0
      unpackage/dist/dev/mp-weixin/pagesAccount/like/index.json
  79. 1 0
      unpackage/dist/dev/mp-weixin/pagesAccount/like/index.wxml
  80. 12 0
      unpackage/dist/dev/mp-weixin/pagesAccount/like/index.wxss
  81. 81 38
      unpackage/dist/dev/mp-weixin/pagesAccount/login/index.js
  82. 2 0
      unpackage/dist/dev/mp-weixin/pagesAccount/login/index.json
  83. 1 1
      unpackage/dist/dev/mp-weixin/pagesAccount/login/index.wxml
  84. 6 3
      unpackage/dist/dev/mp-weixin/pagesAccount/login/index.wxss
  85. 192 0
      unpackage/dist/dev/mp-weixin/pagesAccount/other/agree.js
  86. 5 0
      unpackage/dist/dev/mp-weixin/pagesAccount/other/agree.json
  87. 1 0
      unpackage/dist/dev/mp-weixin/pagesAccount/other/agree.wxml
  88. 12 0
      unpackage/dist/dev/mp-weixin/pagesAccount/other/agree.wxss
  89. 189 17
      unpackage/dist/dev/mp-weixin/pagesAccount/register/index.js
  90. 7 1
      unpackage/dist/dev/mp-weixin/pagesAccount/register/index.json
  91. 1 1
      unpackage/dist/dev/mp-weixin/pagesAccount/register/index.wxml
  92. 21 1
      unpackage/dist/dev/mp-weixin/pagesAccount/register/index.wxss
  93. 1 1
      unpackage/dist/dev/mp-weixin/pagesCommon/test/index.js
  94. 104 28
      unpackage/dist/dev/mp-weixin/pagesHome/account/index.js
  95. 1 0
      unpackage/dist/dev/mp-weixin/pagesHome/account/index.json
  96. 1 1
      unpackage/dist/dev/mp-weixin/pagesHome/account/index.wxml
  97. 1 1
      unpackage/dist/dev/mp-weixin/pagesHome/app/index.js
  98. 14 14
      unpackage/dist/dev/mp-weixin/pagesHome/components/home-frame.js
  99. 1 1
      unpackage/dist/dev/mp-weixin/pagesHome/find/index.js
  100. 0 0
      unpackage/dist/dev/mp-weixin/pagesHome/home/index.js

+ 3 - 2
common/api.js

@@ -2,6 +2,7 @@ import config from "../common/config";
 const getDomain = (uri, type) => {
 	const {
 		serverUrl,
+		fileserverUrl,
 		wechatUrl
 	} = config;
 	// 自定义
@@ -38,10 +39,10 @@ export const requestBase = async (uri, method = "GET", data, type) => {
 // 图片请求
 export const requestFile = (uri, method, data, type) => {
 	// 请求地址
-	let baseUrl = getDomain(uri, type);
+	// let baseUrl = getDomain(uri, type);
 	return new Promise((resolve, reject) => {
 		uni.uploadFile({
-			url: `https://broadcast.waityou24.cn/${uri}`,
+			url: `${config.fileserverUrl}/${uri}`,
 			filePath: data,
 			name: 'file',
 			formData: {},

+ 2 - 1
common/config.js

@@ -1,6 +1,7 @@
 export default {
 	// 接口地址
-	serverUrl: "http://192.168.1.144:10102",//http://47.93.34.200   http://www.freeskyghw.cn   http://192.168.1.144:10102
+	serverUrl: "http://192.168.1.144:10102", //http://47.93.34.200   http://www.freeskyghw.cn   http://192.168.1.144:10102
+	fileserverUrl: 'http://47.93.34.200',
 	wechatUrl: "http://47.93.34.200",
 	// 设备信息
 	system: uni.getSystemInfoSync(),

+ 77 - 0
common/weapp-jwt.js

@@ -0,0 +1,77 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+var b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;
+exports.weBtoa = function (string) {
+    string = String(string);
+    var bitmap, a, b, c, result = "", i = 0, rest = string.length % 3;
+    for (; i < string.length;) {
+        if ((a = string.charCodeAt(i++)) > 255 ||
+            (b = string.charCodeAt(i++)) > 255 ||
+            (c = string.charCodeAt(i++)) > 255)
+            throw new TypeError("Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.");
+        bitmap = (a << 16) | (b << 8) | c;
+        result += b64.charAt(bitmap >> 18 & 63) + b64.charAt(bitmap >> 12 & 63) +
+            b64.charAt(bitmap >> 6 & 63) + b64.charAt(bitmap & 63);
+    }
+    return rest ? result.slice(0, rest - 3) + "===".substring(rest) : result;
+};
+exports.weAtob = function (string) {
+    string = String(string).replace(/[\t\n\f\r ]+/g, "");
+    if (!b64re.test(string))
+        throw new TypeError("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.");
+    string += "==".slice(2 - (string.length & 3));
+    var bitmap, result = "", r1, r2, i = 0;
+    for (; i < string.length;) {
+        bitmap = b64.indexOf(string.charAt(i++)) << 18 | b64.indexOf(string.charAt(i++)) << 12 |
+            (r1 = b64.indexOf(string.charAt(i++))) << 6 | (r2 = b64.indexOf(string.charAt(i++)));
+        result += r1 === 64 ? String.fromCharCode(bitmap >> 16 & 255) :
+            r2 === 64 ? String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255) :
+                String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255, bitmap & 255);
+    }
+    return result;
+};
+function b64DecodeUnicode(str) {
+    return decodeURIComponent(exports.weAtob(str).replace(/(.)/g, function (p) {
+        var code = p.charCodeAt(0).toString(16).toUpperCase();
+        if (code.length < 2) {
+            code = "0" + code;
+        }
+        return "%" + code;
+    }));
+}
+function base64_url_decode(str) {
+    var output = str.replace(/-/g, "+").replace(/_/g, "/");
+    switch (output.length % 4) {
+        case 0:
+            break;
+        case 2:
+            output += "==";
+            break;
+        case 3:
+            output += "=";
+            break;
+        default:
+            throw "Illegal base64url string!";
+    }
+    try {
+        return b64DecodeUnicode(output);
+    }
+    catch (err) {
+        return exports.weAtob(output);
+    }
+}
+function weappJwtDecode(token, options) {
+    if (typeof token !== "string") {
+        throw ("Invalid token specified");
+    }
+    options = options || {};
+    var pos = options.header === true ? 0 : 1;
+    try {
+        return JSON.parse(base64_url_decode(token.split(".")[pos]));
+    }
+    catch (e) {
+        throw ("Invalid token specified: " + e.message);
+    }
+}
+exports.default = weappJwtDecode;

+ 2 - 2
components/upload/index.vue

@@ -32,14 +32,14 @@
 		methods: {
 			uplSuc() {
 				const that = this;
-				let serverUrl = that.$config.serverUrl;
+				let serverUrl = that.$config.fileserverUrl;
 				uni.chooseImage({
 					count: 1,
 					sizeType: ["original", "compressed"],
 					sourceType: ["album", "camera"],
 					async success(chooseRes) {
 						let file = JSON.parse(JSON.stringify(chooseRes.tempFilePaths));
-						let res = await that.$apifile("files/test/upload", null, file[0]);
+						let res = await that.$apifile("files/projectadmin/upload", null, file[0]);
 						res = JSON.parse(res);
 						if (res.errcode == "0") {
 							let data = {

+ 3 - 0
main.js

@@ -10,6 +10,9 @@ Vue.prototype.$config = config;
 import { requestBase, requestFile } from "@/common/api.js";
 Vue.prototype.$api = requestBase;
 Vue.prototype.$apifile = requestFile;
+// jwt解析
+import weappJwt from '@/common/weapp-jwt.js';
+Vue.prototype.$jwt = weappJwt;
 App.mpType = "app";
 const app = new Vue({ ...App });
 app.$mount();

+ 24 - 0
pages.json

@@ -71,6 +71,30 @@
 						"navigationBarTitleText": "账号注册",
 						"enablePullDownRefresh": false //是否启用下拉刷新
 					}
+				},{
+					"path": "other/agree",
+					"style": {
+						"navigationBarTitleText": "用户协议",
+						"enablePullDownRefresh": false //是否启用下拉刷新
+					}
+				},{
+					"path": "like/index",
+					"style": {
+						"navigationBarTitleText": "我的喜欢",
+						"enablePullDownRefresh": true //是否启用下拉刷新
+					}
+				},{
+					"path": "collect/index",
+					"style": {
+						"navigationBarTitleText": "我的收藏",
+						"enablePullDownRefresh": true //是否启用下拉刷新
+					}
+				},{
+					"path": "basic/index",
+					"style": {
+						"navigationBarTitleText": "账号信息",
+						"enablePullDownRefresh": false //是否启用下拉刷新
+					}
 				}
 			]
 		}

+ 2 - 3
pages/index/index.vue

@@ -37,7 +37,7 @@
 		methods: {
 			async search() {
 				const that = this;
-				let url = '/pagesAccount/register/index';
+				let url = '/pagesHome/account/index';
 				// 可返回
 				// uni.navigateTo({
 				// 	url
@@ -54,12 +54,11 @@
 							// 	url
 							// })
 							// 可返回
-							uni.navigateTo({
+							uni.redirectTo({
 								url
 							})
 						}
 					});
-
 				} else {
 					uni.showToast({
 						title: res.errmsg,

+ 145 - 0
pagesAccount/basic/index.vue

@@ -0,0 +1,145 @@
+<template>
+	<view class="content">
+		<uni-forms ref="form" :model="form" :rules="rules" label-width="auto">
+			<uni-forms-item name="account">
+				<uni-easyinput v-model="form.account" placeholder="请输入登录账号" disabled />
+			</uni-forms-item>
+			<uni-forms-item name="phone">
+				<uni-easyinput v-model="form.phone" placeholder="请输入联系电话" />
+			</uni-forms-item>
+			<uni-forms-item name="nick_name">
+				<uni-easyinput v-model="form.nick_name" placeholder="请输入账号昵称" />
+			</uni-forms-item>
+			<uni-forms-item name="gender">
+				<uni-data-checkbox v-model="form.gender" :localdata="genderList" :map="{text:'label',value:'value'}" />
+			</uni-forms-item>
+			<uni-forms-item name="logo_url">
+				<upload :list="form.logo_url" name="logo_url" :count="1" @uplSuc="uplSuc" @uplDel="uplDel"></upload>
+			</uni-forms-item>
+		</uni-forms>
+		<view class="btn">
+			<button size="mini" @tap="toSubmit('form')">提交保存</button>
+		</view>
+	</view>
+</template>
+
+<script>
+	import upload from "@/components/upload/index.vue";
+	export default {
+		components: {
+			upload,
+		},
+		data() {
+			return {
+				form: {
+					logo_url: [],
+				},
+				// 规则
+				rules: {
+					account: {
+						rules: [{
+							required: true,
+							errorMessage: '请输入登录账号'
+						}]
+					},
+					phone: {
+						rules: [{
+							required: true,
+							errorMessage: '请输入联系电话'
+						}]
+					},
+				},
+				// 性别
+				genderList: []
+			};
+		},
+		onLoad() {},
+		onShow() {
+			const that = this;
+			that.search();
+			that.searchOther();
+		},
+		methods: {
+			search() {
+				const that = this;
+				uni.getStorage({
+					key: 'token',
+					success: async (res) => {
+						let arr = that.$jwt(res.data);
+						if (arr) {
+							let user = await that.$api(`user/${arr._id}`, 'GET', {})
+							if (user && user.errcode == '0') {
+								that.$set(that, `form`, user.data)
+							}
+						}
+					}
+				})
+			},
+			// 图片保存
+			uplSuc(e) {
+				const that = this;
+				that.$set(that.form, `${e.name}`, [...that.form[e.name], e.data]);
+			},
+			// 图片删除
+			uplDel(e) {
+				const that = this;
+				let data = that.form[e.name];
+				let arr = data.filter((i, index) => index != e.data.index);
+				that.$set(that.form, `${e.name}`, arr);
+			},
+			// 提交保存
+			toSubmit(ref) {
+				const that = this;
+				let agree = that.agree;
+				that.$refs[ref].validate().then(async parmas => {
+					let res = await that.$api(`user/${that.form._id}`, 'POST', parmas)
+					if (res.errcode == '0') {
+						uni.showToast({
+							title: '维护信息成功',
+							icon: 'none'
+						})
+						uni.navigateBack()
+					} else {
+						uni.showToast({
+							title: res.errmsg,
+							icon: 'none'
+						})
+					}
+				}).catch(err => {
+					console.log('err', err);
+				})
+			},
+			// 查询其他信息
+			async searchOther() {
+				const that = this;
+				let res;
+				res = await that.$api('dictdata', 'GET', {
+					type: 'gender'
+				})
+				if (res.errcode == '0') {
+					that.$set(that, `genderList`, res.data)
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.content {
+		background-color: var(--rgb000);
+		padding: 0 2vw;
+		overflow-y: auto;
+
+		.btn {
+			padding: 2vw 0 0 0;
+			text-align: center;
+
+			button {
+				width: 80%;
+				background-color: var(--rgbfa4);
+				color: var(--rgbfff);
+				padding: 1vw 0;
+			}
+		}
+	}
+</style>

+ 23 - 0
pagesAccount/collect/index.vue

@@ -0,0 +1,23 @@
+<template>
+	<view class="content">
+		我的收藏
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {};
+		},
+		onLoad() {},
+		onShow() {},
+		methods: {}
+	}
+</script>
+
+<style lang="scss">
+	.content {
+		background-color: var(--rgb000);
+		padding: 0 2vw;
+	}
+</style>

+ 23 - 0
pagesAccount/like/index.vue

@@ -0,0 +1,23 @@
+<template>
+	<view class="content">
+		我的喜欢
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {};
+		},
+		onLoad() {},
+		onShow() {},
+		methods: {}
+	}
+</script>
+
+<style lang="scss">
+	.content {
+		background-color: var(--rgb000);
+		padding: 0 2vw;
+	}
+</style>

+ 62 - 26
pagesAccount/login/index.vue

@@ -5,13 +5,21 @@
 		</view>
 		<view class="two">
 			<uni-forms ref="form" :model="form" :rules="rules" label-width="auto">
-				<uni-forms-item label="登录账号" name="account">
+				<uni-forms-item name="account">
 					<uni-easyinput type="text" v-model="form.account" placeholder="请输入登录账号" />
 				</uni-forms-item>
-				<uni-forms-item label="登录密码" name="password">
+				<uni-forms-item name="password">
 					<uni-easyinput type="text" v-model="form.password" placeholder="请输入登录密码" />
 				</uni-forms-item>
 			</uni-forms>
+			<view class="agree">
+				<checkbox-group @change="changeAgree">
+					<label>
+						<checkbox :checked="agree" />
+						<text @tap.stop="toAgree()">我已阅读并同意“用户协议”和“隐私政策”</text>
+					</label>
+				</checkbox-group>
+			</view>
 			<view class="btn">
 				<button size="mini" @tap="toSubmit('form')">提交登录</button>
 			</view>
@@ -38,7 +46,7 @@
 							}
 						]
 					},
-					passowrd: {
+					password: {
 						rules: [ //
 							{
 								required: true,
@@ -47,13 +55,11 @@
 						]
 					}
 				},
-				// 协议
-				agree: true
+				// 用戶协议
+				agree: true,
 			};
 		},
-		onLoad() {
-
-		},
+		onLoad() {},
 		onShow() {
 			const that = this;
 			that.searchBasic();
@@ -70,32 +76,59 @@
 				})
 			},
 			// 提交登录
-			async toSubmit(ref) {
+			toSubmit(ref) {
 				const that = this;
 				let agree = that.agree;
-				let form = that.form;
-				if (agree) {
-					let res = await that.$api('user/login', 'POST', form)
-					if (res.errcode == '0') {
-						console.log(res.data);
+				that.$refs[ref].validate().then(async parmas => {
+					if (agree) {
+						let res = await that.$api('user/login', 'POST', parmas)
+						if (res.errcode == '0') {
+							uni.showToast({
+								title: '账号登录成功',
+								icon: 'none'
+							})
+							uni.setStorage({
+								key: 'token',
+								data: res.data,
+								success: function() {
+									uni.navigateBack()
+								}
+							});
+						} else {
+							uni.showToast({
+								title: res.errmsg,
+								icon: 'none'
+							})
+						}
 					} else {
 						uni.showToast({
-							title: res.errmsg,
+							title: '请阅读并同意用户协议和隐私政策',
 							icon: 'none'
 						})
 					}
-				} else {
-					uni.showToast({
-						title: '请阅读并同意用户协议和隐私政策',
-						icon: 'none'
-					})
-				}
+				}).catch(err => {
+					console.log('err', err);
+				})
 			},
 			toRegister() {
 				uni.navigateTo({
 					url: '/pagesAccount/register/index'
 				})
-			}
+			},
+			// 同意隐私协议
+			changeAgree() {
+				const that = this;
+				let agree = true;
+				if (that.agree) agree = false;
+				that.$set(that, `agree`, agree);
+			},
+			// 查看隐私协议
+			toAgree() {
+				const that = this;
+				uni.navigateTo({
+					url: `/pagesAccount/other/agree`
+				})
+			},
 		}
 	}
 </script>
@@ -116,10 +149,6 @@
 		.two {
 			margin: 0 0 4vw 0;
 
-			.uni-easyinput {
-				margin: 0 0 15px 0;
-			}
-
 			.btn {
 				padding: 2vw 0 0 0;
 				text-align: center;
@@ -142,4 +171,11 @@
 			}
 		}
 	}
+
+	.agree {
+		text-align: center;
+		font-size: 12px;
+		margin: 0 0 2vw 0;
+		color: var(--rgbfff);
+	}
 </style>

+ 23 - 0
pagesAccount/other/agree.vue

@@ -0,0 +1,23 @@
+<template>
+	<view class="content">
+		用户协议
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {};
+		},
+		onLoad() {},
+		onShow() {},
+		methods: {}
+	}
+</script>
+
+<style lang="scss">
+	.content {
+		background-color: var(--rgb000);
+		padding: 0 2vw;
+	}
+</style>

+ 159 - 5
pagesAccount/register/index.vue

@@ -4,19 +4,80 @@
 			{{basicInfo.name}}
 		</view>
 		<view class="two">
-			注册
+			<uni-forms ref="form" :model="form" :rules="rules" label-width="auto">
+				<uni-forms-item name="account">
+					<uni-easyinput v-model="form.account" placeholder="请输入登录账号" />
+				</uni-forms-item>
+				<uni-forms-item name="password">
+					<uni-easyinput type="password" v-model="form.password" placeholder="请输入登录密码" />
+				</uni-forms-item>
+				<uni-forms-item name="phone">
+					<uni-easyinput v-model="form.phone" placeholder="请输入联系电话" />
+				</uni-forms-item>
+				<uni-forms-item name="nick_name">
+					<uni-easyinput v-model="form.nick_name" placeholder="请输入账号昵称" />
+				</uni-forms-item>
+				<uni-forms-item name="gender">
+					<uni-data-checkbox v-model="form.gender" :localdata="genderList"
+						:map="{text:'label',value:'value'}" />
+				</uni-forms-item>
+				<uni-forms-item name="logo_url">
+					<upload :list="form.logo_url" name="logo_url" :count="1" @uplSuc="uplSuc" @uplDel="uplDel"></upload>
+				</uni-forms-item>
+			</uni-forms>
+			<view class="agree">
+				<checkbox-group @change="changeAgree">
+					<label>
+						<checkbox :checked="agree" />
+						<text @tap.stop="toAgree()">我已阅读并同意“用户协议”和“隐私政策”</text>
+					</label>
+				</checkbox-group>
+			</view>
+			<view class="btn">
+				<button size="mini" @tap="toSubmit('form')">提交登录</button>
+			</view>
 		</view>
-
 	</view>
 </template>
 
 <script>
+	import upload from "@/components/upload/index.vue";
 	export default {
+		components: {
+			upload,
+		},
 		data() {
 			return {
 				// 基本信息
 				basicInfo: {},
-
+				form: {
+					logo_url: [],
+				},
+				// 校验规则
+				rules: {
+					account: {
+						rules: [{
+							required: true,
+							errorMessage: '请输入登录账号'
+						}]
+					},
+					password: {
+						rules: [{
+							required: true,
+							errorMessage: '请输入登录密码'
+						}]
+					},
+					phone: {
+						rules: [{
+							required: true,
+							errorMessage: '请输入联系电话'
+						}]
+					},
+				},
+				// 用戶协议
+				agree: true,
+				// 性别
+				genderList: []
 			};
 		},
 		onLoad() {
@@ -25,6 +86,7 @@
 		onShow() {
 			const that = this;
 			that.searchBasic();
+			that.searchOther();
 		},
 		methods: {
 			searchBasic() {
@@ -37,7 +99,76 @@
 					}
 				})
 			},
-
+			// 图片上传
+			uplSuc(e) {
+				const that = this;
+				that.$set(that.form, `${e.name}`, [...that.form[e.name], e.data]);
+			},
+			// 图片删除
+			uplDel(e) {
+				const that = this;
+				let data = that.form[e.name];
+				let arr = data.filter((i, index) => index != e.data.index);
+				that.$set(that.form, `${e.name}`, arr);
+			},
+			// 提交注册
+			toSubmit(ref) {
+				const that = this;
+				let agree = that.agree;
+				that.$refs[ref].validate().then(async parmas => {
+					if (agree) {
+						let res = await that.$api('user', 'POST', parmas)
+						if (res.errcode == '0') {
+							if (res.errcode == '0') {
+								uni.showToast({
+									title: '账号注册成功',
+									icon: 'none'
+								})
+								uni.redirectTo({
+									url: '/pagesAccount/login/index'
+								})
+							}
+						} else {
+							uni.showToast({
+								title: res.errmsg,
+								icon: 'none'
+							})
+						}
+					} else {
+						uni.showToast({
+							title: '请阅读并同意用户协议和隐私政策',
+							icon: 'none'
+						})
+					}
+				}).catch(err => {
+					console.log('err', err);
+				})
+			},
+			// 同意隐私协议
+			changeAgree() {
+				const that = this;
+				let agree = true;
+				if (that.agree) agree = false;
+				that.$set(that, `agree`, agree);
+			},
+			// 查看隐私协议
+			toAgree() {
+				const that = this;
+				uni.navigateTo({
+					url: `/pagesAccount/other/agree`
+				})
+			},
+			// 查询其他信息
+			async searchOther() {
+				const that = this;
+				let res;
+				res = await that.$api('dictdata', 'GET', {
+					type: 'gender'
+				})
+				if (res.errcode == '0') {
+					that.$set(that, `genderList`, res.data)
+				}
+			}
 		}
 	}
 </script>
@@ -46,14 +177,37 @@
 	.content {
 		background-color: var(--rgb000);
 		padding: 0 2vw;
+		overflow-y: auto;
 
 		.one {
 			text-align: center;
 			font-size: 30px;
 			font-family: monospace;
 			color: var(--rgbfff);
-			padding: 10vw 0 10vw 0;
+			padding: 6vw 0;
+		}
+
+		.two {
+			margin: 0 0 4vw 0;
+
+			.btn {
+				padding: 2vw 0 0 0;
+				text-align: center;
+
+				button {
+					width: 80%;
+					background-color: var(--rgbfa4);
+					color: var(--rgbfff);
+					padding: 1vw 0;
+				}
+			}
 		}
+	}
 
+	.agree {
+		text-align: center;
+		font-size: 12px;
+		margin: 0 0 2vw 0;
+		color: var(--rgbfff);
 	}
 </style>

+ 60 - 29
pagesHome/account/index.vue

@@ -3,15 +3,17 @@
 		<view class="main">
 			<view class="one">
 				<view class="one_1">
-					<image class="image" :src="logo_url" mode="">
+					<image class="image"
+						:src="userInfo.logo_url&&userInfo.logo_url.length>0?userInfo.logo_url[0].url:''" mode="">
 					</image>
 				</view>
 				<view class="one_2">
 					<view class="name">
-						{{userInfo.name}}
+						{{userInfo.name||'暂无'}}
 					</view>
 					<view class="id">
-						ID:{{userInfo.account_id}}
+						<uni-icons type="phone-filled" size="15" color="var(--rgbfff)"></uni-icons>
+						:{{userInfo.phone||'暂无'}}
 					</view>
 				</view>
 				<view class="one_3" v-if="!userInfo._id">
@@ -19,7 +21,7 @@
 				</view>
 			</view>
 			<view class="two">
-				<view class="list" v-for="(item,index) in basicInfo.account_btn" :key="index">
+				<view class="list" v-for="(item,index) in basicInfo.account_btn" :key="index" @tap="toCommon(item)">
 					<image class="image" :src="item.img_url&&item.img_url.length>0?item.img_url[0].url:''" mode="">
 					</image>
 					<view class="name">
@@ -43,8 +45,6 @@
 				basicInfo: {},
 				// 用户信息
 				userInfo: {},
-				// 头像
-				logo_url: '',
 			};
 		},
 		onLoad() {
@@ -53,7 +53,6 @@
 		onShow() {
 			const that = this;
 			that.searchBasic();
-			that.search()
 		},
 		methods: {
 			searchBasic() {
@@ -62,37 +61,40 @@
 					key: 'basicInfo',
 					success: (res) => {
 						let data = res.data
+						data.account_btn = data.account_btn.sort((a, b) => {
+							return a.sort - b.sort
+						});
 						that.$set(that, `basicInfo`, data);
+						that.search()
 					}
 				})
 			},
 			search() {
 				const that = this;
 				let user = {
-					_id: '',
-					name: '自由天空',
-					account_id: '123456',
-					logo_url: [ //
-						{
-							id: "20230216100918",
-							name: "头像.jpg",
-							status: "success",
-							uid: 1676513358695,
-							uri: "/files/projectadmin/imgurl/20230216100918.jpg",
-							url: "http://47.93.34.200/files/projectadmin/imgurl/20230216100918.jpg"
-						}
-					]
-				}
-				that.$set(that, `userInfo`, user);
-				// 判断logo
-				let logo_url = '';
-				if (user.logo_url && user.logo_url.length > 0) {
-					logo_url = user.logo_url[0].url
-				} else {
-					logo_url = that.basicInfo.logo_url[0].url
+					name: that.basicInfo.name,
+					phone: 'test',
+					logo_url: that.basicInfo.logo_url
 				}
-				that.$set(that, `logo_url`, logo_url)
+				uni.getStorage({
+					key: 'token',
+					success: async (res) => {
+						let arr = that.$jwt(res.data);
+						let aee = await that.$api(`user/${arr._id}`, 'GET');
+						if (aee.errcode == '0') {
+							user._id = aee.data._id;
+							user.id = aee.data.id;
+							user.phone = aee.data.phone;
+							if (aee.data && aee.data.nick_name) user.name = aee.data.nick_name;
+							if (aee.data && aee.data.logo_url) user.logo_url = aee.data.logo_url;
 
+						}
+					},
+					fail: (err) => {
+						console.log(err);
+					}
+				})
+				that.$set(that, `userInfo`, user)
 			},
 			// 注册,登录
 			toLogin() {
@@ -100,6 +102,35 @@
 					url: '/pagesAccount/login/index'
 				})
 			},
+			// 功能按钮跳转
+			toCommon(e) {
+				const that = this;
+				if (e.is_jump == '0') {
+					if (e.nature == 'share') {
+						console.log('分享');
+					} else if (e.nature == 'logout') {
+						uni.removeStorage({
+							key: 'token',
+							success: function(res) {
+								uni.showToast({
+									title: '退出登录成功',
+									icon: 'none'
+								})
+								that.searchBasic()
+							},
+							fail: (err) => {
+								close(err)
+							}
+						});
+					}
+
+				} else if (e.is_jump == '1') {
+					that.toPath({
+						type: e.type,
+						route: e.route
+					})
+				}
+			},
 			// 跳转页面
 			toPath(e) {
 				let url = `/${e.route}`;

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

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

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

@@ -0,0 +1,821 @@
+<template>
+	<view class="uni-data-checklist" :style="{'margin-top':isTop+'px'}">
+		<template v-if="!isLocal">
+			<view class="uni-data-loading">
+				<uni-load-more v-if="!mixinDatacomErrorMessage" status="loading" iconType="snow" :iconSize="18" :content-text="contentText"></uni-load-more>
+				<text v-else>{{mixinDatacomErrorMessage}}</text>
+			</view>
+		</template>
+		<template v-else>
+			<checkbox-group v-if="multiple" class="checklist-group" :class="{'is-list':mode==='list' || wrap}" @change="chagne">
+				<label class="checklist-box" :class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']"
+				 :style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index">
+					<checkbox class="hidden" hidden :disabled="disabled || !!item.disabled" :value="item[map.value]+''" :checked="item.selected" />
+					<view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')" class="checkbox__inner"  :style="item.styleIcon">
+						<view class="checkbox__inner-icon"></view>
+					</view>
+					<view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}">
+						<text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text>
+						<view v-if="mode === 'list' && icon === 'right'" class="checkobx__list" :style="item.styleBackgroud"></view>
+					</view>
+				</label>
+			</checkbox-group>
+			<radio-group v-else class="checklist-group" :class="{'is-list':mode==='list','is-wrap':wrap}" @change="chagne">
+				<!-- -->
+				<label class="checklist-box" :class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']"
+				 :style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index">
+					<radio class="hidden" hidden :disabled="disabled || item.disabled" :value="item[map.value]+''" :checked="item.selected" />
+					<view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')" class="radio__inner"
+					 :style="item.styleBackgroud">
+						<view class="radio__inner-icon" :style="item.styleIcon"></view>
+					</view>
+					<view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}">
+						<text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text>
+						<view v-if="mode === 'list' && icon === 'right'" :style="item.styleRightIcon" class="checkobx__list"></view>
+					</view>
+				</label>
+			</radio-group>
+		</template>
+	</view>
+</template>
+
+<script>
+	/**
+	 * DataChecklist 数据选择器
+	 * @description 通过数据渲染 checkbox 和 radio
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
+	 * @property {String} mode = [default| list | button | tag] 显示模式
+	 * @value default  	默认横排模式
+	 * @value list		列表模式
+	 * @value button	按钮模式
+	 * @value tag 		标签模式
+	 * @property {Boolean} multiple = [true|false] 是否多选
+	 * @property {Array|String|Number} value 默认值
+	 * @property {Array} localdata 本地数据 ,格式 [{text:'',value:''}]
+	 * @property {Number|String} min 最小选择个数 ,multiple为true时生效
+	 * @property {Number|String} max 最大选择个数 ,multiple为true时生效
+	 * @property {Boolean} wrap 是否换行显示
+	 * @property {String} icon = [left|right]  list 列表模式下icon显示位置
+	 * @property {Boolean} selectedColor 选中颜色
+	 * @property {Boolean} emptyText 没有数据时显示的文字 ,本地数据无效
+	 * @property {Boolean} selectedTextColor 选中文本颜色,如不填写则自动显示
+	 * @property {Object} map 字段映射, 默认 map={text:'text',value:'value'}
+	 * @value left 左侧显示
+	 * @value right 右侧显示
+	 * @event {Function} change  选中发生变化触发
+	 */
+
+	export default {
+		name: 'uniDataChecklist',
+		mixins: [uniCloud.mixinDatacom || {}],
+		emits:['input','update:modelValue','change'],
+		props: {
+			mode: {
+				type: String,
+				default: 'default'
+			},
+
+			multiple: {
+				type: Boolean,
+				default: false
+			},
+			value: {
+				type: [Array, String, Number],
+				default () {
+					return ''
+				}
+			},
+			// TODO vue3
+			modelValue: {
+				type: [Array, String, Number],
+				default() {
+					return '';
+				}
+			},
+			localdata: {
+				type: Array,
+				default () {
+					return []
+				}
+			},
+			min: {
+				type: [Number, String],
+				default: ''
+			},
+			max: {
+				type: [Number, String],
+				default: ''
+			},
+			wrap: {
+				type: Boolean,
+				default: false
+			},
+			icon: {
+				type: String,
+				default: 'left'
+			},
+			selectedColor: {
+				type: String,
+				default: ''
+			},
+			selectedTextColor: {
+				type: String,
+				default: ''
+			},
+			emptyText:{
+				type: String,
+				default: '暂无数据'
+			},
+			disabled:{
+				type: Boolean,
+				default: false
+			},
+			map:{
+				type: Object,
+				default(){
+					return {
+						text:'text',
+						value:'value'
+					}
+				}
+			}
+		},
+		watch: {
+			localdata: {
+				handler(newVal) {
+					this.range = newVal
+					this.dataList = this.getDataList(this.getSelectedValue(newVal))
+				},
+				deep: true
+			},
+			mixinDatacomResData(newVal) {
+				this.range = newVal
+				this.dataList = this.getDataList(this.getSelectedValue(newVal))
+			},
+			value(newVal) {
+				this.dataList = this.getDataList(newVal)
+				// fix by mehaotian is_reset 在 uni-forms 中定义
+				// if(!this.is_reset){
+				// 	this.is_reset = false
+				// 	this.formItem && this.formItem.setValue(newVal)
+				// }
+			},
+			modelValue(newVal) {
+				this.dataList = this.getDataList(newVal);
+				// if(!this.is_reset){
+				// 	this.is_reset = false
+				// 	this.formItem && this.formItem.setValue(newVal)
+				// }
+			}
+		},
+		data() {
+			return {
+				dataList: [],
+				range: [],
+				contentText: {
+					contentdown: '查看更多',
+					contentrefresh: '加载中',
+					contentnomore: '没有更多'
+				},
+				isLocal:true,
+				styles: {
+					selectedColor: '#2979ff',
+					selectedTextColor: '#666',
+				},
+				isTop:0
+			};
+		},
+		computed:{
+			dataValue(){
+				if(this.value === '')return this.modelValue
+				if(this.modelValue === '') return this.value
+				return this.value
+			}
+		},
+		created() {
+			// this.form = this.getForm('uniForms')
+			// this.formItem = this.getForm('uniFormsItem')
+			// this.formItem && this.formItem.setValue(this.value)
+
+			// if (this.formItem) {
+			// 	this.isTop = 6
+			// 	if (this.formItem.name) {
+			// 		// 如果存在name添加默认值,否则formData 中不存在这个字段不校验
+			// 		if(!this.is_reset){
+			// 			this.is_reset = false
+			// 			this.formItem.setValue(this.dataValue)
+			// 		}
+			// 		this.rename = this.formItem.name
+			// 		this.form.inputChildrens.push(this)
+			// 	}
+			// }
+
+			if (this.localdata && this.localdata.length !== 0) {
+				this.isLocal = true
+				this.range = this.localdata
+				this.dataList = this.getDataList(this.getSelectedValue(this.range))
+			} else {
+				if (this.collection) {
+					this.isLocal = false
+					this.loadData()
+				}
+			}
+		},
+		methods: {
+			loadData() {
+				this.mixinDatacomGet().then(res=>{
+					this.mixinDatacomResData = res.result.data
+					if(this.mixinDatacomResData.length === 0){
+						this.isLocal = false
+						this.mixinDatacomErrorMessage = this.emptyText
+					}else{
+						this.isLocal = true
+					}
+				}).catch(err=>{
+					this.mixinDatacomErrorMessage = err.message
+				})
+			},
+			/**
+			 * 获取父元素实例
+			 */
+			getForm(name = 'uniForms') {
+				let parent = this.$parent;
+				let parentName = parent.$options.name;
+				while (parentName !== name) {
+					parent = parent.$parent;
+					if (!parent) return false
+					parentName = parent.$options.name;
+				}
+				return parent;
+			},
+			chagne(e) {
+				const values = e.detail.value
+
+				let detail = {
+					value: [],
+					data: []
+				}
+
+				if (this.multiple) {
+					this.range.forEach(item => {
+
+						if (values.includes(item[this.map.value] + '')) {
+							detail.value.push(item[this.map.value])
+							detail.data.push(item)
+						}
+					})
+				} else {
+					const range = this.range.find(item => (item[this.map.value] + '') === values)
+					if (range) {
+						detail = {
+							value: range[this.map.value],
+							data: range
+						}
+					}
+				}
+				// this.formItem && this.formItem.setValue(detail.value)
+				// TODO 兼容 vue2
+				this.$emit('input', detail.value);
+				// // TOTO 兼容 vue3
+				this.$emit('update:modelValue', detail.value);
+				this.$emit('change', {
+					detail
+				})
+				if (this.multiple) {
+					// 如果 v-model 没有绑定 ,则走内部逻辑
+					// if (this.value.length === 0) {
+					this.dataList = this.getDataList(detail.value, true)
+					// }
+				} else {
+					this.dataList = this.getDataList(detail.value)
+				}
+			},
+
+			/**
+			 * 获取渲染的新数组
+			 * @param {Object} value 选中内容
+			 */
+			getDataList(value) {
+				// 解除引用关系,破坏原引用关系,避免污染源数据
+				let dataList = JSON.parse(JSON.stringify(this.range))
+				let list = []
+				if (this.multiple) {
+					if (!Array.isArray(value)) {
+						value = []
+					}
+				}
+				dataList.forEach((item, index) => {
+					item.disabled = item.disable || item.disabled || false
+					if (this.multiple) {
+						if (value.length > 0) {
+							let have = value.find(val => val === item[this.map.value])
+							item.selected = have !== undefined
+						} else {
+							item.selected = false
+						}
+					} else {
+						item.selected = value === item[this.map.value]
+					}
+
+					list.push(item)
+				})
+				return this.setRange(list)
+			},
+			/**
+			 * 处理最大最小值
+			 * @param {Object} list
+			 */
+			setRange(list) {
+				let selectList = list.filter(item => item.selected)
+				let min = Number(this.min) || 0
+				let max = Number(this.max) || ''
+				list.forEach((item, index) => {
+					if (this.multiple) {
+						if (selectList.length <= min) {
+							let have = selectList.find(val => val[this.map.value] === item[this.map.value])
+							if (have !== undefined) {
+								item.disabled = true
+							}
+						}
+
+						if (selectList.length >= max && max !== '') {
+							let have = selectList.find(val => val[this.map.value] === item[this.map.value])
+							if (have === undefined) {
+								item.disabled = true
+							}
+						}
+					}
+					this.setStyles(item, index)
+					list[index] = item
+				})
+				return list
+			},
+			/**
+			 * 设置 class
+			 * @param {Object} item
+			 * @param {Object} index
+			 */
+			setStyles(item, index) {
+				//  设置自定义样式
+				item.styleBackgroud = this.setStyleBackgroud(item)
+				item.styleIcon = this.setStyleIcon(item)
+				item.styleIconText = this.setStyleIconText(item)
+				item.styleRightIcon = this.setStyleRightIcon(item)
+			},
+
+			/**
+			 * 获取选中值
+			 * @param {Object} range
+			 */
+			getSelectedValue(range) {
+				if (!this.multiple) return this.dataValue
+				let selectedArr = []
+				range.forEach((item) => {
+					if (item.selected) {
+						selectedArr.push(item[this.map.value])
+					}
+				})
+				return this.dataValue.length > 0 ? this.dataValue : selectedArr
+			},
+
+			/**
+			 * 设置背景样式
+			 */
+			setStyleBackgroud(item) {
+				let styles = {}
+				let selectedColor = this.selectedColor?this.selectedColor:'#2979ff'
+				if (this.selectedColor) {
+					if (this.mode !== 'list') {
+						styles['border-color'] = item.selected?selectedColor:'#DCDFE6'
+					}
+					if (this.mode === 'tag') {
+						styles['background-color'] = item.selected? selectedColor:'#f5f5f5'
+					}
+				}
+				let classles = ''
+				for (let i in styles) {
+					classles += `${i}:${styles[i]};`
+				}
+				return classles
+			},
+			setStyleIcon(item) {
+				let styles = {}
+				let classles = ''
+				if (this.selectedColor) {
+					let selectedColor = this.selectedColor?this.selectedColor:'#2979ff'
+					styles['background-color'] = item.selected?selectedColor:'#fff'
+					styles['border-color'] = item.selected?selectedColor:'#DCDFE6'
+					
+					if(!item.selected && item.disabled){
+						styles['background-color'] = '#F2F6FC'
+						styles['border-color'] = item.selected?selectedColor:'#DCDFE6'
+					}
+				}
+				for (let i in styles) {
+					classles += `${i}:${styles[i]};`
+				}
+				return classles
+			},
+			setStyleIconText(item) {
+				let styles = {}
+				let classles = ''
+				if (this.selectedColor) {
+					let selectedColor = this.selectedColor?this.selectedColor:'#2979ff'
+					if (this.mode === 'tag') {
+						styles.color = item.selected?(this.selectedTextColor?this.selectedTextColor:'#fff'):'#666'
+					} else {
+						styles.color = item.selected?(this.selectedTextColor?this.selectedTextColor:selectedColor):'#666'
+					}
+					if(!item.selected && item.disabled){
+						styles.color = '#999'
+					}
+				}
+				for (let i in styles) {
+					classles += `${i}:${styles[i]};`
+				}
+				return classles
+			},
+			setStyleRightIcon(item) {
+				let styles = {}
+				let classles = ''
+				if (this.mode === 'list') {
+					styles['border-color'] = item.selected?this.styles.selectedColor:'#DCDFE6'
+				}
+				for (let i in styles) {
+					classles += `${i}:${styles[i]};`
+				}
+
+				return classles
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	$uni-primary: #2979ff !default;
+	$border-color: #DCDFE6;
+	$disable:0.4;
+
+	@mixin flex {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+	}
+
+	.uni-data-loading {
+		@include flex;
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		height: 36px;
+		padding-left: 10px;
+		color: #999;
+	}
+
+	.uni-data-checklist {
+		position: relative;
+		z-index: 0;
+		flex: 1;
+		// 多选样式
+		.checklist-group {
+			@include flex;
+			flex-direction: row;
+			flex-wrap: wrap;
+
+			&.is-list {
+				flex-direction: column;
+			}
+
+			.checklist-box {
+				@include flex;
+				flex-direction: row;
+				align-items: center;
+				position: relative;
+				margin: 5px 0;
+				margin-right: 25px;
+
+				.hidden {
+					position: absolute;
+					opacity: 0;
+				}
+
+				// 文字样式
+				.checklist-content {
+					@include flex;
+					flex: 1;
+					flex-direction: row;
+					align-items: center;
+					justify-content: space-between;
+					.checklist-text {
+						font-size: 14px;
+						color: #666;
+						margin-left: 5px;
+						line-height: 14px;
+					}
+
+					.checkobx__list {
+						border-right-width: 1px;
+						border-right-color: #007aff;
+						border-right-style: solid;
+						border-bottom-width:1px;
+						border-bottom-color: #007aff;
+						border-bottom-style: solid;
+						height: 12px;
+						width: 6px;
+						left: -5px;
+						transform-origin: center;
+						transform: rotate(45deg);
+						opacity: 0;
+					}
+				}
+
+				// 多选样式
+				.checkbox__inner {
+					/* #ifndef APP-NVUE */
+					flex-shrink: 0;
+					box-sizing: border-box;
+					/* #endif */
+					position: relative;
+					width: 16px;
+					height: 16px;
+					border: 1px solid $border-color;
+					border-radius: 4px;
+					background-color: #fff;
+					z-index: 1;
+					.checkbox__inner-icon {
+						position: absolute;
+						/* #ifdef APP-NVUE */
+						top: 2px;
+						/* #endif */
+						/* #ifndef APP-NVUE */
+						top: 1px;
+						/* #endif */
+						left: 5px;
+						height: 8px;
+						width: 4px;
+						border-right-width: 1px;
+						border-right-color: #fff;
+						border-right-style: solid;
+						border-bottom-width:1px ;
+						border-bottom-color: #fff;
+						border-bottom-style: solid;
+						opacity: 0;
+						transform-origin: center;
+						transform: rotate(40deg);
+					}
+				}
+
+				// 单选样式
+				.radio__inner {
+					@include flex;
+					/* #ifndef APP-NVUE */
+					flex-shrink: 0;
+					box-sizing: border-box;
+					/* #endif */
+					justify-content: center;
+					align-items: center;
+					position: relative;
+					width: 16px;
+					height: 16px;
+					border: 1px solid $border-color;
+					border-radius: 16px;
+					background-color: #fff;
+					z-index: 1;
+
+					.radio__inner-icon {
+						width: 8px;
+						height: 8px;
+						border-radius: 10px;
+						opacity: 0;
+					}
+				}
+
+				// 默认样式
+				&.is--default {
+
+					// 禁用
+					&.is-disable {
+						/* #ifdef H5 */
+						cursor: not-allowed;
+						/* #endif */
+						.checkbox__inner {
+							background-color: #F2F6FC;
+							border-color: $border-color;
+							/* #ifdef H5 */
+							cursor: not-allowed;
+							/* #endif */
+						}
+
+						.radio__inner {
+							background-color: #F2F6FC;
+							border-color: $border-color;
+						}
+						.checklist-text {
+							color: #999;
+						}
+					}
+
+					// 选中
+					&.is-checked {
+						.checkbox__inner {
+							border-color: $uni-primary;
+							background-color: $uni-primary;
+
+							.checkbox__inner-icon {
+								opacity: 1;
+								transform: rotate(45deg);
+							}
+						}
+						.radio__inner {
+							border-color: $uni-primary;
+							.radio__inner-icon {
+								opacity: 1;
+								background-color: $uni-primary;
+							}
+						}
+						.checklist-text {
+							color: $uni-primary;
+						}
+						// 选中禁用
+						&.is-disable {
+							.checkbox__inner {
+								opacity: $disable;
+							}
+
+							.checklist-text {
+								opacity: $disable;
+							}
+							.radio__inner {
+								opacity: $disable;
+							}
+						}
+					}
+				}
+
+				// 按钮样式
+				&.is--button {
+					margin-right: 10px;
+					padding: 5px 10px;
+					border: 1px $border-color solid;
+					border-radius: 3px;
+					transition: border-color 0.2s;
+
+					// 禁用
+					&.is-disable {
+						/* #ifdef H5 */
+						cursor: not-allowed;
+						/* #endif */
+						border: 1px #eee solid;
+						opacity: $disable;
+						.checkbox__inner {
+							background-color: #F2F6FC;
+							border-color: $border-color;
+							/* #ifdef H5 */
+							cursor: not-allowed;
+							/* #endif */
+						}
+						.radio__inner {
+							background-color: #F2F6FC;
+							border-color: $border-color;
+							/* #ifdef H5 */
+							cursor: not-allowed;
+							/* #endif */
+						}
+						.checklist-text {
+							color: #999;
+						}
+					}
+
+					&.is-checked {
+						border-color: $uni-primary;
+						.checkbox__inner {
+							border-color: $uni-primary;
+							background-color: $uni-primary;
+							.checkbox__inner-icon {
+								opacity: 1;
+								transform: rotate(45deg);
+							}
+						}
+
+						.radio__inner {
+							border-color: $uni-primary;
+
+							.radio__inner-icon {
+								opacity: 1;
+								background-color: $uni-primary;
+							}
+						}
+
+						.checklist-text {
+							color: $uni-primary;
+						}
+
+						// 选中禁用
+						&.is-disable {
+							opacity: $disable;
+						}
+					}
+				}
+
+				// 标签样式
+				&.is--tag {
+					margin-right: 10px;
+					padding: 5px 10px;
+					border: 1px $border-color solid;
+					border-radius: 3px;
+					background-color: #f5f5f5;
+
+					.checklist-text {
+						margin: 0;
+						color: #666;
+					}
+
+					// 禁用
+					&.is-disable {
+						/* #ifdef H5 */
+						cursor: not-allowed;
+						/* #endif */
+						opacity: $disable;
+					}
+
+					&.is-checked {
+						background-color: $uni-primary;
+						border-color: $uni-primary;
+
+						.checklist-text {
+							color: #fff;
+						}
+					}
+				}
+				// 列表样式
+				&.is--list {
+					/* #ifndef APP-NVUE */
+					display: flex;
+					/* #endif */
+					padding: 10px 15px;
+					padding-left: 0;
+					margin: 0;
+
+					&.is-list-border {
+						border-top: 1px #eee solid;
+					}
+
+					// 禁用
+					&.is-disable {
+						/* #ifdef H5 */
+						cursor: not-allowed;
+						/* #endif */
+						.checkbox__inner {
+							background-color: #F2F6FC;
+							border-color: $border-color;
+							/* #ifdef H5 */
+							cursor: not-allowed;
+							/* #endif */
+						}
+						.checklist-text {
+							color: #999;
+						}
+					}
+
+					&.is-checked {
+						.checkbox__inner {
+							border-color: $uni-primary;
+							background-color: $uni-primary;
+
+							.checkbox__inner-icon {
+								opacity: 1;
+								transform: rotate(45deg);
+							}
+						}
+						.radio__inner {
+							.radio__inner-icon {
+								opacity: 1;
+							}
+						}
+						.checklist-text {
+							color: $uni-primary;
+						}
+
+						.checklist-content {
+							.checkobx__list {
+								opacity: 1;
+								border-color: $uni-primary;
+							}
+						}
+
+						// 选中禁用
+						&.is-disable {
+							.checkbox__inner {
+								opacity: $disable;
+							}
+
+							.checklist-text {
+								opacity: $disable;
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+</style>

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

@@ -0,0 +1,84 @@
+{
+  "id": "uni-data-checkbox",
+  "displayName": "uni-data-checkbox 数据选择器",
+  "version": "1.0.3",
+  "description": "通过数据驱动的单选框和复选框",
+  "keywords": [
+    "uni-ui",
+    "checkbox",
+    "单选",
+    "多选",
+    "单选多选"
+],
+  "repository": "https://github.com/dcloudio/uni-ui",
+  "engines": {
+    "HBuilderX": "^3.1.1"
+  },
+  "directories": {
+    "example": "../../temps/example_temps"
+  },
+"dcloudext": {
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "无",
+      "permissions": "无"
+    },
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
+    "type": "component-vue"
+  },
+  "uni_modules": {
+    "dependencies": ["uni-load-more","uni-scss"],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y"
+      },
+      "client": {
+        "App": {
+          "app-vue": "y",
+          "app-nvue": "y"
+        },
+        "H5-mobile": {
+          "Safari": "y",
+          "Android Browser": "y",
+          "微信浏览器(Android)": "y",
+          "QQ浏览器(Android)": "y"
+        },
+        "H5-pc": {
+          "Chrome": "y",
+          "IE": "y",
+          "Edge": "y",
+          "Firefox": "y",
+          "Safari": "y"
+        },
+        "小程序": {
+          "微信": "y",
+          "阿里": "y",
+          "百度": "y",
+          "字节跳动": "y",
+          "QQ": "y"
+        },
+        "快应用": {
+          "华为": "u",
+          "联盟": "u"
+        },
+        "Vue": {
+            "vue2": "y",
+            "vue3": "y"
+        }
+      }
+    }
+  }
+}

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

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

+ 92 - 0
uni_modules/uni-forms/changelog.md

@@ -0,0 +1,92 @@
+## 1.4.9(2023-02-10)
+- 修复 required 参数无法动态绑定
+## 1.4.8(2022-08-23)
+- 优化 根据 rules 自动添加 required 的问题
+## 1.4.7(2022-08-22)
+- 修复 item 未设置 require 属性,rules 设置 require 后,星号也显示的 bug,详见:[https://ask.dcloud.net.cn/question/151540](https://ask.dcloud.net.cn/question/151540)
+## 1.4.6(2022-07-13)
+- 修复 model 需要校验的值没有声明对应字段时,导致第一次不触发校验的bug
+## 1.4.5(2022-07-05)
+- 新增 更多表单示例
+- 优化 子表单组件过期提示的问题
+- 优化 子表单组件uni-datetime-picker、uni-data-select、uni-data-picker的显示样式
+## 1.4.4(2022-07-04)
+- 更新 删除组件日志
+## 1.4.3(2022-07-04)
+- 修复 由 1.4.0 引发的 label 插槽不生效的bug
+## 1.4.2(2022-07-04)
+- 修复 子组件找不到 setValue 报错的bug
+## 1.4.1(2022-07-04)
+- 修复 uni-data-picker 在 uni-forms-item 中报错的bug
+- 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug
+## 1.4.0(2022-06-30)
+- 【重要】组件逻辑重构,部分用法用旧版本不兼容,请注意兼容问题
+- 【重要】组件使用 Provide/Inject 方式注入依赖,提供了自定义表单组件调用 uni-forms 校验表单的能力
+- 新增 model 属性,等同于原 value/modelValue 属性,旧属性即将废弃
+- 新增 validateTrigger 属性的 blur 值,仅 uni-easyinput 生效
+- 新增 onFieldChange 方法,可以对子表单进行校验,可替代binddata方法
+- 新增 子表单的 setRules 方法,配合自定义校验函数使用
+- 新增 uni-forms-item 的 setRules 方法,配置动态表单使用可动态更新校验规则
+- 优化 动态表单校验方式,废弃拼接name的方式
+## 1.3.3(2022-06-22)
+- 修复 表单校验顺序无序问题
+## 1.3.2(2021-12-09)
+-
+## 1.3.1(2021-11-19)
+- 修复 label 插槽不生效的bug
+## 1.3.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-forms](https://uniapp.dcloud.io/component/uniui/uni-forms)
+## 1.2.7(2021-08-13)
+- 修复 没有添加校验规则的字段依然报错的Bug
+## 1.2.6(2021-08-11)
+- 修复 重置表单错误信息无法清除的问题
+## 1.2.5(2021-08-11)
+- 优化 组件文档
+## 1.2.4(2021-08-11)
+- 修复 表单验证只生效一次的问题
+## 1.2.3(2021-07-30)
+- 优化 vue3下事件警告的问题
+## 1.2.2(2021-07-26)
+- 修复 vue2 下条件编译导致destroyed生命周期失效的Bug
+- 修复 1.2.1 引起的示例在小程序平台报错的Bug
+## 1.2.1(2021-07-22)
+- 修复 动态校验表单,默认值为空的情况下校验失效的Bug
+- 修复 不指定name属性时,运行报错的Bug
+- 优化 label默认宽度从65调整至70,使required为true且四字时不换行
+- 优化 组件示例,新增动态校验示例代码
+- 优化 组件文档,使用方式更清晰
+## 1.2.0(2021-07-13)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.1.2(2021-06-25)
+- 修复 pattern 属性在微信小程序平台无效的问题
+## 1.1.1(2021-06-22)
+- 修复 validate-trigger属性为submit且err-show-type属性为toast时不能弹出的Bug
+## 1.1.0(2021-06-22)
+- 修复 只写setRules方法而导致校验不生效的Bug
+- 修复 由上个办法引发的错误提示文字错位的Bug
+## 1.0.48(2021-06-21)
+- 修复 不设置 label 属性 ,无法设置label插槽的问题
+## 1.0.47(2021-06-21)
+- 修复 不设置label属性,label-width属性不生效的bug
+- 修复 setRules 方法与rules属性冲突的问题
+## 1.0.46(2021-06-04)
+- 修复 动态删减数据导致报错的问题
+## 1.0.45(2021-06-04)
+- 新增 modelValue 属性 ,value 即将废弃
+## 1.0.44(2021-06-02)
+- 新增 uni-forms-item 可以设置单独的 rules
+- 新增 validate 事件增加 keepitem 参数,可以选择那些字段不过滤
+- 优化 submit 事件重命名为 validate
+## 1.0.43(2021-05-12)
+- 新增 组件示例地址
+## 1.0.42(2021-04-30)
+- 修复 自定义检验器失效的问题
+## 1.0.41(2021-03-05)
+- 更新 校验器
+- 修复 表单规则设置类型为 number 的情况下,值为0校验失败的Bug
+## 1.0.40(2021-03-04)
+- 修复 动态显示uni-forms-item的情况下,submit 方法获取值错误的Bug
+## 1.0.39(2021-02-05)
+- 调整为uni_modules目录规范
+- 修复 校验器传入 int 等类型 ,返回String类型的Bug

+ 627 - 0
uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue

@@ -0,0 +1,627 @@
+<template>
+	<view class="uni-forms-item"
+		:class="['is-direction-' + localLabelPos ,border?'uni-forms-item--border':'' ,border && isFirstBorder?'is-first-border':'']">
+		<slot name="label">
+			<view class="uni-forms-item__label" :class="{'no-label':!label && !required}"
+				:style="{width:localLabelWidth,justifyContent: localLabelAlign}">
+				<text v-if="required" class="is-required">*</text>
+				<text>{{label}}</text>
+			</view>
+		</slot>
+		<!-- #ifndef APP-NVUE -->
+		<view class="uni-forms-item__content">
+			<slot></slot>
+			<view class="uni-forms-item__error" :class="{'msg--active':msg}">
+				<text>{{msg}}</text>
+			</view>
+		</view>
+		<!-- #endif -->
+		<!-- #ifdef APP-NVUE -->
+		<view class="uni-forms-item__nuve-content">
+			<view class="uni-forms-item__content">
+				<slot></slot>
+			</view>
+			<view class="uni-forms-item__error" :class="{'msg--active':msg}">
+				<text class="error-text">{{msg}}</text>
+			</view>
+		</view>
+		<!-- #endif -->
+	</view>
+</template>
+
+<script>
+	/**
+	 * uni-fomrs-item 表单子组件
+	 * @description uni-fomrs-item 表单子组件,提供了基础布局已经校验能力
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=2773
+	 * @property {Boolean} required 是否必填,左边显示红色"*"号
+	 * @property {String } 	label 				输入框左边的文字提示
+	 * @property {Number } 	labelWidth 			label的宽度,单位px(默认65)
+	 * @property {String } 	labelAlign = [left|center|right] label的文字对齐方式(默认left)
+	 * 	@value left		label 左侧显示
+	 * 	@value center	label 居中
+	 * 	@value right	label 右侧对齐
+	 * @property {String } 	errorMessage 		显示的错误提示内容,如果为空字符串或者false,则不显示错误信息
+	 * @property {String } 	name 				表单域的属性名,在使用校验规则时必填
+	 * @property {String } 	leftIcon 			【1.4.0废弃】label左边的图标,限 uni-ui 的图标名称
+	 * @property {String } 	iconColor 		【1.4.0废弃】左边通过icon配置的图标的颜色(默认#606266)
+	 * @property {String} validateTrigger = [bind|submit|blur]	【1.4.0废弃】校验触发器方式 默认 submit
+	 * 	@value bind 	发生变化时触发
+	 * 	@value submit 提交时触发
+	 * 	@value blur 	失去焦点触发
+	 * @property {String } 	labelPosition = [top|left] 【1.4.0废弃】label的文字的位置(默认left)
+	 * 	@value top	顶部显示 label
+	 * 	@value left	左侧显示 label
+	 */
+
+	export default {
+		name: 'uniFormsItem',
+		options: {
+			virtualHost: true
+		},
+		provide() {
+			return {
+				uniFormItem: this
+			}
+		},
+		inject: {
+			form: {
+				from: 'uniForm',
+				default: null
+			},
+		},
+		props: {
+			// 表单校验规则
+			rules: {
+				type: Array,
+				default () {
+					return null;
+				}
+			},
+			// 表单域的属性名,在使用校验规则时必填
+			name: {
+				type: [String, Array],
+				default: ''
+			},
+			required: {
+				type: Boolean,
+				default: false
+			},
+			label: {
+				type: String,
+				default: ''
+			},
+			// label的宽度 ,默认 80
+			labelWidth: {
+				type: [String, Number],
+				default: ''
+			},
+			// label 居中方式,默认 left 取值 left/center/right
+			labelAlign: {
+				type: String,
+				default: ''
+			},
+			// 强制显示错误信息
+			errorMessage: {
+				type: [String, Boolean],
+				default: ''
+			},
+			// 1.4.0 弃用,统一使用 form 的校验时机
+			// validateTrigger: {
+			// 	type: String,
+			// 	default: ''
+			// },
+			// 1.4.0 弃用,统一使用 form 的label 位置
+			// labelPosition: {
+			// 	type: String,
+			// 	default: ''
+			// },
+			// 1.4.0 以下属性已经废弃,请使用  #label 插槽代替
+			leftIcon: String,
+			iconColor: {
+				type: String,
+				default: '#606266'
+			},
+		},
+		data() {
+			return {
+				errMsg: '',
+				userRules: null,
+				localLabelAlign: 'left',
+				localLabelWidth: '65px',
+				localLabelPos: 'left',
+				border: false,
+				isFirstBorder: false,
+			};
+		},
+		computed: {
+			// 处理错误信息
+			msg() {
+				return this.errorMessage || this.errMsg;
+			}
+		},
+		watch: {
+			// 规则发生变化通知子组件更新
+			'form.formRules'(val) {
+				// TODO 处理头条vue3 watch不生效的问题
+				// #ifndef MP-TOUTIAO
+				this.init()
+				// #endif
+			},
+			'form.labelWidth'(val) {
+				// 宽度
+				this.localLabelWidth = this._labelWidthUnit(val)
+
+			},
+			'form.labelPosition'(val) {
+				// 标签位置
+				this.localLabelPos = this._labelPosition()
+			},
+			'form.labelAlign'(val) {
+
+			}
+		},
+		created() {
+			this.init(true)
+			if (this.name && this.form) {
+				// TODO 处理头条vue3 watch不生效的问题
+				// #ifdef MP-TOUTIAO
+				this.$watch('form.formRules', () => {
+					this.init()
+				})
+				// #endif
+
+				// 监听变化
+				this.$watch(
+					() => {
+						const val = this.form._getDataValue(this.name, this.form.localData)
+						return val
+					},
+					(value, oldVal) => {
+						const isEqual = this.form._isEqual(value, oldVal)
+						// 简单判断前后值的变化,只有发生变化才会发生校验
+						// TODO  如果 oldVal = undefined ,那么大概率是源数据里没有值导致 ,这个情况不哦校验 ,可能不严谨 ,需要在做观察
+						// fix by mehaotian 暂时取消 && oldVal !== undefined ,如果formData 中不存在,可能会不校验
+						if (!isEqual) {
+							const val = this.itemSetValue(value)
+							this.onFieldChange(val, false)
+						}
+					}, {
+						immediate: false
+					}
+				);
+			}
+
+		},
+		// #ifndef VUE3
+		destroyed() {
+			if (this.__isUnmounted) return
+			this.unInit()
+		},
+		// #endif
+		// #ifdef VUE3
+		unmounted() {
+			this.__isUnmounted = true
+			this.unInit()
+		},
+		// #endif
+		methods: {
+			/**
+			 * 外部调用方法
+			 * 设置规则 ,主要用于小程序自定义检验规则
+			 * @param {Array} rules 规则源数据
+			 */
+			setRules(rules = null) {
+				this.userRules = rules
+				this.init(false)
+			},
+			// 兼容老版本表单组件
+			setValue() {
+				// console.log('setValue 方法已经弃用,请使用最新版本的 uni-forms 表单组件以及其他关联组件。');
+			},
+			/**
+			 * 外部调用方法
+			 * 校验数据
+			 * @param {any} value 需要校验的数据
+			 * @param {boolean} 是否立即校验
+			 * @return {Array|null} 校验内容
+			 */
+			async onFieldChange(value, formtrigger = true) {
+				const {
+					formData,
+					localData,
+					errShowType,
+					validateCheck,
+					validateTrigger,
+					_isRequiredField,
+					_realName
+				} = this.form
+				const name = _realName(this.name)
+				if (!value) {
+					value = this.form.formData[name]
+				}
+				// fixd by mehaotian 不在校验前清空信息,解决闪屏的问题
+				// this.errMsg = '';
+
+				// fix by mehaotian 解决没有检验规则的情况下,抛出错误的问题
+				const ruleLen = this.itemRules.rules && this.itemRules.rules.length
+				if (!this.validator || !ruleLen || ruleLen === 0) return;
+
+				// 检验时机
+				// let trigger = this.isTrigger(this.itemRules.validateTrigger, this.validateTrigger, validateTrigger);
+				const isRequiredField = _isRequiredField(this.itemRules.rules || []);
+				let result = null;
+				// 只有等于 bind 时 ,才能开启时实校验
+				if (validateTrigger === 'bind' || formtrigger) {
+					// 校验当前表单项
+					result = await this.validator.validateUpdate({
+							[name]: value
+						},
+						formData
+					);
+
+					// 判断是否必填,非必填,不填不校验,填写才校验 ,暂时只处理 undefined  和空的情况
+					if (!isRequiredField && (value === undefined || value === '')) {
+						result = null;
+					}
+
+					// 判断错误信息显示类型
+					if (result && result.errorMessage) {
+						if (errShowType === 'undertext') {
+							// 获取错误信息
+							this.errMsg = !result ? '' : result.errorMessage;
+						}
+						if (errShowType === 'toast') {
+							uni.showToast({
+								title: result.errorMessage || '校验错误',
+								icon: 'none'
+							});
+						}
+						if (errShowType === 'modal') {
+							uni.showModal({
+								title: '提示',
+								content: result.errorMessage || '校验错误'
+							});
+						}
+					} else {
+						this.errMsg = ''
+					}
+					// 通知 form 组件更新事件
+					validateCheck(result ? result : null)
+				} else {
+					this.errMsg = ''
+				}
+				return result ? result : null;
+			},
+			/**
+			 * 初始组件数据
+			 */
+			init(type = false) {
+				const {
+					validator,
+					formRules,
+					childrens,
+					formData,
+					localData,
+					_realName,
+					labelWidth,
+					_getDataValue,
+					_setDataValue
+				} = this.form || {}
+				// 对齐方式
+				this.localLabelAlign = this._justifyContent()
+				// 宽度
+				this.localLabelWidth = this._labelWidthUnit(labelWidth)
+				// 标签位置
+				this.localLabelPos = this._labelPosition()
+				// 将需要校验的子组件加入form 队列
+				this.form && type && childrens.push(this)
+
+				if (!validator || !formRules) return
+				// 判断第一个 item
+				if (!this.form.isFirstBorder) {
+					this.form.isFirstBorder = true;
+					this.isFirstBorder = true;
+				}
+
+				// 判断 group 里的第一个 item
+				if (this.group) {
+					if (!this.group.isFirstBorder) {
+						this.group.isFirstBorder = true;
+						this.isFirstBorder = true;
+					}
+				}
+				this.border = this.form.border;
+				// 获取子域的真实名称
+				const name = _realName(this.name)
+				const itemRule = this.userRules || this.rules
+				if (typeof formRules === 'object' && itemRule) {
+					// 子规则替换父规则
+					formRules[name] = {
+						rules: itemRule
+					}
+					validator.updateSchema(formRules);
+				}
+				// 注册校验规则
+				const itemRules = formRules[name] || {}
+				this.itemRules = itemRules
+				// 注册校验函数
+				this.validator = validator
+				// 默认值赋予
+				this.itemSetValue(_getDataValue(this.name, localData))
+			},
+			unInit() {
+				if (this.form) {
+					const {
+						childrens,
+						formData,
+						_realName
+					} = this.form
+					childrens.forEach((item, index) => {
+						if (item === this) {
+							this.form.childrens.splice(index, 1)
+							delete formData[_realName(item.name)]
+						}
+					})
+				}
+			},
+			// 设置item 的值
+			itemSetValue(value) {
+				const name = this.form._realName(this.name)
+				const rules = this.itemRules.rules || []
+				const val = this.form._getValue(name, value, rules)
+				this.form._setDataValue(name, this.form.formData, val)
+				return val
+			},
+
+			/**
+			 * 移除该表单项的校验结果
+			 */
+			clearValidate() {
+				this.errMsg = '';
+			},
+
+			// 是否显示星号
+			_isRequired() {
+				// TODO 不根据规则显示 星号,考虑后续兼容
+				// if (this.form) {
+				// 	if (this.form._isRequiredField(this.itemRules.rules || []) && this.required) {
+				// 		return true
+				// 	}
+				// 	return false
+				// }
+				return this.required
+			},
+
+			// 处理对齐方式
+			_justifyContent() {
+				if (this.form) {
+					const {
+						labelAlign
+					} = this.form
+					let labelAli = this.labelAlign ? this.labelAlign : labelAlign;
+					if (labelAli === 'left') return 'flex-start';
+					if (labelAli === 'center') return 'center';
+					if (labelAli === 'right') return 'flex-end';
+				}
+				return 'flex-start';
+			},
+			// 处理 label宽度单位 ,继承父元素的值
+			_labelWidthUnit(labelWidth) {
+
+				// if (this.form) {
+				// 	const {
+				// 		labelWidth
+				// 	} = this.form
+				return this.num2px(this.labelWidth ? this.labelWidth : (labelWidth || (this.label ? 65 : 'auto')))
+				// }
+				// return '65px'
+			},
+			// 处理 label 位置
+			_labelPosition() {
+				if (this.form) return this.form.labelPosition || 'left'
+				return 'left'
+
+			},
+
+			/**
+			 * 触发时机
+			 * @param {Object} rule 当前规则内时机
+			 * @param {Object} itemRlue 当前组件时机
+			 * @param {Object} parentRule 父组件时机
+			 */
+			isTrigger(rule, itemRlue, parentRule) {
+				//  bind  submit
+				if (rule === 'submit' || !rule) {
+					if (rule === undefined) {
+						if (itemRlue !== 'bind') {
+							if (!itemRlue) {
+								return parentRule === '' ? 'bind' : 'submit';
+							}
+							return 'submit';
+						}
+						return 'bind';
+					}
+					return 'submit';
+				}
+				return 'bind';
+			},
+			num2px(num) {
+				if (typeof num === 'number') {
+					return `${num}px`
+				}
+				return num
+			}
+		}
+	};
+</script>
+
+<style lang="scss">
+	.uni-forms-item {
+		position: relative;
+		display: flex;
+		/* #ifdef APP-NVUE */
+		// 在 nvue 中,使用 margin-bottom error 信息会被隐藏
+		padding-bottom: 22px;
+		/* #endif */
+		/* #ifndef APP-NVUE */
+		margin-bottom: 22px;
+		/* #endif */
+		flex-direction: row;
+
+		&__label {
+			display: flex;
+			flex-direction: row;
+			align-items: center;
+			text-align: left;
+			font-size: 14px;
+			color: #606266;
+			height: 36px;
+			padding: 0 12px 0 0;
+			/* #ifndef APP-NVUE */
+			vertical-align: middle;
+			flex-shrink: 0;
+			/* #endif */
+
+			/* #ifndef APP-NVUE */
+			box-sizing: border-box;
+
+			/* #endif */
+			&.no-label {
+				padding: 0;
+			}
+		}
+
+		&__content {
+			/* #ifndef MP-TOUTIAO */
+			// display: flex;
+			// align-items: center;
+			/* #endif */
+			position: relative;
+			font-size: 14px;
+			flex: 1;
+			/* #ifndef APP-NVUE */
+			box-sizing: border-box;
+			/* #endif */
+			flex-direction: row;
+
+			/* #ifndef APP || H5 || MP-WEIXIN || APP-NVUE */
+			// TODO 因为小程序平台会多一层标签节点 ,所以需要在多余节点继承当前样式
+			&>uni-easyinput,
+			&>uni-data-picker {
+				width: 100%;
+			}
+
+			/* #endif */
+
+		}
+
+		& .uni-forms-item__nuve-content {
+			display: flex;
+			flex-direction: column;
+			flex: 1;
+		}
+
+		&__error {
+			color: #f56c6c;
+			font-size: 12px;
+			line-height: 1;
+			padding-top: 4px;
+			position: absolute;
+			/* #ifndef APP-NVUE */
+			top: 100%;
+			left: 0;
+			transition: transform 0.3s;
+			transform: translateY(-100%);
+			/* #endif */
+			/* #ifdef APP-NVUE */
+			bottom: 5px;
+			/* #endif */
+
+			opacity: 0;
+
+			.error-text {
+				// 只有 nvue 下这个样式才生效
+				color: #f56c6c;
+				font-size: 12px;
+			}
+
+			&.msg--active {
+				opacity: 1;
+				transform: translateY(0%);
+			}
+		}
+
+		// 位置修饰样式
+		&.is-direction-left {
+			flex-direction: row;
+		}
+
+		&.is-direction-top {
+			flex-direction: column;
+
+			.uni-forms-item__label {
+				padding: 0 0 8px;
+				line-height: 1.5715;
+				text-align: left;
+				/* #ifndef APP-NVUE */
+				white-space: initial;
+				/* #endif */
+			}
+		}
+
+		.is-required {
+			// color: $uni-color-error;
+			color: #dd524d;
+			font-weight: bold;
+		}
+	}
+
+
+	.uni-forms-item--border {
+		margin-bottom: 0;
+		padding: 10px 0;
+		// padding-bottom: 0;
+		border-top: 1px #eee solid;
+
+		/* #ifndef APP-NVUE */
+		.uni-forms-item__content {
+			flex-direction: column;
+			justify-content: flex-start;
+			align-items: flex-start;
+
+			.uni-forms-item__error {
+				position: relative;
+				top: 5px;
+				left: 0;
+				padding-top: 0;
+			}
+		}
+
+		/* #endif */
+
+		/* #ifdef APP-NVUE */
+		display: flex;
+		flex-direction: column;
+
+		.uni-forms-item__error {
+			position: relative;
+			top: 0px;
+			left: 0;
+			padding-top: 0;
+			margin-top: 5px;
+		}
+
+		/* #endif */
+
+	}
+
+	.is-first-border {
+		/* #ifndef APP-NVUE */
+		border: none;
+		/* #endif */
+		/* #ifdef APP-NVUE */
+		border-width: 0;
+		/* #endif */
+	}
+</style>

+ 397 - 0
uni_modules/uni-forms/components/uni-forms/uni-forms.vue

@@ -0,0 +1,397 @@
+<template>
+	<view class="uni-forms">
+		<form>
+			<slot></slot>
+		</form>
+	</view>
+</template>
+
+<script>
+	import Validator from './validate.js';
+	import {
+		deepCopy,
+		getValue,
+		isRequiredField,
+		setDataValue,
+		getDataValue,
+		realName,
+		isRealName,
+		rawData,
+		isEqual
+	} from './utils.js'
+
+	// #ifndef VUE3
+	// 后续会慢慢废弃这个方法
+	import Vue from 'vue';
+	Vue.prototype.binddata = function(name, value, formName) {
+		if (formName) {
+			this.$refs[formName].setValue(name, value);
+		} else {
+			let formVm;
+			for (let i in this.$refs) {
+				const vm = this.$refs[i];
+				if (vm && vm.$options && vm.$options.name === 'uniForms') {
+					formVm = vm;
+					break;
+				}
+			}
+			if (!formVm) return console.error('当前 uni-froms 组件缺少 ref 属性');
+			formVm.setValue(name, value);
+		}
+	};
+	// #endif
+	/**
+	 * Forms 表单
+	 * @description 由输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=2773
+	 * @property {Object} rules	表单校验规则
+	 * @property {String} validateTrigger = [bind|submit|blur]	校验触发器方式 默认 submit
+	 * @value bind		发生变化时触发
+	 * @value submit	提交时触发
+	 * @value blur	  失去焦点时触发
+	 * @property {String} labelPosition = [top|left]	label 位置 默认 left
+	 * @value top		顶部显示 label
+	 * @value left	左侧显示 label
+	 * @property {String} labelWidth	label 宽度,默认 65px
+	 * @property {String} labelAlign = [left|center|right]	label 居中方式  默认 left
+	 * @value left		label 左侧显示
+	 * @value center	label 居中
+	 * @value right		label 右侧对齐
+	 * @property {String} errShowType = [undertext|toast|modal]	校验错误信息提示方式
+	 * @value undertext	错误信息在底部显示
+	 * @value toast			错误信息toast显示
+	 * @value modal			错误信息modal显示
+	 * @event {Function} submit	提交时触发
+	 * @event {Function} validate	校验结果发生变化触发
+	 */
+	export default {
+		name: 'uniForms',
+		emits: ['validate', 'submit'],
+		options: {
+			virtualHost: true
+		},
+		props: {
+			// 即将弃用
+			value: {
+				type: Object,
+				default () {
+					return null;
+				}
+			},
+			// vue3 替换 value 属性
+			modelValue: {
+				type: Object,
+				default () {
+					return null;
+				}
+			},
+			// 1.4.0 开始将不支持 v-model ,且废弃 value 和 modelValue
+			model: {
+				type: Object,
+				default () {
+					return null;
+				}
+			},
+			// 表单校验规则
+			rules: {
+				type: Object,
+				default () {
+					return {};
+				}
+			},
+			//校验错误信息提示方式 默认 undertext 取值 [undertext|toast|modal]
+			errShowType: {
+				type: String,
+				default: 'undertext'
+			},
+			// 校验触发器方式 默认 bind 取值 [bind|submit]
+			validateTrigger: {
+				type: String,
+				default: 'submit'
+			},
+			// label 位置,默认 left 取值  top/left
+			labelPosition: {
+				type: String,
+				default: 'left'
+			},
+			// label 宽度
+			labelWidth: {
+				type: [String, Number],
+				default: ''
+			},
+			// label 居中方式,默认 left 取值 left/center/right
+			labelAlign: {
+				type: String,
+				default: 'left'
+			},
+			border: {
+				type: Boolean,
+				default: false
+			}
+		},
+		provide() {
+			return {
+				uniForm: this
+			}
+		},
+		data() {
+			return {
+				// 表单本地值的记录,不应该与传如的值进行关联
+				formData: {},
+				formRules: {}
+			};
+		},
+		computed: {
+			// 计算数据源变化的
+			localData() {
+				const localVal = this.model || this.modelValue || this.value
+				if (localVal) {
+					return deepCopy(localVal)
+				}
+				return {}
+			}
+		},
+		watch: {
+			// 监听数据变化 ,暂时不使用,需要单独赋值
+			// localData: {},
+			// 监听规则变化
+			rules: {
+				handler: function(val, oldVal) {
+					this.setRules(val)
+				},
+				deep: true,
+				immediate: true
+			}
+		},
+		created() {
+			// #ifdef VUE3
+			let getbinddata = getApp().$vm.$.appContext.config.globalProperties.binddata
+			if (!getbinddata) {
+				getApp().$vm.$.appContext.config.globalProperties.binddata = function(name, value, formName) {
+					if (formName) {
+						this.$refs[formName].setValue(name, value);
+					} else {
+						let formVm;
+						for (let i in this.$refs) {
+							const vm = this.$refs[i];
+							if (vm && vm.$options && vm.$options.name === 'uniForms') {
+								formVm = vm;
+								break;
+							}
+						}
+						if (!formVm) return console.error('当前 uni-froms 组件缺少 ref 属性');
+						formVm.setValue(name, value);
+					}
+				}
+			}
+			// #endif
+
+			// 子组件实例数组
+			this.childrens = []
+			// TODO 兼容旧版 uni-data-picker ,新版本中无效,只是避免报错
+			this.inputChildrens = []
+			this.setRules(this.rules)
+		},
+		methods: {
+			/**
+			 * 外部调用方法
+			 * 设置规则 ,主要用于小程序自定义检验规则
+			 * @param {Array} rules 规则源数据
+			 */
+			setRules(rules) {
+				// TODO 有可能子组件合并规则的时机比这个要早,所以需要合并对象 ,而不是直接赋值,可能会被覆盖
+				this.formRules = Object.assign({}, this.formRules, rules)
+				// 初始化校验函数
+				this.validator = new Validator(rules);
+			},
+
+			/**
+			 * 外部调用方法
+			 * 设置数据,用于设置表单数据,公开给用户使用 , 不支持在动态表单中使用
+			 * @param {Object} key
+			 * @param {Object} value
+			 */
+			setValue(key, value) {
+				let example = this.childrens.find(child => child.name === key);
+				if (!example) return null;
+				this.formData[key] = getValue(key, value, (this.formRules[key] && this.formRules[key].rules) || [])
+				return example.onFieldChange(this.formData[key]);
+			},
+
+			/**
+			 * 外部调用方法
+			 * 手动提交校验表单
+			 * 对整个表单进行校验的方法,参数为一个回调函数。
+			 * @param {Array} keepitem 保留不参与校验的字段
+			 * @param {type} callback 方法回调
+			 */
+			validate(keepitem, callback) {
+				return this.checkAll(this.formData, keepitem, callback);
+			},
+
+			/**
+			 * 外部调用方法
+			 * 部分表单校验
+			 * @param {Array|String} props 需要校验的字段
+			 * @param {Function} 回调函数
+			 */
+			validateField(props = [], callback) {
+				props = [].concat(props);
+				let invalidFields = {};
+				this.childrens.forEach(item => {
+					const name = realName(item.name)
+					if (props.indexOf(name) !== -1) {
+						invalidFields = Object.assign({}, invalidFields, {
+							[name]: this.formData[name]
+						});
+					}
+				});
+				return this.checkAll(invalidFields, [], callback);
+			},
+
+			/**
+			 * 外部调用方法
+			 * 移除表单项的校验结果。传入待移除的表单项的 prop 属性或者 prop 组成的数组,如不传则移除整个表单的校验结果
+			 * @param {Array|String} props 需要移除校验的字段 ,不填为所有
+			 */
+			clearValidate(props = []) {
+				props = [].concat(props);
+				this.childrens.forEach(item => {
+					if (props.length === 0) {
+						item.errMsg = '';
+					} else {
+						const name = realName(item.name)
+						if (props.indexOf(name) !== -1) {
+							item.errMsg = '';
+						}
+					}
+				});
+			},
+
+			/**
+			 * 外部调用方法 ,即将废弃
+			 * 手动提交校验表单
+			 * 对整个表单进行校验的方法,参数为一个回调函数。
+			 * @param {Array} keepitem 保留不参与校验的字段
+			 * @param {type} callback 方法回调
+			 */
+			submit(keepitem, callback, type) {
+				for (let i in this.dataValue) {
+					const itemData = this.childrens.find(v => v.name === i);
+					if (itemData) {
+						if (this.formData[i] === undefined) {
+							this.formData[i] = this._getValue(i, this.dataValue[i]);
+						}
+					}
+				}
+
+				if (!type) {
+					console.warn('submit 方法即将废弃,请使用validate方法代替!');
+				}
+
+				return this.checkAll(this.formData, keepitem, callback, 'submit');
+			},
+
+			// 校验所有
+			async checkAll(invalidFields, keepitem, callback, type) {
+				// 不存在校验规则 ,则停止校验流程
+				if (!this.validator) return
+				let childrens = []
+				// 处理参与校验的item实例
+				for (let i in invalidFields) {
+					const item = this.childrens.find(v => realName(v.name) === i)
+					if (item) {
+						childrens.push(item)
+					}
+				}
+
+				// 如果validate第一个参数是funciont ,那就走回调
+				if (!callback && typeof keepitem === 'function') {
+					callback = keepitem;
+				}
+
+				let promise;
+				// 如果不存在回调,那么使用 Promise 方式返回
+				if (!callback && typeof callback !== 'function' && Promise) {
+					promise = new Promise((resolve, reject) => {
+						callback = function(valid, invalidFields) {
+							!valid ? resolve(invalidFields) : reject(valid);
+						};
+					});
+				}
+
+				let results = [];
+				// 避免引用错乱 ,建议拷贝对象处理
+				let tempFormData = JSON.parse(JSON.stringify(invalidFields))
+				// 所有子组件参与校验,使用 for 可以使用  awiat
+				for (let i in childrens) {
+					const child = childrens[i]
+					let name = realName(child.name);
+					const result = await child.onFieldChange(tempFormData[name]);
+					if (result) {
+						results.push(result);
+						// toast ,modal 只需要执行第一次就可以
+						if (this.errShowType === 'toast' || this.errShowType === 'modal') break;
+					}
+				}
+
+
+				if (Array.isArray(results)) {
+					if (results.length === 0) results = null;
+				}
+				if (Array.isArray(keepitem)) {
+					keepitem.forEach(v => {
+						let vName = realName(v);
+						let value = getDataValue(v, this.localData)
+						if (value !== undefined) {
+							tempFormData[vName] = value
+						}
+					});
+				}
+
+				// TODO submit 即将废弃
+				if (type === 'submit') {
+					this.$emit('submit', {
+						detail: {
+							value: tempFormData,
+							errors: results
+						}
+					});
+				} else {
+					this.$emit('validate', results);
+				}
+
+				// const resetFormData = rawData(tempFormData, this.localData, this.name)
+				let resetFormData = {}
+				resetFormData = rawData(tempFormData, this.name)
+				callback && typeof callback === 'function' && callback(results, resetFormData);
+
+				if (promise && callback) {
+					return promise;
+				} else {
+					return null;
+				}
+
+			},
+
+			/**
+			 * 返回validate事件
+			 * @param {Object} result
+			 */
+			validateCheck(result) {
+				this.$emit('validate', result);
+			},
+			_getValue: getValue,
+			_isRequiredField: isRequiredField,
+			_setDataValue: setDataValue,
+			_getDataValue: getDataValue,
+			_realName: realName,
+			_isRealName: isRealName,
+			_isEqual: isEqual
+		}
+	};
+</script>
+
+<style lang="scss">
+	.uni-forms {}
+</style>

+ 293 - 0
uni_modules/uni-forms/components/uni-forms/utils.js

@@ -0,0 +1,293 @@
+/**
+ * 简单处理对象拷贝
+ * @param {Obejct} 被拷贝对象
+ * @@return {Object} 拷贝对象
+ */
+export const deepCopy = (val) => {
+	return JSON.parse(JSON.stringify(val))
+}
+/**
+ * 过滤数字类型
+ * @param {String} format 数字类型
+ * @@return {Boolean} 返回是否为数字类型
+ */
+export const typeFilter = (format) => {
+	return format === 'int' || format === 'double' || format === 'number' || format === 'timestamp';
+}
+
+/**
+ * 把 value 转换成指定的类型,用于处理初始值,原因是初始值需要入库不能为 undefined
+ * @param {String} key 字段名
+ * @param {any} value 字段值
+ * @param {Object} rules 表单校验规则
+ */
+export const getValue = (key, value, rules) => {
+	const isRuleNumType = rules.find(val => val.format && typeFilter(val.format));
+	const isRuleBoolType = rules.find(val => (val.format && val.format === 'boolean') || val.format === 'bool');
+	// 输入类型为 number
+	if (!!isRuleNumType) {
+		if (!value && value !== 0) {
+			value = null
+		} else {
+			value = isNumber(Number(value)) ? Number(value) : value
+		}
+	}
+
+	// 输入类型为 boolean
+	if (!!isRuleBoolType) {
+		value = isBoolean(value) ? value : false
+	}
+
+	return value;
+}
+
+/**
+ * 获取表单数据
+ * @param {String|Array} name 真实名称,需要使用 realName 获取
+ * @param {Object} data 原始数据
+ * @param {any} value  需要设置的值
+ */
+export const setDataValue = (field, formdata, value) => {
+	formdata[field] = value
+	return value || ''
+}
+
+/**
+ * 获取表单数据
+ * @param {String|Array} field 真实名称,需要使用 realName 获取
+ * @param {Object} data 原始数据
+ */
+export const getDataValue = (field, data) => {
+	return objGet(data, field)
+}
+
+/**
+ * 获取表单类型
+ * @param {String|Array} field 真实名称,需要使用 realName 获取
+ */
+export const getDataValueType = (field, data) => {
+	const value = getDataValue(field, data)
+	return {
+		type: type(value),
+		value
+	}
+}
+
+/**
+ * 获取表单可用的真实name
+ * @param {String|Array} name 表单name
+ * @@return {String} 表单可用的真实name
+ */
+export const realName = (name, data = {}) => {
+	const base_name = _basePath(name)
+	if (typeof base_name === 'object' && Array.isArray(base_name) && base_name.length > 1) {
+		const realname = base_name.reduce((a, b) => a += `#${b}`, '_formdata_')
+		return realname
+	}
+	return base_name[0] || name
+}
+
+/**
+ * 判断是否表单可用的真实name
+ * @param {String|Array} name 表单name
+ * @@return {String} 表单可用的真实name
+ */
+export const isRealName = (name) => {
+	const reg = /^_formdata_#*/
+	return reg.test(name)
+}
+
+/**
+ * 获取表单数据的原始格式
+ * @@return {Object|Array} object 需要解析的数据
+ */
+export const rawData = (object = {}, name) => {
+	let newData = JSON.parse(JSON.stringify(object))
+	let formData = {}
+	for(let i in newData){
+		let path = name2arr(i)
+		objSet(formData,path,newData[i])
+	}
+	return formData
+}
+
+/**
+ * 真实name还原为 array
+ * @param {*} name 
+ */
+export const name2arr = (name) => {
+	let field = name.replace('_formdata_#', '')
+	field = field.split('#').map(v => (isNumber(v) ? Number(v) : v))
+	return field
+}
+
+/**
+ * 对象中设置值
+ * @param {Object|Array} object 源数据
+ * @param {String| Array} path 'a.b.c' 或 ['a',0,'b','c']
+ * @param {String} value 需要设置的值
+ */
+export const objSet = (object, path, value) => {
+	if (typeof object !== 'object') return object;
+	_basePath(path).reduce((o, k, i, _) => {
+		if (i === _.length - 1) { 
+			// 若遍历结束直接赋值
+			o[k] = value
+			return null
+		} else if (k in o) { 
+			// 若存在对应路径,则返回找到的对象,进行下一次遍历
+			return o[k]
+		} else { 
+			// 若不存在对应路径,则创建对应对象,若下一路径是数字,新对象赋值为空数组,否则赋值为空对象
+			o[k] = /^[0-9]{1,}$/.test(_[i + 1]) ? [] : {}
+			return o[k]
+		}
+	}, object)
+	// 返回object
+	return object;
+}
+
+// 处理 path, path有三种形式:'a[0].b.c'、'a.0.b.c' 和 ['a','0','b','c'],需要统一处理成数组,便于后续使用
+function _basePath(path) {
+	// 若是数组,则直接返回
+	if (Array.isArray(path)) return path
+	// 若有 '[',']',则替换成将 '[' 替换成 '.',去掉 ']'
+	return path.replace(/\[/g, '.').replace(/\]/g, '').split('.')
+}
+
+/**
+ * 从对象中获取值
+ * @param {Object|Array} object 源数据
+ * @param {String| Array} path 'a.b.c' 或 ['a',0,'b','c']
+ * @param {String} defaultVal 如果无法从调用链中获取值的默认值
+ */
+export const objGet = (object, path, defaultVal = 'undefined') => {
+	// 先将path处理成统一格式
+	let newPath = _basePath(path)
+	// 递归处理,返回最后结果
+	let val = newPath.reduce((o, k) => {
+		return (o || {})[k]
+	}, object);
+	return !val || val !== undefined ? val : defaultVal
+}
+
+
+/**
+ * 是否为 number 类型 
+ * @param {any} num 需要判断的值
+ * @return {Boolean} 是否为 number
+ */
+export const isNumber = (num) => {
+	return !isNaN(Number(num))
+}
+
+/**
+ * 是否为 boolean 类型 
+ * @param {any} bool 需要判断的值
+ * @return {Boolean} 是否为 boolean
+ */
+export const isBoolean = (bool) => {
+	return (typeof bool === 'boolean')
+}
+/**
+ * 是否有必填字段
+ * @param {Object} rules 规则
+ * @return {Boolean} 是否有必填字段
+ */
+export const isRequiredField = (rules) => {
+	let isNoField = false;
+	for (let i = 0; i < rules.length; i++) {
+		const ruleData = rules[i];
+		if (ruleData.required) {
+			isNoField = true;
+			break;
+		}
+	}
+	return isNoField;
+}
+
+
+/**
+ * 获取数据类型
+ * @param {Any} obj 需要获取数据类型的值
+ */
+export const type = (obj) => {
+	var class2type = {};
+
+	// 生成class2type映射
+	"Boolean Number String Function Array Date RegExp Object Error".split(" ").map(function(item, index) {
+		class2type["[object " + item + "]"] = item.toLowerCase();
+	})
+	if (obj == null) {
+		return obj + "";
+	}
+	return typeof obj === "object" || typeof obj === "function" ?
+		class2type[Object.prototype.toString.call(obj)] || "object" :
+		typeof obj;
+}
+
+/**
+ * 判断两个值是否相等
+ * @param {any} a 值  
+ * @param {any} b 值  
+ * @return {Boolean} 是否相等
+ */
+export const isEqual = (a, b) => {
+	//如果a和b本来就全等
+	if (a === b) {
+		//判断是否为0和-0
+		return a !== 0 || 1 / a === 1 / b;
+	}
+	//判断是否为null和undefined
+	if (a == null || b == null) {
+		return a === b;
+	}
+	//接下来判断a和b的数据类型
+	var classNameA = toString.call(a),
+		classNameB = toString.call(b);
+	//如果数据类型不相等,则返回false
+	if (classNameA !== classNameB) {
+		return false;
+	}
+	//如果数据类型相等,再根据不同数据类型分别判断
+	switch (classNameA) {
+		case '[object RegExp]':
+		case '[object String]':
+			//进行字符串转换比较
+			return '' + a === '' + b;
+		case '[object Number]':
+			//进行数字转换比较,判断是否为NaN
+			if (+a !== +a) {
+				return +b !== +b;
+			}
+			//判断是否为0或-0
+			return +a === 0 ? 1 / +a === 1 / b : +a === +b;
+		case '[object Date]':
+		case '[object Boolean]':
+			return +a === +b;
+	}
+	//如果是对象类型
+	if (classNameA == '[object Object]') {
+		//获取a和b的属性长度
+		var propsA = Object.getOwnPropertyNames(a),
+			propsB = Object.getOwnPropertyNames(b);
+		if (propsA.length != propsB.length) {
+			return false;
+		}
+		for (var i = 0; i < propsA.length; i++) {
+			var propName = propsA[i];
+			//如果对应属性对应值不相等,则返回false
+			if (a[propName] !== b[propName]) {
+				return false;
+			}
+		}
+		return true;
+	}
+	//如果是数组类型
+	if (classNameA == '[object Array]') {
+		if (a.toString() == b.toString()) {
+			return true;
+		}
+		return false;
+	}
+}

+ 486 - 0
uni_modules/uni-forms/components/uni-forms/validate.js

@@ -0,0 +1,486 @@
+var pattern = {
+	email: /^\S+?@\S+?\.\S+?$/,
+	idcard: /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,
+	url: new RegExp(
+		"^(?!mailto:)(?:(?:http|https|ftp)://|//)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$",
+		'i')
+};
+
+const FORMAT_MAPPING = {
+	"int": 'integer',
+	"bool": 'boolean',
+	"double": 'number',
+	"long": 'number',
+	"password": 'string'
+	// "fileurls": 'array'
+}
+
+function formatMessage(args, resources = '') {
+	var defaultMessage = ['label']
+	defaultMessage.forEach((item) => {
+		if (args[item] === undefined) {
+			args[item] = ''
+		}
+	})
+
+	let str = resources
+	for (let key in args) {
+		let reg = new RegExp('{' + key + '}')
+		str = str.replace(reg, args[key])
+	}
+	return str
+}
+
+function isEmptyValue(value, type) {
+	if (value === undefined || value === null) {
+		return true;
+	}
+
+	if (typeof value === 'string' && !value) {
+		return true;
+	}
+
+	if (Array.isArray(value) && !value.length) {
+		return true;
+	}
+
+	if (type === 'object' && !Object.keys(value).length) {
+		return true;
+	}
+
+	return false;
+}
+
+const types = {
+	integer(value) {
+		return types.number(value) && parseInt(value, 10) === value;
+	},
+	string(value) {
+		return typeof value === 'string';
+	},
+	number(value) {
+		if (isNaN(value)) {
+			return false;
+		}
+		return typeof value === 'number';
+	},
+	"boolean": function(value) {
+		return typeof value === 'boolean';
+	},
+	"float": function(value) {
+		return types.number(value) && !types.integer(value);
+	},
+	array(value) {
+		return Array.isArray(value);
+	},
+	object(value) {
+		return typeof value === 'object' && !types.array(value);
+	},
+	date(value) {
+		return value instanceof Date;
+	},
+	timestamp(value) {
+		if (!this.integer(value) || Math.abs(value).toString().length > 16) {
+			return false
+		}
+		return true;
+	},
+	file(value) {
+		return typeof value.url === 'string';
+	},
+	email(value) {
+		return typeof value === 'string' && !!value.match(pattern.email) && value.length < 255;
+	},
+	url(value) {
+		return typeof value === 'string' && !!value.match(pattern.url);
+	},
+	pattern(reg, value) {
+		try {
+			return new RegExp(reg).test(value);
+		} catch (e) {
+			return false;
+		}
+	},
+	method(value) {
+		return typeof value === 'function';
+	},
+	idcard(value) {
+		return typeof value === 'string' && !!value.match(pattern.idcard);
+	},
+	'url-https'(value) {
+		return this.url(value) && value.startsWith('https://');
+	},
+	'url-scheme'(value) {
+		return value.startsWith('://');
+	},
+	'url-web'(value) {
+		return false;
+	}
+}
+
+class RuleValidator {
+
+	constructor(message) {
+		this._message = message
+	}
+
+	async validateRule(fieldKey, fieldValue, value, data, allData) {
+		var result = null
+
+		let rules = fieldValue.rules
+
+		let hasRequired = rules.findIndex((item) => {
+			return item.required
+		})
+		if (hasRequired < 0) {
+			if (value === null || value === undefined) {
+				return result
+			}
+			if (typeof value === 'string' && !value.length) {
+				return result
+			}
+		}
+
+		var message = this._message
+
+		if (rules === undefined) {
+			return message['default']
+		}
+
+		for (var i = 0; i < rules.length; i++) {
+			let rule = rules[i]
+			let vt = this._getValidateType(rule)
+
+			Object.assign(rule, {
+				label: fieldValue.label || `["${fieldKey}"]`
+			})
+
+			if (RuleValidatorHelper[vt]) {
+				result = RuleValidatorHelper[vt](rule, value, message)
+				if (result != null) {
+					break
+				}
+			}
+
+			if (rule.validateExpr) {
+				let now = Date.now()
+				let resultExpr = rule.validateExpr(value, allData, now)
+				if (resultExpr === false) {
+					result = this._getMessage(rule, rule.errorMessage || this._message['default'])
+					break
+				}
+			}
+
+			if (rule.validateFunction) {
+				result = await this.validateFunction(rule, value, data, allData, vt)
+				if (result !== null) {
+					break
+				}
+			}
+		}
+
+		if (result !== null) {
+			result = message.TAG + result
+		}
+
+		return result
+	}
+
+	async validateFunction(rule, value, data, allData, vt) {
+		let result = null
+		try {
+			let callbackMessage = null
+			const res = await rule.validateFunction(rule, value, allData || data, (message) => {
+				callbackMessage = message
+			})
+			if (callbackMessage || (typeof res === 'string' && res) || res === false) {
+				result = this._getMessage(rule, callbackMessage || res, vt)
+			}
+		} catch (e) {
+			result = this._getMessage(rule, e.message, vt)
+		}
+		return result
+	}
+
+	_getMessage(rule, message, vt) {
+		return formatMessage(rule, message || rule.errorMessage || this._message[vt] || message['default'])
+	}
+
+	_getValidateType(rule) {
+		var result = ''
+		if (rule.required) {
+			result = 'required'
+		} else if (rule.format) {
+			result = 'format'
+		} else if (rule.arrayType) {
+			result = 'arrayTypeFormat'
+		} else if (rule.range) {
+			result = 'range'
+		} else if (rule.maximum !== undefined || rule.minimum !== undefined) {
+			result = 'rangeNumber'
+		} else if (rule.maxLength !== undefined || rule.minLength !== undefined) {
+			result = 'rangeLength'
+		} else if (rule.pattern) {
+			result = 'pattern'
+		} else if (rule.validateFunction) {
+			result = 'validateFunction'
+		}
+		return result
+	}
+}
+
+const RuleValidatorHelper = {
+	required(rule, value, message) {
+		if (rule.required && isEmptyValue(value, rule.format || typeof value)) {
+			return formatMessage(rule, rule.errorMessage || message.required);
+		}
+
+		return null
+	},
+
+	range(rule, value, message) {
+		const {
+			range,
+			errorMessage
+		} = rule;
+
+		let list = new Array(range.length);
+		for (let i = 0; i < range.length; i++) {
+			const item = range[i];
+			if (types.object(item) && item.value !== undefined) {
+				list[i] = item.value;
+			} else {
+				list[i] = item;
+			}
+		}
+
+		let result = false
+		if (Array.isArray(value)) {
+			result = (new Set(value.concat(list)).size === list.length);
+		} else {
+			if (list.indexOf(value) > -1) {
+				result = true;
+			}
+		}
+
+		if (!result) {
+			return formatMessage(rule, errorMessage || message['enum']);
+		}
+
+		return null
+	},
+
+	rangeNumber(rule, value, message) {
+		if (!types.number(value)) {
+			return formatMessage(rule, rule.errorMessage || message.pattern.mismatch);
+		}
+
+		let {
+			minimum,
+			maximum,
+			exclusiveMinimum,
+			exclusiveMaximum
+		} = rule;
+		let min = exclusiveMinimum ? value <= minimum : value < minimum;
+		let max = exclusiveMaximum ? value >= maximum : value > maximum;
+
+		if (minimum !== undefined && min) {
+			return formatMessage(rule, rule.errorMessage || message['number'][exclusiveMinimum ?
+				'exclusiveMinimum' : 'minimum'
+			])
+		} else if (maximum !== undefined && max) {
+			return formatMessage(rule, rule.errorMessage || message['number'][exclusiveMaximum ?
+				'exclusiveMaximum' : 'maximum'
+			])
+		} else if (minimum !== undefined && maximum !== undefined && (min || max)) {
+			return formatMessage(rule, rule.errorMessage || message['number'].range)
+		}
+
+		return null
+	},
+
+	rangeLength(rule, value, message) {
+		if (!types.string(value) && !types.array(value)) {
+			return formatMessage(rule, rule.errorMessage || message.pattern.mismatch);
+		}
+
+		let min = rule.minLength;
+		let max = rule.maxLength;
+		let val = value.length;
+
+		if (min !== undefined && val < min) {
+			return formatMessage(rule, rule.errorMessage || message['length'].minLength)
+		} else if (max !== undefined && val > max) {
+			return formatMessage(rule, rule.errorMessage || message['length'].maxLength)
+		} else if (min !== undefined && max !== undefined && (val < min || val > max)) {
+			return formatMessage(rule, rule.errorMessage || message['length'].range)
+		}
+
+		return null
+	},
+
+	pattern(rule, value, message) {
+		if (!types['pattern'](rule.pattern, value)) {
+			return formatMessage(rule, rule.errorMessage || message.pattern.mismatch);
+		}
+
+		return null
+	},
+
+	format(rule, value, message) {
+		var customTypes = Object.keys(types);
+		var format = FORMAT_MAPPING[rule.format] ? FORMAT_MAPPING[rule.format] : (rule.format || rule.arrayType);
+
+		if (customTypes.indexOf(format) > -1) {
+			if (!types[format](value)) {
+				return formatMessage(rule, rule.errorMessage || message.typeError);
+			}
+		}
+
+		return null
+	},
+
+	arrayTypeFormat(rule, value, message) {
+		if (!Array.isArray(value)) {
+			return formatMessage(rule, rule.errorMessage || message.typeError);
+		}
+
+		for (let i = 0; i < value.length; i++) {
+			const element = value[i];
+			let formatResult = this.format(rule, element, message)
+			if (formatResult !== null) {
+				return formatResult
+			}
+		}
+
+		return null
+	}
+}
+
+class SchemaValidator extends RuleValidator {
+
+	constructor(schema, options) {
+		super(SchemaValidator.message);
+
+		this._schema = schema
+		this._options = options || null
+	}
+
+	updateSchema(schema) {
+		this._schema = schema
+	}
+
+	async validate(data, allData) {
+		let result = this._checkFieldInSchema(data)
+		if (!result) {
+			result = await this.invokeValidate(data, false, allData)
+		}
+		return result.length ? result[0] : null
+	}
+
+	async validateAll(data, allData) {
+		let result = this._checkFieldInSchema(data)
+		if (!result) {
+			result = await this.invokeValidate(data, true, allData)
+		}
+		return result
+	}
+
+	async validateUpdate(data, allData) {
+		let result = this._checkFieldInSchema(data)
+		if (!result) {
+			result = await this.invokeValidateUpdate(data, false, allData)
+		}
+		return result.length ? result[0] : null
+	}
+
+	async invokeValidate(data, all, allData) {
+		let result = []
+		let schema = this._schema
+		for (let key in schema) {
+			let value = schema[key]
+			let errorMessage = await this.validateRule(key, value, data[key], data, allData)
+			if (errorMessage != null) {
+				result.push({
+					key,
+					errorMessage
+				})
+				if (!all) break
+			}
+		}
+		return result
+	}
+
+	async invokeValidateUpdate(data, all, allData) {
+		let result = []
+		for (let key in data) {
+			let errorMessage = await this.validateRule(key, this._schema[key], data[key], data, allData)
+			if (errorMessage != null) {
+				result.push({
+					key,
+					errorMessage
+				})
+				if (!all) break
+			}
+		}
+		return result
+	}
+
+	_checkFieldInSchema(data) {
+		var keys = Object.keys(data)
+		var keys2 = Object.keys(this._schema)
+		if (new Set(keys.concat(keys2)).size === keys2.length) {
+			return ''
+		}
+
+		var noExistFields = keys.filter((key) => {
+			return keys2.indexOf(key) < 0;
+		})
+		var errorMessage = formatMessage({
+			field: JSON.stringify(noExistFields)
+		}, SchemaValidator.message.TAG + SchemaValidator.message['defaultInvalid'])
+		return [{
+			key: 'invalid',
+			errorMessage
+		}]
+	}
+}
+
+function Message() {
+	return {
+		TAG: "",
+		default: '验证错误',
+		defaultInvalid: '提交的字段{field}在数据库中并不存在',
+		validateFunction: '验证无效',
+		required: '{label}必填',
+		'enum': '{label}超出范围',
+		timestamp: '{label}格式无效',
+		whitespace: '{label}不能为空',
+		typeError: '{label}类型无效',
+		date: {
+			format: '{label}日期{value}格式无效',
+			parse: '{label}日期无法解析,{value}无效',
+			invalid: '{label}日期{value}无效'
+		},
+		length: {
+			minLength: '{label}长度不能少于{minLength}',
+			maxLength: '{label}长度不能超过{maxLength}',
+			range: '{label}必须介于{minLength}和{maxLength}之间'
+		},
+		number: {
+			minimum: '{label}不能小于{minimum}',
+			maximum: '{label}不能大于{maximum}',
+			exclusiveMinimum: '{label}不能小于等于{minimum}',
+			exclusiveMaximum: '{label}不能大于等于{maximum}',
+			range: '{label}必须介于{minimum}and{maximum}之间'
+		},
+		pattern: {
+			mismatch: '{label}格式不匹配'
+		}
+	};
+}
+
+
+SchemaValidator.message = new Message();
+
+export default SchemaValidator

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

@@ -0,0 +1,88 @@
+{
+  "id": "uni-forms",
+  "displayName": "uni-forms 表单",
+  "version": "1.4.9",
+  "description": "由输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据",
+  "keywords": [
+    "uni-ui",
+    "表单",
+    "校验",
+    "表单校验",
+    "表单验证"
+],
+  "repository": "https://github.com/dcloudio/uni-ui",
+  "engines": {
+    "HBuilderX": ""
+  },
+  "directories": {
+    "example": "../../temps/example_temps"
+  },
+"dcloudext": {
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "无",
+      "permissions": "无"
+    },
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
+    "type": "component-vue"
+  },
+  "uni_modules": {
+    "dependencies": [
+			"uni-scss",
+      "uni-icons"
+    ],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y"
+      },
+      "client": {
+        "App": {
+          "app-vue": "y",
+          "app-nvue": "y"
+        },
+        "H5-mobile": {
+          "Safari": "y",
+          "Android Browser": "y",
+          "微信浏览器(Android)": "y",
+          "QQ浏览器(Android)": "y"
+        },
+        "H5-pc": {
+          "Chrome": "y",
+          "IE": "y",
+          "Edge": "y",
+          "Firefox": "y",
+          "Safari": "y"
+        },
+        "小程序": {
+          "微信": "y",
+          "阿里": "y",
+          "百度": "y",
+          "字节跳动": "y",
+        "QQ": "y",
+        "京东": "u"
+        },
+        "快应用": {
+          "华为": "u",
+          "联盟": "u"
+        },
+        "Vue": {
+            "vue2": "y",
+            "vue3": "y"
+        }
+      }
+    }
+  }
+}

+ 23 - 0
uni_modules/uni-forms/readme.md

@@ -0,0 +1,23 @@
+
+
+## Forms 表单
+
+> **组件名:uni-forms**
+> 代码块: `uForms`、`uni-forms-item`
+> 关联组件:`uni-forms-item`、`uni-easyinput`、`uni-data-checkbox`、`uni-group`。
+
+
+uni-app的内置组件已经有了 `<form>`组件,用于提交表单内容。
+
+然而几乎每个表单都需要做表单验证,为了方便做表单验证,减少重复开发,`uni ui` 又基于 `<form>`组件封装了 `<uni-forms>`组件,内置了表单验证功能。
+
+`<uni-forms>` 提供了 `rules`属性来描述校验规则、`<uni-forms-item>`子组件来包裹具体的表单项,以及给原生或三方组件提供了 `binddata()` 来设置表单值。
+
+每个要校验的表单项,不管input还是checkbox,都必须放在`<uni-forms-item>`组件中,且一个`<uni-forms-item>`组件只能放置一个表单项。
+
+`<uni-forms-item>`组件内部预留了显示error message的区域,默认是在表单项的底部。
+
+另外,`<uni-forms>`组件下面的各个表单项,可以通过`<uni-group>`包裹为不同的分组。同一`<uni-group>`下的不同表单项目将聚拢在一起,同其他group保持垂直间距。`<uni-group>`仅影响视觉效果。
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-forms)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 

+ 19 - 0
uni_modules/uni-load-more/changelog.md

@@ -0,0 +1,19 @@
+## 1.3.3(2022-01-20)
+- 新增 showText属性 ,是否显示文本
+## 1.3.2(2022-01-19)
+- 修复 nvue 平台下不显示文本的bug
+## 1.3.1(2022-01-19)
+- 修复 微信小程序平台样式选择器报警告的问题
+## 1.3.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-load-more](https://uniapp.dcloud.io/component/uniui/uni-load-more)
+## 1.2.1(2021-08-24)
+- 新增 支持国际化
+## 1.2.0(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.1.8(2021-05-12)
+- 新增 组件示例地址
+## 1.1.7(2021-03-30)
+- 修复 uni-load-more 在首页使用时,h5 平台报 'uni is not defined' 的 bug
+## 1.1.6(2021-02-05)
+- 调整为uni_modules目录规范

+ 5 - 0
uni_modules/uni-load-more/components/uni-load-more/i18n/en.json

@@ -0,0 +1,5 @@
+{
+	"uni-load-more.contentdown": "Pull up to show more",
+	"uni-load-more.contentrefresh": "loading...",
+	"uni-load-more.contentnomore": "No more data"
+}

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

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

+ 5 - 0
uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json

@@ -0,0 +1,5 @@
+{
+	"uni-load-more.contentdown": "上拉显示更多",
+	"uni-load-more.contentrefresh": "正在加载...",
+	"uni-load-more.contentnomore": "没有更多数据了"
+}

+ 5 - 0
uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json

@@ -0,0 +1,5 @@
+{
+	"uni-load-more.contentdown": "上拉顯示更多",
+	"uni-load-more.contentrefresh": "正在加載...",
+	"uni-load-more.contentnomore": "沒有更多數據了"
+}

文件差异内容过多而无法显示
+ 399 - 0
uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue


+ 86 - 0
uni_modules/uni-load-more/package.json

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

+ 14 - 0
uni_modules/uni-load-more/readme.md

@@ -0,0 +1,14 @@
+
+
+### LoadMore 加载更多
+> **组件名:uni-load-more**
+> 代码块: `uLoadMore`
+
+
+用于列表中,做滚动加载使用,展示 loading 的各种状态。
+
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-load-more)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 
+
+

文件差异内容过多而无法显示
+ 1 - 1
unpackage/dist/dev/.sourcemap/mp-weixin/common/main.js.map


文件差异内容过多而无法显示
+ 1 - 1
unpackage/dist/dev/.sourcemap/mp-weixin/common/runtime.js.map


文件差异内容过多而无法显示
+ 1 - 1
unpackage/dist/dev/.sourcemap/mp-weixin/common/vendor.js.map


文件差异内容过多而无法显示
+ 1 - 1
unpackage/dist/dev/.sourcemap/mp-weixin/components/upload/index.js.map


文件差异内容过多而无法显示
+ 1 - 1
unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/index.js.map


文件差异内容过多而无法显示
+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pagesAccount/basic/index.js.map


文件差异内容过多而无法显示
+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pagesAccount/collect/index.js.map


文件差异内容过多而无法显示
+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pagesAccount/like/index.js.map


文件差异内容过多而无法显示
+ 1 - 1
unpackage/dist/dev/.sourcemap/mp-weixin/pagesAccount/login/index.js.map


文件差异内容过多而无法显示
+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pagesAccount/other/agree.js.map


文件差异内容过多而无法显示
+ 1 - 1
unpackage/dist/dev/.sourcemap/mp-weixin/pagesAccount/register/index.js.map


文件差异内容过多而无法显示
+ 1 - 1
unpackage/dist/dev/.sourcemap/mp-weixin/pagesHome/account/index.js.map


文件差异内容过多而无法显示
+ 1 - 1
unpackage/dist/dev/.sourcemap/mp-weixin/pagesHome/app/index.js.map


文件差异内容过多而无法显示
+ 1 - 1
unpackage/dist/dev/.sourcemap/mp-weixin/pagesHome/components/home-frame.js.map


文件差异内容过多而无法显示
+ 1 - 1
unpackage/dist/dev/.sourcemap/mp-weixin/pagesHome/find/index.js.map


文件差异内容过多而无法显示
+ 1 - 1
unpackage/dist/dev/.sourcemap/mp-weixin/pagesHome/home/index.js.map


文件差异内容过多而无法显示
+ 1 - 1
unpackage/dist/dev/.sourcemap/mp-weixin/pagesHome/hot/index.js.map


文件差异内容过多而无法显示
+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.js.map


文件差异内容过多而无法显示
+ 1 - 1
unpackage/dist/dev/.sourcemap/mp-weixin/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.js.map


文件差异内容过多而无法显示
+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.js.map


文件差异内容过多而无法显示
+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/uni_modules/uni-forms/components/uni-forms/uni-forms.js.map


文件差异内容过多而无法显示
+ 1 - 1
unpackage/dist/dev/.sourcemap/mp-weixin/uni_modules/uni-icons/components/uni-icons/uni-icons.js.map


文件差异内容过多而无法显示
+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.js.map


文件差异内容过多而无法显示
+ 2 - 2
unpackage/dist/dev/app-plus/app-config-service.js


文件差异内容过多而无法显示
+ 9968 - 334
unpackage/dist/dev/app-plus/app-service.js


文件差异内容过多而无法显示
+ 2603 - 346
unpackage/dist/dev/app-plus/app-view.js


文件差异内容过多而无法显示
+ 834 - 90
unpackage/dist/dev/app-plus/pagesAccount/app-sub-service.js


文件差异内容过多而无法显示
+ 1 - 1
unpackage/dist/dev/app-plus/pagesCommon/app-sub-service.js


文件差异内容过多而无法显示
+ 68 - 18
unpackage/dist/dev/app-plus/pagesHome/app-sub-service.js


+ 5 - 1
unpackage/dist/dev/mp-weixin/app.json

@@ -23,7 +23,11 @@
       "root": "pagesAccount",
       "pages": [
         "login/index",
-        "register/index"
+        "register/index",
+        "other/agree",
+        "like/index",
+        "collect/index",
+        "basic/index"
       ]
     }
   ],

文件差异内容过多而无法显示
+ 4 - 0
unpackage/dist/dev/mp-weixin/common/main.js


文件差异内容过多而无法显示
+ 2 - 2
unpackage/dist/dev/mp-weixin/common/runtime.js


文件差异内容过多而无法显示
+ 19231 - 10920
unpackage/dist/dev/mp-weixin/common/vendor.js


文件差异内容过多而无法显示
+ 17 - 17
unpackage/dist/dev/mp-weixin/components/upload/index.js


+ 2 - 2
unpackage/dist/dev/mp-weixin/pages/index/index.js

@@ -198,7 +198,7 @@ var _default = {
             switch (_context.prev = _context.next) {
               case 0:
                 that = _this;
-                url = '/pagesAccount/register/index'; // 可返回
+                url = '/pagesHome/account/index'; // 可返回
                 // uni.navigateTo({
                 // 	url
                 // })
@@ -217,7 +217,7 @@ var _default = {
                       // 	url
                       // })
                       // 可返回
-                      uni.navigateTo({
+                      uni.redirectTo({
                         url: url
                       });
                     }

文件差异内容过多而无法显示
+ 376 - 0
unpackage/dist/dev/mp-weixin/pagesAccount/basic/index.js


+ 11 - 0
unpackage/dist/dev/mp-weixin/pagesAccount/basic/index.json

@@ -0,0 +1,11 @@
+{
+  "navigationBarTitleText": "账号信息",
+  "enablePullDownRefresh": false,
+  "usingComponents": {
+    "uni-forms": "/uni_modules/uni-forms/components/uni-forms/uni-forms",
+    "uni-forms-item": "/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item",
+    "uni-easyinput": "/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput",
+    "uni-data-checkbox": "/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox",
+    "upload": "/components/upload/index"
+  }
+}

文件差异内容过多而无法显示
+ 1 - 0
unpackage/dist/dev/mp-weixin/pagesAccount/basic/index.wxml


+ 23 - 0
unpackage/dist/dev/mp-weixin/pagesAccount/basic/index.wxss

@@ -0,0 +1,23 @@
+.content {
+  display: flex;
+  flex-direction: column;
+  box-sizing: border-box;
+  width: 100vw;
+  height: 100vh;
+}
+.content {
+  background-color: var(--rgb000);
+  padding: 0 2vw;
+  overflow-y: auto;
+}
+.content .btn {
+  padding: 2vw 0 0 0;
+  text-align: center;
+}
+.content .btn button {
+  width: 80%;
+  background-color: var(--rgbfa4);
+  color: var(--rgbfff);
+  padding: 1vw 0;
+}
+

文件差异内容过多而无法显示
+ 192 - 0
unpackage/dist/dev/mp-weixin/pagesAccount/collect/index.js


+ 5 - 0
unpackage/dist/dev/mp-weixin/pagesAccount/collect/index.json

@@ -0,0 +1,5 @@
+{
+  "navigationBarTitleText": "我的收藏",
+  "enablePullDownRefresh": true,
+  "usingComponents": {}
+}

+ 1 - 0
unpackage/dist/dev/mp-weixin/pagesAccount/collect/index.wxml

@@ -0,0 +1 @@
+<view class="content">我的收藏</view>

+ 12 - 0
unpackage/dist/dev/mp-weixin/pagesAccount/collect/index.wxss

@@ -0,0 +1,12 @@
+.content {
+  display: flex;
+  flex-direction: column;
+  box-sizing: border-box;
+  width: 100vw;
+  height: 100vh;
+}
+.content {
+  background-color: var(--rgb000);
+  padding: 0 2vw;
+}
+

文件差异内容过多而无法显示
+ 192 - 0
unpackage/dist/dev/mp-weixin/pagesAccount/like/index.js


+ 5 - 0
unpackage/dist/dev/mp-weixin/pagesAccount/like/index.json

@@ -0,0 +1,5 @@
+{
+  "navigationBarTitleText": "我的喜欢",
+  "enablePullDownRefresh": true,
+  "usingComponents": {}
+}

+ 1 - 0
unpackage/dist/dev/mp-weixin/pagesAccount/like/index.wxml

@@ -0,0 +1 @@
+<view class="content">我的喜欢</view>

+ 12 - 0
unpackage/dist/dev/mp-weixin/pagesAccount/like/index.wxss

@@ -0,0 +1,12 @@
+.content {
+  display: flex;
+  flex-direction: column;
+  box-sizing: border-box;
+  width: 100vw;
+  height: 100vh;
+}
+.content {
+  background-color: var(--rgb000);
+  padding: 0 2vw;
+}
+

+ 81 - 38
unpackage/dist/dev/mp-weixin/pagesAccount/login/index.js

@@ -100,8 +100,14 @@ __webpack_require__.r(__webpack_exports__);
 var components
 try {
   components = {
+    uniForms: function () {
+      return Promise.all(/*! import() | uni_modules/uni-forms/components/uni-forms/uni-forms */[__webpack_require__.e("common/vendor"), __webpack_require__.e("uni_modules/uni-forms/components/uni-forms/uni-forms")]).then(__webpack_require__.bind(null, /*! @/uni_modules/uni-forms/components/uni-forms/uni-forms.vue */ 130))
+    },
+    uniFormsItem: function () {
+      return __webpack_require__.e(/*! import() | uni_modules/uni-forms/components/uni-forms-item/uni-forms-item */ "uni_modules/uni-forms/components/uni-forms-item/uni-forms-item").then(__webpack_require__.bind(null, /*! @/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue */ 143))
+    },
     uniEasyinput: function () {
-      return __webpack_require__.e(/*! import() | uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput */ "uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput").then(__webpack_require__.bind(null, /*! @/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue */ 128))
+      return __webpack_require__.e(/*! import() | uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput */ "uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput").then(__webpack_require__.bind(null, /*! @/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue */ 150))
     },
   }
 } catch (e) {
@@ -191,6 +197,14 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(/*! @babel/r
 //
 //
 //
+//
+//
+//
+//
+//
+//
+//
+//
 var _default = {
   data: function data() {
     return {
@@ -206,7 +220,7 @@ var _default = {
             errorMessage: '请输入登录账号'
           }]
         },
-        passowrd: {
+        password: {
           rules: [
           //
           {
@@ -215,7 +229,7 @@ var _default = {
           }]
         }
       },
-      // 协议
+      // 用戶协议
       agree: true
     };
   },
@@ -237,51 +251,80 @@ var _default = {
     },
     // 提交登录
     toSubmit: function toSubmit(ref) {
-      var _this = this;
-      return (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
-        var that, agree, form, res;
-        return _regenerator.default.wrap(function _callee$(_context) {
-          while (1) {
-            switch (_context.prev = _context.next) {
-              case 0:
-                that = _this;
-                agree = that.agree;
-                form = that.form;
-                if (!agree) {
-                  _context.next = 10;
+      var that = this;
+      var agree = that.agree;
+      that.$refs[ref].validate().then( /*#__PURE__*/function () {
+        var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(parmas) {
+          var res;
+          return _regenerator.default.wrap(function _callee$(_context) {
+            while (1) {
+              switch (_context.prev = _context.next) {
+                case 0:
+                  if (!agree) {
+                    _context.next = 7;
+                    break;
+                  }
+                  _context.next = 3;
+                  return that.$api('user/login', 'POST', parmas);
+                case 3:
+                  res = _context.sent;
+                  if (res.errcode == '0') {
+                    uni.showToast({
+                      title: '账号登录成功',
+                      icon: 'none'
+                    });
+                    uni.setStorage({
+                      key: 'token',
+                      data: res.data,
+                      success: function success() {
+                        uni.navigateBack();
+                      }
+                    });
+                  } else {
+                    uni.showToast({
+                      title: res.errmsg,
+                      icon: 'none'
+                    });
+                  }
+                  _context.next = 8;
                   break;
-                }
-                _context.next = 6;
-                return that.$api('user/login', 'POST', form);
-              case 6:
-                res = _context.sent;
-                if (res.errcode == '0') {
-                  console.log(res.data);
-                } else {
+                case 7:
                   uni.showToast({
-                    title: res.errmsg,
+                    title: '请阅读并同意用户协议和隐私政策',
                     icon: 'none'
                   });
-                }
-                _context.next = 11;
-                break;
-              case 10:
-                uni.showToast({
-                  title: '请阅读并同意用户协议和隐私政策',
-                  icon: 'none'
-                });
-              case 11:
-              case "end":
-                return _context.stop();
+                case 8:
+                case "end":
+                  return _context.stop();
+              }
             }
-          }
-        }, _callee);
-      }))();
+          }, _callee);
+        }));
+        return function (_x) {
+          return _ref.apply(this, arguments);
+        };
+      }()).catch(function (err) {
+        console.log('err', err);
+      });
     },
     toRegister: function toRegister() {
       uni.navigateTo({
         url: '/pagesAccount/register/index'
       });
+    },
+    // 同意隐私协议
+    changeAgree: function changeAgree() {
+      var that = this;
+      var agree = true;
+      if (that.agree) agree = false;
+      that.$set(that, "agree", agree);
+    },
+    // 查看隐私协议
+    toAgree: function toAgree() {
+      var that = this;
+      uni.navigateTo({
+        url: "/pagesAccount/other/agree"
+      });
     }
   }
 };

+ 2 - 0
unpackage/dist/dev/mp-weixin/pagesAccount/login/index.json

@@ -2,6 +2,8 @@
   "navigationBarTitleText": "账号登录",
   "enablePullDownRefresh": false,
   "usingComponents": {
+    "uni-forms": "/uni_modules/uni-forms/components/uni-forms/uni-forms",
+    "uni-forms-item": "/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item",
     "uni-easyinput": "/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput"
   }
 }

文件差异内容过多而无法显示
+ 1 - 1
unpackage/dist/dev/mp-weixin/pagesAccount/login/index.wxml


+ 6 - 3
unpackage/dist/dev/mp-weixin/pagesAccount/login/index.wxss

@@ -19,9 +19,6 @@
 .content .two {
   margin: 0 0 4vw 0;
 }
-.content .two .uni-easyinput {
-  margin: 0 0 15px 0;
-}
 .content .two .btn {
   padding: 2vw 0 0 0;
   text-align: center;
@@ -39,4 +36,10 @@
   background-color: var(--rgbfa4);
   color: var(--rgbfff);
 }
+.agree {
+  text-align: center;
+  font-size: 12px;
+  margin: 0 0 2vw 0;
+  color: var(--rgbfff);
+}
 

文件差异内容过多而无法显示
+ 192 - 0
unpackage/dist/dev/mp-weixin/pagesAccount/other/agree.js


+ 5 - 0
unpackage/dist/dev/mp-weixin/pagesAccount/other/agree.json

@@ -0,0 +1,5 @@
+{
+  "navigationBarTitleText": "用户协议",
+  "enablePullDownRefresh": false,
+  "usingComponents": {}
+}

+ 1 - 0
unpackage/dist/dev/mp-weixin/pagesAccount/other/agree.wxml

@@ -0,0 +1 @@
+<view class="content">用户协议</view>

+ 12 - 0
unpackage/dist/dev/mp-weixin/pagesAccount/other/agree.wxss

@@ -0,0 +1,12 @@
+.content {
+  display: flex;
+  flex-direction: column;
+  box-sizing: border-box;
+  width: 100vw;
+  height: 100vh;
+}
+.content {
+  background-color: var(--rgb000);
+  padding: 0 2vw;
+}
+

文件差异内容过多而无法显示
+ 189 - 17
unpackage/dist/dev/mp-weixin/pagesAccount/register/index.js


+ 7 - 1
unpackage/dist/dev/mp-weixin/pagesAccount/register/index.json

@@ -1,5 +1,11 @@
 {
   "navigationBarTitleText": "账号注册",
   "enablePullDownRefresh": false,
-  "usingComponents": {}
+  "usingComponents": {
+    "uni-forms": "/uni_modules/uni-forms/components/uni-forms/uni-forms",
+    "uni-forms-item": "/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item",
+    "uni-easyinput": "/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput",
+    "uni-data-checkbox": "/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox",
+    "upload": "/components/upload/index"
+  }
 }

文件差异内容过多而无法显示
+ 1 - 1
unpackage/dist/dev/mp-weixin/pagesAccount/register/index.wxml


+ 21 - 1
unpackage/dist/dev/mp-weixin/pagesAccount/register/index.wxss

@@ -8,12 +8,32 @@
 .content {
   background-color: var(--rgb000);
   padding: 0 2vw;
+  overflow-y: auto;
 }
 .content .one {
   text-align: center;
   font-size: 30px;
   font-family: monospace;
   color: var(--rgbfff);
-  padding: 10vw 0 10vw 0;
+  padding: 6vw 0;
+}
+.content .two {
+  margin: 0 0 4vw 0;
+}
+.content .two .btn {
+  padding: 2vw 0 0 0;
+  text-align: center;
+}
+.content .two .btn button {
+  width: 80%;
+  background-color: var(--rgbfa4);
+  color: var(--rgbfff);
+  padding: 1vw 0;
+}
+.agree {
+  text-align: center;
+  font-size: 12px;
+  margin: 0 0 2vw 0;
+  color: var(--rgbfff);
 }
 

+ 1 - 1
unpackage/dist/dev/mp-weixin/pagesCommon/test/index.js

@@ -143,7 +143,7 @@ exports.default = void 0;
 var _toConsumableArray2 = _interopRequireDefault(__webpack_require__(/*! @babel/runtime/helpers/toConsumableArray */ 18));
 var upload = function upload() {
   Promise.all(/*! require.ensure | components/upload/index */[__webpack_require__.e("common/vendor"), __webpack_require__.e("components/upload/index")]).then((function () {
-    return resolve(__webpack_require__(/*! @/components/upload/index.vue */ 106));
+    return resolve(__webpack_require__(/*! @/components/upload/index.vue */ 108));
   }).bind(null, __webpack_require__)).catch(__webpack_require__.oe);
 };
 var _default = {

+ 104 - 28
unpackage/dist/dev/mp-weixin/pagesHome/account/index.js

@@ -98,22 +98,47 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "recyclableRender", function() { return recyclableRender; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "components", function() { return components; });
 var components
+try {
+  components = {
+    uniIcons: function () {
+      return Promise.all(/*! import() | uni_modules/uni-icons/components/uni-icons/uni-icons */[__webpack_require__.e("common/vendor"), __webpack_require__.e("uni_modules/uni-icons/components/uni-icons/uni-icons")]).then(__webpack_require__.bind(null, /*! @/uni_modules/uni-icons/components/uni-icons/uni-icons.vue */ 115))
+    },
+  }
+} catch (e) {
+  if (
+    e.message.indexOf("Cannot find module") !== -1 &&
+    e.message.indexOf(".vue") !== -1
+  ) {
+    console.error(e.message)
+    console.error("1. 排查组件名称拼写是否正确")
+    console.error(
+      "2. 排查组件是否符合 easycom 规范,文档:https://uniapp.dcloud.net.cn/collocation/pages?id=easycom"
+    )
+    console.error(
+      "3. 若组件不符合 easycom 规范,需手动引入,并在 components 中注册该组件"
+    )
+  } else {
+    throw e
+  }
+}
 var render = function () {
   var _vm = this
   var _h = _vm.$createElement
   var _c = _vm._self._c || _h
+  var g0 = _vm.userInfo.logo_url && _vm.userInfo.logo_url.length > 0
   var l0 = _vm.__map(_vm.basicInfo.account_btn, function (item, index) {
     var $orig = _vm.__get_orig(item)
-    var g0 = item.img_url && item.img_url.length > 0
+    var g1 = item.img_url && item.img_url.length > 0
     return {
       $orig: $orig,
-      g0: g0,
+      g1: g1,
     }
   })
   _vm.$mp.data = Object.assign(
     {},
     {
       $root: {
+        g0: g0,
         l0: l0,
       },
     }
@@ -153,13 +178,16 @@ __webpack_require__.r(__webpack_exports__);
 "use strict";
 /* WEBPACK VAR INJECTION */(function(uni) {
 
+var _interopRequireDefault = __webpack_require__(/*! @babel/runtime/helpers/interopRequireDefault */ 4);
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.default = void 0;
+var _regenerator = _interopRequireDefault(__webpack_require__(/*! @babel/runtime/regenerator */ 35));
+var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(/*! @babel/runtime/helpers/asyncToGenerator */ 37));
 var homeFrame = function homeFrame() {
   __webpack_require__.e(/*! require.ensure | pagesHome/components/home-frame */ "pagesHome/components/home-frame").then((function () {
-    return resolve(__webpack_require__(/*! ../components/home-frame.vue */ 121));
+    return resolve(__webpack_require__(/*! ../components/home-frame.vue */ 123));
   }).bind(null, __webpack_require__)).catch(__webpack_require__.oe);
 };
 var _default = {
@@ -171,16 +199,13 @@ var _default = {
       // 基本信息
       basicInfo: {},
       // 用户信息
-      userInfo: {},
-      // 头像
-      logo_url: ''
+      userInfo: {}
     };
   },
   onLoad: function onLoad() {},
   onShow: function onShow() {
     var that = this;
     that.searchBasic();
-    that.search();
   },
   methods: {
     searchBasic: function searchBasic() {
@@ -189,36 +214,59 @@ var _default = {
         key: 'basicInfo',
         success: function success(res) {
           var data = res.data;
+          data.account_btn = data.account_btn.sort(function (a, b) {
+            return a.sort - b.sort;
+          });
           that.$set(that, "basicInfo", data);
+          that.search();
         }
       });
     },
     search: function search() {
       var that = this;
       var user = {
-        _id: '',
-        name: '自由天空',
-        account_id: '123456',
-        logo_url: [
-        //
-        {
-          id: "20230216100918",
-          name: "头像.jpg",
-          status: "success",
-          uid: 1676513358695,
-          uri: "/files/projectadmin/imgurl/20230216100918.jpg",
-          url: "http://47.93.34.200/files/projectadmin/imgurl/20230216100918.jpg"
-        }]
+        name: that.basicInfo.name,
+        phone: 'test',
+        logo_url: that.basicInfo.logo_url
       };
+      uni.getStorage({
+        key: 'token',
+        success: function () {
+          var _success = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(res) {
+            var arr, aee;
+            return _regenerator.default.wrap(function _callee$(_context) {
+              while (1) {
+                switch (_context.prev = _context.next) {
+                  case 0:
+                    arr = that.$jwt(res.data);
+                    _context.next = 3;
+                    return that.$api("user/".concat(arr._id), 'GET');
+                  case 3:
+                    aee = _context.sent;
+                    if (aee.errcode == '0') {
+                      user._id = aee.data._id;
+                      user.id = aee.data.id;
+                      user.phone = aee.data.phone;
+                      if (aee.data && aee.data.nick_name) user.name = aee.data.nick_name;
+                      if (aee.data && aee.data.logo_url) user.logo_url = aee.data.logo_url;
+                    }
+                  case 5:
+                  case "end":
+                    return _context.stop();
+                }
+              }
+            }, _callee);
+          }));
+          function success(_x) {
+            return _success.apply(this, arguments);
+          }
+          return success;
+        }(),
+        fail: function fail(err) {
+          console.log(err);
+        }
+      });
       that.$set(that, "userInfo", user);
-      // 判断logo
-      var logo_url = '';
-      if (user.logo_url && user.logo_url.length > 0) {
-        logo_url = user.logo_url[0].url;
-      } else {
-        logo_url = that.basicInfo.logo_url[0].url;
-      }
-      that.$set(that, "logo_url", logo_url);
     },
     // 注册,登录
     toLogin: function toLogin() {
@@ -226,6 +274,34 @@ var _default = {
         url: '/pagesAccount/login/index'
       });
     },
+    // 功能按钮跳转
+    toCommon: function toCommon(e) {
+      var that = this;
+      if (e.is_jump == '0') {
+        if (e.nature == 'share') {
+          console.log('分享');
+        } else if (e.nature == 'logout') {
+          uni.removeStorage({
+            key: 'token',
+            success: function success(res) {
+              uni.showToast({
+                title: '退出登录成功',
+                icon: 'none'
+              });
+              that.searchBasic();
+            },
+            fail: function fail(err) {
+              close(err);
+            }
+          });
+        }
+      } else if (e.is_jump == '1') {
+        that.toPath({
+          type: e.type,
+          route: e.route
+        });
+      }
+    },
     // 跳转页面
     toPath: function toPath(e) {
       var url = "/".concat(e.route);

+ 1 - 0
unpackage/dist/dev/mp-weixin/pagesHome/account/index.json

@@ -2,6 +2,7 @@
   "navigationBarTitleText": "账户",
   "enablePullDownRefresh": false,
   "usingComponents": {
+    "uni-icons": "/uni_modules/uni-icons/components/uni-icons/uni-icons",
     "home-frame": "/pagesHome/components/home-frame"
   }
 }

文件差异内容过多而无法显示
+ 1 - 1
unpackage/dist/dev/mp-weixin/pagesHome/account/index.wxml


+ 1 - 1
unpackage/dist/dev/mp-weixin/pagesHome/app/index.js

@@ -159,7 +159,7 @@ Object.defineProperty(exports, "__esModule", {
 exports.default = void 0;
 var homeFrame = function homeFrame() {
   __webpack_require__.e(/*! require.ensure | pagesHome/components/home-frame */ "pagesHome/components/home-frame").then((function () {
-    return resolve(__webpack_require__(/*! ../components/home-frame.vue */ 121));
+    return resolve(__webpack_require__(/*! ../components/home-frame.vue */ 123));
   }).bind(null, __webpack_require__)).catch(__webpack_require__.oe);
 };
 var _default = {

文件差异内容过多而无法显示
+ 14 - 14
unpackage/dist/dev/mp-weixin/pagesHome/components/home-frame.js


+ 1 - 1
unpackage/dist/dev/mp-weixin/pagesHome/find/index.js

@@ -168,7 +168,7 @@ Object.defineProperty(exports, "__esModule", {
 exports.default = void 0;
 var homeFrame = function homeFrame() {
   __webpack_require__.e(/*! require.ensure | pagesHome/components/home-frame */ "pagesHome/components/home-frame").then((function () {
-    return resolve(__webpack_require__(/*! ../components/home-frame.vue */ 121));
+    return resolve(__webpack_require__(/*! ../components/home-frame.vue */ 123));
   }).bind(null, __webpack_require__)).catch(__webpack_require__.oe);
 };
 var _default = {

+ 0 - 0
unpackage/dist/dev/mp-weixin/pagesHome/home/index.js


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