## 常用的工具类方法

常用的工具类方法定义在
```html
<script>
import utils from "hotent-ui/src/utils.js";

// TODO 使用utils.method()即可调用工具类方法了
</script>
```

## 方法一览表
|方法|说明|方法|说明
|:---|:---|:---|:---|
|getName()|获取随机名称|getWriteable(permission)|判断控件是否可编辑|
|mergeValidate(rules, appendRules)|融合校验规则|reduceValidate(rules, reduceRules)|移除校验规则|
|validateString2Object(rule)|字符串校验规则转对象|stringSplit(str, sep)|字符串分割为数组|
|addRequiredOrNot(permission, validate)|判断控件是否要添加必填校验|formatDate(value)|格式化日期时间|
|formatDateYear(value)|格式化日期|dateIsBefore(dateOne, dateTwo, canEquals)|判断日期1是否早于日期2|
|dateCalc(startDate, endDate, op)|计算开始时间和结束时间的间隔|tile2nest(array, key, pKey, childrenKey)|将平铺结构转为嵌套结构|
|getOnlineFormInstance(instance)|获取表单的VueComponent实例|getSubScopeElAndIndex(element)|获取子表的VueComponent实例及当前行索引|
|getSubInputScopeByModelExpression(subScopeEl, expression)|根据子表VueComponent实例获取表达式所对应的VueComponent实例|validateForm(instance, scopeName)|校验指定作用域的表单|
|getParentElementByAttribute(element, attribute)|获取上级元素中有指定属性的元素|getSomeAttributeFromParentElement(element, attribute)|获取上级元素中指定属性的值|
|getWholePathOfSub(subPath, mainPath, index)|将子表属性路径转换为完整的属性路径|getValueByPath(instance, path, subIndex)|获取路径所对应的值|
|setValueByPath(instance, path, value, subIndex)|根据路径设置值|parseToJson(jsonStr, type)|字符串解析为JSON对象|
|convertCurrency(currencyDigits)|数字转人民币大写|getUrlKey(name)|获取URL地址中指定参数的值|
|arrayMove(ary, part, direct)|将数组中的一个或多个元素调整顺序|getValueByConfigKey(instance, config, key)|通过配置来获取对应的值|
|setValueByConfigKey(instance, config, key, value)|通过配置来设置对应的值|objectEquals(obj1, obj2, props)|深度对比两个对象是否相等|
|arrayEquals(ary1, ary2)|深度对比两个数组是否相等|trimEachLine(text)|对大文本进行缩进处理|
|hashCode(text)|获取大文本的哈希编码|Array.prototype.remove(item)|数组中移除指定项|
|Array.prototype.unique(arg)|数组去重复|Array.prototype.trim()|数组去除空白项|
|Array.prototype.groupByKey(key)|数组按指定属性分组|-|-|
|Array.prototype.extractByKey(key)|数组抽取指定属性的值成为一个新的数组|nest2tile(arr,childrenKey,obtainChildren)|将嵌套结构转换为平铺结构|


## getName()
返回值`string`

获得一个随机产生的8位长度的字母数字组成的名称。

## getWriteable(permission)
返回值`boolean`

判断`permission`权限是否对应可编辑状态。

## mergeValidate(rules, appendRules)
返回值`string/object`

在已有规则`rules`中追加新的规则`appendRules`，如果`rules`和`appendRules`均为字符串格式，合并后仍为字符串格式；如果其中一个为Object格式，合并后为Object格式。
`rules`和`appendRules`均支持多个校验规则的情况下完成合并，而且在旧规则和追加规则中均有某一个规则时，会以`appendRules`中的规则覆盖掉`rules`中的规则。

## reduceValidate(rules, reduceRules)
返回值`string/object`

从已有规则`rules`中移除`reduceRules`对应的规则，返回的规则与`rules`的格式一样。

## validateString2Object(rule)
返回值`object`

将字符串格式的规则`rule`转换为对象格式。

## stringSplit(str, sep)
返回值`array`

字符串str按照sep分割为数组，并清理掉数组结果中的空白项。

## addRequiredOrNot(permission, validate)
返回值`string/object`

根据您`permission`权限信息来判断，当前`validate`中是否需要添加校验规则。是则返回添加了必填规则的校验规则表达式，否则返回原校验规则表达式。

## formatDate(value)
返回值`string`

按照`yyyy-MM-dd HH:mm:ss`的格式对`value`进行日期时间格式化，`value`的类型支持`Date`、时间戳、字符串等多种格式。

## formatDateYear(value)
返回值`string`

按照`yyyy-MM-dd`的格式对`value`进行日期格式化，`value`的类型支持字符串格式的日期类型。

## dateIsBefore(dateOne, dateTwo, canEquals)
返回值`boolean`

日期`dateOne`是否早于日期`dateTwo`，是则返回`true`，否则返回`false`。

另外参数`canEquals`表示两个日期能否不相等，该参数默认为`false`，表示不能相等，即日期`dateOne`等于`dateTwo`时返回`false`；反之如果该参数传入`true`时，日期`dateOne`等于`dateTwo`时返回`true`。

## dateCalc(startDate, endDate, op)
返回值`number`

计算`startDate`和`endDate`之间相差几个`op`单位，`op`的默认值为`day`，`op`的选项有：
+ year
- month
- day
- hour
- minute
- second


## tile2nest(array, key, pKey, childrenKey)
返回值`array`

将平铺结构的数组转换为嵌套结构的数组。参数说明：
+ `array`为待转换的平铺结构数组
- `key`为数据的主键，默认为`id`
- `pKey`为数据中存放父级数据主键的key，默认为`parentId`
- `childrenKey`为当数据转为嵌套结构后，子数据以什么key来存放，默认为`children`

如下所示，转换前后的结构：
```javascript
// 平铺结构（其中通过parentId标记出其父级数据的id）
const tile = [
    { id: "1", parentId: "-1", name: "1" },
    { id: "2", parentId: "1", name: "1-2" },
    { id: "3", parentId: "2", name: "1-2-3" },
    { id: "4", parentId: "2", name: "1-2-4" },
    { id: "5", parentId: "1", name: "1-5" },
    { id: "6", parentId: "5", name: "1-5-6" }
];
// 转换为嵌套结构后
const nest = [
    { id: "1", name: "1", children: [
        { id: "2", name: "1-2", children: [{ id: "3", name: "1-2-3" }, { id: "4", name: "1-2-4" }] },
        { id: "5", name: "1-5", children: [{ id: "6", name: "1-5-6" }] }
    ]}
];
```

## getOnlineFormInstance(instance)
返回值`object`

通过控件的`vueComponent`实例获取控件所在的表单的`vueComponent`实例。

## getSubScopeElAndIndex(element)
返回值`{ vueComponent, integer }`

根据子表对象中的某个Dom元素获取子表所对应的`vueComponent`对象及当前索引`index`。

<span style="color:#f00;font-weight:bold">特别注意：</span>
因为是通过`data-subname`来确定是否为子表，以及通过`data-index`来记录索引，所以只当子表按照以下格式时，该方法才能返回正确的结果。
```html
<element
v-for="(row, index) in data.sub"
:key="index"
:data-index="index"
data-subname="data.sub"
>
...
</element>
```

## getSubInputScopeByModelExpression(subScopeEl, expression)
返回值`vueComponent`

根据当前子表`vueComponent`对象获取其中`expression`所对应的`vueComponent`实例。

<span style="color:#f00;font-weight:bold">特别注意：</span>
因为是通过`class="inputs"`来查找子表中的控件，所以只有表达式`expression`使用在hotent-ui的控件上时，才能正确的返回结果。

在如下的代码中，通过`utils.getSubInputScopeByModelExpression(subScopeEl, "row.name")`就可以获取到该行中`<ht-input />`所对应的`vueComponent`实例。
```html
<li
v-for="(row, index) in data.sub"
:key="index"
:data-index="index"
data-subname="data.sub">
    <div>
        <ht-input v-model="row.name" />
        ...
    </div>
</li>
```

## validateForm(instance, scopeName)
返回值`promise`

对当前`vueComponent`实例中作用域为`scopeName`的表单进行校验，校验通过则触发`promise`中的`resolve`，否则触发`reject`，在`reject`中返回了`errors.items`，即校验失败的所有元素。

使用示例如下：
```html
<template>
    <form data-vv-scope="form1" v-form>
    ...
    </form>
</template>
<script>
...
    utils.validateForm(this, "form1")
         .then(r => {
            Message.success(JSON.stringify(this.data));
         })
         .catch(items => {
            Message.error(`有${items.length}个字段未通过校验，无法提交表单。`);
         })
         .finally(() => {
            this.loading = false;
         });
...
</script>
```

## getParentElementByAttribute(element, attribute)
返回值`HTMLElement`

获取`element`的父级元素中，拥有指定属性`attribute`的`HTMLElement`对象。

## getSomeAttributeFromParentElement(element, attribute)
返回值`any`

获取`element`的父级元素中，拥有指定属性`attribute`的`HTMLElement`对象中这个指定属性的值。

## getWholePathOfSub(subPath, mainPath, index)
返回值`string`

将子表属性路径转换为完整的属性路径，参数说明：
+ `subPath`子表中的表达式，如：item.name, row.name等
- `mainPath`子表在整体对象中的路径，例如:data.sub, data.children等
- `index`为子表哪一条数据的索引。


例如：当调用该方法时传递的参数为`utils.getWholePathOfSub('item.name', 'data.sub', 0)`时,结果为`data.sub[0].name`。

## getValueByPath(instance, path, subIndex)
返回值`any`

通过路径`path`获取实例`instance`中对应的值，如果是子表数据，需要传入`subIndex`指定索引。

使用示例如下所示：
```javascript
data(){
    return {
        data: {
            user: {
                name: "张三",
                age: 23,
                experice: [
                    { company: "设计院", start: "1999-07-28", end: "2000-09-18" },
                    { company: "图灵", start: "2000-10-11", end: "2001-12-11" }
                ]
            }
        }
    };
},
...
// 获取到的值为"张三"
utils.getValueByPath(this, "data.user.name");
// 获取子表数据，获取到的结果为"图灵"
utils.getValueByPath(this, "data.user.experice.company", 1);
...
```

## setValueByPath(instance, path, value, subIndex)
无返回值

设置`path`的值`value`到实例`instance`中，如果设置的值为子表数据，则需要传递`subIndex`作为索引。

使用示例如下：

```javascript
data(){
    return {
        data: {
            user: {
                name: "张三",
                age: 23,
                experice: [
                    { company: "设计院", start: "1999-07-28", end: "2000-09-18" },
                    { company: "图灵", start: "2000-10-11", end: "2001-12-11" }
                ]
            }
        }
    };
},
...
utils.setValueByPath(this, "data.user.name", "李四");
utils.setValueByPath(this, "data.user.experice.company", "水滴", 1);
...
// 设置后的data数据
user: {
    name: "李四",
    age: 23,
    experice: [
        { company: "设计院", start: "1999-07-28", end: "2000-09-18" },
        { company: "水滴", start: "2000-10-11", end: "2001-12-11" }
    ]
}
```

## parseToJson(jsonStr, type)
返回值`object/array`

将字符串`jsonStr`转换为对象格式，`type`为默认为1，可选值为
+ `1`使用`JSON.parse(jsonStr)`的方式来解析
- `2`使用`eval()`的方式来解析
在解析失败的情况下，系统会按照type从小到大的方式依次尝试解析。

## convertCurrency(currencyDigits)
返回值`string`

将数字转换为人民币大写。

## getUrlKey(name)
返回值`string`

通过`name`获取页面url地址参数。

## arrayMove(ary, part, direct)
返回值`array`

将数组`ary`中的指定部分`part`按照方向`direct`调整顺序，将调整顺序后的数组返回。`direct`的可选值有`up`和`down`，默认值为`down`。

## getValueByConfigKey(instance, config, key)
返回值`any`

通过配置中指定的`key`所对应的属性路径在当前表单中获取对应的值，支持通过`data.main.name`或者是 `item.name`来分别获取主表数据及子表数据的情况。当然，对于子表要求子表具有`data-subname`属性。

示例代码如下，在组件`my-role-selector`中，通过`utils.getValueByConfigKey(this, config, "id")`就能获取到`data.xxb.roleId`的值。

```javascript
<my-role-selector
    v-model="data.xxb.roles"
    permission="w"
    :config="{id:'data.xxb.roleId',code: 'data.xxb.roleCode'}"
    placeholder="请选择" />
```

## setValueByConfigKey(instance, config, key, value)
无返回值

通过配置中指定的`key`来设置值到对应的属性路径上，支持设置主表数据`data.main.name`或设置子表数据`item.name`。当然，对于子表要求子表具有`data-subname`属性。

示例代码如下，在组件`my-role-selector`中，通过`utils.setValueByConfigKey(this, config, "id")`就能将当前组件中`id`的值设置给`data.xxb.roleId`。

```javascript
<my-role-selector
    v-model="data.xxb.roles"
    permission="w"
    :config="{id:'data.xxb.roleId',code: 'data.xxb.roleCode'}"
    placeholder="请选择" />
```

## objectEquals(obj1, obj2, props)
返回值`boolean`

判断对象`obj1`和对象`obj2`是否相等，深度对比两个对象的所有属性值（如果属性为对象会继续深度对比）。当传入了`props`属性数组时，只会对传入的属性进行对比。

## arrayEquals(ary1, ary2)
返回值`boolean`

深度对比两个数组`ary1`,`ary2`，包括数组中的对象也会进行深度对比。

## trimEachLine(text)
返回值`string`

以第一行文本的缩进空格数为基准，后续的每一行都去掉这个基准所对应的空格。

## hashCode(text)
返回值`string`

获取文本所对应的哈希编码。

## Array.prototype.remove(item)
无返回值

【数组原型方法】在数组中移除指定项`item`。

## Array.prototype.unique(arg)
返回值`array`

【数组原型方法】对数组进行去重，如果传入了`arg`参数，则会对数组中的对象的`arg`属性进行判定，如果该属性相等则认为这两个对象相同。

## Array.prototype.trim()
返回值`array`

去除数组中的空字符串选项。

## Array.prototype.groupByKey(key)
返回值`object`

将数组中的所有对象按照`key`进行分组，并以`key`为对象key，以子数组为value构建为对象返回。


## Array.prototype.extractByKey(key)
返回值`Array`

 将数组对象中的某一个属性值单独抽取出来成为一个新的数组  [{id:'1',name:'苹果'},{id:'2',name:'香蕉'}].extractByKey("id") ==> ['1','2']。

## utils.nest2tile(arr,childrenKey,obtainChildren)
 返回值`Array` 
 childrenKey 默认值为 children  
 obtainChildren 如果为true 返回值包含children

