### 视图模型 ViewModel 类
#### 视图模型说明
视图模型是用于根据所填写的规则来生成相应视图的类, 视图模型目录: `application\admin\viewModel\`, 每个视图模型类都继承 `app\common\ViewModel`, `app\common\ViewModel` 类中仅包含一些基础公用的方法, 具体的方法和属性根据逻辑拆分成了多个 `trait` , 所以在 `app\common\ViewModel` 中可以看到代码中
```php
use IndexView,
AddView,
UpdateView,
Export,
Import;
```
其中 IndexView 包含 Index 页面所需要的属性和方法, AddView, UpdateView 分别包含 Add 页面, Update 页面所需属性和方法, Export 和 Import 则包含了处理导出和导入的属性和方法, 这些 `trait` 位于`application\traits` 目录下
#### 属性和方法说明
##### 通用属性和方法
###### $tableName
对应的表的名称, 如果未设置, 将会把当前类的名称转换称表名使用, 转换格式如: app\admin\viewModel\ProductCategory => product_category
###### $fieldsName
声明所有用到的字段的展示名, 是一个键值对数组, 数组的键为字段名, 值为对应的展示名, 如果字段不是表 `$tableName` 定义的那么需要加上相对于的表前缀或表的别名, 例如:
```php
public $fieldsName = [
'id' => 'ID',
'name' => '分类名称',
'create_time' => '添加时间',
];
```
###### $variables
声明所需要用到的表的名称, 声明之后可以在 `$fieldsName`, `$indexFields`, `$updateFields`, `$addFields`, `$search` 等属性中使用别名来代替原始的表名作为表前缀, 例如:
```php
public $variables = ['product_category', 'product_info'];
// 声明后, 在可用的其它属性中可以使用 $1 代替 product_category, $2 代替 product_info
public $fieldsName = [
'id' => 'ID',
'cid' => '商品分类id',
'name' => '商品名称',
'price' => '商品价格',
'status' => '状态',
'thumb' => '商品封面',
'banners' => '商品banner',
'create_time' => '添加时间',
'update_time' => '修改时间',
'$1.name' => '商品分类', // $1.name => product_category.name
'$2.information' => '商品详情', // $2.information => product_info.information
];
```
###### $pk
视图模型对应表的主键, 默认为 `id`
##### Index 页面相关
###### $join
join 规则, 是一个多维数组, 数组的每一项都是一个单独的 join 规则, 可以使用 `$variables` 中声明的别名
```
public $join = [
['$1', '$1.pid=$0.id', 'left']
];
// $0 为当前视图模型对应的表名
```
###### $indexFields
Index 页面中需要展示的字段和规则, 键值对数组, 键为字段名(如果不是当前视图模型对应的表中的字段, 必须加上表前缀或别名), 值为所使用的表格组件和参数, 可以是数组或者字符串, 例如
```php
public $indexFields = [
'id' => 'text',
// 为了防止重名, $.name 或 name 中需要有一个字段设置别名, 并在 fieldsName 中声明这个别名的展示名, 这里我们把 $.name 设置别名为 c_name
'$1.name' => ['text', 'alias' => 'c_name'],
'name' => 'text',
'price' => 'text',
// 状态使用 表格组件中的 Convert 组件, 并将数组 [1 => '上架', 2 => '下架'] 作为参数传入 convert 组件中
'status' => ['convert', [1 => '上架', 2 => '下架']],
'thumb' => 'img',
'create_time' => 'text',
'update_time' => 'text',
];
```
*表格组件相关信息请参考 [表格组件.md](表格组件.md)*
**特殊情况**
1. 当字段的参数数组的 `not_field` 选项为 true 或不为空时, 当前字段不会从数据库获取
2. 当组件名为 `@hidden` 时, 该字仍会从数据库获取, 但是不会在 表格中展示
3. 当组件名为一个模板文件的路径时, 这个模板文件将会当成当前字段的组件尝试渲染
###### $order
排序规则, 同 thinkphp 中的 `\think\Db::order` 方法的参数
###### $page
是否开启分页功能
###### $buttons
表格中每一行对应的操作按钮, 是一个多维数组, 数组中的每一项对应一个操作按钮, 语法如下:
```php
/** @var $buttons array 操作按钮 */
public $buttons = [
[
'url' => 'update', // 转跳链接
'type' => 'info', // 按钮类型(样式) 目前支持: primary, default, info, danger, warning
'name' => '编辑', // 按钮名称
'params' => [ // 转跳链接携带的参数
'@pk' => '@pk' // '@pk' 对应的键将会替换成当前表的主键字段名, '@pk' 对应的值将会替换成当前行的主键的值
]
],
[
'url' => 'delete',
'type' => 'danger',
'confirm' => '确认要删除该项吗(该操作无法恢复)', // confirm 参数存在时, 用户点击按钮将会先弹出相应提示, 确认后才会进行转跳, 一般危险操作(如: 删除)建议使用该参数
'name' => '删除',
'params' => [
'@pk' => '@pk'
]
]
];
```
###### $search
用于搜索的字段, 是一个键值对数组, 键名为要参与搜索的字段名, 值为要使用的搜索组件的名称, 是否模糊搜索, 和组件参数, 例如
```php
public $search = [
'name' => ['text', 'like'], // 数组第一项表示组件名, 第二项是否模糊搜索('like'为开启模糊搜索, null 为不开启), 第三项作为参数传入搜索组件
'create_time' => ['datetime', ],
// 使用搜索组件中的 selector 组件, 使用 product_category 表中的数据
'cid' => ['selector', null, [
'table' => 'product_category',
'field' => 'name',
'value' => 'id'
]],
// 使用搜索组件中的 selector 组件, 使用固定数据
'status' => ['selector', null, [
'list' => [
[1, '上架'],
[2, '下架']
],
'field' => 1,
'value' => 0
]],
];
```
*搜索组件相关信息参考 [搜索组件.md](搜索组件.md)*
###### 方法 fetchButtons ($row) :array
用于手动构建每一行的操作按钮, 参数 `$row` 为当前行的数据, 必须返回一个 `buttons` 数组格式参考 `$buttons` 属性
示例:
```php
public fetchButtons ($row) {
$buttons = $this->buttons;
// todo some thing ...
return $buttons;
}
```
###### 方法 filter (&$param) :array|string|null
该方法存在时, 将会在执行真正的搜索前, 先将获取到的参数传到 filter 方法中处理, 可以返回一个 `think\Db::where` 方法的参数, 用于查询, 也可以先返回空值, 仅将搜索的参数处理一边
```php
public filter (&$param) {
if (!empty($params['status']) && $params['status'] === '_empty') {
unset($param['status']);
}
}
// 如果搜索条件中 status 为 _empty 时, 不对 status 字段进行搜索
```
##### Update 和 Add 页面
###### $updateFields 和 $addFields
这两个属性分别表示 update 页面的表单规则 和 add 页面的表单规则, 写法完全一样, 是一个键值对数组, 键为字段名(当字段不属于视图模型对应的表时, 需要加上表前缀或者别名), 值为使用的使用的表单组件和相应的规则
数组的第一个参数时表单组件的名称, 第二个参数是验证规则(同thinkphp验证器规则), 第三个参数是提示文本, 第四个参数是表单组件的参数
**当 `$updateFields` 与 `$addFields` 完全相同时, 可以省略 `$addFields`**
示例:
```php
public $updateFields = [
// 使用表单组件中的 selector 组件, 使用 product_category 表中的数据
'cid' => ['selector', 'require', null, [
'table' => 'product_category',
'field' => 'name',
'value' => 'id'
]],
// 数组的第一个参数时表单组件的名称, 第二个参数是验证规则(同thinkphp验证器规则), 第三个参数是提示文本, 第四个参数是表单组件的参数
'name' => ['text', 'require'],
'price' => ['text', 'require'],
// 使用表单组件中的 selector 组件, 使用固定数据
'status' => ['selector', 'require', null, [
'list' => [
[1, '上架'],
[2, '下架']
],
'field' => 1,
'value' => 0
]],
'thumb' => ['image', 'require'],
'banners' => ['image', null],
// 使用表单组件 中的 Html 富文本组件
'information' => ['html', null],
];
```
*表单组件的详细信息可以参考 [表单组件.md](表单组件.md)*
**特殊情况**
1. 参数数组中 def 选项可以为表单指定一个默认值 (该选项需要表单组件支持), 如:
```php
public $updateFields = [
'order' => ['text', 'require', 'def' => '50'] // order 的默认值将会是 50
];
```
2. 表单组件的名称可以是一个有效的模板文件路径, 该模板文件将会被作为该字段的表单组件参与渲染
##### 导出
###### $showExportButton
是否开启导出功能
###### $exportStartCell
导出的起始单元格(左上角)
###### $exportFields
导出字段
示例:
```php
// 字符串数组
public $exportFields = ['field1', 'field2', 'field3'];
// 用","分割的字符串数组
public $exportFields = [
'field1,field1_name,convertMethod1',
'field2,field2_name,convertMethod2'
];
// 二维数组
public $exportFields = [
[
'field1', // 字段名
'field1_name', // 字段展示名
'convertMenthod1' // 字段处理方法
]
];
/**
* 字段处理方法
* @param $val string 当前字段的值
* @param $row array 当前行的数据
* @param $field string 当前字段名称
* @return string
*/
public function convertMethod1 ($val, $row, $field) {
return $val;
}
```
##### 导入
###### $showImportButton
是否开启导入功能
###### $importStartCell
导入的起始单元格(左上角)
###### $excelLayout
excel 的布局 'row' 行 'col' 列
###### $importFields
导入字段
示例:
```php
['field1', 'field2', ...]
[
'field1,field1_alias1|field1_alias2,convertMethod1',
'field2,field2_alias1|field2_alias2,convertMethod2',
...
]
[
[
'field1', // 字段名
'field1_alias1|field1_alias2', // 字段别名, 多个别名之间使用 "|" 分隔
'convertMethod1' // 字段处理方法
],
...
]
/**
* 字段处理方法
* @param $val string 当前字段的值
* @param $row array 当前行的数据
* @param $field string 当前字段名称
* @return string
*/
public function convertMethod1 ($val, $row, $field) {}
```