592 lines
18 KiB
PHP
592 lines
18 KiB
PHP
<?php
|
|
|
|
namespace admin\components\UI\Table;
|
|
|
|
use admin\components\UI\Form\Cascader;
|
|
use admin\components\UI\Tools;
|
|
use admin\components\UI\Widget\Icon;
|
|
|
|
/**
|
|
* 表格节点
|
|
* @package backend\components\UI\Table
|
|
*/
|
|
class Node
|
|
{
|
|
private string $url;
|
|
private ?string $key;
|
|
private ?string $title;
|
|
private bool $tree = false;
|
|
private bool $urlBind = true;
|
|
private string $class = '';
|
|
private array $params = [];
|
|
private array $data = ['show'=>[],'filter'=>[]];
|
|
private array $columns = [];
|
|
private array $expand = [];
|
|
private array $filter = [];
|
|
private array $quickFilter = [];
|
|
private array $action = [];
|
|
private array $bath = [];
|
|
private array $page = ['left'=>[],'right'=>[]];
|
|
private array $type = [];
|
|
private array $side = ['left'=>[],'right'=>[]];
|
|
private array $sideSize = ['left'=>'','right'=>''];
|
|
private array $header = [];
|
|
private array $footer = [];
|
|
private array $script = [];
|
|
private array $scriptReturn = [];
|
|
private array $scriptData = [];
|
|
private ?string $eventName = null;
|
|
private $filterLayout =null;
|
|
|
|
/**
|
|
* Node constructor.
|
|
* @param string $url
|
|
* @param string $key
|
|
* @param string|null $title
|
|
*/
|
|
public function __construct(string $url, string $key, ?string $title = '')
|
|
{
|
|
$this->url = $url;
|
|
$this->key = $key;
|
|
$this->title = $title;
|
|
}
|
|
|
|
/**
|
|
* @param $urlBind
|
|
* @return $this
|
|
*/
|
|
public function urlBind($urlBind): self
|
|
{
|
|
$this->urlBind = $urlBind;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $class
|
|
* @return $this
|
|
*/
|
|
public function class($class): self
|
|
{
|
|
$this->class .= ' ' . $class;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $params
|
|
* @return $this
|
|
*/
|
|
public function params($params): self
|
|
{
|
|
$this->params = $params;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* 附加参数
|
|
* @param $key
|
|
* @param $value
|
|
* @return $this
|
|
*/
|
|
public function nParams($key,$value){
|
|
$this->params[$key] = $value;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param array $filter
|
|
* @return $this
|
|
*/
|
|
public function data(array $filter): self
|
|
{
|
|
$this->data['filter'] = $filter;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $content
|
|
* @param $return
|
|
* @return $this
|
|
*/
|
|
public function script($content, $return): self
|
|
{
|
|
if ($content instanceof \Closure) {
|
|
$this->script[] = $content();
|
|
} else {
|
|
$this->script[] = $content;
|
|
}
|
|
$this->scriptReturn[] = $return;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $data
|
|
* @return $this
|
|
*/
|
|
public function scriptData($data): self
|
|
{
|
|
$this->scriptData = array_merge($this->scriptData, $data);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $config
|
|
* @return $this
|
|
*/
|
|
public function tree($config): self
|
|
{
|
|
$this->tree = $config;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param array $node
|
|
* @return $this
|
|
*/
|
|
public function columns(array $node): self
|
|
{
|
|
$this->columns = $node;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param array $node
|
|
* @return $this
|
|
*/
|
|
public function expand(array $node): self
|
|
{
|
|
$this->expand = $node;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param array $node
|
|
* @return $this
|
|
*/
|
|
public function type(array $node): self
|
|
{
|
|
$this->type = $node;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param array $node
|
|
* @return $this
|
|
*/
|
|
public function filter(array $node): self
|
|
{
|
|
$this->filter = array_values(array_filter($node));
|
|
return $this;
|
|
}
|
|
|
|
public function filterLayout($l):self{
|
|
$this->filterLayout =$l;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param array $node
|
|
* @return $this
|
|
*/
|
|
public function quickFilter(array $node): self
|
|
{
|
|
if ($node) {
|
|
$this->quickFilter = $node;
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param array $node
|
|
* @return $this
|
|
*/
|
|
public function action(array $node): self
|
|
{
|
|
$this->action = $node;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param array $node
|
|
* @return $this
|
|
*/
|
|
public function bath(array $node): self
|
|
{
|
|
$this->bath = $node;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param string|null $eventName
|
|
* @return $this
|
|
*/
|
|
public function eventName(?string $eventName): self
|
|
{
|
|
$this->eventName = $eventName;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $node
|
|
* @param string $type
|
|
* @param false $resize
|
|
* @param string $width
|
|
* @return $this
|
|
*/
|
|
public function side($node, string $type = 'left', bool $resize = false, string $width = '100px'): self
|
|
{
|
|
$this->side[$type] = is_callable($node) ? $node() : $node;
|
|
if ($resize) {
|
|
$this->sideSize[$type] = $width;
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $node
|
|
* @param string $type
|
|
* @return $this
|
|
*/
|
|
public function page($node, string $type = 'left'): self
|
|
{
|
|
$this->page[$type] = is_callable($node) ? $node() : $node;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $node
|
|
* @return $this
|
|
*/
|
|
public function header($node): self
|
|
{
|
|
$this->header = $node;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $node
|
|
* @return $this
|
|
*/
|
|
public function footer($node): self
|
|
{
|
|
$this->footer = $node;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @return array[]
|
|
*/
|
|
private function headNode(): array
|
|
{
|
|
if($this->filterLayout=='rows'){
|
|
$ret[] = [
|
|
'nodeName'=>'a-row',
|
|
'child'=>[
|
|
[
|
|
'nodeName'=>'a-col',
|
|
'child'=>[
|
|
'nodeName' => 'a-form',
|
|
"label-align"=>"left",
|
|
"vBind:label-col-props"=>"{'span':'8'}",
|
|
"vBind:wrapper-col-props"=>"{'span':'16'}",
|
|
'child'=>[
|
|
[
|
|
'nodeName'=>'a-row',
|
|
"vBind:gutter"=>"16",
|
|
'child' => $this->filter
|
|
],
|
|
]
|
|
]
|
|
],
|
|
]
|
|
];
|
|
if(!empty($this->action)){
|
|
if(!empty($this->filter)){
|
|
$ret[] = [
|
|
'nodeName'=>'a-divider',
|
|
'style'=>'margin-top: 0',
|
|
];
|
|
}
|
|
$ret[] = [
|
|
'nodeName'=>'a-row',
|
|
"style"=>"margin-bottom: 16px",
|
|
'child'=>[
|
|
'nodeName' => 'a-col',
|
|
'vBind:span'=>'16',
|
|
'child'=>[
|
|
'nodeName' => 'a-space',
|
|
'child'=>$this->action
|
|
]
|
|
]
|
|
];
|
|
}
|
|
return $ret;
|
|
}
|
|
if ($this->filter) {
|
|
$this->quickFilter[] = [
|
|
'nodeName' => 'a-trigger',
|
|
'position' => 'br',
|
|
'trigger' => 'click',
|
|
'child' => [
|
|
[
|
|
'nodeName' => 'a-button',
|
|
'type' => 'secondary',
|
|
'child' => [
|
|
'筛选',
|
|
[
|
|
'vSlot:icon' => '',
|
|
'nodeName' => 'icon-filter',
|
|
]
|
|
]
|
|
],
|
|
[
|
|
'vSlot:content' => '',
|
|
'nodeName' => 'div',
|
|
'class' => 'flex flex-col rounded shadow bg-white dark:bg-blackgray-1 dark:text-gray-400 p-2 w-56',
|
|
'child' => $this->filter
|
|
]
|
|
]
|
|
];
|
|
}
|
|
$header=[];
|
|
$ret = [];
|
|
if ($this->type) {
|
|
$header = [
|
|
'nodeName' => 'a-radio-group',
|
|
'name' => 'type',
|
|
'type' => 'button',
|
|
'vModel:modelValue' => 'data.filter.type',
|
|
'child' => $this->type
|
|
];
|
|
$ret[] = [
|
|
'nodeName' => 'div',
|
|
'class' => 'flex-grow lg:w-10 flex justify-center lg:justify-start',
|
|
'child' => $header
|
|
];
|
|
}
|
|
$ret[] = [
|
|
'nodeName' => 'div',
|
|
'class' => 'flex-none flex gap-2',
|
|
'child' => array_filter(array_merge($this->quickFilter, $this->action))
|
|
];
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
public function tableNode(): array
|
|
{
|
|
// 指定行key
|
|
$this->params['row-key'] = $this->key;
|
|
|
|
// 设置扩展行
|
|
if ($this->expand) {
|
|
$this->params['vChild:expandable'] = $this->expand;
|
|
}
|
|
|
|
// 分组表头线
|
|
$children = false;
|
|
foreach ($this->columns as $col) {
|
|
if (isset($col['children']) && $col['children']) {
|
|
$children = true;
|
|
break;
|
|
}
|
|
}
|
|
if ($children) {
|
|
$this->params['bordered'] = [
|
|
'headerCell' => true
|
|
];
|
|
}
|
|
|
|
return [
|
|
'nodeName' => 'app-table',
|
|
'requestEventName' => $this->eventName,
|
|
'class' => $this->class,
|
|
'url' => $this->url,
|
|
'urlBind' => $this->urlBind,
|
|
'n-params' => $this->params,
|
|
'columns' => $this->columns,
|
|
'vBind:filter' => 'data.filter',
|
|
'select' => (bool)$this->bath,
|
|
'table-layout-fixed' => true,
|
|
'child' => [
|
|
'vSlot:footer' => 'footer',
|
|
'nodeName' => 'div',
|
|
'class' => 'flex gap-2',
|
|
'child' => $this->bath
|
|
]
|
|
];
|
|
}
|
|
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
public function render(): array
|
|
{
|
|
|
|
/*$this->script[] = <<<JS
|
|
JS;
|
|
$this->scriptReturn[] = 'dataRef';*/
|
|
|
|
$value = [
|
|
'filter' => $this->data['filter'] ?: [],
|
|
'show' => $this->data['show'] ?: []
|
|
];
|
|
$value = array_merge($this->scriptData, $value);
|
|
return [
|
|
'node' => [
|
|
'nodeName' => 'app-form',
|
|
'value' => $value,
|
|
'child' => [
|
|
'nodeName' => 'div',
|
|
'class' => 'flex h-screen',
|
|
'vSlot' => '{value: data}',
|
|
'child' => [
|
|
$this->side['left'] ? [
|
|
'nodeName' => isset($this->sideSize['left']) ? 'a-resize-box' : 'div',
|
|
'style' => $this->sideSize['left'] ? 'width:' . $this->sideSize['left'] : '',
|
|
'directions' => ['right'],
|
|
'class' => 'border-r border-gray-200 dark:border-gray-700 flex-none bg-white dark:bg-blackgray-4 h-screen',
|
|
'child' => $this->side['left']
|
|
] : [],
|
|
|
|
[
|
|
'nodeName' => 'app-layout',
|
|
'class' => 'flex-grow w-10',
|
|
'title' => $this->title ?: '列表数据',
|
|
'child' => [
|
|
[
|
|
'vSlot' => '',
|
|
'nodeName' => 'div',
|
|
'class' => 'flex flex-row items-start gap-4 p-4',
|
|
'child' => [
|
|
$this->page['left'] ?: [],
|
|
[
|
|
'nodeName' => 'div',
|
|
'class' => 'flex-grow lg:w-10 p-4 bg-white dark:bg-blackgray-4 rounded shadow',
|
|
'child' => [
|
|
$this->header ? [
|
|
'nodeName' => 'div',
|
|
'class' => 'pb-4',
|
|
'child' => $this->header
|
|
] : [],
|
|
[
|
|
'nodeName' => 'div',
|
|
'class' => 'flex-none flex-row gap-2 items-center pb-4',
|
|
'child' => $this->headNode()
|
|
|
|
],
|
|
$this->tableNode(),
|
|
$this->footer ? [
|
|
'nodeName' => 'div',
|
|
'class' => 'pb-4',
|
|
'child' => $this->footer
|
|
] : [],
|
|
],
|
|
],
|
|
$this->page['right'] ?: [],
|
|
]
|
|
]
|
|
]
|
|
],
|
|
|
|
|
|
$this->side['right'] ? [
|
|
'nodeName' => $this->sideSize['right'] ? 'a-resize-box' : 'div',
|
|
'style' => $this->sideSize['right'] ? 'width:' . $this->sideSize['left'] : '',
|
|
'directions' => ['left'],
|
|
'class' => 'border-l border-gray-200 dark:border-gray-700 flex-none bg-white dark:bg-blackgray-4 h-screen',
|
|
'child' => $this->side['right']
|
|
] : [],
|
|
]
|
|
],
|
|
],
|
|
'setupScript' => implode("\n", $this->script) . "\n" . ' return {' . implode(",", $this->scriptReturn) . '}'
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 渲染table核心
|
|
* @return array[]
|
|
*/
|
|
public function renderTableCore(): array
|
|
{
|
|
$value = [
|
|
'filter' => $this->data['filter'] ?: [],
|
|
'show' => $this->data['show'] ?: []
|
|
];
|
|
$value = array_merge($this->scriptData, $value);
|
|
return [
|
|
'node' => [
|
|
'nodeName' => 'app-form',
|
|
'value' => $value,
|
|
'child' => [
|
|
'nodeName' => 'app-dialog',
|
|
'vSlot' => '{value: data}',
|
|
'title' => $this->title ?: '信息详情',
|
|
'class' => 'flex-grow',
|
|
'child' => [
|
|
[
|
|
'nodeName' => 'div',
|
|
'class' => 'flex',
|
|
'vSlot' => '{value: data}',
|
|
'child' => [
|
|
$this->side['left'] ? [
|
|
'nodeName' => 'div',
|
|
'class' => 'flex-none',
|
|
'child' => $this->side['left']
|
|
] : [],
|
|
[
|
|
'nodeName' => 'div',
|
|
'class' => 'flex-grow lg:w-10 p-4 bg-white dark:bg-blackgray-4 rounded shadow',
|
|
'child' => [
|
|
$this->header ? [
|
|
'nodeName' => 'div',
|
|
'class' => 'pb-4',
|
|
'child' => $this->header
|
|
] : [],
|
|
[
|
|
'nodeName' => 'div',
|
|
'class' => 'flex-none flex flex-row gap-2 items-center pb-4',
|
|
'child' => $this->headNode()
|
|
|
|
],
|
|
$this->tableNode(),
|
|
$this->footer ? [
|
|
'nodeName' => 'div',
|
|
'class' => 'pb-4',
|
|
'child' => $this->footer
|
|
] : [],
|
|
],
|
|
],
|
|
$this->side['right'] ? [
|
|
'nodeName' => 'div',
|
|
'class' => 'flex-none',
|
|
'child' => $this->side['right']
|
|
] : []
|
|
]
|
|
],
|
|
[
|
|
'nodeName' => 'div',
|
|
'vSlot:footer' => '',
|
|
'class' => 'arco-modal-footer',
|
|
'child' => [
|
|
[
|
|
'nodeName' => 'route',
|
|
'type' => 'back',
|
|
'child' => [
|
|
'nodeName' => 'a-button',
|
|
'child' => '关闭'
|
|
]
|
|
]
|
|
]
|
|
]
|
|
]
|
|
]
|
|
]
|
|
];
|
|
}
|
|
|
|
}
|