增删改查

基类继承

// 接口基类
app/common/basics/Api.php

// 后端基类
app/common/basics/Backend.php

// 前端基类
app/common/basics/Frontend.php

// 服务基类
app/common/basics/Service.php

Curd类

  • 控制器中继承基类 Backend (根据应用继承)
  • 服务层中也需要继承基类 Service, 没继承是没办法用搜索器的
  • 为什么要继承基类?答: 因为基类实现了拦截 和 大量好用的方法
class ArticleController extends Backend
{
    // 列表
    public function index() { }
    
    // 新增
    public function add() { }
    
    // 编辑
    public function edit() { }
    
    // 删除
    public function del() { }
}

验证器

  • 验证器写在validate目录中并继承 app\common\basics\Validate
  • 如果没有继承自定义的基类验证器,则无法使用切面验证写法
// 1、定义验证器, 具体请参考代码 或 查看ThinkPHP6的开发文档
use app\common\basics\Validate;
class ArticleValidate extends Validate
{
    protected $rule = [
        'id'           => 'require|integer',
        'title'        => 'require'
    ];
}

// 2、在控制器中使用验证器
class ArticleController extends Backend
{
    public function add() { 
        if ($this->isAjaxPost()) {
            (new ArticleValidate())->addCheck(); // 验证器: 验证新增数据
            ArticleService::add($this->request->post());
            return AjaxUtils::success();
        }
        
        return view();
    }
}

// 3、以下是场景验证器的使用方式
// 目前提供了4种快捷验证: addCheck / editCheck / idCheck / idsCheck
// 如果以下4种满足不了, 可以指定场景 goCheck('此处填场景')

// 验证新增数据
(new ArticleValidate())->addCheck();

// 验证编辑数据
(new ArticleValidate())->editCheck();

// 验证数字类型ID
(new ArticleValidate())->idCheck();

// 验证数组类型的ID
(new ArticleValidate())->idsCheck();

// 验证分页参数
(new PageValidate())->goCheck();

业务流程

  • 1、创建 controller
  • 2、创建 service
  • 3、创建 validate
  • 4、创建 view
  • 5、创建 model

controller
     调用validate验证参数      调用service处理具体逻辑      view返回HTML页面

service
     调用model实现增删改查      使用具体的逻辑需求

视图页面

列表页常用模板

{extend name="common/layout" /}

{block name="body"}
<div class="container">
    <!-- 搜索栏 -->
    <form class="layui-form layui-search" lay-filter="filter-search-form">
        <div class="layui-form-item">
            <!-- 多类型搜索 -->
            <div class="layui-inline">
                <label for="keyword" class="layui-form-label">搜索类型:</label>
                <div class="layui-input-inline layui-sm-select">
                    <input type="hidden" id="search-filter-type" name="type">
                    <div class="layui-inline">
                        <label for="keyword_type" class="layui-hide"></label>
                        <select id="keyword_type" name="keyword_type">
                            <option value="">请选择</option>
                            <option value="licence_sn">授权编号</option>
                            <option value="user_sn">用户编号</option>
                            <option value="nickname">用户昵称</option>
                        </select>
                    </div>
                    <div class="layui-inline" >
                        <input type="text" id="keyword" name="keyword" placeholder="请输入关键词" class="layui-input">
                    </div>
                </div>
            </div>
            <!-- 文本框搜索 -->
            <div class="layui-inline">
                <label for="title" class="layui-form-label">标题:</label>
                <div class="layui-input-inline">
                    <input type="text" id="title" name="title" class="layui-input" placeholder="请输入标题名称" autocomplete="off">
                </div>
            </div>
            <!-- 下拉式搜索 -->
            <div class="layui-inline">
                <label for="status" class="layui-form-label">状态:</label>
                <div class="layui-input-inline">
                    <select id="status" name="status">
                        <option value="" selected>全部</option>
                        <option value="0">显示</option>
                        <option value="1">隐藏</option>
                    </select>
                </div>
            </div>
            <!-- 时间范围搜索 -->
            <div class="layui-inline layui-input-datetime">
                <label for="datetime" class="layui-form-label">操作时间:</label>
                <div class="layui-input-block">
                    <input type="text" id="datetime" name="datetime" class="layui-input" placeholder="开始时间 - 结束时间" readonly>
                </div>
            </div>
            <!-- 搜索按钮 -->
            <div class="layui-inline">
                <a class="layui-btn layui-btn-sm layui-btn-default" lay-submit lay-filter="search">查询</a>
                <a class="layui-btn layui-btn-sm layui-btn-primary" lay-submit lay-filter="clear-search">重置</a>
            </div>
        </div>
    </form>

    <!-- 表格栏 -->
    <div class="layui-card">
        <div class="layui-card-body">
            <!-- 渲染节点 -->
            <table id="wait-table-list" lay-filter="wait-table-list"></table>
            <!-- 表格头操作 -->
            <script type="text/html" id="toolbar">
                <div class="layui-btn-container">
                    <a class="layui-btn layui-btn-sm layui-btn-default" lay-event="add">
                        <i class="layui-icon icon-add"></i>
                        <span>新增</span>
                    </a>
                    <a class="layui-btn layui-btn-sm layui-btn-danger layui-btn-forbid" lay-event="leave">
                        <i class="layui-icon icon-del"></i>
                        <span>删除</span>
                    </a>
                </div>
            </script>
            <!-- 表格行操作 -->
            <script type="text/html" id="table-operate">
                <button type="button" class="layui-btn layui-btn-xs layui-btn-default" lay-event="edit">
                    <i class="layui-icon icon-edit"></i>
                </button>
                <button type="button" class="layui-btn layui-btn-xs layui-btn-danger" lay-event="del">
                    <i class="layui-icon icon-del"></i>
                </button>
            </script>
        </div>
    </div>
</div>

{block name="js"}
<script>
    layui.use(['laydate'], function() {
        let laydate = layui.laydate;

        // 时间选择
        laydate.render({elem: '#datetime' ,type: 'datetime' ,trigger: 'click' ,range: true});
        
        // 渲染表格
        let table = waitUtil.table({
            elem: '#wait-table-list'
            ,url: '{:route("content.article/index")}'
            ,cols: [[
                {type:'checkbox', width:48},
                {field:'id', title:'ID', width:60, align:'center', event:'id'},
                {fixed:'right', title:'操作', width:90, align:'center', toolbar:'#table-operate'}
            ]]
        });

        // 逻辑事件
        waitUtil.event({
            add: function () {
                waitUtil.popup({
                    title: '新增',
                    url: '{:route("content.article/add")}',
                    area: ['95%', '95%'],
                    success: function (layero, index) {
                        layero.layui.form.on('submit(addForm)', function(data) {
                            waitUtil.locking(this);
                            data.field['content'] = layero.tinymce.activeEditor.getContent();
                            waitUtil.ajax({
                                url: '{:route("content.article/add")}',
                                type: 'POST',
                                data: data.field
                            }).then((res) => {
                                waitUtil.unlock(this);
                                if (res.code === 0) {
                                    table.reload({page: {curr: 1}});
                                    layer.close(index);
                                }
                            }).catch(() => {
                                waitUtil.unlock(this);
                            });
                        });
                    }
                });
            },
            edit: function (obj) {
                waitUtil.popup({
                    title: '编辑',
                    url: '{:route("content.article/edit")}?id='+obj.data.id,
                    area: ['95%', '95%'],
                    success: function (layero, index) {
                        layero.layui.form.on('submit(addForm)', function(data) {
                            waitUtil.locking(this);
                            data.field['id'] = obj.data.id;
                            waitUtil.ajax({
                                url: '{:route("content.article/edit")}',
                                type: 'POST',
                                data: data.field
                            }).then((res) => {
                                waitUtil.unlock(this);
                                if (res.code === 0) {
                                    table.reload();
                                    layer.close(index);
                                }
                            }).catch(() => {
                                waitUtil.unlock(this);
                            });
                        });
                    }
                });
            },
            del: function (obj) {
                layer.confirm('确定要删除此项数据吗?', function(index) {
                    layer.close(index);
                    waitUtil.ajax({
                        url: '{:route("content.article/del")}',
                        type: 'POST',
                        data: {ids: [obj.data.id]}
                    }).then((res) => {
                        if (res.code === 0) {
                            table.reload();
                        }
                    });
                });
            },
            leave: function () {
                let ids = waitUtil.checkbox();
                if (!ids.length) {
                    return layer.msg('请至少选择一项!', {icon: 2});
                }
                layer.confirm(`确定要删除选中的${ids.length}项数据吗?`, function(index) {
                    layer.close(index);
                    waitUtil.ajax({
                        url: '{:route("content.article/del")}',
                        type: 'POST',
                        data: {ids: ids}
                    }).then((res) => {
                        if (res.code === 0) {
                            table.reload();
                        }
                    });
                });
            }
        });

        // 搜索事件
        waitUtil.search(table);
    }};
</script>

新增页常用模板

{extend name="common/layout" /}

{block name="body"}
<form class="layui-form">
    <!-- 主体内容 -->
    <div class="wait-body-content">
        <!-- 下拉框 -->
        <div class="layui-form-item">
            <label for="cid" class="layui-form-label"><span class="asterisk">*</span>类目:</label>
            <div class="layui-input-block">
                <select id="cid" name="cid" lay-verify="required|number">
                    <option value="">请选择</option>
                    {volist name="$category" id="vo"}
                        <option value="{$vo.id}">{$vo.name}</option>
                    {/volist}
                </select>
            </div>
        </div>
        <!-- 文本框 -->
        <div class="layui-form-item">
            <label for="title" class="layui-form-label"><span class="asterisk">*</span>标题:</label>
            <div class="layui-input-block">
                <input type="text" id="title" name="title"
                       autocomplete="off" class="layui-input" lay-verType="tips" lay-verify="required">
            </div>
        </div>
        <!-- 封面图 -->
        <div class="layui-form-item">
            <label class="layui-form-label">封面:</label>
            <div class="layui-input-block">
                <div class="thumbnail" data-type="image" data-field="image" data-limit="1">
                    <div class="musters"></div>
                    <div class="builder">
                        <i class="layui-icon layui-icon-camera"></i>
                        <p>上传封面</p>
                        <div class="mask">
                            <div class="item layui-auto">图库选择</div>
                            <div class="item layui-auto-call">本地上传</div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <!-- 头像图 -->
        <div class="thumbnail" data-type="image" data-field="avatar" data-limit="1">
            <div class="musters"></div>
            <div class="builder layui-auto-call">
                <i class="layui-icon layui-icon-camera"></i>
                <p>上传头像</p>
            </div>
        </div>
        <!-- 内容框 -->
        <div class="layui-form-item">
            <label for="intro" class="layui-form-label">简介:</label>
            <div class="layui-input-block">
                <textarea id="intro" name="intro" class="layui-textarea"></textarea>
            </div>
        </div>
        <!-- 单选框 -->
        <div class="layui-form-item">
            <label class="layui-form-label"><span class="asterisk">*</span>状态:</label>
            <div class="layui-input-block">
                <input type="radio" name="is_show" value="1" title="显示" checked>
                <input type="radio" name="is_show" value="0" title="隐藏">
            </div>
        </div>
    </div>

    <!-- 提交按钮 -->
    <div class="wait-body-footer">
        <a class="layui-layer-btn0" lay-submit lay-filter="addForm">确定</a>
        <a class="layui-layer-btn1" id="closePopupWindow">取消</a>
    </div>
</form>
{/block}

编辑页常用模板

{extend name="common/layout" /}

{block name="body"}
<form class="layui-form">
    <!-- 主体内容 -->
    <div class="wait-body-content">
        <!-- 下拉框 -->
        <div class="layui-form-item">
            <label for="cid" class="layui-form-label"><span class="asterisk">*</span>类目:</label>
            <div class="layui-input-block">
                <select id="cid" name="cid" lay-verify="required|number">
                    <option value="">请选择</option>
                    {volist name="$category" id="vo"}
                        <option value="{$vo.id}" {if $detail.cid==$vo.id}selected{/if}>{$vo.name}</option>
                    {/volist}
                </select>
            </div>
        </div>
        <!-- 文本框 -->
        <div class="layui-form-item">
            <label for="title" class="layui-form-label"><span class="asterisk">*</span>标题:</label>
            <div class="layui-input-block">
                <input type="text" id="title" name="title" value="{$detail.title}"
                       autocomplete="off" class="layui-input" lay-verType="tips" lay-verify="required">
            </div>
        </div>
        <!-- 封面图 -->
        <div class="layui-form-item">
            <label for="image" class="layui-form-label">封面:</label>
            <div class="layui-input-block">
                <div class="thumbnail" data-type="image" data-limit="1">
                    <div class="musters">
                        {if $detail.image}
                            <div class="preview">
                                <input type="hidden" id="image" name="image" value="{$detail.image}">
                                <i class="layui-icon layui-icon-close"></i>
                                <img src="{$detail.image}" alt="img">
                            </div>
                        {/if}
                    </div>
                    <div class="builder {if $detail.image}layui-hide{/if}">
                        <i class="layui-icon layui-icon-camera"></i>
                        <p>上传封面</p>
                        <div class="mask">
                            <div class="item layui-auto">图库选择</div>
                            <div class="item layui-auto-call">本地上传</div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <!-- 头像图 -->
        <div class="thumbnail" data-type="image" data-field="avatar" data-limit="1">
            <div class="musters">
                {if $detail.avatar}
                    <div class="preview">
                        <input type="hidden" name="avatar" value="{$detail.avatar}">
                        <i class="layui-icon layui-icon-close"></i>
                        <img src="{$detail.avatar}" alt="img">
                    </div>
                {/if}
            </div>
            <div class="builder layui-auto-call {if $detail.avatar}layui-hide{/if}">
                <i class="layui-icon layui-icon-camera"></i>
                <p>上传头像</p>
            </div>
        </div>
        <!-- 内容框 -->
        <div class="layui-form-item">
            <label for="intro" class="layui-form-label">简介:</label>
            <div class="layui-input-block">
                <textarea id="intro" name="intro" class="layui-textarea">{$detail.intro}</textarea>
            </div>
        </div>
        <!-- 单选框 -->
        <div class="layui-form-item">
            <label class="layui-form-label"><span class="asterisk">*</span>状态:</label>
            <div class="layui-input-block">
                <input type="radio" name="is_show" value="1" title="显示" {if $detail.is_show==1}checked{/if}>
                <input type="radio" name="is_show" value="0" title="隐藏" {if $detail.is_show==0}checked{/if}>
            </div>
        </div>
    </div>

    <!-- 提交按钮 -->
    <div class="wait-body-footer">
        <a class="layui-layer-btn0" lay-submit lay-filter="addForm">确定</a>
        <a class="layui-layer-btn1" id="closePopupWindow">取消</a>
    </div>
</form>
{/block}

Layui常用标签

<!-- 输入框 -->
<div class="layui-form-item">
    <label for="username" class="layui-form-label">输入框</label>
    <div class="layui-input-block">
        <input type="text" id="username" name="username" placeholder="请输入" 
               autocomplete="off" class="layui-input" lay-verType="tips" lay-verify="required" />
    </div>
</div>

<!-- 普通文本域 -->
<div class="layui-form-item layui-form-text">
    <label class="layui-form-label">普通文本域</label>
    <div class="layui-input-block">
        <textarea placeholder="请输入内容" class="layui-textarea"></textarea>
    </div>
</div>

<!-- 单行选择框 -->
<div class="layui-form-item">
    <label for="interest" class="layui-form-label">单行选择框</label>
    <div class="layui-input-block">
        <select id="interest" name="interest" lay-filter="interest">
            <option value=""></option>
            <option value="0">写作</option>
            <option value="1" selected>阅读</option>
            <option value="2">游戏</option>
        </select>
    </div>
</div>

<!-- 开关 -->
<div class="layui-form-item">
    <label for="open" class="layui-form-label">开关-默认开</label>
    <div class="layui-input-block">
        <input type="checkbox" id="open" name="open" lay-skin="switch" lay-filter="switchTest" title="开关" checked>
    </div>
</div>

<!-- 复选框 -->
<div class="layui-form-item">
    <label class="layui-form-label">复选框</label>
    <div class="layui-input-block">
        <input type="checkbox" name="arr1[0]" lay-skin="tag" title="选项1" checked>
        <input type="checkbox" name="arr1[1]" lay-skin="tag" title="选项2">
        <input type="checkbox" name="arr1[2]" lay-skin="tag" title="选项3" disabled>
    </div>
</div>

<!-- 单选框 -->
<div class="layui-form-item">
    <label class="layui-form-label">单选框</label>
    <div class="layui-input-block">
        <input type="radio" name="sex" value="" title="" checked>
        <input type="radio" name="sex" value="" title="">
        <input type="radio" name="sex" value="" title="禁用" disabled>
    </div>
</div>

Layui常用事件

layui.use(['form', 'laydate', 'util'], function() {
    let form = layui.form;
    let layer = layui.layer;
    let laydate = layui.laydate;
    let util = layui.util;

    // 指向所有 select 组件的选择事件
    form.on('select', function(data){
        console.log(data);
    });

    // 指向元素为 `<select lay-filter="test"></select>` 的选择事件
    form.on('select(test)', function(data){
        console.log(data);
    });
    
    // 监听复选框事件
    form.on('checkbox(test)', function(data){
        console.log(data);
    });

    // 监听单选框事件
    form.on('radio(test)', function(data){
        console.log(data);
    });

    // 监听开关事件
    form.on('switch(switchTest)', function(data) {
        layer.msg('开关 checked:'+ (this.checked ? 'true' : 'false'), {
            offset: '6px'
        });
        layer.tips('温馨提示:请注意开关状态的文字可以随意定义,而不仅仅是 ON|OFF', data.othis)
    });

    // 监听提交事件
    form.on('submit(demo1)', function(data) {
        let field = data.field; // 获取表单字段值
        // 显示填写结果仅作演示用
        layer.alert(JSON.stringify(field), {
            title: '当前填写的字段值'
        });
        // 此处可执行 Ajax 等操作
        // …
        return false; // 阻止默认 form 跳转
    });

    // 日期事件
    laydate.render({
        elem: '#date'
    });
    
    // 自定义验证规则
    form.verify({
        pass: [
            /^[\S]{6,12}$/,
            '密码必须6到12位,且不能出现空格'
        ]
    });

    // 普通事件
    util.on('lay-on', {
        // 获取验证码
        "get-vercode": function(othis){
            var isvalid = form.validate('.demo-phone'); // 主动触发验证,v2.7.0 新增 
            // 验证通过
            if(isvalid){
                layer.msg('手机号规则验证通过');
                // 此处可继续书写「发送验证码」等后续逻辑
                // …
            }
        }
    });

});
上次更新:
贡献者: windy, windy