laravel--通用后台管理系统--分页--图片上传
程序员文章站
2022-05-25 09:09:07
...
学习总结
1.文章列表的分页,前端使用layui中的laypage进行渲染,后端使用laravel中的paginate(每页显示的记录个数)
方法实现文章列表的分页
2.在DBServiceProvider.php中把paginate()
进行扩展,扩展后的方法名称为pages()
以数组的形式返回所查询到的数据,并且返回数据记录的总数
3.文件上传使用layui的Upload进行文件上传操作,上传的文件通过Upload
控制器中的upload_img
方法进行存储,并且返回可访问的地址。
4.默认upload上传的图片存储在storage目录中,需要使用artisan命令在public目录下建立软链接才可以访问到存储的图片php artisan storage:link
在public目录下创建storage目录的软链接相当于快捷方式。
5.上传的文件应当存储在storage目录下的public
目录下
6.渲染保存在数据库的富文本编辑器中的内容 应该使用{!! $detail['contents'] !!}
1.文章控制器Article.php
<?php
namespace App\Http\Controllers\admins;
use App\Http\Controllers\Controller;
//登录验证
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
//引入数据库查询构造器,链式调用
use Illuminate\Support\Facades\DB;
//后台文章管理控制器
class Article extends Controller
{
//显示文章列表
public function index(Request $req)
{
$res['page'] =(int)$req->page;//当前显示的是第几页
$limit = 8;//每页显示的记录数
$pageInfo = DB::table('article')->orderby('id','desc')->pages($limit);//pages()方法为自定义的分页方法
$res['articles'] = $pageInfo['data'];//得到分页数据
$res['total'] = $pageInfo['total'];//得到记录总数
$res['limit'] = $limit;//得到每页显示多少条记录
//$res['articles'] = DB::table('article')->paginate(1);
// $res['articles'] = DB::table('article')->lists();
$res['cates'] = DB::table('article_cate')->cate('id');
$res['auths'] = DB::table('admin')->select('id','real_name')->cate('id');
// echo '<pre>';
// print_r($res);
// exit;
return view('/admins/article/index',$res);
}
//添加修改文章
public function add(Request $req)
{
//获取当前登录用户的id
$res['admin_id'] = Auth::user()->id;
//使用aid判断用户是添加文章=0,修改文章aid不为0
$res['aid'] = (int)$req->aid;
$res['article'] = DB::table('article')->where('id',$res['aid'])->item();
//把文章分类数据带入视图中
$res['cates'] = DB::table('article_cate')->lists();
//把文章作者数据带入视图中
$res['auths'] = DB::table('admin')->select('id','real_name')->lists();
//获取文章详情
$res['detail']= DB::table('article_detail')->where('aid',$res['aid'])->item();
// echo '<pre>';
// print_r($res);
// exit;
return view('/admins/article/add',$res);
}
//保存文章
public function save(Request $req)
{
$aid = (int)$req->aid;
$data['title'] = trim($req->title);
if($data['title']==''):
return (json_encode(['status'=>'1','msg'=>'文章标题不能为空']));
endif;
$data['cid'] =(int)$req->cid;
$data['auth_id'] =(int)$req->auth_id;
$data['subtitle'] = trim($req->subtitle);
$data['thumb'] = $req->thumb;
$data['keywords'] = trim($req->keywords);
$data['descs'] = trim($req->descs);
$data['status'] =(int)$req->status;
$content = $req->detail;
// echo '<pre>';
// print_r($data);
// exit;
if($aid==0):
$data['add_time'] =time();
$artIndex = DB::table('article')->insertGetId($data);//插入文章后获取文章id索引
if($artIndex>0):
$res = DB::table('article_detail')->insert(['aid'=>$artIndex,'contents'=>$content]);//把文章详情插入文章内容表中
endif;
else:
$artIndex = DB::table('article')->where('id',$aid)->update($data);//修改文章
$res = DB::table('article_detail')->where('aid',$aid)->update(['contents'=>$content]);//更新文章内容表中的内容
endif;
return json_encode(['status'=>0,'msg'=>'保存成功']);
}
//删除文章
public function del(Request $req)
{
$aid = $req->aid;
$res = DB::table('article')->where('id',$aid)->delete();
$res = DB::table('article_detail')->where('aid',$aid)->delete();
return json_encode(['status'=>0,'msg'=>'删除成功']);
}
public function cates()
{
return view('/admins/article/cates');
}
}
2.显示文章列表,进行分页渲染index.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/static/plugins/layui/css/layui.css">
<script src="/static/plugins/layui/layui.js"></script>
<title>文章管理</title>
</head>
<style>
.addBtn {
margin-top: 10px;
width: 120px;
margin-left: auto;
margin-right: 50px;
}
.layui-table {
width: 95%;
margin: 20px;
}
</style>
<body>
<div class="addBtn">
<button class="layui-btn" onclick="add()">添加文章</button>
</div>
<table class="layui-table">
<thead>
<tr>
<th>编号</th>
<th>文章分类</th>
<th>标题</th>
<th>封面图</th>
<th>作者</th>
<th>状态</th>
<th>注册时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
@foreach($articles as $article)
<tr>
<td>{{$article['id']}}</td>
<td>{{$cates[$article['cid']]['title']}}</td>
<td>{{$article['title']}}</td>
<td><img src="{{$article['thumb']}}" alt="" style="height:30px"></td>
<td>{{$auths[$article['auth_id']]['real_name']}}</td>
<td>{{$article['status']?'已发布':'草稿'}}</td>
<td>{{$article['add_time']?date('Y-m-d',$article['add_time']):''}}</td>
<td>
<button class="layui-btn layui-btn-xs" onclick="add({{$article['id']}})">修改</button>
<button class="layui-btn layui-btn-xs layui-btn-danger"
onclick="del({{$article['id']}})">删除</button>
</td>
</tr>
@endforeach
</tbody>
</table>
<div id="pageList" style="width:500px;margin-left: auto; margin-right:auto;"></div>
</body>
<script>
layui.use(['layer', 'laypage'], function() {
layer = layui.layer;
$ = layui.jquery;
//创建分页
laypage = layui.laypage;
//渲染分页条
laypage.render({
elem: 'pageList',
count:{{$total}}, //数据记录总数
limit: {{$limit}}, //每页显示几条数据
curr:{{ $page }},//当前显示的是第几页的数据
groups: 5, //中间连续显示几个页码
layout:['prev','page','next','skip','count'],
// first: '首页',可以自定义首页,下一页,尾页,上一页的文件显示
// last: '尾页',
// prev: '上一页',
// next: '下一页',
jump: function(obj, first) {
//console.log(obj.curr);当前点击分页条的页码数
if (!first) {
window.location.href="?page="+obj.curr;
}
}
});
});
//添加修改文章
function add(aid) {
//iframe层
layer.open({
type: 2,
title: aid?'修改文章':'添加文章',
shadeClose: true,
shade: 0.8,
area: ['680px', '100%'],
content: '/admins/article/add?aid='+aid, //iframe的url
btn: ['保存'],
yes: function(index, layero) {
//得到iframe页的窗口对象,执行iframe页的方法:iframeWin.子页面的方法名称();
var iframeWin = window[layero.find('iframe')[0]['name']];;
iframeWin.save();
}
});
}
//删除文章
function del(aid) {
layer.confirm('确认要删除文章吗?', function() {
$.get('/admins/article/del?aid=' + aid, function(res) {
if (res.status > 0) {
layer.alert(res.msg, {
icon: 2
});
} else {
layer.msg(res.msg, {
time: 3000
});
window.location.reload();
}
}, 'json');
});
}
</script>
</html>
3.添加或者修改文章add.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/static/plugins/layui/css/layui.css">
<script src="/static/plugins/layui/layui.js"></script>
<!-- html文件编辑器配置文件 -->
<script src="/static/plugins/ueditor/ueditor.config.js"></script>
<!-- 编辑器源码文件 -->
<script src="/static/plugins/ueditor/ueditor.all.js"></script>
<title>添加文章</title>
<style>
.layui-form {
margin-top: 20px;
margin-right: 20px;
}
</style>
</head>
<body>
<form action="" class="layui-form">
@csrf
<input type="hidden" name="aid" id="" value="{{ $article['id']?$article['id']:0 }}">
<div class="layui-form-item">
<label for="" class="layui-form-label">标题</label>
<div class="layui-input-block">
<input type="text" class="layui-input" name="title" value="{{ $article['title'] }}">
</div>
</div>
<div class="layui-form-item">
<label for="" class="layui-form-label">作者</label>
<div class="layui-input-block">
<select name="auth_id" id="">
<option value=""></option>
@foreach ($auths as $auth )
@if($aid>0)
{{-- 修改文章时作者id为数据库中保存的作者id --}}
<option value="{{ $auth['id'] }}" {{ $auth['id'] === $article['auth_id']?'selected':'' }}>{{ $auth['real_name'] }}</option>
@else
{{-- 添加文章时作者id为登录用户的id --}}
<option value="{{ $auth['id'] }}" {{ $auth['id'] === $admin_id?'selected':'' }}>{{ $auth['real_name'] }}</option>
@endif
@endforeach
</select>
</div>
</div>
<div class="layui-form-item">
<label for="" class="layui-form-label">文章分类</label>
<div class="layui-input-block">
<select name="cid" id="">
<option value=""></option>
@foreach ($cates as $cate )
<option value="{{ $cate['id'] }}" {{ $cate['id'] === $article['cid']?'selected':'' }}>{{ $cate['title'] }}</option>
@endforeach
</select>
</div>
</div>
<div class="layui-form-item">
<label for="" class="layui-form-label">封面图片</label>
<div class="layui-input-block">
<img src="{{ $article['thumb'] }}" alt="" id="show_thumb" style="height: 30px;">
<button type="button" class="layui-btn" id="thumb">
<i class="layui-icon"></i>上传图片
</button>
</div>
</div>
<div class="layui-form-item">
<label for="" class="layui-form-label">副标题</label>
<div class="layui-input-block">
<input type="text" class="layui-input" name="subtitle" value="{{ $article['subtitle'] }}">
</div>
</div>
<div class="layui-form-item">
<label for="" class="layui-form-label">关键词</label>
<div class="layui-input-block">
<input type="text" class="layui-input" name="keywords" value="{{ $article['keywords'] }}">
</div>
</div>
<div class="layui-form-item">
<label for="" class="layui-form-label">描述</label>
<div class="layui-input-block">
<textarea class="layui-textarea" name="descs">{{ $article['descs'] }}</textarea>
</div>
</div>
<div class="layui-form-item">
<label for="" class="layui-form-label">是否发布</label>
<div class="layui-input-block">
<input type="checkbox" lay-skin="switch" name="status" lay-text="发布|草稿" {{ $article['status']?'checked':'' }}>
</div>
</div>
<!-- html文本编辑器 -->
<div class="layui-form-item" style="padding-left:10px">
<!-- 加载编辑器的容器 -->
{{-- {!! $detail['contents'] !!} 进行html解析 --}}
<script id="detail" name="detail" type="text/plain">{!! $detail['contents'] !!}</script>
</div>
</form>
</body>
<script>
layui.use(['form', 'layer', 'upload'], function() {
var form = layui.form;
var layer = layui.layer;
$ = layui.jquery;
//<!-- 实例化编辑器 -->
//var ue = UE.getEditor('detail', {
ue = UE.getEditor('detail', {//副文本编辑器去掉var关键字,变成全局变量
initialFrameWidth: '100%', //设定ueditor的宽度
initialFrameHeight: '500' //设定ueditor的高度
});
var upload = layui.upload;
_token = $('input[name="_token"]').val();//_token也去掉var关键字,成为全局变量
//上传封面图片执行实例
var uploadInst = upload.render({
elem: '#thumb' //绑定元素
,
url: '/admins/upload/upload_img' //上传接口
,
data: {
_token: _token
},
done: function(res) {
//上传完毕回调
// console.log(res.data.src);
$('#show_thumb').attr('src', res.data.src);
},
error: function() {
//请求异常回调
layer.alert('封面图片上传失败', {
icon: 2
});
}
});
});
//在父窗口中调用了save方法
function save() {
if ($('input[name="title"]').val().trim() === '') {
error('请输入文章标题');
return false;
}
//把form表单中的数据序列化后通过post提交
var data ={
_token:_token,
aid: $('input[name="aid"]').val(),
title: $('input[name="title"]').val(),
auth_id: $('select[name="auth_id"]').val(),
cid: $('select[name="cid"]').val(),
thumb:$('#show_thumb').attr('src'),
subtitle:$('input[name="subtitle"]').val(),
keywords:$('input[name="keywords"]').val(),
descs:$('textarea[name="descs"]').val(),
//获取状态的checed属性值,如果选中保存为1=已发布,否则保存为0=草稿
status:$('input[name="status"]').attr('checked')?1:0,
detail:ue.getContent(),//获取副文本编辑器中的数据
};
//把js对象转换为一个json字符串,然后在网络中传输
JSON.stringify(data);
$.post('/admins/article/save',
data,
function(res) {
if (res.status > 0) {
error(res.msg);
} else {
layer.msg(res.msg);
setTimeout(function() {
//假设这是iframe页
var index = parent.layer.getFrameIndex(window.name); //先得到当前iframe层的索引
//关闭当前窗口
parent.layer.close(index); //再执行关闭
//刷新父窗口,重新显示账号管理员列表
parent.window.location.reload();
}, 1000);
}
}, 'json');
function error(msg) {
layer.alert(msg, {
icon: 2
});
}
}
</script>
</html>
4.路由文件web.php
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function(){
return view('welcome');
});
//登录页面
Route::get('/admins/account/login','admins\Account@login')->name('login');//使用name()方法对路由进行命名
//验证码图片
Route::get('/admins/account/captcha','admins\Account@captcha');
//登录操作
Route::post('/admins/account/dologin','admins\Account@dologin');
//后台首页
//调用框架自带的auth中间件判断是否登录,namespace()方法指定控制器的命令空间,group()方法中是一个回调函数,把一组路由写在这个回调函数中
Route::namespace('admins')->middleware(['auth','rights'])->group(function(){
Route::get('/admins/home/index','Home@index');
Route::get('/admins/home/welcome','Home@welcome');
Route::get('/admins/home/logout','Home@logout');
//账号管理
Route::get('/admins/admin/index','Admin@index');
//添加账号
Route::get('/admins/admin/add','Admin@add');
//修改账号
Route::get('/admins/admin/edit','Admin@edit');
//保存账号
Route::post('/admins/admin/save','Admin@save');
//删除账号
Route::get('/admins/admin/del','Admin@del');
//菜单管理
Route::get('/admins/menus/index','Menus@index');
//添加菜单
Route::get('/admins/menus/add','Menus@add');
//修改菜单
Route::get('/admins/menus/edit','Menus@edit');
//保存菜单
Route::post('/admins/menus/save','Menus@save');
//删除菜单
Route::get('/admins/menus/del','Menus@del');
//角色管理
Route::get('/admins/groups/index','Groups@index');
//添加角色
Route::get('/admins/groups/add','Groups@add');
//修改角色
Route::get('/admins/groups/edit','Groups@edit');
//保存角色
Route::post('/admins/groups/save','Groups@save');
//删除角色
Route::get('/admins/groups/del','Groups@del');
//文章管理
Route::get('/admins/article/index','Article@index');
//添加文章
Route::get('/admins/article/add','Article@add');
//修改文章
Route::get('/admins/article/edit','Article@edit');
//保存文章
Route::post('/admins/article/save','Article@save');
//删除文章
Route::get('/admins/article/del','Article@del');
//文件上传管理
//文章封面上传
Route::post('/admins/upload/upload_img','Upload@upload_img');
});
5.数据库扩展DBserviceProvider.php
<?php
namespace App\Providers;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Support\ServiceProvider;
class DBServiceProvider extends ServiceProvider
{
public function boot()
{
//扩展DB类中的查询结果集的方法,把结果集转换为数组
QueryBuilder::macro('lists',function(){
$res=[];
$data = $this->get()->toArray();
foreach($data as $item):
$res[]=(array)$item;
endforeach;
return $res?$res:false;//判断返回结果是否为空,为空返回false,这样前端渲染数据不容易出错
});
//扩展DB类中的查询结果为一条记录,把结果转换为数组
QueryBuilder::macro('item',function(){
$data=[];
$data = $this->get()->first();
$data = (array)$data;
return $data?$data:false;//判断返回结果是否为空,为空返回false,这样前端渲染数据不容易出错
});
//扩展DB类中的查询结果为数组的索引转换为记录的索引
QueryBuilder::macro('cate',function($index){
$res=[];
$data = $this->lists();
foreach($data as $item):
//把查询结果集中的索引转换为记录中索引号
$res[$item[$index]]=(array)$item;
endforeach;
return $res?$res:false;//判断返回结果是否为空,为空返回false,这样前端渲染数据不容易出错
});
QueryBuilder::macro('pages',function( $perPage = 15,$columns = ['*'],$pageName = 'page',$page = null){
$res= [];
$res['data']=[];
$res['total']=[];
$pageObj = $this->paginate($perPage,$columns,$pageName,$page);
$lists = $pageObj->items();
foreach($lists as $list):
$res['data'][] = (array)$list;
endforeach;
$res['total'] = $pageObj->total();
return $res?$res:false;//判断返回结果是否为空,为空返回false,这样前端渲染数据不容易出错
});
}
}
6.文件上传控制器Upload.php
<?php
namespace App\Http\Controllers\admins;
use App\Http\Controllers\Controller;
//引入storage类,用于文件存储
use Illuminate\Support\Facades\Storage;
use Illuminate\Http\Request;
//引入数据库查询构造器,链式调用
use Illuminate\Support\Facades\DB;
use PhpParser\Node\Expr\FuncCall;
//文件上传控制器
class Upload extends Controller
{
public function upload_img(Request $req)
{
//把上传的文件进行存储,存储在stroage目录中的app目录下的public/thumb
$path = $req->file('file')->store('public/thumb/'.date('Y/m/d'));
//使用
//把存储文件地址转换为能访问的文件地址
$path = Storage::url($path);
// echo '<pre>';
// print_r($path);
// exit;
return json_encode(['status'=>'0','msg'=>'文件上传成功','data'=>['src'=>$path]]);
}
}
推荐阅读
-
laravel--通用后台管理系统--添加菜单--角色添加权限--根据用户权限显示菜单
-
laravel--通用后台管理系统--从数据库中自动加载菜单
-
laravel--通用后台管理系统--权限中间件
-
laravel--通用后台管理系统--分页--图片上传
-
laravel--通用后台管理系统--用户的登录和退出--用户的增删改查
-
laravel--通用后台管理系统--添加菜单--角色添加权限--根据用户权限显示菜单
-
laravel--通用后台管理系统--用户的登录和退出--用户的增删改查
-
laravel--通用后台管理系统--分页--图片上传
-
laravel--通用后台管理系统--权限中间件
-
laravel--通用后台管理系统--从数据库中自动加载菜单