From bf05e84eee2fb4e1d11b1d19699f83771efac7da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A0=82=E7=B3=96?= Date: Sat, 26 Jul 2025 14:06:06 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BA=93=E5=AD=98=E7=9B=98=E7=82=B9=E5=92=8C?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E7=9A=84=E5=88=9D=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/oa/oaContract.js | 45 ++ api/oa/wms/stock.js | 10 + pages.json | 32 + pages/workbench/index/index.vue | 23 +- pages/workbench/project/add.vue | 139 ++++ pages/workbench/project/detail.vue | 197 ++++++ pages/workbench/project/project.vue | 254 +++++++ pages/workbench/wms/wms.vue | 385 +++++++++++ static/images/project.png | Bin 0 -> 5422 bytes static/images/stock.png | Bin 0 -> 3597 bytes uni_modules/uni-forms/changelog.md | 100 +++ .../uni-forms-item/uni-forms-item.vue | 632 ++++++++++++++++++ .../components/uni-forms/uni-forms.vue | 404 +++++++++++ .../uni-forms/components/uni-forms/utils.js | 293 ++++++++ .../components/uni-forms/validate.js | 486 ++++++++++++++ uni_modules/uni-forms/package.json | 89 +++ uni_modules/uni-forms/readme.md | 23 + .../uni-tag/components/uni-tag/uni-tag.vue | 4 +- 18 files changed, 3112 insertions(+), 4 deletions(-) create mode 100644 api/oa/oaContract.js create mode 100644 api/oa/wms/stock.js create mode 100644 pages/workbench/project/add.vue create mode 100644 pages/workbench/project/detail.vue create mode 100644 pages/workbench/project/project.vue create mode 100644 pages/workbench/wms/wms.vue create mode 100644 static/images/project.png create mode 100644 static/images/stock.png create mode 100644 uni_modules/uni-forms/changelog.md create mode 100644 uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue create mode 100644 uni_modules/uni-forms/components/uni-forms/uni-forms.vue create mode 100644 uni_modules/uni-forms/components/uni-forms/utils.js create mode 100644 uni_modules/uni-forms/components/uni-forms/validate.js create mode 100644 uni_modules/uni-forms/package.json create mode 100644 uni_modules/uni-forms/readme.md diff --git a/api/oa/oaContract.js b/api/oa/oaContract.js new file mode 100644 index 0000000..251f93d --- /dev/null +++ b/api/oa/oaContract.js @@ -0,0 +1,45 @@ +import request from "@/util/oaRequest" + +// 根据项目id查询合同信息 +export function findContractByProjectId(query) { + return request({ + url: '/oa/oaContract/findContract', + method: 'get', + params: query + }) +} + +// 根据项目id查询合同列表 +export function selectContractByProjectId(query) { + return request({ + url: '/oa/oaContract/selectContract', + method: 'get', + params: query + }) +} + +// 新增合同管理 +export function addOaContract(data) { + return request({ + url: '/oa/oaContract', + method: 'post', + data: data + }) +} + +// 修改合同管理 +export function updateOaContract(data) { + return request({ + url: '/oa/oaContract', + method: 'put', + data: data + }) +} + +// 删除合同管理 +export function delOaContract(contractId) { + return request({ + url: '/oa/oaContract/' + contractId, + method: 'delete' + }) +} diff --git a/api/oa/wms/stock.js b/api/oa/wms/stock.js new file mode 100644 index 0000000..531a47b --- /dev/null +++ b/api/oa/wms/stock.js @@ -0,0 +1,10 @@ +import request from "@/util/oaRequest" + +// 查询库存管理列表 +export function listStock(query) { + return request({ + url: '/oa/oaWarehouse/list', + method: 'get', + params: query + }) +} \ No newline at end of file diff --git a/pages.json b/pages.json index a742880..73e6566 100644 --- a/pages.json +++ b/pages.json @@ -317,6 +317,38 @@ "navigationBarTitleText" : "快递信息", "navigationStyle": "default" } + }, + { + "path" : "pages/workbench/project/project", + "style" : + { + "navigationBarTitleText" : "项目中心", + "navigationStyle": "default" + } + }, + { + "path" : "pages/workbench/wms/wms", + "style" : + { + "navigationBarTitleText" : "库存管理", + "navigationStyle": "default" + } + }, + { + "path" : "pages/workbench/project/add", + "style" : + { + "navigationBarTitleText" : "新建项目", + "navigationStyle": "default" + } + }, + { + "path" : "pages/workbench/project/detail", + "style" : + { + "navigationBarTitleText" : "项目详情", + "navigationStyle": "default" + } } ], "tabBar": { diff --git a/pages/workbench/index/index.vue b/pages/workbench/index/index.vue index f7e5adf..0c81569 100644 --- a/pages/workbench/index/index.vue +++ b/pages/workbench/index/index.vue @@ -24,9 +24,18 @@ - 快递信息 + 快递信息 + + + + 项目中心 + + + + 库存盘点 + @@ -81,7 +90,17 @@ export default { uni.navigateTo({ url: '/pages/workbench/express/express' }) - } + }, + goProject() { + uni.navigateTo({ + url: '/pages/workbench/project/project' + }) + }, + goStock() { + uni.navigateTo({ + url: '/pages/workbench/wms/wms' + }) + } }, }; diff --git a/pages/workbench/project/add.vue b/pages/workbench/project/add.vue new file mode 100644 index 0000000..10a0414 --- /dev/null +++ b/pages/workbench/project/add.vue @@ -0,0 +1,139 @@ + + + + + diff --git a/pages/workbench/project/detail.vue b/pages/workbench/project/detail.vue new file mode 100644 index 0000000..14f13b2 --- /dev/null +++ b/pages/workbench/project/detail.vue @@ -0,0 +1,197 @@ + + + + + diff --git a/pages/workbench/project/project.vue b/pages/workbench/project/project.vue new file mode 100644 index 0000000..ae15ef6 --- /dev/null +++ b/pages/workbench/project/project.vue @@ -0,0 +1,254 @@ + + + + + diff --git a/pages/workbench/wms/wms.vue b/pages/workbench/wms/wms.vue new file mode 100644 index 0000000..2105a59 --- /dev/null +++ b/pages/workbench/wms/wms.vue @@ -0,0 +1,385 @@ + + + + + diff --git a/static/images/project.png b/static/images/project.png new file mode 100644 index 0000000000000000000000000000000000000000..fc94695ca9937cdcd799d6e92717d7bbcacb91dd GIT binary patch literal 5422 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 literal 0 HcmV?d00001 diff --git a/static/images/stock.png b/static/images/stock.png new file mode 100644 index 0000000000000000000000000000000000000000..8b2deea2c70a1f8eead775008e9aaff65a52eb4d GIT binary patch literal 3597 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 T?G=ru?*QC+8}sV3p7;I__ydRB literal 0 HcmV?d00001 diff --git a/uni_modules/uni-forms/changelog.md b/uni_modules/uni-forms/changelog.md new file mode 100644 index 0000000..0b58ab8 --- /dev/null +++ b/uni_modules/uni-forms/changelog.md @@ -0,0 +1,100 @@ +## 1.4.13(2024-10-08) +- 修复 校验规则在抖音开发者工具上不生效的bug,详见:[https://ask.dcloud.net.cn/question/191933](https://ask.dcloud.net.cn/question/191933) +## 1.4.12 (2024-9-21) +- 修复 form上次修改的问题 +## 1.4.11 (2024-9-14) +- 修复 binddata的兼容性问题 +## 1.4.10(2023-11-03) +- 优化 labelWidth 描述错误 +## 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 diff --git a/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue b/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue new file mode 100644 index 0000000..c924882 --- /dev/null +++ b/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue @@ -0,0 +1,632 @@ + + + + + diff --git a/uni_modules/uni-forms/components/uni-forms/uni-forms.vue b/uni_modules/uni-forms/components/uni-forms/uni-forms.vue new file mode 100644 index 0000000..d061313 --- /dev/null +++ b/uni_modules/uni-forms/components/uni-forms/uni-forms.vue @@ -0,0 +1,404 @@ + + + + + diff --git a/uni_modules/uni-forms/components/uni-forms/utils.js b/uni_modules/uni-forms/components/uni-forms/utils.js new file mode 100644 index 0000000..6da2421 --- /dev/null +++ b/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; + } +} diff --git a/uni_modules/uni-forms/components/uni-forms/validate.js b/uni_modules/uni-forms/components/uni-forms/validate.js new file mode 100644 index 0000000..1834c6c --- /dev/null +++ b/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 diff --git a/uni_modules/uni-forms/package.json b/uni_modules/uni-forms/package.json new file mode 100644 index 0000000..0d72c63 --- /dev/null +++ b/uni_modules/uni-forms/package.json @@ -0,0 +1,89 @@ +{ + "id": "uni-forms", + "displayName": "uni-forms 表单", + "version": "1.4.13", + "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", + "alipay": "n" + }, + "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" + } + } + } + } +} diff --git a/uni_modules/uni-forms/readme.md b/uni_modules/uni-forms/readme.md new file mode 100644 index 0000000..63d5a04 --- /dev/null +++ b/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的内置组件已经有了 `
`组件,用于提交表单内容。 + +然而几乎每个表单都需要做表单验证,为了方便做表单验证,减少重复开发,`uni ui` 又基于 ``组件封装了 ``组件,内置了表单验证功能。 + +`` 提供了 `rules`属性来描述校验规则、``子组件来包裹具体的表单项,以及给原生或三方组件提供了 `binddata()` 来设置表单值。 + +每个要校验的表单项,不管input还是checkbox,都必须放在``组件中,且一个``组件只能放置一个表单项。 + +``组件内部预留了显示error message的区域,默认是在表单项的底部。 + +另外,``组件下面的各个表单项,可以通过``包裹为不同的分组。同一``下的不同表单项目将聚拢在一起,同其他group保持垂直间距。``仅影响视觉效果。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-forms) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-tag/components/uni-tag/uni-tag.vue b/uni_modules/uni-tag/components/uni-tag/uni-tag.vue index 7274436..d140578 100644 --- a/uni_modules/uni-tag/components/uni-tag/uni-tag.vue +++ b/uni_modules/uni-tag/components/uni-tag/uni-tag.vue @@ -120,7 +120,7 @@ .uni-tag { line-height: 14px; - font-size: 12px; + font-size: 12rpx; font-weight: 200; padding: $tag-default-pd; color: #fff; @@ -151,7 +151,7 @@ &--mini { padding: $tag-mini-pd; - font-size: 12px; + font-size: 8px !important; border-radius: 2px; }