批改状态:合格
老师批语:还在认真写作业的不多了, 希望你能坚持 到最后
laravel的分页查询功能, 搭配layui的分页组件, 可以简便的实现分页功能.
laravel的文件上传, 文件存放的根目录在/storage/app/public中, 而laravel对外开放的目录是/public, 要把已上传的文件暴露给前端, 需要在/public创建一个指向/storage/app/public目录的短连接.
页面中嵌入富文本编辑器, 跟其他前端组件一样, 先引入必要的js, css文件, 再通过js创建相关组件对象, 然后传入字面量对象进行初始化.
使用laravel提供的分页查询功能获取分页数据
使用 DB::pagenate(每页显示记录数, 查询字段, "当前页"参数名, 当前页码) 查询分页数据.
$request 对象中获取当前页码, 获取当前页码的参数名由第三个参数指定.DB::pagenate() 方法返回的是对象数组, 一条记录是一个对象.使用laravel提供的”宏扩展”功能扩展数据库访问类方法, 添加返回二维数组格式的结果集方法 pages() . “宏扩展”介绍点这里.
/*** 扩展laravel的DB类,把查询分页的结果由对象数组改为二维数组* $perPage: 每页行数* $columns: 查询的列* $pageName: 请求参数中指定当前页的参数名* $page: 当前页*/QueryBuilder::macro('pages', function($perPage = 15, $columns = ['*'], $pageName = 'page', $page = null) {/* 查询分页对象 */$paginateObj = $this->paginate($perPage, $columns, $pageName, $page);/* 查询结果对象数组 */$items = $paginateObj->items();$rtn = [];// 遍历对象数组,把对象强转成数组,后作为$rtn的元素foreach($items as $item) {$rtn[] = (array) $item;}return ['page_data' => $rtn, 'total' => $paginateObj->total()];});
layui提供的分页组件 laypage 渲染分页条.
在布局中给要布局分页条的地方添加一个容器, 并给个id值: <div id="paginate"></div>
在 layui.use() 方法的参数回调中, 渲染分页条.
<script>layui.use(['layer', 'laypage'], function() {layer = layui.layer;laypage = layui.laypage;laypage.render({elem: 'paginate', // 注意,这里的 test1 是 ID,不用加 # 号count: {{$total}}, // 查询到的记录总数,从数据库中获取limit: {{$limit}}, // 每页容纳的记录数curr: {{$currPage}}, // 当前页layout: ['prev', 'page', 'next', 'count', 'limit', 'refresh', 'skip'], // 要显示的分页条各部分, 分别是: ['上一页', '页码表', '下一页', '总页数', '每页显示记录数下拉列表', '刷新当前页', '页定位表单'], 可根据需要增删数组成员.limits: [1, 5, 10, 15, 20], // 每页显示记录数下拉列表项jump: function(obj, first) { // 获取指定页码数据的回调//obj包含了当前分页的所有参数,比如:console.log(obj.curr); //得到当前页,以便向服务端请求对应页的数据。console.log(obj.limit); //得到每页显示的条数console.log(obj);//首次不执行if (!first) {window.location.href = "?limit=" + obj.limit + "&page=" + obj.curr;}}});});</script>
使用layui提供的上传组件 upload 处理前端显示和数据提交.
<div class="layui-form-item"><label for="thumb" class="layui-form-label">缩略图</label><div class="layui-input-block">/* 上传按钮 */<button type="button" class="layui-btn" id="btn_upload"><i class="layui-icon"></i>上传图片</button>/* 上传成功后显示上传图片的缩略图 */<img id="preview_img" src="" alt="" style="height: 36px;" onclick="big_img(this)">/* 点击显示大图 */</div></div>
layui.use() 方法的参数回调中, 渲染文件上传组件.
<script>layui.use(['form', 'layer', 'upload'], function() {layer = layui.layer;form = layui.form;upload = layui.upload;$ = layui.jquery;// 执行实例var uploadInst = upload.render({elem: '#btn_upload', // 绑定元素url: '/admin/upload/pic_upload', // 上传接口data: {_token: $('input[name="_token"]').val()}, // 额外需要上传的参数done: function(res) {// 上传完毕回调$('#preview_img').attr('src', res.data.src);// 点击缩略图看大图中的大图$('#tong > img').attr('src', res.data.src);},error: function() {// 请求异常回调}});}</script>
后端使用laravel提供的 $request 对象处理上传.
通过chrome的开发者工具中查看layui的 upload 插件提交的数据, 存放文件的参数名叫 file .
在控制器方法中, 执行 $path = $request->file('file')->store(相对/storage/app/路径的子目录); 语句就能完成PHP原生上传的N大步骤. file() 方法的参数, 就是上面提到的参数名 file .
public function picUpload(Request $request) {// file(请求中的文件参数名), store(文件存放子路径). 文件存放目录: ../storage/app/[store指定的子目录],// 为能使用软连接访问上传的图片, 强烈建议子目录以public目录开始. 建议在public中分目录, 以年份, 或者年份月份,// 或者年月日为public子目录来存放文件, 这样更方便查找. 也可以分得更细, 如: 精确到小时, 分钟等./* 此时返回的是.../public/avatars/2020/06/18/xxxxxx.png, 实际并不能以该路径来访问 */$path = $request->file('file')->store('public/avatars/' . date('Y/m/d'));// 获取前端能访问到的真实的url地址$url = Storage::url($path);// layui的上传组件要求返回的json数据的格式$res = ['code' => 0, 'msg' => '', 'data' => ['src' => $url]];return json_encode($res);}
在 /public 目录中生成指向``目录的快捷方式/软连接.
laravel文件上传的存放根目录是: /storage/app/public , 而lavaral项目的实际执行根目录是 /public 目录, 所以要从网络上访问上传的文件, 需要在 /public 目录中创建一个指向 /storage/app/public 子目录的”快捷方式”, 即, 软连接.
生成软连接的方法: 在laravel项目根目录(artisan文件所在目录), 执行 php artisan storage:link 命令, 该命令会在 /public/ 目录生成一个名叫 storage , 指向 /storage/app/public 目录的快捷方式/软连接.
使用 Storage::url() 方法, 传入上传文件时返回的 $path 路径, 生成可访问上传文件的真是url地址.
自己加料: 点击上传成功的缩略图, 显示大图
给显示缩略图的 <img> 元素加上点击事件的处理方法: <img id="preview_img" src="" alt="" style="height: 36px;" onclick="big_img(this)">/* 点击显示大图 */
在页面布局中放入一个显示大图用的 <img> 元素, 默认不显示
<div id="tong" class="hide"><img src="" style="max-width: 100%; max-height: 100%"></div>
layui.open() 方法, type属性值为1, 就表示弹出显示的元素是HTML元素容器)
function big_img(img) {// 缩略图的src属性没有值时, 不处理if (img.src == undefined || img.src == "") {return;}//页面层-图片layer.open({type: 1,title: false,closeBtn: 0,area: ['auto'],skin: 'layui-layer-nobg', //没有背景色shadeClose: true,content: $('#tong')});}
百度的 Ueditor 是比较流行的富文本编辑器. 官网地址点这里. 在官网下载合适的 Ueditor 文件包.
下载下来的 Ueditor 文件包, 放到 /public 目录中, 一般来说, 放在 /public/static/plugin/ 下较好.
前端页面加载 Ueditor :
<!-- ueditor-start --><!-- 配置文件 --><script type="text/javascript" src="/static/plugin/ueditor/ueditor.config.js"></script><!-- 编辑器源码文件 --><script type="text/javascript" src="/static/plugin/ueditor/ueditor.all.js"></script><!-- ueditor-end -->
Ueditor 的地方, 放一个加载编辑器的容器:
<!-- 实际生成的是div. 给div添加contenteditable="true", 这个div就能编辑 --><script id="container" name="content" type="text/plain">这里写你的初始化内容</script>
// 实例化编辑器// 第一个参数是容器的id值/* 第二个参数是配置属性对象 *//* 不要写var, 把ue声明为全局变量, 因为其他地方也用到ue对象 *//* var */ue = UE.getEditor('container', {initialFrameWidth: '100%', //初始化编辑器宽度,默认1000initialFrameHeight: '500' //初始化编辑器高度,默认320});
经过上面几步骤, 就可以把 Ueditor 嵌入到网页中了.
js获取 Ueditor 中的内容, 使用 ue.getContent() 方法. 而设置 Ueditor 中的内容, 一般来说, 都是使用HTML标签和css来设置格式的, 所以用 {!!$content!!} 往 Ueditor 中设置内容.
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>站点设置</title><link rel="stylesheet" href="/static/plugin/layui/css/layui.css"><script src="/static/plugin/layui/layui.js"></script><style>body {padding: 10px;}/* grid实现label固定宽度, 输入框充满剩下的宽度 */.site-name {display: grid;grid-template-columns: 110px auto;}.site-name > .layui-input-inline {margin: 0;width: 100%;/* box-sizing: border-box;padding-right: 10px; */}.site-name > .layui-input-inline > input{margin-right: 10px;}/* 用定位方式实现label固定宽度, 输入框充满剩下的宽度 */.site-keywords {position: relative;}.site-keywords > label {width: 110px;box-sizing: border-box;}.site-keywords > .layui-input-inline {position: absolute;width: unset;left: 110px;right: 0;margin: 0;}/* .site-keywords > .layui-input-inline input {width: 100%;} *//* 用flex布局实现 */.site-desc {display: flex;flex-flow: row nowrap;}.site-desc > .layui-form-label {width: 124px;box-sizing: border-box;}.site-desc > .layui-input-inline {width: 100%;margin: 0;}.site-desc > .layui-input-inline >textarea {box-sizing: border-box;/* border: 0; */margin: 0;}</style></head><body><div class="layui-row"><div class="layui-col-lg6 layui-col-md8 layui-col-sm10 layui-col-xs12"><div class="layui-form site-form">@csrf<div class="layui-form-item site-name"><label for="title" class="layui-form-label">站点名称</label><div class="layui-input-inline"><input type="text" name="title" id="title" class="layui-input" value="{{$site['title']}}"></div></div><div class="layui-form-item site-keywords"><label for="keywords" class="layui-form-label">关键字</label><div class="layui-input-inline"><input type="text" name="keywords" id="keywords" class="layui-input" value="{{$site['keywords']}}"></div></div><div class="layui-form-item site-desc"><label for="descs" class="layui-form-label">描述</label><div class="layui-input-inline"><textarea name="descs" id="descs" placeholder="请输入内容" class="layui-textarea">{{$site['descs']}}</textarea></div></div><div class="layui-form-item"><label for="status" class="layui-form-label">站点状态</label><div class="layui-input-inline"><input type="checkbox" name="status" id="status" lay-skin="switch" lay-text="启用|停用" {{$site['status'] ? '' : 'checked'}}></div></div><div class="layui-form-item"><div class="layui-input-block"><button:button class="layui-btn layui-btn-success" onclick="save()">保存</button:button></div></div></div></div></div></body><script>layui.use(['form', 'layer'], function() {var form = layui.form;var layer = layui.layer;$ = layui.jquery;});function save() {var data = {_token : $('input[name="_token"]').val(),title : $.trim($('#title').val()),keywords : $.trim($('#keywords').val()),descs : $.trim($('#descs').val()),status : Boolean($('#status').prop('checked')) ? 0 : 1};var checkRes = checkData(data);if(checkRes.status == 1) {return layer.alert(checkRes.message);}$.post('/admin/setting/save',data,function(res) {if(res.status != undefined && res.status == '0') {return layer.msg(res.message, {icon: 1});} else if(res.status != undefined) {return layer.alert(res.message, {icon: 2});} else {return layer.alert('保存失败');}},'json');}function checkData(data) {$res = {status: 1};if(data.title == undefined || data.title == "") {$res.message = "站点名称不能为空";return $res;}if(data.keywords == undefined || data.keywords == "") {$res.message = "关键字不能为空";return $res;}if(data.descs == undefined || data.descs == "") {$res.message = "站点描述不能为空";return $res;}if($res.message == undefined) {$res.status = 0;}return $res;}</script></html>
<?phpnamespace App\Http\Controllers\admins;use App\Http\Controllers\Controller;use Illuminate\Support\Facades\DB;use Illuminate\Http\Request;class Setting extends Controller {public function index() {$res = DB::table('setting')->where('names', 'site')->getFirst();if($res) {$data['site'] = json_decode($res['vals'], true);} else {$data['site'] = ['title' => '', 'keywords' => '', 'descs' => '', 'status' => 1];}return view('admins/setting/index', $data);}public function save(Request $req) {$data = $req->all();unset($data['_token']);$data['status'] = (int) $data['status'];$checkRes = $this->checkData($data);if($checkRes['status'] > 0) {return json_encode($checkRes);}$site['vals'] = json_encode($data);$siteSetting = DB::table('setting')->where('names', 'site')->getFirst();if($siteSetting) {$res = DB::table('setting')->where('names', 'site')->update($site);} else {$site['names'] = 'site';$res = DB::table('setting')->insert($site);}if($res) {return json_encode(['status' => 0, 'message' => '保存成功']);} else {return json_encode(['status' => 1, 'message' => '保存失败']);}}protected function checkData($data) {$res['status'] = 1;if($data['title'] == null || $data['title'] == '') {$res['message'] = '站点名称不能为空';return $res;}if($data['keywords'] == null || $data['keywords'] == '') {$res['message'] = '关键字不能为空';return $res;}if($data['descs'] == null || $data['keywords'] == '') {$res['message'] = '站点描述不能为空';return $res;}return ['status' => 0];}}
1-文章分类视图
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>文章分类列表</title><link rel="stylesheet" href="/static/plugin/layui/css/layui.css"><script src="/static/plugin/layui/layui.js"></script><style>body {padding: 10px;}.opera-area {text-align: right;}</style></head><body><div class="opera-area"><span class="layui-btn layui-btn-success">添加</span></div><table class="layui-table"><thead><tr><td>ID</td><td>分类名称</td><td>操作</td></tr></thead><tbody>@if(!empty($cates))@foreach($cates as $cate)<tr><td>{{$cate['id']}}</td><td>{{$cate['title']}}</td><td style="width: 150px;"><span class="layui-btn layui-btn-warm layui-btn-xs">修改</span></td></tr>@endforeach@else<tr><td colspan="3">啥也没查到....</td></tr>@endif</tbody></table></body><script>layui.use(['layer'], function() {layer = layui.layer;$ = layui.jquery;$(".opera-area span").on('click', add)});function add(e) {layer.open({type: 2,title: '添加文章分类',shadeClose: false,shade: 0.8,area: ['400px', '200px'],content: '/admin/article/add_cate'});}</script></html>
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>添加分类</title><link rel="stylesheet" href="/static/plugin/layui/css/layui.css"><script src="/static/plugin/layui/layui.js"></script><style>body {padding: 10px;}</style></head><body><div class="layui-form">@csrf<div class="layui-form-item"><label for="title" class="layui-form-label">分类名称</label><div class="layui-input-inline"><input type="text" name="title" id="title" class="layui-input" placeholder="请输入分类名称"></div></div><div class="layui-form-item"><div class="layui-input-block"><span class="layui-btn layui-btn-success" onclick="save()">保存</span></div></div></div></body><script>layui.use(['layer'], function() {layer = layui.layer;$ = layui.jquery;});function save() {var title = $.trim($('#title').val());if(title == undefined || title == '') {return layer.alert('分类名称不能为空', {icon: 2});}$.post('/admin/article/save_cate',{_token: $('input[name="_token"]').val(),title: title},function(res) {if(res.status != undefined && res.status == "0") {layer.msg(res.message, {icon: 1});setTimeout(() => {parent.window.location.reload();}, 1000);} else if(res.status != undefined) {layer.alert(res.message, {icon: 2});} else {layer.alert('操作失败', {icon: 2});}},'json');}</script></html>
文章管理视图
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>文章列表</title><link rel="stylesheet" href="/static/plugin/layui/css/layui.css"><script src="/static/plugin/layui/layui.js"></script></head><body style="padding: 10px;"><div style="text-align: center; color: #666;"><h2>管理员列表</h2></div><div style="text-align: right;"><span class="layui-btn layui-btn-success" onclick="add()">新增</span></div><table class="layui-table"><thead><tr><td>ID</td><td>文章分类</td><td>缩略图</td><td>文章标题</td><td>文章作者</td><td>浏览量</td><td>添加时间</td><td>状态</td><td>操作</td></tr></thead><tbody>@if(!empty($articles))@foreach($articles as $article)<tr><td>{{$article['id']}}</td><td>{{$cates[$article['cid']]}}</td><td><img src="{{$article['thumb']}}"></td><td>{{$article['title']}}</td><td>{{$user[$article['auth_id']]}}</td><td>{{$article['pv']}}</td><td>{{date('Y-m-d H:i:s', $article['add_time'])}}</td><td>{{$article['status'] ? '已发布' : '草稿'}}</td><td><span class="layui-btn layui-btn-warm layui-btn-xs" onclick="edit({{$article['id']}})">修改</span><span class="layui-btn layui-btn-danger layui-btn-xs">删除</span></td></tr>@endforeach@endif</tbody></table><div id="paginate"></div></body><script>layui.use(['layer', 'laypage'], function() {layer = layui.layer;laypage = layui.laypage;laypage.render({elem: 'paginate', // 注意,这里的 test1 是 ID,不用加 # 号count: {{$total}}, // 查询到的记录总数,从数据库中获取limit: {{$limit}}, // 每页容纳的记录数curr: {{$currPage}}, // 当前页first: '首页',last: '尾页',layout: ['first', 'prev', 'page', 'next', 'last', 'count', 'limit', 'refresh', 'skip'],limits: [1, 5, 10, 15, 20],jump: function(obj, first){//obj包含了当前分页的所有参数,比如:console.log(obj.curr); //得到当前页,以便向服务端请求对应页的数据。console.log(obj.limit); //得到每页显示的条数console.log(obj);//首次不执行if(!first){window.location.href = "?limit=" + obj.limit + "&page=" + obj.curr;}}});});function add() {layer.open({type: 2,title: '新增文章',shadeClose: false,shade: 0.8,area: ['100%', '100%'],content: '/admin/article/add_article',btn: ['保存'],yes: function(index, layero) {var body = layer.getChildFrame('body', index);// 得到iframe页的窗口对象var iframeWin = window[layero.find('iframe')[0]['name']];// 执行iframe页的方法: iframeWin.要调用的方法名();iframeWin.save();}});}function edit(id) {layer.open({type: 2,title: '修改文章',shadeClose: false,shade: 0.8,area: ['100%', '100%'],content: '/admin/article/edit_article?id=' + id,btn: ['保存'],yes: function(index, layero) {var body = layer.getChildFrame('body', index);// 得到iframe页的窗口对象var iframeWin = window[layero.find('iframe')[0]['name']];// 执行iframe页的方法: iframeWin.要调用的方法名();iframeWin.save();}});}</script></html>
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>新增文章</title><link rel="stylesheet" href="/static/plugin/layui/css/layui.css"><script src="/static/plugin/layui/layui.js"></script><!-- ueditor-start --><!-- 配置文件 --><script type="text/javascript" src="/static/plugin/ueditor/ueditor.config.js"></script><!-- 编辑器源码文件 --><script type="text/javascript" src="/static/plugin/ueditor/ueditor.all.js"></script><!-- ueditor-end --><style>body {padding: 10px;}.hide {display: none;}</style></head><body><div class="layui-form">@csrf<div class="layui-form-item"><label for="title" class="layui-form-label">标题</label><div class="layui-input-block"><input type="text" class="layui-input" name="title" id="title"></div></div><div class="layui-form-item"><label for="subtitle" class="layui-form-label">副标题</label><div class="layui-input-block"><input type="text" name="subtitle" id="subtitle" class="layui-input"></div></div><div class="layui-form-item"><label for="cid" class="layui-form-label">文章分类</label><div class="layui-input-block"><select name="cid" id="cid" class="layui-input"><option value=""></option>@if(!empty($cates))@foreach($cates as $key => $val)<option value="{{$key}}">{{$val}}</option>@endforeach@endif</select></div></div><div class="layui-form-item"><label for="thumb" class="layui-form-label">缩略图</label><div class="layui-input-block"><button type="button" class="layui-btn" id="btn_upload"><i class="layui-icon"></i>上传图片</button><img id="preview_img" src="" alt="" style="height: 36px;" onclick="big_img(this)"></div></div><div class="layui-form-item"><label for="keywords" class="layui-form-label">关键字</label><div class="layui-input-block"><input type="text" name="keywords" id="keywords" class="layui-input"></div></div><div class="layui-form-item"><label for="descs" class="layui-form-label">文章描述</label><div class="layui-input-block"><textarea name="descs" id="descs" class="layui-textarea"></textarea></div></div><div class="layui-form-item"><label for="status" class="layui-form-label">文章状态</label><div class="layui-input-block"><input type="radio" name="status" id="status_0" value="0" title="草稿"><input type="radio" name="status" id="status_1" value="1" title="发布" checked></div></div><div class="layui-form-item"><label for="content" class="layui-form-label">文章正文</label><div class="layui-input-block"><!-- 加载编辑器的容器 --><!-- 实际生成的是div. 给div添加contenteditable="true", 这个div就能编辑 --><script id="container" name="content" type="text/plain">这里写你的初始化内容</script></div></div></div><div id="tong" class="hide" ><img src="" style="max-width: 100%; max-height: 100%"></div></body><script>layui.use(['form', 'layer', 'upload'], function() {layer = layui.layer;form = layui.form;upload = layui.upload;$ = layui.jquery;// 执行实例var uploadInst = upload.render({elem: '#btn_upload', // 绑定元素url: '/admin/upload/pic_upload', // 上传接口data: {_token: $('input[name="_token"]').val()},done: function(res) {// 上传完毕回调$('#preview_img').attr('src', res.data.src);$('#tong > img').attr('src', res.data.src);},error: function() {// 请求异常回调}});// 实例化编辑器/* 第二个参数是配置属性对象 *//* 不要写var, 把ue声明为全局变量, 因为其他地方也用到ue对象 *//* var */ue = UE.getEditor('container', {initialFrameWidth: '100%', //初始化编辑器宽度,默认1000initialFrameHeight: '500' //初始化编辑器高度,默认320});});function big_img(img) {if (img.src == undefined || img.src == "") {return;}//页面层-图片layer.open({type: 1,title: false,closeBtn: 0,area: ['auto'],skin: 'layui-layer-nobg', //没有背景色shadeClose: true,content: $('#tong')});}function save() {var data = {};data._token = $('input[name="_token"]').val();data.title = $.trim($('#title').val());data.subtitle = $.trim($('#subtitle').val());data.cid = parseInt($('#cid').val());data.thumb = $.trim($('#preview_img').attr('src'));data.status = $('input[name="status"]:checked').val();data.descs = $.trim($('#descs').val());data.keywords = $.trim($('#keywords').val());data.content = ue.getContent();if(data.title == '') {return layer.alert('请填写文章标题', {icon: 2});}if(data.content == '') {return layer.alert('请输入文章内容', {icon: 2});}if(isNaN(data.cid) || data.cid < 1) {return layer.alert('请选择文章分类', {icon: 2});}$.ajax({url: '/admin/article/save_article',data: data,type: 'POST',async: true,dataType: 'json',success: function(res) {if(res.status != undefined && res.status == '0') {layer.msg(res.message, {icon: 1});setTimeout(() => {window.parent.location.reload();}, 1000);} else if(res.status != undefined) {return layer.alert(res.message, {icon: 2});} else {return layer.alert('文章提交失败', {icon: 2});}}});}</script></html>
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>修改文章</title><link rel="stylesheet" href="/static/plugin/layui/css/layui.css"><script src="/static/plugin/layui/layui.js"></script><!-- ueditor-start --><!-- 配置文件 --><script type="text/javascript" src="/static/plugin/ueditor/ueditor.config.js"></script><!-- 编辑器源码文件 --><script type="text/javascript" src="/static/plugin/ueditor/ueditor.all.js"></script><!-- ueditor-end --><style>body {padding: 10px;}.hide {display: none;}</style></head><body><div class="layui-form">@csrf<input type="hidden" name="id" value="{{$article['id']}}"><div class="layui-form-item"><label for="title" class="layui-form-label">标题</label><div class="layui-input-block"><input type="text" class="layui-input" name="title" id="title" value="{{$article['title']}}"></div></div><div class="layui-form-item"><label for="subtitle" class="layui-form-label">副标题</label><div class="layui-input-block"><input type="text" name="subtitle" id="subtitle" class="layui-input" value="{{$article['subtitle']}}"></div></div><div class="layui-form-item"><label for="cid" class="layui-form-label">文章分类</label><div class="layui-input-block"><select name="cid" id="cid" class="layui-input" value="{{$article['cid']}}"><option value=""></option>@if(!empty($cates))@foreach($cates as $key => $val)<option value="{{$key}}" {{$article['cid'] == $key ? 'selected' : ''}}>{{$val}}</option>@endforeach@endif</select></div></div><div class="layui-form-item"><label for="thumb" class="layui-form-label">缩略图</label><div class="layui-input-block"><button type="button" class="layui-btn" id="btn_upload"><i class="layui-icon"></i>上传图片</button><img id="preview_img" src="{{$article['thumb']}}" alt="" style="height: 36px;" onclick="big_img(this)"></div></div><div class="layui-form-item"><label for="keywords" class="layui-form-label">关键字</label><div class="layui-input-block"><input type="text" name="keywords" id="keywords" class="layui-input" value="{{$article['keywords']}}"></div></div><div class="layui-form-item"><label for="descs" class="layui-form-label">文章描述</label><div class="layui-input-block"><textarea name="descs" id="descs" class="layui-textarea">{{$article['descs']}}</textarea></div></div><div class="layui-form-item"><label for="status" class="layui-form-label">文章状态</label><div class="layui-input-block"><input type="radio" name="status" id="status_0" value="0" title="草稿" {{$article['status'] == 0 ? 'checked' : ''}}><input type="radio" name="status" id="status_1" value="1" title="发布" {{$article['status'] == 1 ? 'checked' : ''}}></div></div><div class="layui-form-item"><label for="content" class="layui-form-label">文章正文</label><div class="layui-input-block"><!-- 加载编辑器的容器 --><!-- 实际生成的是div. 给div添加contenteditable="true", 这个div就能编辑 --><script id="container" name="content" type="text/plain">{!!$content!!}</script></div></div></div><div id="tong" class="hide" ><img src="{{$article['thumb']}}" style="max-width: 100%; max-height: 100%"></div></body><script>layui.use(['form', 'layer', 'upload'], function() {layer = layui.layer;form = layui.form;upload = layui.upload;$ = layui.jquery;// 执行实例var uploadInst = upload.render({elem: '#btn_upload', // 绑定元素url: '/admin/upload/pic_upload', // 上传接口data: {_token: $('input[name="_token"]').val()},done: function(res) {// 上传完毕回调$('#preview_img').attr('src', res.data.src);$('#tong > img').attr('src', res.data.src);},error: function() {// 请求异常回调}});// 实例化编辑器/* 第二个参数是配置属性对象 *//* 不要写var, 把ue声明为全局变量, 因为其他地方也用到ue对象 *//* var */ue = UE.getEditor('container', {initialFrameWidth: '100%', //初始化编辑器宽度,默认1000initialFrameHeight: '500' //初始化编辑器高度,默认320});});// 点击上传的缩略图, 显示大图function big_img(img) {if (img.src == undefined || img.src == "") {return;}//页面层-图片layer.open({type: 1,title: false,closeBtn: 0,area: ['auto'],skin: 'layui-layer-nobg', //没有背景色shadeClose: true,content: $('#tong')});}function save() {var data = {};data._token = $('input[name="_token"]').val();data.id = parseInt($('input[name="id"]').val());data.title = $.trim($('#title').val());data.subtitle = $.trim($('#subtitle').val());data.cid = parseInt($('#cid').val());data.thumb = $.trim($('#preview_img').attr('src'));data.status = $('input[name="status"]:checked').val();data.descs = $.trim($('#descs').val());data.keywords = $.trim($('#keywords').val());data.content = ue.getContent();if(data.title == '') {return layer.alert('请填写文章标题', {icon: 2});}if(data.content == '') {return layer.alert('请输入文章内容', {icon: 2});}if(isNaN(data.cid) || data.cid < 1) {return layer.alert('请选择文章分类', {icon: 2});}if(isNaN(data.id) || data.id < 1) {return layer.alert('文章id不能为空', {icon: 2});}$.ajax({url: '/admin/article/update_article',data: data,type: 'POST',async: true,dataType: 'json',success: function(res) {if(res.status != undefined && res.status == '0') {layer.msg(res.message, {icon: 1});setTimeout(() => {window.parent.location.reload();}, 1000);} else if(res.status != undefined) {return layer.alert(res.message, {icon: 2});} else {return layer.alert('文章更新失败', {icon: 2});}}});}</script></html>
<?phpnamespace App\Http\Controllers\admins;use App\Http\Controllers\Controller;use Illuminate\Http\Request;use Illuminate\Support\Facades\DB;class Article extends Controller {/*** 文章列表*/public function index(Request $req) {// 一页可容纳的记录数$pageSize = empty($req->limit) ? 1 : $req->limit;// 当前页$currPage = empty($req->page) ? 1 : $req->page;// dump($pageSize);dump($currPage);die;$data['cates'] = DB::table('article_cate')->keyval('id', 'title');$data['user'] = DB::table('admin')->keyval('id', 'real_name');// $data['articles'] = DB::table('article')->lists();/* 换成分页的方式(返回对象数组) */// $data['articles'] = DB::table('article')->paginate(2);/* 换成自己扩展的分页方式(返回二维数组) */$pageData = DB::table('article')->orderby('id' , 'desc')->pages($pageSize);// dump($pageData);die;$data['articles'] = $pageData['page_data'];$data['total'] = $pageData['total'];$data['limit'] = $pageSize;$data['currPage'] = $currPage;return view('/admins/article/index', $data);}/*** 跳转到新增文章界面*/public function addArticle() {$data['cates'] = DB::table('article_cate')->keyval('id', 'title');return view('admins/article/add_article', $data);}public function editArticle(Request $req) {$data['cates'] = DB::table('article_cate')->keyval('id', 'title');$id = (int) $req->id;$data['article'] = DB::table('article')->where('id', $id)->getFirst();if(!$data['article']) {return json_encode(['status' => 1, 'message' => '无效的文章ID']);}$data['content'] = (DB::table('article_detail')->select('contents')->where('aid', $id)->getFirst())['contents'];return view('/admins/article/edit_article', $data);}public function saveArticle(Request $req) {$data['title'] = trim($req->title);$data['subtitle'] = trim($req->subtitle);$data['cid'] = (int) ($req->cid);$data['thumb'] = trim($req->thumb);$data['status'] = (int) $req->status;$data['descs'] = trim($req->descs);$data['keywords'] = trim($req->keywords);$data['auth_id'] = $req->loginInfo->id;$data['add_time'] = time();$content = trim($req->content);$id = DB::table('article')->insertGetId($data);if($id) {DB::table('article_detail')->insert(['aid' => $id, 'contents' => $content]);return json_encode(['status' => 0, 'message' => '文章保存成功']);}return json_encode(['status' => 1, 'message' => '文章保存失败']);}public function updateArticle(Request $req) {$data['id'] = (int) $req->id;$data['title'] = trim($req->title);$data['subtitle'] = trim($req->subtitle);$data['cid'] = (int) ($req->cid);$data['thumb'] = trim($req->thumb);$data['status'] = (int) $req->status;$data['descs'] = trim($req->descs);$data['keywords'] = trim($req->keywords);$data['auth_id'] = $req->loginInfo->id;$data['add_time'] = time();$content = trim($req->content);$id = DB::table('article')->where('id', $data['id'])->update($data);if($id) {DB::table('article_detail')->where('aid', $data['id'])->update(['contents' => $content]);return json_encode(['status' => 0, 'message' => '文章修改成功']);}return json_encode(['status' => 1, 'message' => '文章修改失败']);}/*** 文章分类列表*/public function cates() {// 查询所有分类$data['cates'] = DB::table('article_cate')->lists();return view('/admins/article/cates', $data);}/*** 添加文章分类*/public function addCate(Request $req) {return view('/admins/article/add_cate');}public function saveCate(Request $req) {$title = $req->title;$cate = DB::table('article_cate')->where('title', $title)->getFirst();if($cate) {return json_encode(['status' => 1, 'message' => '已存在同名分类, 请另命名分类后再重试']);}$res = DB::table('article_cate')->insertGetId(['title' => $title]);if($res) {return json_encode(['status' => 0, 'message' => '添加成功']);}return json_encode(['status' => 1, 'message' => '添加失败']);}}
<?phpnamespace App\Http\Controllers\admins;use App\Http\Controllers\Controller;use Illuminate\Http\Request;use Illuminate\Support\Facades\Storage;class Upload extends Controller {public function picUpload(Request $request) {// file(请求中的文件参数名), store(文件存放子路径). 文件存放目录: ../storage/app/[store指定的子目录],// 为能使用软连接访问上传的图片, 强烈建议子目录以public目录开始. 建议在public中分目录, 以年份, 或者年份月份,// 或者年月日为public子目录来存放文件, 这样更方便查找. 也可以分得更细, 如: 精确到小时, 分钟等./* 此时返回的是.../public/avatars/2020/06/18/xxxxxx.png, 实际并不能以该路径来访问 */$path = $request->file('file')->store('public/avatars/' . date('Y/m/d'));// 获取前端能访问到的真实的url地址$url = Storage::url($path);// layui的上传组件要求返回的json数据的格式$res = ['code' => 0, 'msg' => '', 'data' => ['src' => $url]];return json_encode($res);}}
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号