初始化仓库

This commit is contained in:
2024-09-19 11:32:39 +08:00
commit 8f5315e936
921 changed files with 76455 additions and 0 deletions

View File

@@ -0,0 +1,101 @@
<?php
namespace admin\components\UI\Form;
/**
* 地区选择器
* @package backend\components\UI\Form
*/
class Area extends Element implements Component
{
protected bool $multi = false;
protected array $map = [
'province' => 'province',
'city' => 'city',
'region' => 'region',
'street' => 'street',
];
/**
* @param string $name
* @param array $map
* @param string $has
*/
public function __construct(string $name, array $map = [], string $has = '')
{
if ($map) {
$this->map = $map;
}
$this->name = $name;
$this->field = end($this->map);
$this->has = $has;
$this->attr['placeholder'] = null;
}
/**
* @return $this
*/
public function multi(): self
{
$this->multi = true;
return $this;
}
/**
* @return array
*/
public function render(): array
{
$data = [
'nodeName' => 'app-cascader',
'nParams' => [
'cascade' => true,
'show-path' => true,
'filterable' => false,
'clearable' => true,
'leaf-only' => true,
'multiple' => $this->multi,
'placeholder' => $this->attr['placeholder'] ?: '请选择' . $this->name,
],
'dataUrl' => route('service.area', ['level' => count($this->map)]),
];
if ($this->model) {
$data['vModel:value'] = $this->getModelField();
}
return $data;
}
/**
* @param $data
* @return array
*/
public function appendInput($data): array
{
$info = \backend\components\Model\Area::where(['code' => $data])->first();
$code = $info->parent_code;
if ($info->level > 3) {
$region = \backend\components\Model\Area::where(['code' => $code])->first();
$code = $region['parent_code'];
}
if ($info->level > 2) {
$city = \backend\components\Model\Area::where(['code' => $code])->first();
$code = $city['parent_code'];
}
if ($info->level > 1) {
$province = \backend\components\Model\Area::where(['code' => $code])->first();
}
$data = [];
if ($region) {
$data[$this->map['region']] = $region->code;
}
if ($city) {
$data[$this->map['city']] = $city->code;
}
if ($province) {
$data[$this->map['province']] = $province->code;
}
return $data;
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace admin\components\UI\Form;
use admin\components\UI\Form;
/**
* 卡片布局
* @package backend\components\UI\Table
*/
class Card extends Composite implements Component
{
protected \Closure $callback;
public function __construct($callback)
{
$this->callback = $callback;
$form = new Form();
$form->dialog($this->dialog);
$form->vertical($this->vertical);
$callback($form);
$this->column[] = [
'object' => $form,
];
}
/**
* @return array
*/
public function render(): array
{
$inner = [];
foreach ($this->column as $vo) {
$inner = $vo['object']->renderForm();
}
if (!$this->dialog) {
$this->class('mb-4 bg-white dark:bg-blackgray-4 rounded shadow p-7 pb-2');
}
return [
'nodeName' => 'div',
'class' => implode(' ', $this->class),
'child' => $inner
];
}
}

View File

@@ -0,0 +1,200 @@
<?php
namespace admin\components\UI\Form;
/**
* 级联选择器
* @package backend\components\UI\Form
*/
class Cascader extends Element implements Component
{
protected bool $tip = false;
protected bool $multi = false;
protected bool $leaf = true;
private array $params = [];
protected bool $treeData = false;
protected string $url = '';
protected string $route = '';
protected $data;
/**
* @param string $name
* @param string $field
* @param null $data
* @param string $has
*/
public function __construct(string $name, string $field, $data = null, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->data = $data;
$this->has = $has;
$this->attr['placeholder'] = null;
}
/**
* 添加选项
* @param $name
* @param $id
* @param $pid
* @return $this
*/
public function add($name, $id, $pid): self
{
$this->data[] = [
'name' => $name,
'id' => $id,
'pid' => $pid
];
return $this;
}
/**
* @param $url
* @return $this
*/
public function url($url): self
{
$this->url = $url;
return $this;
}
/**
* @param string $route
* @param array $params
* @return $this
*/
public function route(string $route, array $params = []): self
{
$this->route = $route;
$this->url = app_route($route, $params);
return $this;
}
/**
* @return $this
*/
public function multi(): self
{
$this->multi = true;
return $this;
}
/**
* leaf choice
* @param bool $leaf
* @return $this
*/
public function leaf(bool $leaf): self
{
$this->leaf = $leaf;
return $this;
}
/**
* tree data
* @param bool $bool
* @return $this
*/
public function tree(bool $bool = true): self
{
$this->treeData = $bool;
return $this;
}
/**
* 标签显示最大条数
* @param int $num
* @return $this
*/
public function maxTagCount(int $num){
return $this->nParams('maxTagCount',$num);
}
/**
* 附加参数
* @param $key
* @param $value
* @return $this
*/
public function nParams($key,$value){
$this->params[$key] = $value;
return $this;
}
/**
* @return array
*/
public function render(): array
{
$data = [];
if ($this->data instanceof \Closure) {
$data = call_user_func($this->data, $this);
}
if (is_array($this->data)) {
$data = $this->data;
}
if (!$this->treeData) {
$options = [];
foreach ($data as $vo) {
$options[] = [
'id' => $vo['id'],
'pid' => $vo['parent_id'],
'value' => $vo['id'],
'label' => $vo['name'],
];
}
$options = \backend\components\Tree::arr2tree($options, 'id', 'pid', 'children');
} else {
$options = $data;
}
$data = [
'nodeName' => 'app-cascader',
'nParams' => array_merge($this->params, [
'check-strictly' => !$this->leaf,
'multiple' => $this->multi,
'options' => $options,
'placeholder' => $this->attr['placeholder'] ?: '请选择' . $this->name,
])
];
if ($this->route) {
$data['vBind:dataUrl'] = $this->url;
} else {
$data['dataUrl'] = $this->url;
}
if ($this->model) {
$data['vModel:value'] = $this->getModelField();
}
return $data;
}
/**
* @param $value
* @return array|mixed
*/
public function dataValue($value)
{
return $this->multi ? array_values(array_filter((array)$this->getValueArray($value))) : $this->getValue($value);
}
/**
* @param $data
* @return string
*/
public function dataInput($data): ?string
{
return is_array($data) ? implode(',', $data) : $data;
}
}

View File

@@ -0,0 +1,96 @@
<?php
namespace admin\components\UI\Form;
/**
* 多选框
* @package backend\components\UI\Form
*/
class Checkbox extends Element implements Component
{
protected $data;
/**
* Select constructor.
* @param string $name
* @param string $field
* @param null|array|callable $data
* @param string $has
*/
public function __construct(string $name, string $field, $data = null, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->data = $data;
$this->has = $has;
}
/**
* add data
* @param $name
* @param $value
* @return $this
*/
public function add($name, $value): self
{
$this->data[] = [
'name' => $name,
'value' => $value
];
return $this;
}
/**
* @return array
*/
public function render(): array
{
$data = [];
if ($this->data instanceof \Closure) {
$data = call_user_func($this->data);
}
if (is_array($this->data)) {
$data = $this->data;
}
$child = [];
foreach ($data as $key => $vo) {
$child[] = [
'nodeName' => 'a-checkbox',
'value' => $key,
'child' => $vo,
];
}
$data = [
'nodeName' => 'a-checkbox-group',
'child' => $child
];
if ($this->model) {
$data['vModel:model-value'] = $this->getModelField();
}
return $data;
}
/**
* @param $value
* @return array
*/
public function dataValue($value): array
{
return array_values(array_filter((array)$this->getValueArray($value)));
}
/**
* @param $data
* @return string
*/
public function dataInput($data): ?string
{
return is_array($data) ? implode(',', $data) : $data;
}
}

View File

@@ -0,0 +1,184 @@
<?php
namespace admin\components\UI\Form;
use admin\components\Exceptions\ErrorException;
/**
* 表格管理选择器
* @package backend\components\UI\Form
*/
class Choice extends Element implements Component
{
protected array $column = [];
protected array $ajax = [];
protected bool $option = true;
protected int $number = 0;
/**
* Text constructor.
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
}
/**
* @param string $url
* @param string $key
* @param callable $column
* @param array $types
* @return $this
*/
public function ajax(string $url, string $key, callable $column, array $types = []): self
{
$this->ajax = [
'url' => $url,
'key' => $key,
'column' => $column,
'type' => $types
];
return $this;
}
/**
* text column
* @param string $name
* @param string $field
* @return $this
*/
public function text(string $name, string $field): self
{
$this->column[] = [
'name' => $name,
'key' => $field,
'type' => 'text'
];
return $this;
}
/**
* image column
* @param string $name
* @param string $field
* @return $this
*/
public function image(string $name, string $field): self
{
$this->column[] = [
'name' => $name,
'key' => $field,
'type' => 'image'
];
return $this;
}
/**
* show column
* @param string $name
* @param string $field
* @return $this
*/
public function show(string $name, string $field): self
{
$this->column[] = [
'name' => $name,
'key' => $field,
'type' => 'show'
];
return $this;
}
/**
* hidden column
* @param string $name
* @param string $field
* @return $this
*/
public function hidden(string $name, string $field): self
{
$this->column[] = [
'name' => $name,
'key' => $field,
'type' => 'hidden'
];
return $this;
}
/**
* option status
* @param bool $status
* @return $this
*/
public function option(bool $status = true): self
{
$this->option = $status;
return $this;
}
/**
* maximum number
* @param int $num
* @return $this
*/
public function num(int $num = 0): self
{
$this->number = $num;
return $this;
}
/**
* @return array
* @throws ErrorException
*/
public function render(): array
{
$url = route('service.image.placeholder', ['w' => 64, 'h' => 64, 't' => $this->attr['placeholder'] ?: '图片']);
$ajaxColumn = $this->ajax['column'] ?: [];
if (is_callable($ajaxColumn)) {
$ajaxColumn = $ajaxColumn(new ChoiceColumn());
if (!$ajaxColumn instanceof ChoiceColumn) {
app_error('Choice component configuration error');
}
$ajaxColumn = $ajaxColumn->getData();
}
return [
'nodeName' => 'app-choice',
'vModel:value' => $this->getModelField(),
'column' => $this->column,
'ajaxColumn' => $ajaxColumn,
'ajaxType' => $this->ajax['type'],
'key' => $this->ajax['key'],
'url' => $this->ajax['url'],
'number' => $this->number,
'option' => $this->option,
];
}
/**
* @param $value
* @return array|null
*/
public function dataValue($value): ?array
{
$value = $this->getValue($value);
if ($value instanceof \Illuminate\Database\Eloquent\Collection && $value->count()) {
$values = $value->toArray();
} else if (is_array($value)) {
$values = $value;
} else {
$values = [];
}
return $values;
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace admin\components\UI\Form;
/**
* 表格关联选择器列
* @package backend\components\UI\Form
*/
class ChoiceColumn
{
/**
* @var array
*/
private array $column;
/**
* @param string $name
* @param string $field
* @return $this
*/
public function text(string $name, string $field): self
{
$this->column[] = [
'name' => $name,
'key' => $field,
'type' => 'text'
];
return $this;
}
/**
* @param string $name
* @param string $field
* @return $this
*/
public function image(string $name, string $field): self
{
$this->column[] = [
'name' => $name,
'key' => $field,
'type' => 'image'
];
return $this;
}
/**
* @return array
*/
public function getData(): array
{
return $this->column;
}
}

View File

@@ -0,0 +1,72 @@
<?php
namespace admin\components\UI\Form;
/**
* 颜色选择器
* @package backend\components\UI\Form
*/
class Color extends Element implements Component
{
protected array $color = [];
protected bool $picker = false;
/**
* Text constructor.
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
$this->attr['placeholder'] = null;
}
/**
* @return $this
*/
public function picker(): self
{
$this->picker = true;
return $this;
}
/**
* @param array $data
* @return $this
*/
public function color(array $data): self
{
$this->color = $data;
return $this;
}
/**
* @return array
*/
public function render(): array
{
if ($this->picker) {
// 暂无组件
$data = [
];
}else {
$data = [
'nodeName' => 'app-color',
'colors' => $this->color,
'placeholder' => $this->attr['placeholder'] ?: '请选择' . $this->name,
];
}
if ($this->model) {
$data['vModel:value'] = $this->getModelField();
}
return $data;
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace admin\components\UI\Form;
/**
* 组件接口
* Class Component
* @package backend\components\UI
*/
interface Component
{
}

View File

@@ -0,0 +1,62 @@
<?php
namespace admin\components\UI\Form;
use admin\components\UI\Tools;
/**
* 复合组件
* @package backend\components\UI
*/
class Composite extends Element
{
public array $column = [];
public bool $component = true;
public object $form;
/**
* @param null $key
* @param string $item
* @return array|object
*/
public function getColumn($key = null, string $item = '')
{
return $key !== null ? ($item ? $this->column[$key][$item] : $this->column[$key]) : $this->column;
}
/**
* 获取值
* @param string $time
* @return array
*/
public function getInput(string $time = 'add'): array
{
$data = [];
foreach ($this->column as $vo) {
$vo['object']->getElement()->map(function ($item) use (&$data, $time) {
foreach ($item->getInput($time) as $k => $v) {
$data[$k] = $v;
}
});
}
return $data;
}
/**
* @param $info
* @return array
*/
public function getData($info): array
{
$data = [];
foreach ($this->column as $vo) {
$vo['object']->getElement()->map(function ($item) use (&$data, $info) {
foreach ($item->getData($info) as $k => $v) {
$data[$k] = $v;
}
});
}
return $data;
}
}

View File

@@ -0,0 +1,213 @@
<?php
namespace admin\components\UI\Form;
use admin\components\UI\Widget\Icon;
/**
* 动态数据编辑器
* @package backend\components\UI\Form
*/
class Data extends Element implements Component
{
protected array $column = [];
protected bool $option = true;
protected ?int $numberMax = null;
protected ?int $numberMin = null;
/**
* Text constructor.
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
}
/**
* 文本列
* @param string $name
* @param string $field
* @param null $width
* @return $this
*/
public function text(string $name, string $field, $width = null): self
{
$this->column[] = [
'name' => $name,
'key' => $field,
'type' => 'text',
'width' => $width,
];
return $this;
}
/**
* 图片列
* @param string $name
* @param string $field
* @param null $width
* @return $this
*/
public function image(string $name, string $field, $width = null): self
{
$this->column[] = [
'name' => $name,
'key' => $field,
'type' => 'image',
'width' => $width,
];
return $this;
}
/**
* 展示列
* @param string $name
* @param string $field
* @param null $width
* @return $this
*/
public function show(string $name, string $field, $width = null): self
{
$this->column[] = [
'name' => $name,
'key' => $field,
'type' => 'show',
'width' => $width,
];
return $this;
}
/**
* 隐藏列
* @param string $name
* @param string $field
* @return $this
*/
public function hidden(string $name, string $field): self
{
$this->column[] = [
'name' => $name,
'key' => $field,
'type' => 'hidden'
];
return $this;
}
/**
* 操作状态
* @param bool $status
* @return $this
*/
public function option(bool $status = true): self
{
$this->option = $status;
return $this;
}
/**
* 最大数量
* @param int $num
* @return $this
*/
public function max(int $num = 0): self
{
$this->numberMax = $num;
return $this;
}
/**
* 最小数量
* @param int $num
* @return $this
*/
public function min(int $num = 0): self
{
$this->numberMin = $num;
return $this;
}
/**
* @return array
*/
public function render(): array
{
$url = route('service.image.placeholder', ['w' => 64, 'h' => 64, 't' => $this->attr['placeholder'] ?: '图片']);
$inner = [];
$default = [];
foreach ($this->column as $column) {
$default[$column['key']] = '';
$field = "value['{$column['key']}']";
if ($column['type'] === 'text') {
$inner[] = [
'nodeName' => 'div',
'class' => 'flex-grow',
'child' => [
'nodeName' => 'a-input',
'placeholder' => '请输入' . $column['name'],
'vModel:model-value' => $field
]
];
}
if ($column['type'] === 'image') {
$inner[] = [
'nodeName' => 'div',
'class' => 'flex-none',
'child' => [
'nodeName' => 'app-file',
'image' => 'true',
'mini' => true,
'size' => 8,
'vModel:value' => $field
]
];
}
if ($column['type'] === 'show') {
$inner[] = [
'nodeName' => 'div',
'class' => 'flex-grow',
'child' => "{{ $field || '-'}}"
];
}
}
$create = json_encode($default);
$data = [
'nodeName' => 'app-dynamic-data',
'vModel:value' => $this->getModelField(),
'vBind:on-create' => "() => { return $create }",
'child' => [
'vSlot' => '{ index, value }',
'nodeName' => 'div',
'class' => 'flex flex-grow gap-4 items-center',
'child' => $inner
]
];
if ($this->numberMax) {
$data['max'] = $this->numberMax;
}
if ($this->numberMin) {
$data['min'] = $this->numberMin;
}
return $data;
}
/**
* @param $data
* @return array|null
*/
public function dataValue($data): ?array
{
$data = $this->getValue($data);
return $data ?: [];
}
}

View File

@@ -0,0 +1,87 @@
<?php
namespace admin\components\UI\Form;
/**
* 时间选择器
* @package backend\components\UI\Form
*/
class Date extends Element implements Component
{
protected ?string $type = null;
private array $types = [
'year',
'month',
];
/**
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
$this->attr['placeholder'] = null;
}
/**
* @param string $type
* @return $this
*/
public function type(string $type): self
{
if (!in_array($type, $this->types)) {
throw new \RuntimeException('There is no type "' . $type . '"');
}
$this->type = $type;
return $this;
}
/**
* @return array
*/
public function render(): array
{
$data = [
'nodeName' => 'a-date-picker',
'allowClear' => true,
'placeholder' => $this->attr['placeholder'] ?: '请选择' . $this->name,
'vModel:modelValue' => $this->getModelField()
];
if ($this->type) {
$data['nodeName'] = 'a-' . $this->type . '-picker';
}
if($this->replace != ''){
$data['vStringReplace'] = $this->replace;
}
return $data;
}
/**
* @param $data
* @return string|null
*/
public function dataInput($data): ?string
{
return $data ? date('Y-m-d', strtotime($data)) : null;
}
/**
* @param $data
* @return string|null
*/
public function dataValue($data): ?string
{
$data = $this->getValue($data);
return $data ?: null;
}
}

View File

@@ -0,0 +1,106 @@
<?php
namespace admin\components\UI\Form;
use admin\components\UI\Tools;
/**
* 时间范围选择器
* @package backend\components\UI\Form
*/
class Daterange extends Element implements Component
{
private string $stopField;
/**
* Text constructor.
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
}
/**
* 设置结束字段
* @param $field
* @return $this
*/
public function stopField($field): self
{
$this->stopField = $field;
return $this;
}
/**
* @return array
*/
public function render(): array
{
$data = [
'nodeName' => 'a-range-picker',
'allowClear' => true,
'vModel:modelValue' => $this->getModelField()
];
if($this->replace != ''){
$data['vStringReplace'] = $this->replace;
}
return $data;
}
/**
* @param $value
* @return array
*/
public function appendInput($value): array
{
if (!$this->stopField) {
return [];
}
$data = [];
$data[$this->stopField] = is_array($value) && $value[1] ? date('Y-m-d H:i:s', strtotime($value[1])) : null;
return $data;
}
/**
* @param $value
* @return string|null
*/
public function dataInput($value): ?string
{
if ($this->stopField) {
return is_array($value) && $value[0] ? date('Y-m-d H:i:s',strtotime($value[0])) : null;
}
return is_array($value) ? date('Y-m-d H:i:s', strtotime($value[0])) . ',' . date('Y-m-d H:i:s', strtotime($value[1])) : null;
}
/**
* @param $value
* @param $info
* @return array|null
*/
public function dataValue($value, $info): ?array
{
$value = $this->getValue($value);
$data = [];
if ($this->stopField) {
$data[] = $value ?: null;
$stopValue = Tools::parsingArrData($info, $this->stopField);
$data[] = $stopValue ?: null;
return $data;
}
if ($value) {
$data = explode(',', $value);
}
return $data ? [$data[0], $data[1]] : null;
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace admin\components\UI\Form;
/**
* 日期时间选择器
* @package backend\components\UI\Form
*/
class Datetime extends Element implements Component
{
protected string $string = 'YYYY-MM-DD HH:mm';
/**
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
}
/**
* 日期格式
* @param string $format
* @return $this
*/
public function string(string $format): self
{
$this->string = $format;
return $this;
}
/**
* 渲染组件
* @return array
*/
public function render(): array
{
$data = [
'nodeName' => 'a-date-picker',
'vModel:value' => $this->getModelField(),
'showTime' => true,
'allowClear' => true,
'format' => $this->string,
'placeholder' => $this->attr['placeholder'] ?: '请选择' . $this->name,
'vModel:modelValue' => $this->getModelField()
];
if($this->replace != ''){
$data['vStringReplace'] = $this->replace;
}
return $data;
}
/**
* @param $data
* @return string|null
*/
public function dataInput($data): ?string
{
return $data ? date('Y-m-d H:i:s', strtotime($data)) : null;
}
/**
* @param $data
* @return string|null
*/
public function dataValue($data): ?string
{
$data = $this->getValue($data);
return $data ?: null;
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace admin\components\UI\Form;
/**
* 编辑器
* @package backend\components\UI\Form
*/
class Editor extends Element implements Component
{
/**
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
}
/**
* @return array
*/
public function render(): array
{
$data = [
'nodeName' => 'app-editor'
];
if ($this->model) {
$data['vModel:value'] = $this->getModelField();
}
return $data;
}
}

View File

@@ -0,0 +1,536 @@
<?php
namespace admin\components\UI\Form;
use admin\components\UI\Tools;
/**
* 单元素组件
* Class Component
* @package backend\components\UI
*/
class Element
{
protected string $name = '';
protected string $field = '';
protected string $has = '';
protected $help = '';
protected $helpLine = '';
protected string $prompt = '';
protected string $model = 'data.';
protected array $class = [];
protected $replace = '';
protected array $attr = [];
protected array $layoutAttr = [];
protected array $style = [];
protected array $pivot = [];
protected array $verify = [];
protected array $verifyMsg = [];
protected array $format = [];
protected bool $dialog = false;
protected bool $vertical = false;
protected bool $label = true;
protected bool $component = false;
protected bool $must = false;
protected array $group = [];
protected ?int $sort = null;
protected $modelElo;
protected $value;
protected $default;
/**
* 设置弹窗
* @param $bool
* @return $this
*/
public function dialog($bool): self
{
$this->dialog = $bool;
return $this;
}
/**
* 设置方向
* @param $bool
* @return $this
*/
public function vertical($bool): self
{
$this->vertical = $bool;
return $this;
}
/**
* 设置数据模型
*/
public function modelElo($class)
{
$this->modelElo = $class;
return $this;
}
/**
* 设置数据前缀
*/
public function model($model)
{
$this->model = $model;
return $this;
}
/**
* 获取模型字段
* @return string
*/
public function getModelField()
{
return $this->model . $this->field;
}
/**
* 获取标签状态
* @return bool
*/
public function getLabel(): bool
{
return $this->label;
}
/**
* 获取字段名
* @return string
*/
public function getField(): string
{
return $this->field;
}
/**
* 获取关联模型
* @return string
*/
public function getHas(): string
{
return $this->has;
}
/**
* 获取名称
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* 获取值
* @param $value
* @return mixed
*/
public function getValue($value = null)
{
return ($this->value ?? $value) ?? $this->default;
}
/**
* 获取数组值
* @param $value
* @param bool $json
* @return array|null
*/
public function getValueArray($value, bool $json = false): ?array
{
if ($value instanceof \Illuminate\Database\Eloquent\Collection) {
if ($value->count()) {
$values = $value->pluck($value->first()->getKeyName())->toArray();
} else {
$values = $json ? [] : null;
}
} else if (is_array($value)) {
$values = $value;
} else if ($value !== null) {
$values = $json ? json_decode($value, true) : explode(',', $value);
} else {
$values = $json ? [] : null;
}
return $values;
}
/**
* 获取回调数据组
* @param $data
* @param $value
* @return array
*/
public function getCallbackArray($data, $value): array
{
if ($data instanceof \Closure) {
return call_user_func($data, [$value]);
}
if (is_array($data)) {
return $data;
}
return [];
}
/**
* 设置选项值
* @param $value
* @return $this
*/
public function value($value): self
{
$this->value = $value;
return $this;
}
/**
* 设置默认值
* @param $value
* @return $this
*/
public function default($value): self
{
$this->default = $value;
return $this;
}
/**
* 设置帮助信息
* @param string|array $value
* @param bool $line
* @return $this
*/
public function help($value, bool $line = false): self
{
if ($line) {
$this->helpLine = $value;
} else {
$this->help = $value;
}
return $this;
}
/**
* 属性数据
* @param string $name
* @param string|array $value
* @return $this
*/
public function attr(string $name, $value): self
{
$this->attr[$name] = $value;
return $this;
}
/**
* 布局树形
* @param string $name
* @param $value
* @return $this
*/
public function layoutAttr(string $name, $value): self
{
$this->layoutAttr[$name] = $value;
return $this;
}
/**
* 属性数组
* @param $attr
* @return $this
*/
public function attrArray($attr): self
{
$this->attr = $attr;
return $this;
}
/**
* class样式
* @param string $name
* @return $this
*/
public function class(string $name): self
{
$this->class[] = $name;
return $this;
}
/**
* 字符串替换标签(数字字符串处理使用)
* @param $replace
* @return $this
*/
public function replace($replace): self
{
$this->replace = $replace;
return $this;
}
/**
* 设置提示
* @param $name
* @return $this
*/
public function placeholder($name): self
{
if ($name) {
$this->attr['placeholder'] = $name;
}
return $this;
}
/**
* 元素分组
* @param $name
* @param $value
* @return $this
*/
public function group($name, $value): self
{
$this->group[] = [
'name' => $name,
'value' => $value
];
return $this;
}
/**
* 必填样式
* @return $this
*/
public function must(): self
{
$this->must = true;
$this->verify['all'][$this->field][] = 'required';
$this->verifyMsg['all'][$this->field . '.' . 'required'] = '请输入' . $this->name;
return $this;
}
/**
* 帮助信息
* @param $content
* @return $this
*/
public function prompt($content): self
{
$this->prompt = $content;
return $this;
}
/**
* 排序
* @param $num
* @return $this
*/
public function sort($num): self
{
$this->sort = $num;
return $this;
}
/**
* 获取分组
* @return array
*/
public function getGroup(): array
{
return $this->group;
}
/**
* 获取必须
* @return bool
*/
public function getMust(): bool
{
return $this->must;
}
/**
* 获取提醒
* @return string
*/
public function getPrompt(): string
{
return $this->prompt;
}
/**
* 获取帮助行
* @return string|array
*/
public function getHelpLine()
{
return $this->helpLine;
}
/**
* 获取层属性
* @return array
*/
public function getLayoutAttr()
{
return $this->layoutAttr;
}
/**
* 同步附加数据
* @param $data
* @return $this
*/
public function pivot($data)
{
$this->pivot = $data;
return $this;
}
/**
* 设置字段验证
* @param $rule
* @param array $msg
* @param string $time
* @return $this
*/
public function verify($rule, array $msg = [], string $time = 'all'): self
{
$this->verify[$time][$this->field] = $rule;
foreach ($msg as $key => $vo) {
$this->verifyMsg[$time][$this->field . '.' . $key] = $vo;
}
return $this;
}
/**
* 获取验证规则
* @param string $time
* @return array
*/
public function getVerify(string $time = 'add'): array
{
return [
'rule' => (array)$this->verify['all'] + (array)$this->verify[$time],
'msg' => (array)$this->verifyMsg['all'] + (array)$this->verifyMsg[$time]
];
}
/**
* 设置表单格式化
* @param string|callable $rule
* @param string $time
* @return $this
*/
public function format($rule, string $time = 'all'): self
{
$this->format[$time][] = $rule;
return $this;
}
/**
* 获取表单格式化
* @param string $time
* @return array
*/
public function getFormat(string $time = 'add'): array
{
return (array)$this->format['all'] + (array)$this->format[$time];
}
/**
* 获取提交数据
* @param string $time
* @return mixed
*/
public function getInput(string $time = 'add'): array
{
$data = \Yii::$app->request->get($this->field);
$inputs = [];
if (method_exists($this, 'appendInput') && !$this->has) {
$appendData = $this->appendInput($data);
foreach ($appendData as $key => $vo) {
$inputs[$key] = ['value' => $vo];
}
}
if (method_exists($this, 'dataInput') && !$this->has) {
$data = $this->dataInput($data);
}
$inputs[$this->field] = ['value' => $data, 'has' => $this->has, 'format' => $this->getFormat($time), 'verify' => $this->getVerify($time), 'pivot' => $this->pivot];
return $inputs;
}
/**
* 获取帮助信息
* @return string|array
*/
public function getHelp()
{
return $this->help;
}
/**
* 获取顺序
* @return null
*/
public function getSort(): ?int
{
return $this->sort;
}
/**
* 复合组件
* @return bool
*/
public function getComponent(): bool
{
return $this->component;
}
/**
* 获取渲染组件
* @return array
*/
public function getRender(): array
{
if ($this->class) {
$this->attr['class'] = implode(' ', $this->class);
}
return array_merge($this->render(), $this->attr);
}
/**
* 获取数据值
* @param $info
* @return array
*/
public function getData($info): array
{
$field = $this->getHas() ?: $this->getField();
$value = Tools::parsingArrData($info, $field);
$data = [];
if (method_exists($this, 'appendValue')) {
$appendValue = $this->appendValue($info);
foreach ($appendValue as $key => $vo) {
$data[$key] = $vo;
}
}
if (method_exists($this, 'dataValue')) {
$value = $this->dataValue($value, $info);
} else {
$value = $this->getValue($value);
}
$data[$this->getField()] = $value;
return $data;
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace admin\components\UI\Form;
/**
* 邮箱输入
* @package backend\components\UI\Form
*/
class Email extends Element implements Component
{
protected Text $object;
/**
* Text constructor.
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
$this->object = new Text($this->name, $this->field, $this->has);
$this->object->afterIcon('email');
}
/**
* @return array
*/
public function render(): array
{
return $this->object->getRender();
}
}

View File

@@ -0,0 +1,84 @@
<?php
namespace admin\components\UI\Form;
/**
* 文件上传
* @package backend\components\UI\Form
*/
class File extends Element implements Component
{
protected string $type = 'upload';
protected string $url = '';
protected string $fileUrl = '';
/**
* File constructor.
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
}
/**
* 上传方式
* @param string $type
* @return $this
*/
public function type(string $type = 'upload'): self
{
$this->type = $type;
return $this;
}
/**
* 上传地址
* @param string $url
* @return $this
*/
public function url(string $url): self
{
$this->url = $url;
return $this;
}
/**
* 文件地址
* @param string $url
* @return $this
*/
public function fileUrl(string $url): self
{
$this->fileUrl = $url;
return $this;
}
/**
* @return array
*/
public function render(): array
{
$data = [
'nodeName' => 'app-file',
];
if ($this->url) {
$data['upload'] = $this->url;
}
if ($this->fileUrl) {
$data['fileUrl'] = $this->fileUrl;
}
if ($this->type) {
$data['type'] = $this->type;
}
if ($this->model) {
$data['vModel:value'] = $this->getModelField();
}
return $data;
}
}

View File

@@ -0,0 +1,85 @@
<?php
namespace admin\components\UI\Form;
/**
* 多文件上传
* @package backend\components\UI\Form
*/
class Files extends Element implements Component
{
protected string $type = 'manage';
protected string $url = '';
protected string $fileUrl = '';
/**
* Text constructor.
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
}
/**
* 上传方式
* @param string $type
* @return $this
*/
public function type(string $type = 'manage'): self
{
$this->type = $type;
return $this;
}
/**
* 上传地址
* @param string $url
* @return $this
*/
public function url(string $url): self
{
$this->url = $url;
return $this;
}
/**
* 文件地址
* @param string $url
* @return $this
*/
public function fileUrl(string $url): self
{
$this->fileUrl = $url;
return $this;
}
/**
* @return string[]
*/
public function render(): array
{
$data = [
'nodeName' => 'app-files',
];
if ($this->type) {
$data['type'] = $this->type;
}
if ($this->url) {
$data['upload'] = $this->url;
}
if ($this->fileUrl) {
$data['fileUrl'] = $this->fileUrl;
}
if ($this->model) {
$data['vModel:value'] = $this->getModelField();
}
return $data;
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace admin\components\UI\Form;
/**
* 自定义Html
* @package backend\components\UI\Table
*/
class Html extends Element implements Component
{
protected \Closure $callback;
/**
* @param string $name
* @param \Closure $callback
*/
public function __construct(string $name, \Closure $callback)
{
$this->name = $name;
$this->callback = $callback;
}
/**
* @return array
*/
public function render(): array
{
$callback = is_callable($this->callback) ? call_user_func($this->callback) : $this->callback;
if (is_array($callback)) {
return $callback;
}
return [
'nodeName' => 'rich-text',
'nodes' => $callback
];
}
}

View File

@@ -0,0 +1,124 @@
<?php
namespace admin\components\UI\Form;
/**
* Class Image
* 图片上传
* @package backend\components\UI\Form
*/
class Image extends Element implements Component
{
private array $thumb = [];
private array $water = [];
protected string $type = 'manage';
protected string $url = '';
protected string $fileUrl = '';
/**
* Text constructor.
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
}
/**
* 缩图
* @param int $width
* @param int $height
* @param string $type
* @return $this
*/
public function thumb(int $width, int $height, string $type = 'scale'): self
{
$this->thumb = [
'width' => $width,
'height' => $height,
'thumb' => $type
];
return $this;
}
/**
* 水印
* @param string $position
* @param int $alpha
* @return $this
*/
public function water(string $position = 'center', int $alpha = 80): self
{
$this->water = [
'alpha' => $alpha,
'water' => $position
];
return $this;
}
/**
* @param string $type
* @return $this
*/
public function type(string $type = 'manage'): self
{
$this->type = $type;
return $this;
}
/**
* 上传地址
* @param string $url
* @return $this
*/
public function url(string $url): self
{
$this->url = $url;
return $this;
}
/**
* 文件地址
* @param string $url
* @return $this
*/
public function fileUrl(string $url): self
{
$this->fileUrl = $url;
return $this;
}
/**
* 渲染组件
* @return array
*/
public function render(): array
{
$data = [
'nodeName' => 'app-file',
'format' => 'image',
'image' => true,
'size' => 125
];
if ($this->url) {
$data['upload'] = $this->url;
}
if ($this->fileUrl) {
$data['fileUrl'] = $this->fileUrl;
}
if ($this->type) {
$data['type'] = $this->type;
}
if ($this->model) {
$data['vModel:value'] = $this->getModelField();
}
return $data;
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace admin\components\UI\Form;
/**
* 组图上传
* @package backend\components\UI\Form
*/
class Images extends Element implements Component
{
protected string $type = 'manage';
protected string $url = '';
protected string $fileUrl = '';
/**
* Text constructor.
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
}
public function type($type = 'manage')
{
$this->type = $type;
return $this;
}
/**
* 上传地址
* @param string $url
* @return $this
*/
public function url(string $url): self
{
$this->url = $url;
return $this;
}
/**
* 文件地址
* @param string $url
* @return $this
*/
public function fileUrl(string $url): self
{
$this->fileUrl = $url;
return $this;
}
/**
* @return array
*/
public function render(): array
{
$data = [
'nodeName' => 'app-images',
];
if ($this->type) {
$data['type'] = $this->type;
}
if ($this->url) {
$data['upload'] = $this->url;
}
if ($this->fileUrl) {
$data['fileUrl'] = $this->fileUrl;
}
if ($this->model) {
$data['vModel:value'] = $this->getModelField();
}
return $data;
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace admin\components\UI\Form;
/**
* IP地址
* @package backend\components\UI\Form
*/
class Ip extends Element implements Component
{
protected Text $object;
/**
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
$this->object = new Text($this->name, $this->field, $this->has);
$this->object->afterIcon('desktop');
}
/**
* @return array
*/
public function render(): array
{
return $this->object->getRender();
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace admin\components\UI\Form;
/**
* Class Row
* @package backend\components\UI\Table
*/
class Layout extends Composite implements Component
{
protected $callback;
/**
* @param callable|array $callback
*/
public function __construct($callback)
{
$this->callback = $callback;
}
/**
* @return array
*/
public function render(): array
{
$callback = is_callable($this->callback) ? call_user_func($this->callback) : $this->callback;
return [
'nodeName' => 'div',
'class' => 'mb-4',
'child' => $callback
];
}
}

View File

@@ -0,0 +1,96 @@
<?php
namespace admin\components\UI\Form;
/**
* 地图
* @package backend\components\UI\Form
*/
class Location extends Element implements Component
{
protected array $map = [
'province' => 'province',
'city' => 'city',
'district' => 'district',
'street' => 'street',
'streetNumber' => 'streetNumber',
'address' => 'address',
'lat' => 'lat',
'lng' => 'lng'
];
/**
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
}
/**
* @return array
*/
public function render(): array
{
$child = [];
return [
'nodeName' => 'app-map',
'vModel:value' => $this->getModelField(),
'child' => $child,
'placeholder' => '请输入' . $this->name,
];
}
/**
* @param $data
* @return array
*/
public function appendInput($data): array
{
$ret = [];
if ($data->province) {
$ret[$this->map['province']] = $data->province;
}
if ($data->city) {
$ret[$this->map['city']] = $data->city;
}
if ($data->district) {
$ret[$this->map['district']] = $data->district;
}
if ($data->street) {
$ret[$this->map['street']] = $data->street;
}
if ($data->streetNumber) {
$ret[$this->map['streetNumber']] = $data->streetNumber;
}
if ($data->address) {
$ret[$this->map['address']] = $data->address;
}
if ($data->lat) {
$ret[$this->map['lat']] = $data->lat;
}
if ($data->lng) {
$ret[$this->map['lng']] = $data->lng;
}
return $ret;
}
/**
* @param $data
* @return string|null
*/
public function dataValue($data): ?array
{
$data = $this->getValue($data);
if( empty($data) ){
return [];
}else{
return json_decode($data,true);
}
}
}

View File

@@ -0,0 +1,264 @@
<?php
namespace admin\components\UI\Form;
/**
* 表单节点
* @package backend\components\UI\Form
*/
class Node
{
private string $url;
private string $method;
private ?string $title;
private bool $back = false;
private bool $dialog = false;
private bool $vertical = false;
private array $element = [];
private array $data = [];
private array $side = ['left'=>[],'right'=>[]];
private array $script = [];
private array $scriptReturn = [];
/**
* Node constructor.
* @param string $action
* @param string $method
* @param string|null $title
*/
public function __construct(string $action, string $method, ?string $title = '')
{
$this->url = $action;
$this->method = $method;
$this->title = $title;
}
/**
* @param bool $bool
*/
public function back(bool $bool): void
{
$this->back = $bool;
}
/**
* @param Closure|string $content
* @param string $return
* @return $this
*/
public function script($content, string $return): self
{
if ($content instanceof \Closure) {
$this->script[] = $content();
} else {
$this->script[] = $content;
}
$this->scriptReturn[] = $return;
return $this;
}
/**
* @param bool $bool
* @return $this
*/
public function dialog(bool $bool): self
{
$this->dialog = $bool;
$this->vertical = true;
return $this;
}
/**
* @param bool $bool
* @return $this
*/
public function vertical(bool $bool): self
{
$this->vertical = $bool;
return $this;
}
/**
* @param array $node
* @return $this
*/
public function element(array $node): self
{
$this->element = $node;
return $this;
}
/**
* @param Closure|array $node
* @param string $type
* @return $this
*/
public function side($node, string $type = 'left'): self
{
$this->side[$type] = is_callable($node) ? $node() : $node;
return $this;
}
/**
* @param $data
* @return $this
*/
public function data($data): self
{
$this->data = $data;
return $this;
}
/**
* 渲染页面
* @return array[]
*/
private function renderPage(): array
{
return [
$this->side['left'] ? [
'nodeName' => 'div',
'class' => 'flex-none flex h-screen flex-col',
'child' => $this->side['left']
] : [],
[
'nodeName' => 'app-layout',
'class' => 'flex-grow w-10',
'title' => $this->title ?: '信息详情',
'form' => true,
'back' => $this->back,
'vBind:formLoading' => 'loading',
'child' => [
[
'nodeName' => 'div',
'class' => 'p-4',
'child' => [
[
'nodeName' => 'div',
'child' => $this->element
],
[
'nodeName' => 'div',
'class' => 'flex items-center justify-end gap-2 flex-row ',
'child' => [
$this->back ? [
'nodeName' => 'route',
'type' => 'back',
'child' => [
'type' => "outline",
'nodeName' => 'a-button',
'child' => '返回',
]
] : [],
[
'nodeName' => 'a-button',
'html-type' => 'submit',
'vBind:loading' => "loading",
'type' => 'primary',
'child' => $this->back ? '提交' : '保存',
],
]
],
],
],
],
],
$this->side['right']? [
'nodeName' => 'div',
'class' => 'flex-none flex h-screen flex-col',
'child' => $this->side['right']
] : [],
];
}
/**
* 渲染弹窗
* @return array
*/
private function renderDialog(): array
{
return [
'nodeName' => 'app-dialog',
'title' => $this->title ?: '信息详情',
'class' => 'flex-grow',
'child' => [
[
'nodeName' => 'div',
'vSlot:default' => '',
'class' => 'flex',
'child' => [
$this->side['left'] ? [
'nodeName' => 'div',
'class' => 'flex-none',
'child' => $this->side['left']
] : [],
[
'nodeName' => 'div',
'class' => 'flex-grow p-5 pb-0',
'child' => $this->element
],
$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' => '取消'
]
],
[
'nodeName' => 'a-button',
'type' => 'primary',
'html-type' => 'submit',
'vBind:loading' => "loading",
'child' => '提交'
],
]
]
]
];
}
/**
* 渲染布局
* @return array
*/
public function render(): array
{
return [
'node' => [
'nodeName' => 'app-form',
'url' => $this->url,
'method' => $this->method,
'value' => $this->data,
'layout' => $this->vertical ? 'vertical' : 'horizontal',
'back' => $this->back,
'child' => [
'nodeName' => 'div',
'class' => 'flex',
'vSlot' => '{value: data, submitStatus: loading}',
'child' => $this->dialog ? $this->renderDialog() : $this->renderPage()
]
],
'setupScript' => implode("\n", $this->script) . "\n" . ' return {' . implode(",", $this->scriptReturn) . '}'
];
}
}

View File

@@ -0,0 +1,101 @@
<?php
namespace admin\components\UI\Form;
/**
* 数字输入器
* @package backend\components\UI\Form
*/
class Number extends Element implements Component
{
protected Text $object;
/**
* @var int|float
*/
protected $step = 1;
/**
* @var ?int|float
*/
protected $max = null;
/**
* @var int|float
*/
protected $min = 0;
protected ?int $precision = null;
/**
* Text constructor.
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
$this->attr['placeholder'] = null;
}
/**
* 最大值
* @param int|float $default
* @return $this
*/
public function max($default = 0): self
{
$this->max = $default;
return $this;
}
/**
* 最小值
* @param int|float $default
* @return $this
*/
public function min($default = 0): self
{
$this->min = $default;
return $this;
}
/**
* 步进数值
* @param int|float $default
* @param int|null $precision
* @return $this
*/
public function step($default = 1, ?int $precision = null): self
{
$this->step = $default;
$this->precision = $precision;
return $this;
}
/**
* @return array
*/
public function render(): array
{
$data = [
'nodeName' => 'a-input-number',
'placeholder' => $this->attr['placeholder'] ?: '请输入' . $this->name,
'vModel:modelValue' => $this->getModelField(),
'step' => $this->step,
'min' => $this->min,
'mode' => 'button'
];
if ($this->max) {
$data['max'] = $this->max;
}
if ($this->precision) {
$data['precision'] = $this->precision;
}
if($this->replace != ''){
$data['vStringReplace'] = $this->replace;
}
return $data;
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace admin\components\UI\Form;
/**
* 密码输入器
* @package backend\components\UI\Form
*/
class Password extends Element implements Component
{
protected Text $object;
/**
* Text constructor.
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
$this->attr['placeholder'] = null;
}
/**
* @return array
*/
public function render(): array
{
$data = [
'nodeName' => 'a-input-password',
'vModel:modelValue' => $this->getModelField(),
'placeholder' => $this->attr['placeholder'] ?: '请输入' . $this->name,
'allowClear' => true
];
if($this->replace != ''){
$data['vStringReplace'] = $this->replace;
}
return $data;
}
}

View File

@@ -0,0 +1,108 @@
<?php
namespace admin\components\UI\Form;
/**
* 单选框
* @package backend\components\UI\Form
*/
class Radio extends Element implements Component
{
protected array $box = [];
protected $data = [];
protected string $switch = '';
/**
* Select constructor.
* @param string $name
* @param string $field
* @param null|array|callable $data
* @param string $has
*/
public function __construct(string $name, string $field, $data = [], string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->data = $data;
$this->has = $has;
}
/**
* 添加选项
* @param $name
* @param $value
* @return $this
*/
public function add($name, $value): self
{
$this->data[$name] = $value;
return $this;
}
/**
* 切换组件
* @param $group
* @return $this
*/
public function switch($group): self
{
$this->switch = $group;
return $this;
}
/**
* 类型选择
* @param array $data
* @return $this
*/
public function box(array $data): self
{
$this->box = $data;
return $this;
}
/**
* @return array
*/
public function render(): array
{
$data = [];
if ($this->data instanceof \Closure) {
$data = call_user_func($this->data);
}
if (is_array($this->data)) {
$data = $this->data;
}
$this->data = $data;
$child = [];
foreach ($data as $key => $vo) {
$child[] = [
'nodeName' => 'a-radio',
'child' => $vo,
'value' => $key,
];
}
$data = [
'nodeName' => 'a-radio-group',
'name' => $this->field,
'vModel:modelValue' => $this->getModelField(),
'child' => $child
];
if($this->replace != ''){
$data['vStringReplace'] = $this->replace;
}
return $data;
}
public function dataValue($value)
{
return $this->getValue($value) ?? array_key_first((array)$this->data);
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace admin\components\UI\Form;
use admin\components\UI\Form;
/**
* Class Row
* @package backend\components\UI\Table
*/
class Row extends Composite implements Component
{
/**
* 设置列
* @param callable $callback
* @param int $width
* @return $this
*/
public function column(callable $callback, int $width = 0): self
{
$form = new Form();
$callback($form);
$this->column[] = [
'width' => $width,
'object' => $form,
];
return $this;
}
/**
* @return array
*/
public function render(): array
{
$inner = [];
foreach ($this->column as $vo) {
$width = $vo['width'] ? "lg:row-span-{$vo['width']}" : '';
$form = $vo['object']->renderForm();
$inner[] = [
'nodeName' => 'div',
'class' => $width,
'child' => $form
];
}
return [
'nodeName' => 'div',
'class' => 'grid lg:grid-flow-col gap-4',
'child' => $inner
];
}
}

View File

@@ -0,0 +1,198 @@
<?php
namespace admin\components\UI\Form;
/**
* Class Select
* @package backend\components\UI\Form
*/
class Select extends Element implements Component
{
protected string $url = '';
protected string $route = '';
protected int $tagCount = 0;
protected bool $tip = false;
protected bool $search = false;
protected bool $multi = false;
protected array $optionRender = [];
protected $data;
/**
* Select constructor.
* @param string $name
* @param string $field
* @param null $data
* @param string $has
*/
public function __construct(string $name, string $field, $data = null, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->data = $data;
$this->has = $has;
$this->attr['placeholder'] = null;
}
/**
* 添加选项
* @param $name
* @param $value
* @return $this
*/
public function add($name, $value): self
{
$this->data[$value] = $name;
return $this;
}
/**
* 默认提示
* @param bool $tip
* @return $this
*/
public function tip(bool $tip = true): self
{
$this->tip = $tip;
return $this;
}
/**
* 搜索
* @param bool $search
* @return $this
*/
public function search(bool $search = true): self
{
$this->search = $search;
return $this;
}
/**
* 搜索地址
* @param string $url
* @return $this
*/
public function url(string $url): self
{
$this->url = $url;
return $this;
}
/**
* 路由地址
* @param string $route
* @param array $params
* @return $this
*/
public function route(string $route, array $params = []): self
{
$this->route = $route;
$this->url = app_route($route, $params);
return $this;
}
/**
* 多选
* @param int $count
* @return $this
*/
public function multi(int $count = 0): self
{
$this->multi = true;
$this->tagCount = $count;
return $this;
}
/**
* 选项渲染
* @param array $data JS Node
* @return $this
*/
public function optionRender(array $data): self
{
$this->optionRender = $data;
return $this;
}
/**
* @return array
*/
public function render(): array
{
$data = [];
if ($this->data instanceof \Closure) {
$data = call_user_func($this->data);
}
if (is_array($this->data)) {
$data = $this->data;
}
$options = [];
if(isset($data[0]['label'])){
$options=$data;
}else{
foreach ($data as $key => $vo) {
$options[] = [
'label' => $vo,
'value' => $key
];
}
}
$object = [
'nodeName' => 'app-select',
'nParams' => [
'placeholder' => $this->attr['placeholder'] ?: '请选择' . $this->name,
'options' => $options
],
];
if ($this->model) {
$object['vModel:value'] = $this->getModelField();
}
$object['nParams']['allowClear'] = true;
if ($this->multi) {
$object['nParams']['multiple'] = true;
}
if ($this->url) {
$object['nParams']['allowSearch'] = true;
$object['nParams']['filterOption'] = false;
if ($this->route) {
$object['vBind:dataUrl'] = $this->url;
} else {
$object['dataUrl'] = $this->url;
}
}
if ($this->search) {
$object['nParams']['allowSearch'] = true;
}
if ($this->tagCount) {
$object['nParams']['maxTagCount'] = $this->tagCount;
}
if ($this->optionRender) {
$object['vRender:optionRender:item'] = $this->optionRender;
}
return $object;
}
/**
* @param $value
* @return array|mixed
*/
public function dataValue($value)
{
return $this->multi ? array_values(array_filter((array)$this->getValueArray($value))) : $this->getValue($value);
}
/**
* @param $data
* @return string
*/
public function dataInput($data): ?string
{
return is_array($data) ? implode(',', $data) : $data;
}
}

View File

@@ -0,0 +1,99 @@
<?php
namespace admin\components\UI\Form;
use admin\components\UI\Form;
/**
* Class Tab
* 切换组件
* @package backend\components\UI\Table
*/
class Tab extends Composite implements Component
{
/**
* @param $name
* @param callable $callback
* @param int|null $order
* @param string $title
* @param string $desc
* @return $this
*/
public function column($name, callable $callback, int $order = null, string $title = '', string $desc = ''): self
{
$form = new Form();
$form->dialog($this->dialog);
$form->vertical($this->vertical);
$callback($form);
$this->column[] = [
'name' => $name,
'title' => $title,
'desc' => $desc,
'order' => $order ?? (count($this->column) + 1),
'object' => $form,
];
return $this;
}
/**
* @return array
*/
public function render(): array
{
$nodes = [];
$column = collect($this->column)->sortBy('order')->toArray();
foreach ($column as $key => $vo) {
$child = [];
if ($vo['title']) {
$child[] = [
'nodeName' => 'div',
'class' => 'py-4 flex flex-col gap-2',
'child' => [
[
'nodeName' => 'div',
'class' => 'text-xl',
'child' => $vo['title'],
],
[
'nodeName' => 'div',
'class' => 'text-gray-500',
'child' => $vo['desc'],
]
]
];
}
$child[] = [
'nodeName' => 'div',
'class' => 'pt-2',
'child' => $vo['object']->renderForm()
];
$nodes[] = [
'nodeName' => 'a-tab-pane',
'title' => $vo['name'],
'key' => $key,
'class' => !$this->dialog ? ' border-t border-gray-200 dark:border-blackgray-1 px-3 pt-4 pb-0' : '',
'child' => [
'nodeName' => 'div',
'class' => '',
'child' => $child
]
];
}
return [
'nodeName' => 'a-tabs',
'class' => !$this->dialog ? 'mb-4 bg-white dark:bg-blackgray-4 rounded shadow p-4 pb-1' : '',
'type' => 'rounded',
'child' => $nodes
];
}
}

View File

@@ -0,0 +1,78 @@
<?php
namespace admin\components\UI\Form;
/**
* Class Tags
* 标签输入框
* @package backend\components\UI\Form
*/
class Tags extends Element implements Component
{
protected int $limit = 0;
/**
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
$this->attr['placeholder'] = null;
}
/**
* @param $num
* @return $this
*/
public function limit($num): self
{
$this->limit = $num;
return $this;
}
/**
* @return array
*/
public function render(): array
{
$data = [
'nodeName' => 'a-input-tag',
'vModel:modelValue' => $this->getModelField(),
'placeholder' => $this->attr['placeholder'] ?: '请输入' . $this->name,
'allowClear' => true
];
if ($this->limit) {
$data['maxTagCount'] = $this->limit;
}
if($this->replace != ''){
$data['vStringReplace'] = $this->replace;
}
return $data;
}
/**
* @param $value
* @return array
*/
public function dataValue($value): array
{
return array_values(array_filter((array)$this->getValueArray($value)));
}
/**
* @param $data
* @return string
*/
public function dataInput($data): ?string
{
return is_array($data) ? implode(',', $data) : $data;
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace admin\components\UI\Form;
/**
* Class Tel
* @package backend\components\UI\Form
*/
class Tel extends Element implements Component
{
protected Text $object;
protected string $mask = '19999999999';
/**
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
$this->object = new Text($this->name, $this->field, $this->has);
$this->object->afterIcon('phone');
}
/**
* 设置掩码
* @param $value
* @return $this
*/
public function mask($value): self
{
$this->mask = (string) $value;
return $this;
}
/**
* @return array
*/
public function render(): array
{
$this->object->attrArray($this->attr);
return $this->object->getRender();
}
}

View File

@@ -0,0 +1,121 @@
<?php
namespace admin\components\UI\Form;
use admin\components\UI\Widget\Icon;
/**
* 输入框
* @package backend\components\UI\Form
*/
class Text extends Element implements Component
{
protected string $type = 'text';
protected array $before = [];
protected array $after = [];
/**
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
}
/**
* 文本类型
* @param $name
* @return $this
*/
public function type($name): self
{
$this->type = $name;
return $this;
}
/**
* 前置图标
* @param $content
* @return $this
*/
public function beforeIcon($content): self
{
$this->before = (new Icon($content))->attr('vSlot:prepend', '')->getRender();
return $this;
}
/**
* 后置图标
* @param $content
* @return $this
*/
public function afterIcon($content): self
{
$this->after = (new Icon($content))->attr('vSlot:append', '')->getRender();
return $this;
}
/**
* 前置文本
* @param $content
* @return $this
*/
public function beforeText($content): self
{
$this->before = [
'vSlot:prepend' => '',
'nodeName' => 'span',
'child' => $content
];
return $this;
}
/**
* 后置文本
* @param $content
* @return $this
*/
public function afterText($content): self
{
$this->after = [
'vSlot:append' => '',
'nodeName' => 'span',
'child' => $content
];
return $this;
}
/**
* @return array
*/
public function render(): array
{
$child = [];
if ($this->before || $this->after) {
$child = [
$this->before,
$this->after
];
}
$data = [
'nodeName' => 'a-input',
'vModel:modelValue' => $this->getModelField(),
'child' => $child,
'placeholder' => '请输入' . $this->name
];
if($this->replace != ''){
$data['vStringReplace'] = $this->replace;
}
return $data;
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace admin\components\UI\Form;
/**
* Class Textarea
* 多行输入框
* @package backend\components\UI\Form
*/
class Textarea extends Element implements Component
{
protected int $limit = 0;
/**
* Text constructor.
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
$this->attr['placeholder'] = null;
}
/**
* @param $num
* @return $this
*/
public function limit($num): self
{
$this->limit = $num;
return $this;
}
/**
* @return array
*/
public function render(): array
{
$data = [
'nodeName' => 'a-textarea',
'vModel:modelValue' => $this->getModelField(),
'placeholder' => $this->attr['placeholder'] ?: '请输入' . $this->name,
'allowClear' => true,
'showWordLimit' => true
];
if ($this->limit) {
$data['maxLength'] = $this->limit;
}
if($this->replace != ''){
$data['vStringReplace'] = $this->replace;
}
return $data;
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace admin\components\UI\Form;
/**
* Class Time
* 时间选择器
* @package backend\components\UI\Form
*/
class Time extends Element implements Component
{
protected string $string = 'HH:mm:ss';
/**
* Text constructor.
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
$this->attr['placeholder'] = null;
}
/**
* 时间格式
* @param string $format
* @return $this
*/
public function string(string $format): self
{
$this->string = $format;
return $this;
}
/**
* @return array
*/
public function render(): array
{
return [
'nodeName' => 'a-time-picker',
'allowClear' => true,
'format' => $this->string,
'placeholder' => $this->attr['placeholder'] ?: '请选择' . $this->name,
'vModel:model-value' => $this->getModelField()
];
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace admin\components\UI\Form;
/**
* 开关切换
* @package backend\components\UI\Form
*/
class Toggle extends Element implements Component
{
private $checkedValue = 1;
private $uncheckedValue = 0;
/**
* Toggle constructor.
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
}
/**
* @return array
*/
public function render(): array
{
$data = [
'nodeName' => 'a-switch',
'vModel:modelValue' => $this->getModelField(),
'checkedValue' => $this->checkedValue,
'uncheckedValue' => $this->uncheckedValue
];
if($this->replace != ''){
$data['vStringReplace'] = $this->replace;
}
return $data;
}
/**
* 开关数据
* @param string|number|boolean $checkedValue
* @param string|number|boolean $uncheckedValue
* @return $this
*/
public function data($checkedValue,$uncheckedValue){
$this->checkedValue = $checkedValue;
$this->uncheckedValue = $uncheckedValue;
return $this;
}
/**
* @param $data
* @return int
*/
public function dataInput($data): int
{
return $data ? 1 : 0;
}
}

View File

@@ -0,0 +1,96 @@
<?php
namespace admin\components\UI\Form;
/**
* Class Tree
* @package backend\components\UI\Table
*/
class Tree extends Element implements Component
{
protected $data;
/**
* Tree constructor.
* @param string $name
* @param string $field
* @param null $data
* @param string $has
*/
public function __construct(string $name, string $field, $data = null, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->data = $data;
$this->has = $has;
}
/**
* @return array
*/
public function render(): array
{
$data = $this->data;
if ($this->data instanceof \Closure) {
$data = call_user_func($this->data);
}
if ($data instanceof \Illuminate\Database\Eloquent\Collection) {
$data = $data->toArray();
}
$data = $this->loop($data);
$data = [
'nodeName' => 'div',
'class' => 'bg-gray-100 dark:bg-blackgray-2 p-2 rounded w-full h-56 overflow-y-auto app-scrollbar',
'child' => [
'nodeName' => 'a-tree',
'blockNode' => true,
'checkable' => true,
'showLine' => true,
'vModel:checked-keys' => $this->getModelField(),
'data' => $data,
]
];
return $data;
}
/**
* @param $value
* @return array|null
*/
public function dataValue($value): ?array
{
return $this->getValueArray($value);
}
/**
* @param $data
* @return string
*/
public function dataInput($data): ?string
{
return is_array($data) ? implode(',', $data) : '';
}
/**
* @param $data
* @return array
*/
protected function loop($data): array
{
$newData = [];
foreach ($data as $item) {
$tmpData = [
'title' => $item['name'],
'key' => $item['id'],
];
if ($item['children']) {
$tmpData['children'] = $this->loop($item['children']);
}
$newData[] = $tmpData;
}
return $newData;
}
}

View File

@@ -0,0 +1,183 @@
<?php
namespace admin\components\UI\Form;
/**
* Class TreeSelect
* @package backend\components\UI\Form
*/
class TreeSelect extends Element implements Component
{
protected bool $tip = false;
protected bool $multi = false;
protected bool $treeData = false;
protected string $strategy = 'all';
protected string $url = '';
protected string $route = '';
protected $data;
/**
* Select constructor.
* @param string $name
* @param string $field
* @param array|callback|null $data
* @param string $has
*/
public function __construct(string $name, string $field, $data = null, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->data = $data;
$this->has = $has;
$this->attr['placeholder'] = null;
}
/**
* 添加选项
* @param $name
* @param $id
* @param $pid
* @return $this
*/
public function add($name, $id, $pid): self
{
$this->data[] = [
'name' => $name,
'id' => $id,
'pid' => $pid
];
return $this;
}
/**
* 设置动态地址
* @param string $url
* @return $this
*/
public function url(string $url): self
{
$this->url = $url;
return $this;
}
/**
* @param string $route
* @param array $params
* @return $this
*/
public function route(string $route, array $params = []): self
{
$this->route = $route;
$this->url = app_route($route, $params);
return $this;
}
/**
* 多选组件
* @return $this
*/
public function multi(): self
{
$this->multi = true;
return $this;
}
/**
* 树形模式
* @param bool $bool
* @return $this
*/
public function tree(bool $bool = true): self
{
$this->treeData = $bool;
return $this;
}
/**
* 回填方式
* @param string $model
* @return $this
*/
public function strategy(string $model): self
{
$this->strategy = $model;
return $this;
}
/**
* @return array
*/
public function render(): array
{
$data = [];
if ($this->data instanceof \Closure) {
$data = call_user_func($this->data, $this);
}
if (is_array($this->data)) {
$data = $this->data;
}
if (!$this->treeData) {
$options = [];
foreach ($data as $vo) {
$options[] = [
'id' => $vo['id'],
'pid' => $vo['pid'],
'value' => $vo['id'],
'label' => $vo['name'],
];
}
$options = \backend\components\Util\Tree::arr2tree($options, 'id', 'pid', 'children');
} else {
$options = $data;
}
$data = [
'nodeName' => 'app-tree-select',
'nParams' => [
'multiple' => $this->multi,
'treeCheckable' => $this->multi,
'treeCheckedStrategy' => $this->strategy,
'data' => $options,
'placeholder' => $this->attr['placeholder'] ?: '请选择' . $this->name,
]
];
if ($this->route) {
$data['vBind:dataUrl'] = $this->url;
} else {
$data['dataUrl'] = $this->url;
}
if ($this->model) {
$data['vModel:value'] = $this->getModelField();
}
return $data;
}
/**
* @param $value
* @return array|mixed
*/
public function dataValue($value)
{
return $this->multi ? array_values(array_filter((array)$this->getValueArray($value))) : $this->getValue($value);
}
/**
* @param $data
* @return string
*/
public function dataInput($data): ?string
{
return is_array($data) ? implode(',', $data) : $data;
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace admin\components\UI\Form;
/**
* url输入
* @package backend\components\UI\Form
*/
class Url extends Element implements Component
{
protected Text $object;
/**
* Text constructor.
* @param string $name
* @param string $field
* @param string $has
*/
public function __construct(string $name, string $field, string $has = '')
{
$this->name = $name;
$this->field = $field;
$this->has = $has;
$this->object = new Text($this->name, $this->field, $this->has);
$this->object->beforeText('http(s)');
}
/**
* @return array
*/
public function render(): array
{
$this->object->attrArray($this->attr);
return $this->object->getRender();
}
}