Novecane
2025-02-15 a12e5f63a90446525b2f322fb2bbd21d5285cd6d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
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;
    }
}