### 視圖模型 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) {}
```