多数据库访问 - 创建博客页面路由 - 多应用配置系统和博客两个应用
1、访问多少个数据库,切换多个数据库 2、创建博客页面的路由 3、生成多应用,配置管理系统和博客,2个应用
1. 访问多个数据库,切换多个数据库
- config\database.php 默认数据库切换
// 默认使用的数据库连接配置
'default' => env('database.driver', 'mysql'),
- 更多的数据库配置信息下添加
// 更多的数据库配置信息
'laravel' => [
// 数据库类型
'type' => env('database.type', 'mysql'),
// 服务器地址
'hostname' => env('database.hostname', '127.0.0.1'),
// 数据库名
'database' => 'laravel',
// 用户名
'username' => env('database.username', 'root'),
// 密码
'password' => '123456',
// 端口
'hostport' => env('database.hostport', '3306'),
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => env('database.charset', 'utf8'),
// 数据库表前缀
'prefix' => env('database.prefix', ''),
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'deploy' => 0,
// 数据库读写是否分离 主从式有效
'rw_separate' => false,
// 读写分离后 主服务器数量
'master_num' => 1,
// 指定从服务器序号
'slave_no' => '',
// 是否严格检查字段是否存在
'fields_strict' => true,
// 是否需要断线重连
'break_reconnect' => false,
// 监听SQL
'trigger_sql' => env('app_debug', true),
// 开启字段缓存
'fields_cache' => false,
],
- app\index\controller\index.php 访问 laravel 数据库的 cat 前 3 个分类
public function demo()
{
//
$res[] = Db::connect('laravel')->table('cat')->field(['id', 'name'])->where('id', '<=', 3)->select();
halt($res[0]->toArray());
}
2. 创建博客前端页面的路由
- route\app.php 添加
use think\facade\Route;
Route::get('/', 'Index/index'); // 首页
Route::get('/cat/<id>', 'Index/cat')->ext('html'); // 分类页
Route::get('/search', 'Index/search'); // 搜索页
Route::get('/detail/<id>', 'Index/detail')->ext('html'); // 详情页
3. 生成多应用,配置管理系统和博客,2个应用
3.1 多应用已生成,已生成
composer require topthink/think-multi-app
3.2 博客前端页面应用
- 创建公共模型
- 公共模型 app\common\model\Boke.php
namespace app\common\model;
use think\Model;
use app\common\model\Cat;
class Boke extends Model
{
protected $pk = 'id';
protected $name = 'boke';
// 模型字段
protected $schema = [
'id' => 'int',
'title' => 'string',
'img' => 'string',
'content' => 'string',
'date' => 'date',
'cat' => 'int',
'num' => 'int',
'hot' => 'int',
'status' => 'int'
];
// 获取器
public function getStatusAttr($value)
{
$status = [-1 => '删除', 0 => '禁用', 1 => '正常', 2 => '待审核'];
return $status[$value];
}
// 图片
public function getImgAttr($value)
{
if (preg_match('/\/.+?\.(gif|jpg|jpeg|png|bmp|webp|psd|svg|tiff)$/i', $value)) {
$value = '<img src="' . $value . '" style="width:50px;height:30px;" />';
}
return $value;
}
// 分类
public function getCatAttr($value) {
return Cat::where('id', $value)->value('name');
}
// 修改器
public function setDateAttr($value, $data) {
$this->set('date', date('Y-m-d'));
}
// 浏览量
public function setNumAttr($value, $data) {
$this->set('num', (int)$value);
}
}
- app\common\model\Cat.php
namespace app\common\model;
use think\Model;
class Cat extends Model
{
protected $pk = 'id';
protected $name = 'cat';
// 模型字段
protected $schema = [
'id' => 'int',
'name' => 'string',
'sort' => 'int',
'status' => 'int'
];
// 获取器
public function getStatusAttr($value)
{
$status = [0 => '禁用', 1 => '正常'];
return $status[$value];
}
}
- 创建公共控制器
- app\common\controller\Base.php
namespace app\common\controller;
use app\BaseController;
class Base extends BaseController
{
// 初始化
protected function initialize()
{
}
}
- 创建应用继承公共控制器和模型
- 博客控制器 app\controller\Index.php
namespace app\controller;
use app\common\controller\Base;
use app\common\model\Boke;
use app\common\model\Cat;
use think\facade\Db;
use think\facade\View;
use think\facade\Request;
class Index extends Base
{
// 首页
public function index()
{
$map[] = ['status', '=', 1];
$archive = '最新文章';
// 导航
$catList = Cat::where($map)->select();
view::assign('CatList', $catList);
// 分类列表
view::assign('cat', 0);
// 搜索列表
view::assign('search', '');
// 详情页
view::assign('p', 0);
view::assign('archive', $archive);
// 热门文章
$hotList = Boke::where('status', 1)->order('num', 'desc')->limit(5)->select();
view::assign('hotList', $hotList);
// 渲染输出
$artList = Boke::where($map)->order('id', 'desc')->paginate([
'list_rows' => 2, // 分页2条每页
// 'query' => Request::param()
]);
view::assign('artList', $artList);
return view::fetch('index/index');
}
// 分类页
public function cat($id)
{
$map[] = ['status', '=', 1];
$archive = '最新文章';
// 导航
$catList = Cat::where($map)->select();
view::assign('CatList', $catList);
// 分类列表
view::assign('cat', $id);
if ($id) {
$map[] = ['cat', '=', $id];
$archive = Cat::where('id', $id)->value('name');
}
// 搜索列表
view::assign('search', '');
// 详情页
view::assign('p', 0);
view::assign('archive', $archive);
// 热门文章
$hotList = Boke::where('status', 1)->order('num', 'desc')->limit(5)->select();
view::assign('hotList', $hotList);
// 渲染输出
$artList = Boke::where($map)->order('id', 'desc')->paginate([
'list_rows' => 2, // 分页2条每页
// 'query' => Request::param()
]);
view::assign('artList', $artList);
return view::fetch('index/index');
}
// 搜索页
public function search()
{
$map[] = ['status', '=', 1];
$archive = '最新文章';
// 导航
$catList = Cat::where($map)->select();
view::assign('CatList', $catList);
// 分类列表
view::assign('cat', 0);
// 搜索列表
$search = Request::param('search');
view::assign('search', $search);
if ($search) {
$map[] = ['title|content', 'like', "%{$search}%"];
$archive = '搜索结果';
}
// 详情页
view::assign('p', 0);
view::assign('archive', $archive);
// 热门文章
$hotList = Boke::where('status', 1)->order('num', 'desc')->limit(5)->select();
view::assign('hotList', $hotList);
// 渲染输出
$artList = Boke::where($map)->order('id', 'desc')->paginate([
'list_rows' => 2, // 分页2条每页
'query' => Request::param()
]);
view::assign('artList', $artList);
return view::fetch('index/index');
}
// 详情页
public function detail($id)
{
$map[] = ['status', '=', 1];
$archive = '最新文章';
// 导航
$catList = Cat::where($map)->select();
view::assign('CatList', $catList);
// 分类列表
view::assign('cat', 0);
// 搜索列表
view::assign('search', '');
// 详情页
view::assign('p', $id);
if ($id) {
$map[] = ['id', '=', $id];
$archive = '';
// 阅读数自增
Boke::where('id', $id)->inc('num')->update();
}
view::assign('archive', $archive);
// 热门文章
$hotList = Boke::where('status', 1)->order('num', 'desc')->limit(5)->select();
view::assign('hotList', $hotList);
// 渲染输出
$artList = Boke::where($map)->order('id', 'desc')->paginate([
'list_rows' => 2, // 分页2条每页
'query' => Request::param()
]);
view::assign('artList', $artList);
return view::fetch('index/index');
}
}
- 创建博客视图
- 创建静态模板 app\view\public\base.html
{include file='public/header'/}
<div class="container">
<div class="row">
<!-- 左侧列表 -->
<div class="col-md-8">
<div class="panel panel-default">
{block name='archive'}
<div class="panel-heading">Panel heading without title</div>
{/block}
<div class="panel-body">
<!-- 列表 -->
{block name='list'}
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-body">
<div class="row">
<div class="col-sm-3 col-md-3">
<a href="#" class="thumbnail">
<img style="width:100%;max-height:110px;"
src=""
alt="...">
</a>
</div>
<div class="col-sm-9 col-md-9">
<h3 style="margin-top: 0;">Thumbnail label</h3>
<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id
elit non mi porta gravida at eget metus. Nullam id dolor id nibh
ultricies.</p>
<p><a href="#" class="btn btn-primary" role="button">Button</a></p>
</div>
</div>
</div>
</div>
</div>
</div>
{/block}
<!-- 分页 -->
{block name='pages'}
<div class="row">
<div class="col-md-12 text-center">
<nav aria-label="Page navigation">
<ul class="pagination">
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">3</a></li>
<li><a href="#">4</a></li>
<li><a href="#">5</a></li>
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
{/block}
</div>
</div>
</div>
<!-- 右侧侧栏 -->
<div class="col-md-4">
{block name='side'}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Panel title</h3>
</div>
<div class="panel-body">
<!-- Panel content -->
<div class="list-group">
<a href="#" class="list-group-item active">Cras justo odio<span class="badge"></span></a>
<a href="#" class="list-group-item">Dapibus ac facilisis in<span class="badge"></span></a>
<a href="#" class="list-group-item">Morbi leo risus<span class="badge"></span></a>
<a href="#" class="list-group-item">Porta ac consectetur ac<span class="badge"></span></a>
<a href="#" class="list-group-item">Vestibulum at eros<span class="badge"></span></a>
</div>
</div>
</div>
{/block}
</div>
</div>
</div>
{include file='public/footer'/}
- 模板头部 app\view\public\header.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{$title|default="tpboke bootstrap"}</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap-theme.min.css" integrity="sha384-6pzBo3FDv/PJ8r2KRkGHifhEocL+1X2rVCTTkUfGk7/0pbek5mMa1upzvWbrUbOZ" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
</head>
<body>
<!-- 导航 -->
<nav class="navbar navbar-default navbar-static-top">
<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">Brand</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<!-- 导航 -->
<ul class="nav navbar-nav">
<li{if $cat === 0} class="active"{/if}><a href="/">首页</a></li>
{volist name='CatList' id='vo' key='k'}
<li{if $vo.id === (int)$cat} class="active"{/if}><a href="/cat/{$vo.id}.html">{$vo.name}</a></li>
{/volist}
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
<!-- 搜索 -->
<form class="navbar-form navbar-right" action="/search">
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" placeholder="Search" name="search" value="{$search}" required="required" />
<span class="input-group-btn"><button type="submit" class="btn btn-default"><i class="glyphicon glyphicon-search"></i></button>
</span>
</div>
</div>
</form>
</div>
<!-- /.navbar-collapse -->
</div>
<!-- /.container-fluid -->
</nav>
<!-- 面包屑 -->
<div class="container">
<div class="row">
<div class="col-md-12">
<ol class="breadcrumb">
<li><a href="#">Home</a></li>
<li><a href="#">Library</a></li>
<li class="active">Data</li>
</ol>
</div>
</div>
</div>
- 模板底部 app\view\public\footer.html
<div class="container">
<div class="row">
<div class="col-md-12">
<p>© 2021 Company, Inc.</p>
</div>
</div>
</div>
</body>
</html>
- 创建博客继承视图 app\view\index\index.html
{extend name='public/base'/}
{block name='archive'}
{if $archive}
<div class="panel-heading">{$archive}</div>
{/if}
{/block}
<!-- 列表 -->
{block name='list'}
{volist name='artList' id='vo' empty="暂无数据"}
<div class="row">
<div class="col-md-12">
{if $p}
<h1>{$vo.title}</h1>
<p><span class="glyphicon glyphicon-time" aria-hidden="true"></span> {$vo.date} <span
class="glyphicon glyphicon-eye-open" aria-hidden="true"></span> {$vo.num}</p>
<p>{$vo.content|raw}</p>
{else /}
<div class="panel panel-default">
<div class="panel-body">
<div class="row">
{if $vo.img}
<div class="col-sm-3 col-md-3">
<a href="/detail/{$vo.id}.html" title="{$vo.title}" class="thumbnail">
<img alt="{$vo.title}" style="width:100%;max-height:110px;" src="{$vo.img}"
alt="{$vo.title}">
</a>
</div>
{/if}
<div{if $vo.img} class="col-sm-9 col-md-9" {else/} class="col-sm-12 col-md-12" {/if}>
<h3 style="margin-top: 0;"><a href="/detail/{$vo.id}.html"
title="{$vo.title}">{$vo.title}</a></h3>
<p>{$vo.content|mb_strimwidth=0,110,'...','utf-8'}</p>
<p><a href="/detail/{$vo.id}.html" rel="nofollow" title="Reamd more"
class="btn btn-primary" role="button">Read more...</a></p>
</div>
</div>
</div>
</div>
{/if}
</div>
</div>
{/volist}
{/block}
<!-- 分页 -->
{block name='pages'}
{empty name='p'}
<div class="row">
<div class="col-md-12 text-center">
<nav aria-label="Page navigation">
{$artList|raw}
</nav>
</div>
</div>
{/empty}
{/block}
<!-- 侧栏模块 -->
{block name='side'}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">热门文章</h3>
</div>
<div class="panel-body">
<!-- Panel content -->
<div class="list-group">
{volist name='hotList' id='vo' empty='暂无记录'}
<a href="/detail/{$vo.id}.html"
class="list-group-item{if $p === $vo.id} active{/if}">{$vo.title}<span
class="badge">{$vo.num}</span></a>
{/volist}
</div>
</div>
</div>
{/block}
- 运行博客前端
3.3 配置博客管理系统应用
- 创建公用继承模板文件
- layui 供继承的管理系统布局 app\view\public\layui.html 参考修改: https://www.layui.com/demo/layout-admin.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>layout 管理界面大布局示例 - Layui</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="format-detection" content="telephone=no">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/layui@2.6.8/dist/css/layui.css" media="all">
<style>
/* 移动端 */
@media screen and (max-width: 768px) {
.layui-layout-admin .layui-layout-left,
.layui-layout-admin .layui-body,
.layui-layout-admin .layui-footer {
left: 0;
}
.layui-layout-admin .layui-side {
left: -300px;
}
}
</style>
</head>
<body>
<div class="layui-layout layui-layout-admin">
<div class="layui-header">
<div class="layui-logo layui-hide-xs layui-bg-black">layout demo</div>
<!-- 头部区域(可配合layui 已有的水平导航) -->
<ul class="layui-nav layui-layout-left">
<!-- 移动端显示 -->
<li class="layui-nav-item layui-show-xs-inline-block layui-hide-sm" lay-header-event="menuLeft">
<i class="layui-icon layui-icon-spread-left"></i>
</li>
<li class="layui-nav-item layui-hide-xs"><a href="">nav 1</a></li>
<li class="layui-nav-item layui-hide-xs"><a href="">nav 2</a></li>
<li class="layui-nav-item layui-hide-xs"><a href="">nav 3</a></li>
<li class="layui-nav-item">
<a href="javascript:;">nav groups</a>
<dl class="layui-nav-child">
<dd><a href="">menu 11</a></dd>
<dd><a href="">menu 22</a></dd>
<dd><a href="">menu 33</a></dd>
</dl>
</li>
</ul>
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item layui-hide layui-show-md-inline-block">
<a href="javascript:;">
<img src="//tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg"
class="layui-nav-img">
tester
</a>
<dl class="layui-nav-child">
<dd><a href="">Your Profile</a></dd>
<dd><a href="">Settings</a></dd>
<dd><a href="">Sign out</a></dd>
</dl>
</li>
<li class="layui-nav-item" lay-header-event="menuRight" lay-unselect>
<a href="javascript:;">
<i class="layui-icon layui-icon-more-vertical"></i>
</a>
</li>
</ul>
</div>
<div class="layui-side layui-bg-black">
<div class="layui-side-scroll">
<!-- 左侧导航区域(可配合layui已有的垂直导航) -->
<ul class="layui-nav layui-nav-tree" lay-filter="test">
<li class="layui-nav-item layui-nav-itemed">
<a class="" href="javascript:;">menu group 1</a>
<dl class="layui-nav-child">
<dd><a href="/admin/cat/" target="main">博客分类</a></dd>
<dd><a href="/admin/boke/" target="main">博客文章</a></dd>
<dd><a href="javascript:;">menu 3</a></dd>
<dd><a href="">the links</a></dd>
</dl>
</li>
<li class="layui-nav-item">
<a href="javascript:;">menu group 2</a>
<dl class="layui-nav-child">
<dd><a href="javascript:;">list 1</a></dd>
<dd><a href="javascript:;">list 2</a></dd>
<dd><a href="">超链接</a></dd>
</dl>
</li>
<li class="layui-nav-item"><a href="javascript:;">click menu item</a></li>
<li class="layui-nav-item"><a href="">the links</a></li>
</ul>
</div>
</div>
<div class="layui-body">
<!-- 内容主体区域 -->
<iframe name="main" srcdoc="内容主体区域" scrolling="yes" style="width:100%;height:100%;border:none"></iframe>
</div>
<div class="layui-footer">
<!-- 底部固定区域 -->
底部固定区域
</div>
</div>
<script src="//cdn.jsdelivr.net/npm/layui@2.6.8/dist/layui.js" charset="utf-8"></script>
<script>
//JS
layui.use(['element', 'layer', 'util'], function () {
var element = layui.element
, layer = layui.layer
, util = layui.util
, $ = layui.$;
//头部事件
util.event('lay-header-event', {
//左侧菜单事件
menuLeft: function (othis) {
console.log(othis);
layer.msg('展开左侧菜单的操作', { icon: 0 });
}
, menuRight: function () {
layer.open({
type: 1
, title: '更多'
, content: '<div style="padding: 15px;">处理右侧面板的操作</div>'
, area: ['260px', '100%']
, offset: 'rt' //右上角
, anim: 5
, shadeClose: true
, scrollbar: false
});
}
});
});
</script>
</body>
</html>
- layui 供继承的列表页 app\view\public\list.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>layout 管理界面大布局示例 - Layui</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="format-detection" content="telephone=no">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/layui@2.6.8/dist/css/layui.css" media="all">
</head>
<body>
<div style="padding: 15px;">
<!-- 搜索框 -->
{block name='search-form'}
<div class="layui-form">
<div class="layui-form-item" style="margin-bottom: 0;">
<!-- 搜索字段 -->
{block name='search-fields'}
<div class="layui-inline">
<label class="layui-form-label">ID</label>
<div class="layui-input-block">
<input type="text" name="id" value="" placeholder="请输入" class="layui-input">
</div>
</div>
{/block}
<div class="layui-inline"><button type="submit" lay-submit lay-filter="search" class="layui-btn"><i
class="layui-icon layui-icon-search"></i></button></div>
</div>
</div>
{/block}
<!-- 数据表格 -->
{block name='datatable'}
<table id="dataTable" lay-filter="dataTable"></table>
{/block}
<!-- 头工具栏 -->
{block name='toolbar'}
<script type="text/html" id="toolbar">
<div class="layui-btn-container">
<button class="layui-btn layui-btn-sm" lay-event="delAll">批量删除</button>
<button class="layui-btn layui-btn-sm" lay-event="add">添加</button>
<button class="layui-btn layui-btn-sm" lay-event="refresh"><i class="layui-icon layui-icon-refresh"></i></button>
</div>
</script>
{/block}
<!-- 行工具 -->
{block name='databar'}
<script type="text/html" id="databar">
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="detail">查看</a>
<a class="layui-btn layui-btn layui-btn-xs" lay-event="edit">编辑</a>
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
</script>
{/block}
</div>
<script src="//cdn.jsdelivr.net/npm/layui@2.6.8/dist/layui.js" charset="utf-8"></script>
<!-- js -->
{block name='js'}
<script>
var url = "/module/controller/index", //请求路径
page = true, //是否分页
cols = [ //表头字段
[{
checkbox: true,
fixed: 'left'
}, {
field: 'id',
title: 'ID',
width: 80,
sort: true
}, {
title: '操作',
align: 'center',
width: 170,
toolbar: '#databar'
}]
];
</script>
{/block}
<script>
layui.use(['table', 'form', 'upload', 'layedit'], function () {
var $ = layui.jquery,
table = layui.table,
form = layui.form;
var controller = url.substring(0, url.lastIndexOf('/'));
//渲染表格
table.render({
elem: '#dataTable',
toolbar: '#toolbar',
defaultToolbar: ['filter', 'print', 'exports'],
cellMinWidth: 80,
height: $('button[lay-filter="search"]').length ? 'full-95' : 'full-50',
title: $(document).title,
//数据接口
url: url,
//搜索
where: {
search: ""
},
//开启分页
page: page,
//表头
cols: cols
});
// 搜索框事件
form.on('submit(search)', function (data) {
var field = data.field;
//执行重载
table.reload('dataTable', {
where: {
search: field
}
});
});
//头工具栏事件
table.on('toolbar(dataTable)', function (obj) {
var checkStatus = table.checkStatus(obj.config.id);
var data = checkStatus.data;
//批量删除
if (obj.event === 'delAll') {
if (data.length === 0) {
return layer.msg('请选择数据');
}
layer.confirm('确定删除吗?', {
icon: 3
}, function (index) {
var id = [];
data.forEach(elem => {
id.push(elem.id);
});
$.get(controller + '/del', {
id
}, function (res) {
if (res.code) {
return layer.msg(res.msg, {
icon: 2
});
}
layer.msg(res.msg);
table.reload('dataTable');
}, 'json');
});
}
//添加
if (obj.event === 'add') {
layer.open({
type: 2,
maxmin: true,
title: '添加',
shadeClose: true,
shade: 0.3,
area: ["420px", "450px"],
content: controller + '/add',
});
}
//刷新
if (obj.event === 'refresh') {
table.reload('dataTable');
}
});
//监听行工具事件
table.on('tool(dataTable)', function (obj) {
var data = obj.data;
//删除行
if (obj.event === 'del') {
layer.confirm('真的删除行么?', {
icon: 3
}, function (index) {
layer.close(index);
$.get(controller + '/del', {
id: data.id
}, function (res) {
if (res.code) {
return layer.msg(res.msg, {
icon: 2
});
}
obj.del();
layer.msg(res.msg);
}, 'json');
});
}
//编辑行
if (obj.event === 'edit') {
layer.open({
type: 2,
maxmin: true,
title: '编辑',
shadeClose: true,
shade: 0.3,
area: ["420px", "450px"],
content: controller + '/edit?id=' + data.id,
success: function (layero, index) {
form.on('submit(submit)', function (res) {
var field = res.field;
field.id = data.id;
$.post(controller + '/save_edit', field, function (res) {
if (res.code) {
return layer.msg(res.msg, {
icon: 2
});
}
layer.msg(res.msg);
obj.update(field);
layer.close(index);
}, 'json');
});
}
});
}
//详情页
if (obj.event === 'detail') {
window.open(controller.substring(controller.indexOf('/', 2)) + '/' + data.id + '.html', '_blank');
}
});
});
</script>
</body>
</html>
- layui 供继承的表单页 app\view\public\form.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>layout 管理界面大布局示例 - Layui</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="format-detection" content="telephone=no">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/layui@2.6.8/dist/css/layui.css" media="all">
</head>
<body>
<div style="padding: 15px;">
{block name='form'}
<form class="layui-form" action="">
{block name='fields'}
<div class="layui-form-item">
<label class="layui-form-label">输入框</label>
<div class="layui-input-block">
<input type="text" name="title" value="" lay-verify="required" placeholder="请输入" class="layui-input">
</div>
</div>
{/block}
{block name='submit'}
<div class="layui-form-item">
<div class="layui-input-block">
<button type="submit" class="layui-btn" lay-submit="" lay-filter="submit">提交</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
{/block}
</form>
{/block}
</div>
<script src="//cdn.jsdelivr.net/npm/layui@2.6.8/dist/layui.js" charset="utf-8"></script>
<!-- js -->
{block name='js'}
<script>
//请求路径
var url = "/module/controller/save";
</script>
{/block}
<script>
layui.use(['form', 'upload', 'laydate'], function () {
var $ = layui.jquery,
form = layui.form,
upload = layui.upload,
laydate = layui.laydate;
//监听提交
form.on("submit(submit)", function (data) {
$.post(url, data.field, function (res) {
if (res.code) {
return layer.alert(res.msg, {
icon: 2
});
}
layer.alert(res.msg, {
icon: 1
});
setTimeout(function () {
parent.location.reload();
}, 1000);
}, "json");
return false;
});
});
</script>
</body>
</html>
- 管理系统控制器
- 分类控制器 app\admin\controller\Cat.php
namespace app\admin\controller;
use app\common\controller\Base;
use app\common\model\Cat as CatModel;
use think\facade\View;
use think\facade\Request;
class Cat extends Base
{
// 列表
public function index()
{
if (Request::isAjax()) {
$db = CatModel::order('sort', 'desc');
$data['count'] = $db->count();
if ($data['count']) {
$data['code'] = 0;
} else {
$data['code'] = 1;
$data['msg'] = '暂无记录';
}
$data['data'] = $db->select();
return json($data);
}
return view::fetch('/cat/index');
}
// 添加
public function add()
{
return view::fetch('/cat/add');
}
// 保存
public function save()
{
$data = Request::param();
// 验证
try {
$this->validate($data, [
'name|分类' => 'require|chsAlpha|unique:cat', // 验证名称唯一
'sort|排序' => 'require|number',
'status|状态' => 'require|in:0,1',
]);
} catch (\Exception $th) {
return json(['code' => 1, 'msg' => $th->getMessage()]);
}
// 操作
CatModel::create($data);
return json(['code' => 0, 'msg' => '添加成功']);
}
// 编辑
public function edit()
{
$data = Request::param();
// 验证
try {
$this->validate($data, [
'id|分类ID' => 'require|number|unique:cat', // 验证ID唯一
]);
} catch (\Exception $th) {
return json(['code' => 1, 'msg' => $th->getMessage()]);
}
view::assign('data', CatModel::where('id', $data['id'])->find());
return view::fetch('/cat/edit');
}
// 保存编辑
public function save_edit()
{
$data = Request::param();
// 验证
try {
$this->validate($data, [
'id|分类ID' => 'require|number|unique:cat', // 验证ID唯一
'name|分类' => 'require|chsAlpha|unique:cat', // 验证名称唯一
'sort|排序' => 'require|number',
'status|状态' => 'require|in:0,1',
]);
} catch (\Exception $th) {
return json(['code' => 1, 'msg' => $th->getMessage()]);
}
// 操作
CatModel::where('id', $data['id'])->update($data);
return json(['code' => 0, 'msg' => '修改成功']);
}
// 删除
public function del() {
$data = Request::param();
// 操作
CatModel::whereIn('id', (array)$data['id'])->delete();
return json(['code' => 0, 'msg' => '删除成功']);
}
}
- 内容控制器 app\admin\controller\Boke.php
namespace app\admin\controller;
use app\common\controller\Base;
use app\common\model\Boke as BokeModel;
use app\common\model\Cat as CatModel;
use think\facade\View;
use think\facade\Request;
class Boke extends Base
{
// 列表
public function index()
{
if (Request::isAjax()) {
$req = Request::param();
$map = [];
// 搜索
if ($req['search']) {
foreach((array)$req['search'] as $k => $v) {
if ($v) $map[] = [$k, 'like', "%{$v}%"];
}
}
// 查询
$db = BokeModel::where($map)->order('id', 'desc');
$data['count'] = $db->count();
if ($data['count']) {
$data['code'] = 0;
} else {
$data['code'] = 1;
$data['msg'] = '暂无记录';
}
// 分页
$data['data'] = $db->page($req['page'], $req['limit'])->select();
return json($data);
}
return view::fetch('/boke/index');
}
// 添加
public function add()
{
$cats = CatModel::where('status', 1)->order('sort', 'desc')->select();
view::assign('cats', $cats);
return view::fetch('/boke/add');
}
// 保存
public function save()
{
$data = Request::param();
// 验证
try {
$this->validate($data, [
'title|标题' => 'require|unique:boke', // 验证标题唯一
'content|内容' => 'require',
'cat|分类' => 'require|number',
'status|状态' => 'require|in:0,1',
]);
} catch (\Exception $th) {
return json(['code' => 1, 'msg' => $th->getMessage()]);
}
// 操作
CatModel::create($data);
return json(['code' => 0, 'msg' => '添加成功']);
}
// 编辑
public function edit()
{
$data = Request::param();
// 验证
try {
$this->validate($data, [
'id|文章ID' => 'require|number|unique:cat', // 验证ID唯一
]);
} catch (\Exception $th) {
return json(['code' => 1, 'msg' => $th->getMessage()]);
}
$cats = CatModel::where('status', 1)->order('sort', 'desc')->select();
view::assign('cats', $cats);
view::assign('data', BokeModel::where('id', $data['id'])->find());
return view::fetch('/boke/edit');
}
// 保存编辑
public function save_edit()
{
$data = Request::param();
// 验证
try {
$this->validate($data, [
'id|文章ID' => 'require|number|unique:cat', // 验证ID唯一
'title|标题' => 'require|unique:boke', // 验证标题唯一
'content|内容' => 'require',
'cat|分类' => 'require|number',
'status|状态' => 'require|in:0,1',
]);
} catch (\Exception $th) {
return json(['code' => 1, 'msg' => $th->getMessage()]);
}
// 操作
BokeModel::where('id', $data['id'])->update($data);
return json(['code' => 0, 'msg' => '修改成功']);
}
// 删除
public function del() {
$data = Request::param();
// 操作
BokeModel::whereIn('id', (array)$data['id'])->delete();
return json(['code' => 0, 'msg' => '删除成功']);
}
}
- 管理系统视图
3.1 分类视图
- 分类列表视图 app\view\cat\index.html
<!-- 继承列表 -->
{extend name='public/list'/}
<!-- 搜索框置空 -->
{block name='search-form'}
{/block}
<!-- js -->
{block name='js'}
<script>
var url = "/admin/cat/index", //请求路径
page = false, //是否分页
cols = [ //表头字段
[{
checkbox: true,
fixed: 'left'
}, {
field: 'id',
title: 'ID',
width: 80,
sort: true
}, {
field: 'name',
title: '分类名称',
}, {
field: 'sort',
title: '排序',
sort: true
}, {
field: 'status',
title: '状态',
sort: true
}, {
title: '操作',
align: 'center',
width: 170,
toolbar: '#databar'
}]
];
</script>
{/block}
- 添加表单视图 app\view\cat\add.html
<!-- 继承表单 -->
{extend name='public/form'/}
{block name='fields'}
<div class="layui-form-item">
<label class="layui-form-label">分类名称</label>
<div class="layui-input-block">
<input type="text" name="name" value="" lay-verify="required" placeholder="请输入" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">排序</label>
<div class="layui-input-inline">
<input type="number" name="sort" value="0" lay-verify="required" placeholder="请输入" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态</label>
<div class="layui-input-inline">
<select name="status">
<option value="1" selected>正常</option>
<option value="0">禁用</option>
</select>
</div>
</div>
{/block}
{block name='js'}
<script>
//请求路径
var url = "/admin/cat/save";
</script>
{/block}
- 编辑表单视图 app\view\cat\edit.html
<!-- 继承表单 -->
{extend name='public/form'/}
{block name='fields'}
<input type="hidden" name="id" value="{$data['id']}">
<div class="layui-form-item">
<label class="layui-form-label">分类名称</label>
<div class="layui-input-block">
<input type="text" name="name" value="{$data['name']}" lay-verify="required" placeholder="请输入" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">排序</label>
<div class="layui-input-inline">
<input type="number" name="sort" value="{$data['sort']}" lay-verify="required" placeholder="请输入" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态</label>
<div class="layui-input-inline">
<select name="status">
<option value="1"{if $data->getData('status') == '1'} selected{/if}>正常</option>
<option value="0"{if $data->getData('status') == '0'} selected{/if}>禁用</option>
</select>
</div>
</div>
{/block}
{block name='js'}
<script>
//请求路径
var url = "/admin/cat/save_edit";
</script>
{/block}
3.2 内容视图
- 内容列表视图 app\view\boke\index.html
<!-- 继承列表 -->
{extend name='public/list'/}
<!-- 搜索框字段 -->
{block name='search-fields'}
<div class="layui-inline">
<label class="layui-form-label">ID</label>
<div class="layui-input-block">
<input type="text" name="id" value="" placeholder="请输入" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">标题</label>
<div class="layui-input-block">
<input type="text" name="title" value="" placeholder="请输入" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">内容</label>
<div class="layui-input-block">
<input type="text" name="content" value="" placeholder="请输入" class="layui-input">
</div>
</div>
{/block}
<!-- js -->
{block name='js'}
<script>
var url = "/admin/boke/index", //请求路径
page = true, //是否分页
cols = [ //表头字段
[{
checkbox: true,
fixed: 'left'
}, {
field: 'id',
title: 'ID',
width: 80,
sort: true
}, {
field: 'title',
title: '标题',
minWidth: 240
}, {
field: 'img',
title: '图片',
sort: true
}, {
field: 'cat',
title: '分类'
}, {
field: 'num',
title: '浏览量',
sort: true,
hide: true //隐藏列
}, {
field: 'hot',
title: '热门',
sort: true,
hide: true //隐藏列
}, {
field: 'status',
title: '状态',
sort: true
}, {
title: '操作',
align: 'center',
width: 170,
toolbar: '#databar'
}]
];
</script>
{/block}
- 添加表单视图 app\view\boke\add.html
<!-- 继承表单 -->
{extend name='public/form'/}
{block name='fields'}
<div class="layui-form-item">
<label class="layui-form-label">标题</label>
<div class="layui-input-block">
<input type="text" name="title" value="" lay-verify="required" placeholder="请输入" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">内容</label>
<div class="layui-input-block">
<textarea name="content" lay-verify="required" placeholder="请输入内容" class="layui-textarea"></textarea>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">图片</label>
<div class="layui-input-block">
<input type="text" name="img" value="" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">分类</label>
<div class="layui-input-inline">
<select name="cat" lay-verify="required">
<option value="" selected>— 请选择 —</option>
{volist name='cats' id='vo'}
<option value="{$vo.id}">{$vo.name}</option>
{/volist}
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">浏览量</label>
<div class="layui-input-inline">
<input type="text" name="num" value="" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">热门</label>
<div class="layui-input-inline">
<input type="hidden" name="hot" value="0">
<input type="checkbox" name="hot" lay-skin="primary" value="1" title="热门文章">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态</label>
<div class="layui-input-inline">
<select name="status">
<option value="1" selected>正常</option>
<option value="0">禁用</option>
</select>
</div>
</div>
{/block}
{block name='js'}
<script>
//请求路径
var url = "/admin/boke/save";
</script>
{/block}
- 编辑表单视图 app\view\boke\edit.html
<!-- 继承表单 -->
{extend name='public/form'/}
{block name='fields'}
<input type="hidden" name="id" value="{$data['id']}">
<div class="layui-form-item">
<label class="layui-form-label">标题</label>
<div class="layui-input-block">
<input type="text" name="title" value="{$data['title']}" lay-verify="required" placeholder="请输入" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">内容</label>
<div class="layui-input-block">
<textarea name="content" lay-verify="required" placeholder="请输入内容" class="layui-textarea">{$data['content']}</textarea>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">图片</label>
<div class="layui-input-block">
<input type="text" name="img" value="{$data->getData('img')}" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">分类</label>
<div class="layui-input-inline">
<select name="cat" lay-verify="required">
<option value="">— 请选择 —</option>
{volist name='cats' id='vo'}
<option value="{$vo.id}"{if $data->getData('cat') == $vo.id} selected{/if}>{$vo.name}</option>
{/volist}
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">浏览量</label>
<div class="layui-input-inline">
<input type="text" name="num" value="{$data['num']}" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">热门</label>
<div class="layui-input-inline">
<input type="hidden" name="hot" value="0">
<input type="checkbox" name="hot" lay-skin="primary" value="1" title="热门文章"{if ($data['hot'])} checked{/if}>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态</label>
<div class="layui-input-inline">
<select name="status">
<option value="1"{if $data->getData('status') == '1'} selected{/if}>正常</option>
<option value="0"{if $data->getData('status') == '0'} selected{/if}>禁用</option>
</select>
</div>
</div>
{/block}
{block name='js'}
<script>
//请求路径
var url = "/admin/boke/save_edit";
</script>
{/block}
3.3 运行管理系统布局
- 分类管理,编辑一个分类测试
- 内容管理,搜索 linux 测试
- 内容编辑,修改状态测试