招标
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

522 lines
15 KiB

<?php
/**
* Date: 2020/9/25 18:42
* User: chenlong <vip_chenlong@163.com>
*/
namespace sdModule\layui\defaultForm;
use app\common\SdException;
use sdModule\layui\defaultForm\formUnit\AuxTitle;
use sdModule\layui\defaultForm\formUnit\Selects;
use sdModule\layui\defaultForm\formUnit\UEditor;
use sdModule\layui\defaultForm\formUnit\UnitBase;
/**
* Class Form
* @package sdModule\layui\defaultForm
*/
class Form
{
private const UNIT_CLASS = "\\sdModule\\layui\\defaultForm\\formUnit\\%s";
private const FORM_TEMPLATE = '<div class="%s" %s>%s<div class="%s" >%s</div>%s</div>';
private const ITEM_TEMPLATE = '<div class="layui-form-item">%s</div>';
private const LABEL_TEMPLATE = '<label class="layui-form-label">%s</label>';
private const TIP_TEMPLATE = '<div class="layui-form-mid layui-word-aux">%s</div>';
private const SCRIPT_TEMPLATE = '<script type="text/javascript" src="%s"></script>';
private const SUBMIT_TEMPLATE = '<div class="layui-form-item"><div class="layui-input-block sc-submit"><button class="layui-btn" lay-submit lay-filter="sc-form">%s</button><button id="close" class="layui-btn layui-btn-primary">%s</button></div></div>';
/**
* @var array 创建表单的数据
*/
private array $form_data = [];
/**
* @var array 表单默认值数据
*/
private array $default_data = [];
/**
* @var array 表单元素
*/
private array $unit = [];
/**
* @var array js代码
*/
private array $js = [];
/**
* @var array 加载的js
*/
private array $load_js = [];
/**
* @var int 页面占比1 - 12
*/
private int $custom_md = 0;
/**
* @var array 验证规则
*/
private array $verify_rule = [];
/**
* @var array 短表单及提示语, key = name, value = 提示, eg: ['city' => '请选择城市']
*/
private array $short_from_and_tip = [];
/**
* @var string 场景
*/
private string $scene;
/**
* @var string 风格
*/
private string $skin = '';
/**
* 创建表单
* @param array $form_data 创建表单数据
* @param string $scene 场景值
* @return Form
*/
public static function create(array $form_data, string $scene = '')
{
$form = new self();
$form->form_data = $form_data;
$form->scene = $scene;
return $form;
}
/**
* 设置表单风格
* @param bool $pane
* @return $this
*/
public function setSkinToPane($pane = false)
{
$this->skin = $pane ? "layui-form-pane" : "";
return $this;
}
/**
* 获取表单风格
* @return string
*/
public function getSkin()
{
return $this->skin;
}
/**
* 完成创建
* @return $this
* @throws SdException
* @throws \ReflectionException
*/
public function complete()
{
$this->makeUnitCode();
$this->form_data = $this->fieldMerge();
return $this;
}
/**
* 设置占用列
* @param int $custom_md
* @return Form
*/
public function setCustomMd(int $custom_md = 12)
{
if (in_array($custom_md, range(1, 12))){
$this->custom_md = $custom_md;
}
return $this;
}
/**
* 设置短标签
* @param array $tips key = name, value = 提示, eg: ['city' => '请选择城市']
* @return Form
*/
public function setShortFrom(array $tips)
{
$this->short_from_and_tip = $tips;
return $this;
}
/**
* 引入外部js
* @param $js_path
* @return $this
*/
public function importJs($js_path)
{
$this->load_js[] = $this->assets($js_path);
return $this;
}
/**
* 获取html
* @throws SdException
* @throws \ReflectionException
*/
private function makeUnitCode()
{
foreach ($this->form_data as $build_index => $item) {
if ($item instanceof \Closure){ // 处理行内标签
foreach (call_user_func($item) as $items) {
$this->codeGenerate($items, $build_index);
}
}elseif(is_array($item)){ // 处理表格表单
$this->tableCode($item, $build_index);
}else{
$this->codeGenerate($item);
}
}
}
/**
* @param $item
* @param $build_index
* @throws SdException
* @throws \ReflectionException
*/
private function tableCode($item, $build_index)
{
$code = []; // 整个表格的代码
foreach ($item as $items) {
$line = []; // 一行的代码
foreach ($items as $name => $item_){
$attr = '';
if (is_array($item_)){
list($item_, $attr) = $item_;
}
if ($item_ instanceof UnitData){
$item_ = $this->codeGenerate($item_, "T_{$build_index}");
$item_[array_key_first($item_)] = [current($item_), $attr];
$line = array_merge($line, $item_);
}else{
$line[] = [$item_, $attr];
}
}
$code[] = $line;
}
$key = is_string($build_index) ? $build_index : "T_{$build_index}";
$this->unit[$key] = $code;
}
/**
* 代码生成
* @param UnitData $unit_item 表单项目数据
* @param null|int $build_index 组合表单的索引
* @return mixed|string|void
* @throws SdException
* @throws \ReflectionException
*/
private function codeGenerate(UnitData $unit_item, $build_index = null)
{
if (in_array($this->scene, $unit_item->get('remove_scene'))) {
return;
}
$unit = $this->getUnitInstance($unit_item);
$name = $unit_item->get('name');
$unit->setData($unit_item->get('select_data'))
->setPreset($unit_item->get('preset'))
->setConfig($unit_item->get('config'));
if (property_exists($unit, 'default') && isset($this->default_data[$name])) {
$unit->default = $this->default_data[$name];
}
$this->js[$name] = $unit->getJs();
if ($unit instanceof UEditor){
$this->load_js['u-e_config'] = sprintf(self::SCRIPT_TEMPLATE, $this->assets("/admin_static/editor/ueditor.config.js"));
$this->load_js['u-e_all'] = sprintf(self::SCRIPT_TEMPLATE, $this->assets("/admin_static/editor/ueditor.all.js"));
}elseif ($unit instanceof Selects){
$this->load_js['xm-selects'] = sprintf(self::SCRIPT_TEMPLATE, $this->assets("/admin_static/layui/dist/xm-select.js"));
}
$attr = $unit_item->get('input_attr')[$this->scene] ?? '';
$common_attr = $unit_item->get('input_attr')['-'] ?? '';
$attr = implode(' ', [$attr, $common_attr]);
if ($build_index){
if (is_string($build_index)){
return [$name => $unit->getHtml($attr)];
}
$this->unit[$build_index][$name] = $unit->getHtml($attr);
}else{
$this->unit[$name] = $unit->getHtml($attr);
}
}
/**
* 获取表单元素的类
* @param UnitData $unit_item
* @return object|UnitBase
* @throws SdException
* @throws \ReflectionException
*/
private function getUnitInstance(UnitData $unit_item)
{
$class_name = sprintf(self::UNIT_CLASS, parse_name($unit_item->get('type'), 1));
if (!class_exists($class_name)){
throw new SdException("表单类型【{$unit_item->get('type')}】不存在");
}
$unit = new \ReflectionClass($class_name);
return $unit->newInstance($unit_item->get('name'), $unit_item->get('label'), $unit_item->get('placeholder'));
}
/**
* 获取html内容
* @return string
*/
public function getHtml()
{
$html = '';
foreach ($this->unit as $name => $item) {
if (!is_array($item)){
$html .= $this->itemHtml($name, $item);
continue;
}
$html_item = '';
if (is_string($name)){
$html_item = $this->tableHtml($name, $item);
}else{
foreach ($item as $names => $items) {
$html_item .= $this->itemHtml($names, $items, true);
}
}
$html .= sprintf(self::ITEM_TEMPLATE, $html_item);
}
return $html . sprintf(self::SUBMIT_TEMPLATE, lang('submit'), lang('close'));
}
/**
* tableForm的HTML代码创建
* @param string $name
* @param array $item
* @return string
*/
private function tableHtml(string $name, array $item)
{
$html_item = "<table class='layui-table'>";
foreach ($item as $names => $items) {
$html_item .= "<tr>";
foreach ($items as $name_ => $item_){
$style = isset($this->form_data[$name_]) ? '' : 'style="background-color:#f2f2f2"';
list($item_, $attr) = $item_;
$style = preg_match('/style="/', $attr) ? $attr : implode(" ", [$attr, $style]);
$html_item .= sprintf("<td %s>%s</td>", $style, $item_);
}
$html_item .= "</tr>";
}
$html_item .= "</table>";
$label = preg_match('/^T_.*/', $name) ? '' : $name;
$is_label = preg_match('/^N_.*/', $name);
return sprintf(self::FORM_TEMPLATE, 'layui-form-item', '', $is_label ? "" : sprintf(self::LABEL_TEMPLATE, $label), $is_label ? "" : 'layui-input-block', $html_item, '');
}
/**
* 设置js代码
* @param string $js
* @return string
*/
public function setJs(string $js)
{
$this->js['custom-sc'] = $js;
return $this;
}
/**
* 获取js代码
* @return string
*/
public function getJs()
{
return implode("\n\r", [
implode("\n\r", $this->js),
$this->getDefault(),
$this->submitJs()
]);
}
/**
* 需要加载的js代码
* @return string
*/
public function loadJs()
{
return implode("\r\n", $this->load_js);
}
/**
* 表单默认值代码
* @return false|string
*/
private function getDefault()
{
$default = json_encode($this->default_data, JSON_UNESCAPED_UNICODE);
return <<<JS
layui.form.val('sd', {$default});
for(let d in defaultData){
if (defaultData.hasOwnProperty(d) && typeof defaultData[d] === 'function'){
defaultData[d]();
}
}
JS;
}
/**
* 表单元素的html
* @param string $name 表单name
* @param string $item 表单的子元素html
* @param bool $inline 是否为行内元素
* @return string
*/
private function itemHtml($name, $item, $inline = false)
{
/** @var UnitData $unit */
$unit = $this->form_data[$name];
if (in_array($unit->get('type'), [FormData::HIDDEN, FormData::TEXT_SHORT, FormData::AUX_TITLE])){
return $item;
}
$item_class = $inline ? 'layui-inline' : 'layui-form-item';
$input_class = $unit->get('label') && !isset($this->short_from_and_tip[$name]) ? 'layui-input-block' : 'layui-input-inline';
$label = $unit->get('label') ? sprintf(self::LABEL_TEMPLATE, $unit->get('label')) : "";
$tip = isset($this->short_from_and_tip[$name]) ? sprintf(self::TIP_TEMPLATE, $this->short_from_and_tip[$name]) : "";
$pane = $this->skin && in_array($unit->get('type'), [FormData::SWITCH, FormData::CHECKBOX, FormData::RADIO]) ? 'pane' : '';
return sprintf(self::FORM_TEMPLATE, $item_class, $pane ,$label, $input_class, $item, $tip);
}
/**
* 资源路径组合
* @param $src
* @return string
*/
private function assets($src)
{
return rtrim(strtr(dirname($_SERVER['SCRIPT_NAME']), ['\\' => '/']), '/') . $src;
}
/**
* 提交的js代码
* @return string
*/
private function submitJs()
{
$success = lang("success");
$close = request()->get('__sc_tab__') ? "custom.closeTabsPage()" : "parent.layer.closeAll()";
return <<<JS
$('#close').click(function () {
{$close};
return false;
});
layui.form.on('submit(sc-form)', function (data) {
if(window.submit_sc) return false;
let load = custom.loading();
$.ajax({
type: 'post'
, headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
, data: data.field
, success: function (res) {
layer.close(load);
if (res.code === 200) {
parent.layer.closeAll();
try{
window.parent.notice.success('{$success}');
}catch (e) {
notice.success('{$success}');
}
if (window.parent.table){
window.parent.table.reload('sc');
}
} else {
notice.warning(res.msg);
}
},
error: function (err) {
layer.close(load);
}
});
return false;
})
JS;
}
/**
* 获取内容比例
* @return int
*/
public function getCustomMd(): int
{
return $this->custom_md;
}
/**
* 字段合并
* @param array $data
* @return array
*/
private function fieldMerge(array $data = null)
{
$inline_field = [];
$data = $data ?: $this->form_data;
foreach ($data as $key => $item) {
if ($item instanceof \Closure) {
$inline_field = array_merge(call_user_func([$this, 'fieldMerge'], $item()), $inline_field);
unset($data[$key]);
} elseif (is_array($item)) {
foreach ($item as $items){
foreach ($items as $item_){
$item_ instanceof UnitData and $inline_field[] = $item_;
}
}
unset($data[$key]);
} elseif ($item instanceof AuxTitle) {
unset($data[$key]);
}
}
$data = array_merge($inline_field, $data);
$return_data = [];
/** @var UnitData $datum */
foreach ($data as $datum) {
$return_data[$datum->get('name')] = $datum;
}
return $return_data;
}
/**
* 设置默认值
* @param array $default_data
* @return Form
*/
public function setDefaultData(array $default_data): Form
{
$this->default_data = $default_data;
return $this;
}
}