MultiDialog 多选对话框
MultiDialog 多选对话框同样是继承与Field,仅支持 array 类型的Model属性字段注解。MultiDialog 多选对话框 与 SelectDialog 单选对话框 不同在于,多选对话框可以选择多个选项数据.
除了Field 的属性支持以外,MultiDialog 多选对话框自己的属性设置选项如下:
public string $url = '';
打开的对话框URL地址,支持虚拟URL地址。
public int $mode = 1;
填充值的模式,1 是完整填充,包括值与文本,2 是仅填充值
如:
#mode =2 时填充的值为
[1,3,4]
#mode =1 是填充的值为
[{"value"=>1,"text":"选项1"},{"value"=>3,"text":"选项3"},{"value"=>4,"text":"选项4"}]
public string $textSql = '';
使用值获取对应文本的SQL语句, 仅适用于 mode=2 的情况。
例如:
textSql:'select name from @pf_category where id=?'
public string|array|null $textFunc = null;
指定值获取对应文本的函数指定,仅适用于 mode=2 的情况。
函数定义为:
function($value):string
如:
#[MultiDialog(
label: '选择文章1',
url: '~/multi_dialog',
textFunc: [self::class, 'getSelectName']
)]
public array $select = [];
public static function getSelectName(int|string $value): string
{
$row = DB::getRow('select title from @pf_article where id=?', $value);
if ($row == null) {
return '';
}
return $row['title'];
}
public string $itemType = 'string';
在 mode=2 时,每项数据的填充类型。 如果期望是 int 则填写int。
为了演示效果,我们先制作一个用于选择的对话框页面:
控制器代码如下:
/app/home/controller/MultiDialog.php
<?php
namespace app\home\controller;
use beacon\core\Controller;
use beacon\core\DBSelector;
use beacon\core\Method;
class MultiDialog extends Controller
{
//用于提供穿梭框的数据的
#[Method(act: 'index', method: Method::POST | Method::GET)]
public function index(string $keyword = '')
{
#非ajax请求直接返回页面。
if (!$this->isAjax()) {
$this->display('multi_dialog.tpl');
return;
}
$selector = new DBSelector('@pf_article');
$selector->search("title like concat('%',?,'%')", $keyword);
$data = $selector->pageData();
#定义一个字符串模板,用于修饰 $data['list'] 数据。
$template = <<<'TPL'
{hook fn='_choice' rs}<input type="checkbox" class="check-item" data-value="{$rs.id}" data-text="{$rs.title}" value="{$rs.id}"/>{/hook}
{hook fn='columnName' rs}{$rs.columnId|column}{/hook}
{hook fn='categoryName' rs}{$rs.categoryId|category}{/hook}
TPL;
# 以上模板用到 修饰器 column 和 category 是自定义的模板修饰器,可参考 sdopx.wj008.net 模板引擎 修饰器的制作。
# column 是columnId 兑换 栏目名称的修饰器
# category 是categoryId 兑换 栏目名称的修饰器
$data['list'] = $this->hookData($data['list'], 'string:' . $template, 'rs', true);
$this->success('ok', $data);
}
}
对应的模板文件如下:
<!doctype html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<title>多选对话框</title>
<link type="text/css" rel="stylesheet" href="/yeeui/css/yeeui.css"/>
<link type="text/css" rel="stylesheet" href="/icofont/icofont.css"/>
<script src="/yeeui/third/jquery-3.3.1.min.js"></script>
<script src="/yeeui/third/vue.min.js"></script>
<script src="/yeeui/yee.js"></script>
{literal}
<style>
html, body {
background: #fff;
}
</style>
{/literal}
</head>
<body>
<div class="yee-wrap yee-dialog">
<div class="yee-tab">
<!--YeeUI 标签切换控件-->
<ul style="float:left;" yee-module="form-tab">
<li class="curr" data-bind-name="main-list"><a href="javascript:;">待选</a></li>
<li data-bind-name="selected-list"><a href="javascript:;">已选</a></li>
</ul>
<div class="yee-tab-right">
<span> 已选 <span id="selected-count" class="green">0</span>/<span id="records-count">0</span> 条记录</span>
</div>
</div>
<div name="main-list">
<div class="yee-list-search">
<!--YeeUI ajax搜索表单控件-->
<form id="searchForm" yee-module="search-form" data-bind="#list">
<div class="yee-cell">
<label class="yee-label">文章标题:</label>
<span><input name="keyword" class="form-inp text" type="text"/></span>
</div>
<div class="yee-cell">
<input class="form-btn blue" value="查询" type="submit"/>
<input class="form-btn normal" value="重置" type="reset"/>
<input type="hidden" name="sort">
</div>
</form>
</div>
<div class="scrollbar" style="height:calc(100vh - 200px);overflow-y: auto">
<!--YeeUI 数据显示控件-->
<table id="list" width=100% class="yee-datatable" yee-module="datatable" data-auto-load="true">
<thead>
<tr>
<th width="40"><input type="checkbox"></th>
<th align="center" width="60">id</th>
<th align="left">文章标题</th>
<th align="center" width="80">栏目类别</th>
<th align="center" width="80">文章分类</th>
<th align="center" width="80">点击数</th>
<th align="center" width="180">创建时间</th>
</tr>
</thead>
<tbody yee-template="vue">
<tr v-for="rs in list">
<td align="center" v-html="rs._choice"></td>
<td align="center" v-html="rs.id"></td>
<td align="left" v-html="rs.title"></td>
<td align="center" v-html="rs.columnName"></td>
<td align="center" v-html="rs.categoryName"></td>
<td align="center" v-html="rs.hits"></td>
<td align="center" v-html="rs.addTime"></td>
</tr>
<tr v-if="list.length==0">
<td colspan="100"> 没有任何数据信息....</td>
</tr>
</tbody>
</table>
</div>
<!--YeeUI 分页控件-->
<div yee-module="pagebar" data-bind="#list" class="yee-pagebar">
<div yee-template="vue">
<div class="pagebar" v-html="barCode"></div>
<div class="pagebar-info">共有信息:<span v-text="recordsCount"></span> 页次:<span v-text="page"></span>/<span v-text="pageCount"></span> 每页<span v-text="pageSize"></span></div>
</div>
</div>
</div>
<!--用于显示已选中数据-->
<div name="selected-list" class="scrollbar" style="height:calc(100vh - 100px);overflow-y: auto">
<table id="selected-table" class="yee-datatable" border="0" width="100%" style="background:#fff;">
<thead>
<tr>
<th align="center" width="60">ID值</th>
<th align="left">已选选项(文本)</th>
<th width="80">操作</th>
</tr>
</thead>
<tbody>
<tr v-for="rs in Object.values(select)">
<td align="center" v-text="rs.value"></td>
<td align="left" v-text="rs.text"></td>
<td align="center"><a href="javascript:;" class="yee-btn remove" style="margin-right: 5px" @click="remove(rs)">移除</a></td>
</tr>
</tbody>
</table>
</div>
<div class="yee-submit" style="position: fixed; right: 0; bottom: 0; margin: 0px; padding: 10px 0; text-align: right;">
<input id="select-btn" type="button" class="form-btn red" style="margin-right: 10px;" value="确定"/>
<a id="close-btn" href="javascript:;" style="margin-right: 20px;" class="form-btn">关闭</a>
</div>
</div>
{literal}
<script>
//当对话框初始化完成后,该函数会返回 dialog 的对话框句柄。
Yee.readyDialog(function (dialog) {
let dataMap = {};
let table = $("#list");
//使用vue渲已选中的数据
let app = new Vue({
el: '#selected-table',
data: {
select: []
},
methods: {
remove: function (value) {
removeItem(value);
refreshItem();
}
}
});
function addItem(item) {
let key = item.value;
//去重,如果已经存在,不要再加入
if (dataMap[key] !== void 0) {
return;
}
dataMap[key] = item;
app.select.push(item);
$("#selected-count").text(app.select.length);
}
function removeItem(item) {
let key = item.value;
delete dataMap[key];
let temp = [];
for (let i = 0; i < app.select.length; i++) {
let k = app.select[i].value;
if (dataMap[k]) {
temp.push(app.select[i]);
}
}
app.select = temp;
$("#selected-count").text(app.select.length);
}
//刷新列表中的 勾选状态
function refreshItem() {
table.find(':checkbox').prop('checked', false);
for (let key in dataMap) {
let rs = dataMap[key] || null;
if (rs) {
table.find(':checkbox.check-item[value=' + rs.value + ']').prop('checked', true);
}
}
}
function setBox(elem) {
let box = $(elem);
let data = box.data() || {};
if (!box.prop('checked')) {
removeItem(data);
} else {
addItem(data);
}
}
//关闭对话框
$('#close-btn').on('click', function () {
dialog.close();
});
//确定选择
$('#select-btn').on('click', function () {
let items = [];
for (let i = 0; i < app.select.length; i++) {
let rs = app.select[i];
if (rs) {
items.push(rs);
}
}
//使用对话框句柄返回数据 items 数据
dialog.success(items);
//关闭对话框
dialog.close();
});
//列表控件更新后
table.on("render", function (ev, source) {
$("#records-count").text(source.pageInfo.recordsCount || "0");
refreshItem();
});
table.on('click', 'input:checkbox', function () {
if ($(this).is('.check-item')) {
setBox(this);
} else {
setTimeout(function () {
$('#list').find('input:checkbox.check-item').each(function (_, elem) {
setBox(elem);
});
}, 1);
}
});
//从对话框中拿取传过来的数据
if (dialog !== void 0 && dialog.assign && Yee.isArray(dialog.assign)) {
let items = dialog.assign || [];
for (let i = 0; i < items.length; i++) {
if (items[i].value !== void 0) {
addItem(items[i]);
}
}
}
});
</script>
{/literal}
</html>
现在我们修改主Model 来设置多选对话框的使用
UserModel
namespace app\home\model;
use beacon\core\DB;
use beacon\core\Form;
use beacon\widget\MultiDialog;
use beacon\widget\Text;
use beacon\widget\Textarea;
#注意 这里需要使用表单注解
#[Form(title: '用户表单', table: '@pf_user', template: 'user.form.tpl')]
class UserModel
{
#[Text(
label: '团队名称',
validRule: ['r' => '请填写团队名称'],
)]
public string $groupName = '';
#[MultiDialog(
label: '选择文章1',
url: '~/multi_dialog',
mode: 2,
itemType:'int',
textFunc: [self::class, 'getSelectName'],
attrs: [
'data-width' => 1000,#指定对话框宽
'data-height' => 600,#指定对话框高
'data-btn-text' => '选择文章', #指定按钮文本
]
)]
public array $select1 = [];
#[MultiDialog(
label: '选择文章2',
url: '~/multi_dialog',
)]
public array $select2 = [];
#[Textarea(
label: '团队介绍',
validRule: ['r' => '请填写个人介绍'],
)]
public string $intro = '';
public static function getSelectName(int|string $value): string
{
$row = DB::getRow('select title from @pf_article where id=?', $value);
if ($row == null) {
return '';
}
return $row['title'];
}
}
模板文件:
<!doctype html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<title>{$form->title}</title>
<link type="text/css" rel="stylesheet" href="/yeeui/css/yeeui.css"/>
<link type="text/css" rel="stylesheet" href="/icofont/icofont.css"/>
<script src="/yeeui/third/jquery-3.3.1.min.js"></script>
<script src="/yeeui/yee.js"></script>
</head>
<body>
<div style="margin: 20px">
<form method="post" yee-module="ajax validate">
<div class="yee-panel">
<div class="panel-caption">
{if $form->getType()=='add'}添加{elseif $form->getType()=='edit'}编辑{/if}{$form->title}
</div>
<div class="panel-content">
{foreach from=$form->getViewFields() item=field}
{field_row field=$field}
{/foreach}
</div>
<div class="yee-submit">
<label class="submit-label"></label>
<div class="submit-cell">
{*输出隐藏域*}
{$form->fetchHideBox()|raw}
<input type="submit" class="form-btn red" value="提交">
</div>
</div>
</div>
</form>
</div>
</html>
控制器文件:
namespace app\home\controller;
use app\home\model\UserModel;
use beacon\core\Controller;
use beacon\core\Form;
use beacon\core\Logger;
use beacon\core\Method;
class User extends Controller
{
#[Method(act: 'index', method: Method::GET)]
public function index()
{
$form = Form::create(UserModel::class, 'add');
$this->displayForm($form);
}
#[Method(act: 'index', method: Method::POST)]
public function add()
{
$user = new UserModel();
$form = Form::create($user, 'add');
$input = $this->completeForm($form);
Logger::log($input); #input 可以用用于插入或者更新数据库。
Logger::log($user);
//这里需要有返回值 否则 ajax 提交会没有任何内容返回
$this->success('ok');
}
}
最终效果如下:
对话框已选效果:
填完表单,提交后的 debug.php 页面输出如下:
{
"groupName": "测试团队",
"select1": [
5,
7
],
"select2": [
{
"text": "Manjaro",
"value": 9
},
{
"text": "Deepin15.7 编译安装 php 7.2",
"value": 10
},
{
"text": "今天聊聊 Elasticsearch 在PHP项目中的使用。",
"value": 7
}
],
"intro": "这个也帅。"
}
{
"___class_name": "app\\home\\model\\UserModel",
"groupName": "测试团队",
"select1": [
5,
7
],
"select2": [
{
"text": "Manjaro",
"value": 9
},
{
"text": "Deepin15.7 编译安装 php 7.2",
"value": 10
},
{
"text": "今天聊聊 Elasticsearch 在PHP项目中的使用。",
"value": 7
}
],
"intro": "这个也帅。"
}