目录
一、内容详细页
项目介绍
本项目分为前台和后台。前台的功能包括用户登录与注册、内容列表、内容详细页、广告展示、评论和热门内容等。后台在未登录的状态下会自动跳转至登录页面。输入用户名“admin”、密码“123456”和验证码后,单击“登录”按钮,即可进行登录。登录后,页面顶部右侧显示了当前登录的用户名“admin”和“退出”按钮,单击“退出”按钮即可退出后台系统。后台页面的左侧有一个菜单栏,用户可以在菜单栏中选择一个菜单项进行操作。项目中需要使用到的技术点包括文件上传、分页和会话技术。整个项目开发基于实现功能的步骤来完成,先实现后台开发,提供数据支持,再完成前台的数据展示。
安装Laravel
首先选择你想在的哪个文件安装Laravel,然后就选择那个文件执行安装Larave命令:composer create-project --prefer-dist laravel/laravel ./ 5.8.*
比如我想在D盘的 phpstudy_pro->WWW 里下载Laravel,则选择到D盘里的 phpstudy_pro->WWW 文件,然后在文件的上面写上cmd按下回车键,就可以进入到该文件的终端,然后执行安装Laravel的命令即可。操作如下图所示。
配置文件
Laravel安装完成后,在Apache的conf\extra\httpd-vhosts.conf配置文件中创建一个虚拟主机。具体配置为:
<VirtualHost *:80>
DocumentRoot "C:/web/apache2.4/htdocs/cms/public"
ServerName cms.com
<VirtualHost>
然后,编辑Apache的hosts文件,添加一条解析记录“127.0.0.1 cms.com”。如下图所示。
登录MySQL服务器,创建数据库cms,将cms作为内容管理系统的数据库。
打开项目,在config\database.php数据库配置文件中,将数据库名称修改为cms。
在.env文件中配置正确的数据库配置信息。全部完成后,即可在项目中访问数据库。
引入需要的静态文件
一、后台用户登录
1.创建用户表
(1)在命令行中执行如下命令创建迁移文件,具体命令如下:
php artisan make:migration create_admin_user_table
(2)执行完上述命令后,会在database\migrations目录下生成文件名称为时间前缀_create_admin_user_table.php的文件 。
(3)在迁移文件的up()方法中添加表结构信息,具体代码如下:
public function up()
{
Schema::create('admin_user', function (Blueprint $table) {
$table->increments('id')->comment('主键');
$table->string('username', 32)->comment('用户名')->unique();
$table->string('password', 32)->comment('密码');
$table->char('salt', 32)->comment('密码salt');
$table->timestamps();
});
}
(4)迁移文件创建完成后,使用如下命令来执行迁移
php artisan migrate
(5)上述命令会执行迁移文件中的up()方法,来完成数据表的创建。
(6)创建填充文件,具体命令如下:
php artisan make:seeder AdminuserTableSeeder
(7)执行完上述命令后,会在database\seeds目录下生成对应的迁移文件,文件名为AdminuserTableSeeder.php。
(8)在填充文件的run()方法中编写填充代码:
public function run()
{
$salt = md5(uniqid(microtime(), true));
$password = md5(md5('123456') . $salt);
DB::table('admin_user')->insert([
[
'id' => 1,
'username' => 'admin',
'password' => $password,
'salt' => $salt
],
]);
}
(9)执行填充文件命令:
php artisan db:seed --class=AdminuserTableSeeder
(10)数据库创建成功后,创建用户模型:
php artisan make:model Admin
(11)打开app\Admin.php,在模型中指定要操作的表名,具体代码如下:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Admin extends Model
{
protected $table = 'admin_user';
public $fillable = ['username', 'password'];
}
2.显示登录页面
(1)创建User控制器,具体代码如下:
php artisan make:controller Admin/UserController
(2)执行完上述命令后,会在app\Http\Controllers\Admin目录下创建UserController.php,命名空间为App\Http\Controllers\Admin。
(3)打开UserController.php,创建login()方法,具体代码如下:
public function login(){
return view('admin/login');
}
(4)在routes\web.php文件中添加路由规则,具体代码如下:
Route::get('/admin/login','Admin\UserController@login');
(5)在resources\views目录下创建admin目录,该目录用于存放后台相关的模板文件。在admin目录中创建login.blade.php文件,具体代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- 引入静态文件 -->
<title>登录</title>
</head>
<body class="login">
<div class="container">
<!-- 登录表单 -->
</div>
</body>
</html>
(6)在上述的第6行引入静态文件,具体代码如下:
<link rel="stylesheet" href="{
{asset('admin')}}/common/twitter-bootstrap/4.4.1/css/bootstrap.min.css">
<link rel="stylesheet" href="{
{asset('admin')}}/common/font-awesome-4.2.0/css/font-awesome.min.css">
<link rel="stylesheet" href="{
{asset('admin')}}/common/toastr.js/2.1.4/toastr.min.css">
<link rel="stylesheet" href="{
{asset('admin')}}/css/main.css">
<script src="{
{asset('admin')}}/common/jquery/1.12.4/jquery.min.js"></script>
<script src="{
{asset('admin')}}/common/twitter-bootstrap/4.4.1/js/bootstrap.min.js"></script>
<script src="{
{asset('admin')}}/common/toastr.js/2.1.4/toastr.min.js"></script>
<script src="{
{asset('admin')}}/js/main.js"></script>
(7)在注释登录表单下面定义登录表单,具体代码如下:
<form action="" method="post" class="j-login">
<h1>后台管理系统</h1>
<div class="form-group">
<input type="text" name="username" class="form-control" placeholder="用户名" required>
</div>
<div class="form-group">
<input type="password" name="password" class="form-control" placeholder="密码" required>
</div>
<div class="form-group">
<input type="text" name="captcha" class="form-control" placeholder="验证码" required>
</div>
<!-- 验证码 -->
<div class="form-group">
{
{csrf_field()}}
<input type="submit" class="btn btn-lg btn-block btn-success" value="登录">
</div>
</form>
(8)使用Composer载入mews/captcha验证码库,具体代码如下:
composer require mews/captcha=3.0
(9)创建验证码的配置文件 ,具体命令如下:
php artisan vendor:publish
(10)执行完上述命令后,在命令行中输入序号“9”并按"Enter"键,就会自动生成config\captcha.php文件。
(11)编辑config\captcha.php文件,将字符个数改为4,具体代码如下:
'default' => [
'length' => 4, //字符个数
'width' => 120, //图片宽度
'height' => 36, //图片高度
'quality' => 90, //图片质量
'math' => false, //数学计算
],
(12)在config\app.php中将验证码服务注册到服务器中,具体代码如下:
'providers' => [
...(原有代码)
Mews\Captcha\CaptchaServiceProvider::class,
...(原有代码)
]
(13)在config\app.php文件中给验证码服务注册别名,具体代码如下:
'aliases' => [
...(原有代码)
'Captcha' =>Mews\Captcha\Facades\Captcha::class,
]
(14)在登录表单中添加验证码,具体代码如下:
<div class="form-group">
<div class="login-captcha"><img src="{
{ captcha_src() }}" alt="captcha"></div>
</div>
(15)通过浏览器访问,其页面效果如下图:
(16)实现单机验证码图片后更换验证码功能,在模板中编写JavaScript代码,具体代码如下:
<script>
$('.login-captcha img').click(function() {
$(this).attr('src', '{
{ captcha_src()}}' + '?_=' + Math.random());
});
</script>
3.Ajax交互
(1)打开public\admin\js\main.js文件,添加如下代码:
(function (window, $, toastr) {
window.main = {
token: '', // 保存令牌
toastr: toastr,
init: function (opt) {
$.extend(this, opt); // 将传入的opt对象合并到自身对象中
toastr.options.positionClass = 'toast-top-center';
return this;
},
ajax: function (opt, success, error) {
opt = (typeof opt === 'string') ? {url: opt} : opt;
var that = this;
var options = {
success: function (data, status, xhr) {
that.hideLoading();
if (!data) {
toastr.error('请求失败,请重试。');
} else if (data.code === 0) {
toastr.error(data.msg);
error && error(data);
} else {
success && success(data);
}
opt.success && opt.success(data, status, xhr);
},
error: function (xhr, status, err) {
that.hideLoading();
toastr.error('请求失败,请重试。');
opt.error && opt.error(xhr, status, err);
}
};
that.showLoading();
$.ajax($.extend({}, opt, options));
},
showLoading: function() {
$('.main-loading').show();
},
hideLoading: function() {
$('.main-loading').hide();
},
};
})(this, jQuery, toastr);
(2)在main对象中编写ajaxPost()方法,具体代码如下:
ajaxPost: function(opt, success, error) {
opt = (typeof opt === 'string') ? {url: opt} : opt;
var that = this;
var callback = opt.success;
opt.type = 'POST';
opt.success = function(data, status, xhr) {
if (data && data.code === 1) {
toastr.success(data.msg);
}
callback && callback(data, status, xhr);
};
that.ajax(opt, success, error);
},
(3)在main.js中编写ajaxForm()方法,用于将表单改为Ajax提交方式,具体代码如下:
ajaxForm: function (selector, success, error) {
var form = $(selector);
var that = this;
form.submit(function (e) {
e.preventDefault();
that.ajaxPost({
url: form.attr('action'),
data: new FormData(form.get(0)),
contentType: false,
processData: false
}, success, error);
});
},
4.验证用户登录
(1)在routes\web.php文件中添加路由规则,具体代码如下:
//登录验证
Route::post('/admin/check','Admin\UserController@check');
(2)在UserController.php中创建check()方法,具体代码如下:
public function check(Request $request)
{
//声明自动验证规则
$rule = [
'username' => 'required',
'password' => 'required|min:6',
'captcha' => 'required|captcha'
];
// 声明自动验证规则对应的提示信息(验证失败返回信息)
$message = [
'username.required' => '用户名不能为空',
'password.required' => '密码不能为空',
'password.min' => '密码最少为6位',
'captcha.required' => '验证码不能为空',
'captcha.captcha' => '验证码有误'
];
//进行自动验证,验证表单提交数据
$validator = Validator::make($request->all(), $rule, $message);
// 输出验证结果并返回给浏览器
if ($validator->fails()) { //验证失败fails()方法
foreach ($validator->getMessageBag()->toArray() as $v) {
$msg = $v[0];
}
return response()->json(['code' => 0, 'msg' => $msg]);
}
// 获取用户输入的用户名、密码信息,以及数据表中用户名、密码信息
$username = $request->get('username');
$password = $request->get('password');
$theUser = Admin::where('username',$username)->first();
// 对用户输入的密码与数据库中的密码进行比较,如果密码正确则登录成功,并将用户信息保存在session中
// 跳转至后台首页,如果登录失败,则显示“登录失败”
if($theUser->password == md5(md5($password). $theUser->salt))
{
Session::put('user', ['id'=>$theUser->id,'name'=>$username]);
return response()->json(['code' => 1, 'msg' => '登录成功']);
}else{
return response()->json(['code' => 0, 'msg' => '登录失败']);
}
}
(3)在上述代码中使用的一些类需要导入命名空间,具体代码如下:
use App\Admin;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Validator;
(4)在login.blade.php的<script>标签中添加代码,具体代码如下:
main.ajaxForm('.j-login', function() {
location.href = '/index.php/admin/index';
});
(5)通过浏览器访问,输入小于6位的密码,页面出现“密码最少为6位”的错误提示;输入验证码不正确,页面出现“验证码有误”的错误提示;如果提交正确的用户名(admin)和密码(123456),页面中会出现“登录成功”的提示。
5.用户退出
(1)在User控制器中添加logout()方法,具体代码如下:
public function logout(){
if(request()->session()->has('user')){
request()->session()->pull('user',session('user'));
}
return redirect('/admin/login');
}
(2)在routes\web.php文件中添加路由规则,具体代码如下:
//用户退出
Route::get('/admin/logout','Admin\UserController@logout');
(3)通过浏览器访问,在确保用户已经登录以后,访问http://cms.com/index.php/admin/logout,浏览器会自动跳转到登录页面,说明已经成功退出。
二、后台首页
1.后台页面布局
(1)在layouts目录下创建admin.blade.php文件,具体代码如下 :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!--引入静态文件-->
<title>@yield('title')</title>
</head>
<body>
<nav class="navbar navbar-expand-md navbar-light bg-light main-navbar">
<a class="navbar-brand" href="#">后台管理系统</a>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="nav ml-auto main-nav-right">
<li>
<a href="#" class="j-layout-pwd">
<i class="fa fa-user fa-fw"></i>{
{session()->get('user.name')}}
</a>
</li>
<li>
<a href="{
{url('admin/logout')}}">
<i class="fa fa-power-off fa-fw"></i>退出
</a>
</li>
</ul>
</div>
</nav>
<!-- 后台页面的首页部分 -->
<div class="main-container">
<div class="main-content">
<div>@yield('main')</div>
</div>
</div>
</body>
</html>
(2)在页面引入静态资源,具体代码如下:
<link rel="stylesheet" href="{
{asset('admin')}}/common/twitter-bootstrap/4.4.1/css/bootstrap.min.css">
<link rel="stylesheet" href="{
{asset('admin')}}/common/font-awesome-4.2.0/css/font-awesome.min.css">
<link rel="stylesheet" href="{
{asset('admin')}}/common/toastr.js/2.1.4/toastr.min.css">
<link rel="stylesheet" href="{
{asset('admin')}}/css/main.css">
<script src="{
{asset('admin')}}/common/jquery/1.12.4/jquery.min.js"></script>
<script src="{
{asset('admin')}}/common/twitter-bootstrap/4.4.1/js/bootstrap.min.js"></script>
<script src="{
{asset('admin')}}/common/toastr.js/2.1.4/toastr.min.js"></script>
<script src="{
{asset('admin')}}/js/main.js"></script>
(3)在页面中定义左侧导航栏,具体代码如下:
<div class="main-sidebar">
<ul class="nav flex-column main-menu">
</div>
(4)添加首页菜单,具体代码如下:
<li class="">
<a href="{
{url('admin/index')}}" class="active">
<i class="fa fa-home fa-fw"></i>首页
</a>
</li>
(5) 添加栏目菜单,具体代码如下:
<li class="main-sidebar-collapse"> <!-- 被收起的双层项 -->
<a href="#" class="main-sidebar-collapse-btn"> <!-- 链接用于展开或收起子菜单 -->
<i class="fa fa-list-alt fa-fw"></i>栏目
<span class="fa main-sidebar-arrow"></span> <!-- 双层项的右侧小箭头 -->
</a>
<ul class="nav">
<!-- 设置子菜单 -->
<li>
<a href="#" data-name="addcategory">
<i class="fa fa-list fa-fw"></i>添加</a>
</li>
<li>
<a href="#" data-name="category">
<i class="fa fa-table fa-fw"></i>列表</a>
</li>
</ul>
</li>
(6)添加内容表单,具体代码如下:
<li class="main-sidebar-collapse">
<a href="#" class="main-sidebar-collapse-btn">
<i class="fa fa-list-alt fa-fw"></i>内容
<span class="fa main-sidebar-arrow"></span>
</a>
<ul class="nav">
<li>
<a href="#" data-name="addcontent">
<i class="fa fa-list fa-fw"></i>添加</a>
</li>
<li>
<a href="#" data-name="content">
<i class="fa fa-table fa-fw"></i>列表</a>
</li>
</ul>
</li>
(7)添加广告表单,具体代码如下:
<li class="main-sidebar-collapse">
<a href="#" class="main-sidebar-collapse-btn">
<i class="fa fa-cog fa-fw"></i>广告
<span class="fa main-sidebar-arrow"></span>
</a>
<ul class="nav">
<li>
<a href="#" data-name="adv">
<i class="fa fa-list fa-fw"></i>广告位</a>
</li>
<li>
<a href="#" data-name="advcontent">
<i class="fa fa-list-alt fa-fw"></i>广告内容</a>
</li>
</ul>
</li>
(8)添加消息表单,具体代码如下:
@if(!empty(session('message')))
<div class="alert alert-success" role="alert"
style="text-align:center;margin:0 auto;width: 400px">
{
{session('message')}}
</div>
@endif
@if(!empty(session('tip')))
<div class="alert alert-warning" role="alert"
style="text-align:center;margin:0 auto;width: 400px">
{
{session('tip')}}
</div>
@endif
(9)在<body>标签结束前的位置添加<script>标签,控制消息模板的显示时间,具体代码如下:
<script>
// setInterval(myFunction,myTimeLapse),每隔myTimeLapse(毫秒)执行一次myFunction()函数
setInterval(function(){
$('.alert').remove();
},3000);
</script>
(10) 修改public\admin\js\main.js文件,编写layout()方法,具体代码如下:
layout: function() {
$('.main-sidebar-collapse-btn').click(function() {
$(this).parent().find('.nav').slideToggle(200);
$(this).parent().toggleClass('main-sidebar-collapse').siblings().
addClass('main-sidebar-collapse').find('.nav').slideUp(200);
return false;
});
},
(11)在main.js中增加menuActive()方法,用于将指定菜单项设为选中效果,具体代码如下:
menuActive: function(name) {
var menu = $('.main-menu');
menu.find('a').removeClass('active');
menu.find('a[data-name=\'' + name + '\']').addClass('active');
menu.find('a[data-name=\'' + name + '\']').parent().parent().show();
}
(12)在<script>标签中调用layout()方法,具体代码如下:
main.layout();
2.显示后台首页
(1)公共文件创建完成后,接下来创建后台首页admin\index.blade.php,具体代码如下:
@extends('admin/layouts/admin')
@section('title', '后台首页')
@section('main')
<div>
<div class="main-title">
<h2>首页</h2>
</div>
<div class="main-section">
<div class="card">
<div class="card-header">服务器信息</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">系统环境:{
{ $server_version }}</li>
<li class="list-group-item">Laravel版本:{
{ $laravel_version }}</li>
<li class="list-group-item">MySQL版本:{
{ $mysql_version }}</li>
<li class="list-group-item">服务器时间:{
{ $server_time }}</li>
<li class="list-group-item">文件上传限制:{
{ $upload_max_filesize }}</li>
<li class="list-group-item">脚本执行时限:{
{ $max_execution_time }}</li>
</ul>
</div>
</div>
</div>
@endsection
(2)创建Index控制器,具体代码如下:
php artisan make:controller Admin\IndexController
(3) 在Index控制器中添加index()方法,具体代码如下:
public function index(Request $request){
$data = [
'server_version' => $request->server('SERVER_SOFTWARE'),
'laravel_version' => app()::VERSION,
'mysql_version' => $this->getMySQLVer(),
'server_time' => date('Y-m-d H:i:s', time()),
'upload_max_filesize' => ini_get('file_uploads') ?
ini_get('upload_max_filesize') : '已禁用',
'max_execution_time' => ini_get('max_execution_time') . '秒'
];
return view('admin\index', $data);
}
(4)在上述代码中,第六行代码调用getMySQLVer()方法获取MySQL版本,创建getMySQLVer()方法,具体代码如下:
private function getMySQLVer()
{
$res = DB::select('SELECT VERSION() AS ver');
return $res[0]->ver ?? '未知';
}
(5)在getMySQLVer()方法中,使用DB类执行SQL,获取MySQL的版本,导入DB类的命名空间,具体代码如下:
use DB;
(6)在routes\web.php文件中添加路由规则,具体代码如下:
Route::get('/admin/index', 'Admin\IndexController@index');
(7)通过浏览器访问后台首页,其效果如下图:
3.判断登录状态
(1)创建Admin中间件,用于验证用户是否登录,具体代码如下:
php artisan make:middleware Admin
(2)打开app\Http\Middleware\Admin.php,添加验证用户登录的代码,具体代码如下:
public function handle($request, Closure $next)
{
if (request()->session()->has('user')) {
$user = request()->session()->get('user');
view()->share('user', $user);
} else {
return redirect('/admin/login');
}
return $next($request);
}
(3)在app\Http\Kernel.php文件中注册路由中间件,具体代码如下:
protected $routeMiddleware = [
...(原有代码)
'Admin' => \App\Http\Middleware\Admin::class,
];
(4)修改首页的路由规则,为后台首页添加用户验证,具体代码如下:
Route::get('/admin/index', 'Admin\IndexController@index')->middleware(['Admin']);
三、栏目管理
1.创建栏目表
(1)栏目表同样也是通过命令行来创建,按照前面的步骤创建迁移文件和填充文件。
(2)打开栏目表的迁移文件,在该文件的up()方法中添加表结构信息,具体代码如下:
public function up()
{
Schema::create('category', function (Blueprint $table) {
$table->increments('id')->comment('主键');
$table->integer('pid')->comment('父类id') ->default('0');
$table->string('name', 32)->comment('分类名称');
$table->integer('sort')->comment('排序值') ->default('0');
$table->timestamps();
});
}
(3)栏目表创建完成后,为了在项目中操作栏目表,下面创建栏目表对应的模型文件,具体代码如下:
php artisan make:model Category
(4)打开app\Category.php文件,具体代码如下:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
protected $table = "category";
public $fillable = ['pid', 'name', 'sort'];
}
2.添加栏目
(1)创建Category控制器,具体代码如下:
php artisan make:controller Admin\CategoryController
(2)在控制器中添加add()方法,用于实现添加栏目的功能,具体代码如下:
<?php
namespace App\Http\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Category;
class CategoryController extends Controller
{
public function add(){
$category = Category::where('pid', 0)->get();
return view('admin.category.add', ['category' => $category] );
}
}
(3)创建admin\category\add.blade.php视图文件,具体代码如下:
@extends('admin/layouts/admin')
@section('title', ' 添加栏目')
@section('main')
<div class="main-title"><h2>添加栏目</h2></div>
<div class="main-section">
<div style="width:543px">
<!-- 添加栏目表单 -->
<form method="post" action="{
{ url('/category/save') }}">
<div class="form-group row">
<label class="col-sm-2 col-form-label">序号</label>
<div class="col-sm-10">
<input type="number" name="sort" class="form-control" value="0" style="width:80px;">
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">上级栏目</label>
<div class="col-sm-10">
<select name="pid" class="form-control" style="width:200px;">
<option value="0">---</option>
@foreach ($category as $v)
<option value="{
{ $v->id }}"> {
{ $v->name }}</option>
@endforeach
</select>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">名称</label>
<div class="col-sm-10">
<input type="text" name="name" class="form-control" style="width:200px;">
</div>
</div>
<div class="form-group row">
<div class="col-sm-10">
{
{csrf_field()}}
<button type="submit" class="btn btn-primary mr-2">提交表单</button>
<a href="{
{url('category')}}" class="btn btn-secondary">返回列表</a>
</div>
</div>
</form>
</div>
</div>
<script>
main.menuActive('addcategory');
</script>
@endsection
(4)在routes\web.php文件中添加路由规则,具体代码如下:
// 栏目
Route::prefix('category')->namespace('Admin')->middleware(['Admin'])->group(function () {
Route::get('add', 'CategoryController@add');
});
(5)修改布局文件admin.blade.php,为添加栏目的导航添加链接,具体代码如下:
<a href="{
{ url('category/add') }}" data-name="addcategory"><i class="fa fa-list fa-fw"></i>添加</a>
(6)在Category控制器中编写save()方法,用于接收添加栏目的表单数据,具体代码如下:
public function save(Request $request){
$data = $request->all();
$this->validate($request,[
'name'=>'required|unique:category'.$rule,
],[
'name.required'=>'栏目名称不能为空',
'name.unique'=>'栏目名称不能重复'
]);
$re = Category::create($data);
if($re){
return redirect('category')->with('message','添加成功');
}else{
return redirect('category/add')->with('tip','添加失败');
}
}
(7)在routes\web.php文件中栏目的路由组中添加路由规则,具体代码如下:
Route::post('save', 'CategoryController@save');
3.显示栏目列表
(1)在Category控制器中创建index()方法,具体代码如下:
public function index(){
$category = $this->getTreeListCheckLeaf($data);
return view('admin.category.index', ['category' => $category]);
}
(2)在Category模型中添加getTreeListCheckLeaf()方法和treeList()方法,具体代码如下:
public function getTreeListCheckLeaf($data, $name = 'isLeaf')
{
$data = $this->treeList($data);
foreach ($data as $k => $v) {
foreach ($data as $vv) {
$data[$k][$name] = true;
if ($v['id'] === $vv['pid']) {
$data[$k][$name] = false;
break;
}
}
}
return $data;
}
public function treeList($data, $pid = 0, $level = 0, &$tree = [])
{
foreach ($data as $v) {
if ($v['pid'] == $pid) {
$v['level'] = $level;
$tree[] = $v;
$this->treeList($data, $v['id'], $level + 1, $tree);
}
}
return $tree;
}
(3)创建视图文件index.php,具体代码如下:
@extends('admin/layouts/admin')
@section('title', '栏目列表')
@section('main')
<div class="main-title"><h2>栏目管理</h2></div>
<div class="main-section form-inline">
<a href="{
{ url('category/add') }}" class="btn btn-success">+ 新增</a>
</div>
<div class="main-section">
<form method="post" action="" class="j-form">
<table class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th width="75">序号</th><th>名称</th><th width="100">操作</th>
</tr>
</thead>
<tbody>
<!-- 栏目列表 -->
@foreach($category)
<tr class="j-pid-{
{ $v['pid'] }}"
@if($v['level'])style="display:none"@endif>
<td><input type="text" class="form-control j-sort" maxlength="5" value="{
{$v['sort']}}" data-name="sort[{
{$v['id']}}]" style="height:25px;font-size:12px;padding:0 5px;"></td>
<td>
@if($v['level'])
<small class="text-muted">├──</small> {
{$v['name']}}
@else
<a href="#" class="j-toggle" data-id="{
{$v['id']}}">
@if(!$v['isLeaf'])
<i class="fa fa-plus-square-o fa-minus-square-o fa-fw"></i>
@endif
{
{$v['name']}}
</a>
@endif
</td>
<td>
<a href="{
{ url('category/edit', ['id' => $v['id']]) }}" style="margin-right:5px;">编辑</a>
<a href="{
{ url('category/delete', ['id' => $v['id']]) }}" class="j-del text-danger">删除</a>
</td>
</tr>
@endforeach
@if(empty($category))
<tr><td colspan="4" class="text-center">还没有添加栏目</td></tr>
@endif
</tbody>
</table>
{
{csrf_field()}}
<input type="submit" value="改变排序" class="btn btn-primary">
</form>
</div>
<script>
main.menuActive('category');
$('.j-toggle').click(function() {
var id = $(this).attr('data-id');
$(this).find('i').toggleClass('fa-plus-square-o');
$('.j-pid-' + id).toggle();
return false;
});
$('.j-sort').change(function() {
$(this).attr('name', $(this).attr('data-name'));
});
$('.j-del').click(function() {
if (confirm('您确定要删除此项?')) {
var data = { _token: '{
{ csrf_token() }}' };
main.ajaxPost({url:$(this).attr('href'), data: data}, function(){
location.reload();
});
}
return false;
});
</script>
@endsection
(4)在routes\web.php文件中栏目的路由组中添加栏目列表的路由规则,具体代码如下:
Route::get('', 'CategoryController@index');
(5)修改admin.blade.php,为列表菜单项添加链接,具体代码如下:
<a href="{
{ url('category') }}" data-name="category"><i class="fa fa-table fa-fw"></i>列表</a>
(6)通过浏览器访问,栏目列表的页面效果如下图所示:
(7) 在栏目列表页中,为了实现修改栏目的排序,需要设置栏目列表页中表单的提交地址,具体代码如下:
<form method="post" action="{
{ url('category/sort')}}" class="j-form">
(8)在routes\web.php文件中栏目的路由组中添加排序的路由规则,具体代码如下:
Route::post('sort', 'CategoryController@sort');
(9)在Category控制器中添加sort()方法,具体代码如下:
public function sort(Request $request){
$sort = $request->input('sort');
foreach ($sort as $k => $v) {
Category::where('id', (int)$k)->update(['sort' => (int)$v]);
}
return redirect('category')->with('message','改变排序成功');
}
(10)通过浏览器访问,观察栏目功能是否正确执行。
4.编辑栏目
(1)在列表页中为“编辑”按钮添加链接,具体代码如下:
<a href="{
{ url('category/edit', ['id' => $v['id']]) }}" style="margin-right:5px;">编辑</a>
(2)在routes\web.php文件中栏目的路由组中添加编辑栏目的路由规则,具体代码如下:
Route::get('edit/{id}', 'CategoryController@edit');
(3)在Category控制器中添加edit()方法,具体代码如下:
public function edit($id){
$data = [];
if ($id) {
if (!$data = Category::find($id)) {
return back()->with('tip', '记录不存在。');
}
}
$category = Category::where('pid', 0)->get();
return view('admin.category.edit', ['id'=>$id, 'data'=>$data, 'category' => $category]);
}
(4)创建视图文件edit.blade.php,具体代码如下:
@extends('admin/layouts/admin')
@section('title', '栏目列表')
@section('main')
<div class="main-title"><h2>编辑分类</h2></div>
<div class="main-section">
<div style="width:543px">
<!-- 编辑表单 -->
<form method="post" action="{
{ url('/category/save') }}">
<div class="form-group row">
<label class="col-sm-2 col-form-label">序号</label>
<div class="col-sm-10">
<input type="number" name="sort" class="form-control" value="{
{$data->sort}}" style="width:80px;">
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">上级分类</label>
<div class="col-sm-10">
<select name="pid" class="form-control" style="width:200px;">
<option value="0">---</option>
@foreach($category as $v)
<option value="{
{ $v->id }}" @if($data['pid'] == $v['id']) selected @endif> {
{ $v->name }}</option>
@endforeach
</select>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">名称</label>
<div class="col-sm-10">
<input type="text" name="name" class="form-control" value="{
{$data->name}}" style="width:200px;">
</div>
</div>
<div class="form-group row">
<div class="col-sm-10">
{
{csrf_field()}}
<input type="hidden" name="id" value="{
{$id}}">
<button type="submit" class="btn btn-primary mr-2">提交表单</button>
<a href="{
{url('category')}}" class="btn btn-secondary">返回列表</a>
{
{--<a href="{
{url('category')}}">--}}
{
{--<button class="btn btn-secondary">返回列表</button>--}}
{
{--</a>--}}
</div>
</div>
</form>
</div>
</div>
<script>
main.menuActive('category');
</script>
@endsection
(5)修改save()方法,根据栏目id更新栏目内容,具体代码如下:
public function save(Request $request){
$data = $request->all();
$rule = isset($data['id']) ? ',name,'.$data['id'] : '';
$this->validate($request,[
'name'=>'required|unique:category'.$rule,
],[
'name.required'=>'栏目名称不能为空',
'name.unique'=>'栏目名称不能重复'
]);
if(isset($data['id'])){
$id = $data['id'];
unset($data['id']);
unset($data['_token']);
$res = Category::where('id',$id)->update($data);
$type = $res ? "message" : "tip";
$message = $res ? "修改成功" : "修改失败";
return redirect('category')->with($type, $message);
}
$re = Category::create($data);
if($re){
return redirect('category')->with('message','添加成功');
}else{
return redirect('category/add')->with('tip','添加失败');
}
}
5.删除栏目
(1)在列表页中为“删除”按钮添加链接,具体代码如下:
<a href="{
{ url('category/delete', ['id' => $v['id']]) }}" class="j-del text-danger">删除</a>
(2)在Category控制器中添加delete()方法,具体代码如下:
public function delete($id){
if (!$category = Category::find($id)) {
return response()->json(['code' => 0, 'msg' => '删除失败,记录不存在。' ]);
}
$category->delete();
return response()->json(['code' => 1, 'msg' => '删除成功' ]);
}
(3)在routes\web.php文件的栏目路由组中添加删除栏目的路由规则,具体代码如下:
Route::post('delete/{id}', 'CategoryController@delete');
四.内容管理
1.创建内容表
(1)按照上述的步骤创建内容表对应的迁移文件后,在迁移文件的up()方法中添加表结构信息,具体代码如下:
public function up()
{
Schema::create('content', function (Blueprint $table) {
$table->increments('id')->comment('主键');
$table->integer('cid')->comment('栏目id')->default(0);
$table->string('title', 255)->comment('标题');
$table->text('content', 255)->comment('内容');
$table->char('image', 255)->comment('图片');
$table->tinyInteger('status')->comment('状态默认1推荐2')->default(1);
$table->timestamps();
});
}
(2)创建内容表对应的模型文件,具体代码如下:
php artisan make:model Content
(3)执行上述命令后,会自动创建app\Content.php文件,具体代码如下:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Content extends Model
{
protected $table = "content";
public $fillable = ['cid', 'title', 'content', 'image', 'status'];
}
2.添加内容
(1)创建Content控制器,具体代码如下:
php artisan make:controller Admin\ContentController
(2)在控制器中引入add()方法用于实现添加内容的功能,save()方法保存添加的内容,具体代码如下:
public function add()
{
$data = Category::orderBy('sort', 'asc')->get()->toArray();
$cate = new CategoryController();
$category = $cate->getTreeListCheckLeaf($data);
return view('admin.content.add', ['category' => $category]);
}
public function save(Request $request)
{
$data = $request->all();
$this->validate($request,[
'cid'=>'required',
'title'=>'required'
],[
'cid.require'=>'分类不能为空',
'title.require'=>'标题不能为空'
]);
if(isset($data['id'])){
$id = $data['id'];
unset($data['id']);
unset($data['_token']);
$res = Content::where('id',$id)->update($data);
$type = $res ? "message" : "tip";
$message = $res ? "修改成功" : "修改失败";
return redirect('content')->with($type, $message);
}
$re = Content::create($data);
if($re){
return redirect('content')->with('message','添加成功');
}else{
return redirect('content/add')->with('tip','添加失败');
}
}
(3)在控制器中导入Category模型的命名空间和Content的命名空间,具体代码如下:
use App\Category;
use App\Content;
(4)创建resources\views\admin\content\add.blade.php视图文件,具体代码如下:
@extends('admin/layouts/admin')
@section('title', '添加内容')
@section('main')
<div class="main-title"><h2>添加内容</h2></div>
<div class="main-section">
<div style="width:80%">
<!-- 添加内容表单 -->
<form method="post" action="{
{ url('/content/save') }}" class="j-form">
<div class="form-group row">
<label class="col-sm-2 col-form-label">所属分类</label>
<div class="col-sm-10">
<select name="cid" class="form-control" style="width:200px;">
<!-- 分类下拉列表 -->
@foreach($category as $v)
@if($v['level'])
<option value="{
{$v['id']}}">
<small class="text-muted">├──</small>{
{$v['name']}}
</option>
@else
<option value="{
{$v['id']}}"> {
{$v['name']}}</option>
@endif
@endforeach
</select>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">标题</label>
<div class="col-sm-10">
<input type="text" name="title" class="form-control" style="width:200px;">
</div>
</div>
<!-- 上传图片按钮 -->
<div class="form-group row">
<label class="col-sm-2 col-form-label">图片</label>
<div class="col-sm-10">
<input type="file" id="file1" name="image" value="上传图片" multiple="true">
</div>
<div class="col-sm-10 offset-sm-2">
<div class="upload-img-box" id="uploadImg"></div>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">简介</label>
<div class="col-sm-10">
<!-- <textarea class="j-goods-content" name="content" style="height:500px"></textarea> -->
<script type="text/plain" class="j-goods-content" name="content" style="height:500px"></script>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">状态</label>
<div class="col-sm-10">
<div class="form-check form-check-inline" style="height:38px">
<input class="form-check-input" id="inlineRadio1" type="radio" name="status" value="1" checked>
<label class="form-check-label" for="inlineRadio1">默认</label>
</div>
<div class="form-check form-check-inline" style="height:38px">
<input class="form-check-input" id="inlineRadio2" type="radio" name="status" value="2">
<label class="form-check-label" for="inlineRadio2">推荐</label>
</div>
</div>
</div>
<div class="form-group row">
<div class="col-sm-10">
{
{csrf_field()}}
<button type="submit" class="btn btn-primary mr-2">提交表单</button>
<a href="{
{url('content')}}" class="btn btn-secondary">返回列表</a>
</div>
</div>
</form>
</div>
</div>
<link href="{
{asset('admin')}}/common/uploader/uploadifive.css" rel="stylesheet" />
<script src="{
{asset('admin')}}/common/uploader/jquery.uploadifive.js"></script>
<script src="{
{asset('admin')}}/common/editor/ueditor1.4.3.3/ueditor.config.js"></script>
<script src="{
{asset('admin')}}/common/editor/ueditor1.4.3.3/ueditor.all.min.js"></script>
<script src="{
{asset('admin')}}/common/editor/main.editor.js"></script>
<script>
main.menuActive('addcontent');
$(function() {
$('#file1').uploadifive({
'auto' : true,
'fileObjName' : 'image',
'fileType' : 'image',
'buttonText' : '上传图片',
'formData' : { '_token' : "{
{ csrf_token() }}" },
'method' : 'post',
'queueID' : 'uploadImg',
'removeCompleted' : true,
'uploadScript' : '{
{ url('content/upload')}}',
'onUploadComplete': uploadPicture_icon
});
});
function uploadPicture_icon(file, data) {
var obj = $.parseJSON(data);
var src = '';
if (obj.code) {
filename = obj.data.filename;
path = obj.data.path;
$('.upload-img-box').empty();
$('.upload-img-box').html(
'<div class="upload-pre-item" style="max-height:100%;"><img src="' + path + '" style="width:100px;height:100px"/> <input type="hidden" name="image" value="'+filename+'" class="icon_banner"/></div>'
);
} else {
alert(data.info);
}
}
main.editor($('.j-goods-content'), 'goods_edit', function(opt) {
opt.UEDITOR_HOME_URL = '{
{asset('admin')}}/common/editor/ueditor1.4.3.3/';
}, function(editor) {
$('.j-form').submit(function() {
editor.sync();
});
});
</script>
@endsection
(5)在routes\web.php文件在添加内容管理的路由组,具体代码如下:
Route::prefix('content')->namespace('Admin')->middleware(['Admin'])->group(function () {
Route::get('add', 'ContentController@add');
Route::post('save', 'ContentController@save');
});
(6)修改admin.blade.php,为添加内容的菜单项添加链接,具体代码如下:
<a href="{
{ url('content/add') }}" data-name="addcontent">
<i class="fa fa-list fa-fw"></i>添加</a>
3.上传图片
(1)在添加内容的视图中添加上传图片的按钮,具体代码如下:
<div class="form-group row">
<label class="col-sm-2 col-form-label">图片</label>
<div class="col-sm-10">
<input type="file" id="file1" name="image" value="上传图片" multiple="true">
</div>
<div class="col-sm-10 offset-sm-2">
<div class="upload-img-box" id="uploadImg"></div>
</div>
</div>
(2)在视图中引入上传文件所需的样式和JavaScript代码,具体代码如下:
<link href="{
{asset('admin')}}/common/uploader/uploadifive.css" rel="stylesheet" />
<script src="{
{asset('admin')}}/common/uploader/jquery.uploadifive.js"></script>
<script src="{
{asset('admin')}}/common/uploader/jquery.uploadifive.min.js"></script>
(3)在Content控制器中编写upload()方法,具体代码如下:
public function upload(Request $request)
{
if ($request->hasFile('image')) {
$image = $request->file('image');
if ($image->isValid()) {
$name = md5(microtime(true)) . '.' . $image->extension();
$image->move('static/upload', $name);
$path = '/static/upload/' . $name;
$returndata = array(
'filename' => $name,
'path' => $path
);
$result = [
'code' => 1,
'msg' => '上传成功',
'time' => time(),
'data' => $returndata,
];
return response()->json($result);
}
return $image->getErrorMessage();
}
return '文件上传失败';
}
(4)在routes\web.php文件中内容的路由组中添加上传图片的路由规则,具体代码如下:
Route::post('upload', 'ContentController@upload');
4.整合UFditor
(1)创建public\admin\common\editor\main.editor.js文件,具体代码如下:
(function($, main) {
var def = {
UEDITOR_HOME_URL: '', // UEditor URL
serverUrl: '', // UEditor内置上传地址设为空
autoHeightEnabled: false, // 关闭自动调整高度
wordCount: false, // 关闭字数统计
toolbars: [['fullscreen', 'source', '|', // 自定义工具栏按钮
'undo', 'redo', '|', 'bold', 'italic', 'underline', 'strikethrough',
'forecolor', 'backcolor', 'fontfamily', 'fontsize', 'paragraph', 'link',
'blockquote', 'insertorderedlist', 'insertunorderedlist', '|',
'inserttable', 'insertrow', 'insertcol', '|', 'drafts']]
};
var instances = {};
main.editor = function(obj, id, before, ready) {
var opt = $.extend(true, {}, def);
before(opt);
if (instances[id]) {
instances[id].destroy();
$('#' + id).removeAttr('id');
}
return instances[id] = createEditor(obj, id, opt, ready);
};
function createEditor(obj, id, opt, ready) {
obj.attr('id', id);
var editor = UE.getEditor(id, opt);
editor.ready(function() {
ready(editor);
});
return editor;
}
}(jQuery, main));
(2)在add.blade.php文件中引入编辑器相关的文件,具体代码如下:
<script src="{
{asset('admin')}}/common/editor/ueditor1.4.3.3/ueditor.config.js"></script>
<script src="{
{asset('admin')}}/common/editor/ueditor1.4.3.3/ueditor.all.min.js"></script>
<script src="{
{asset('admin')}}/common/editor/main.editor.js"></script>
5.显示内容列表
(1)在Content控制器中编写index()方法,具体代码如下:
public function index($id = 0)
{
$data = Category::orderBy('sort', 'asc')->get()->toArray();
$cate = new CategoryController();
$category = $cate->getTreeListCheckLeaf($data);
$content = Content::get();
if ($id) {
$content = Content::where('cid', $id)->get();
}
return view('admin.content.index', ['category' => $category, 'content' => $content, 'cid' => $id]);
}
(2)在展示内容时,需显示内容对应的栏目,因此在Content模型中添加关联模型,具体代码如下:
public function category()
{
return $this->belongsTo('App\Category', 'cid', 'id');
}
(3)创建resources\views\admin\content\index.blade.php文件,具体代码如下:
@extends('admin/layouts/admin')
@section('title', '内容列表')
@section('main')
<div class="main-title"><h2>内容管理</h2></div>
<div class="main-section form-inline">
<a href="{
{ url('content/add') }}" class="btn btn-success">+ 新增</a>
<!-- 此处编写分类下拉菜单 -->
<select class="j-select form-control" style="min-width:120px;margin-left:8px">
<option value="{
{ url('content', ['id' => 0]) }}">所有分类</option>
@foreach($category as $v)
@if($v['level'])
<option value="{
{ url('content', ['d' => $v['id']]) }}" data-id="{
{$v['id']}}">
<small class="text-muted">--</small> {
{$v['name']}}
</option>
@else
<option value="{
{ url('content', ['id' => $v['id']]) }}" data-id="{
{$v['id']}}">
{
{$v['name']}}
</option>
@endif
@endforeach
</select>
</div>
<div class="main-section">
<form method="post" action="{
{ url('category/sort')}}" class="j-form">
<table class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th width="75">序号</th><th>分类</th><th>图片</th><th>标题</th>
<th>状态</th><th>创建时间</th><th width="100">操作</th>
</tr>
</thead>
<tbody>
@foreach($content as $v)
<!-- 此处编写内容列表代码 -->
<tr class="j-pid-{
{ $v->pid }}" @if($v->level)style="display:none"@endif>
<td>{
{ $v->id }}</td>
<td>{
{ $v->category->name}}</td>
<td><img @if($v->image) src="/static/upload/{
{ $v->image}}" @else src="{
{asset('admin')}}/img/noimg.png" @endif width="50" height="50"></td>
<td>{
{ $v->title }}</td>
<td>@if($v->status==1) 默认 @else 推荐 @endif</td>
<td>{
{ $v->created_at }}</td>
<td><a href="{
{ url('content/edit', ['id' => $v->id ]) }}" style="margin-right:5px;">编辑</a>
<a href="{
{ url('content/delete', ['id' => $v->id ]) }}" class="j-del text-danger">删除</a>
</td>
</tr>
@endforeach
@if(empty($content))
<tr><td colspan="7" class="text-center">还没有添加内容</td></tr>
@endif
</tbody>
</table>
{
{csrf_field()}}
</form>
</div>
<script>
main.menuActive('content');
$('.j-select').change(function() {
location.href = $(this).val();
});
$('option[data-id=' + {
{$cid}} + ']').attr('selected', true);
$('.j-del').click(function() {
if (confirm('您确定要删除此项?')) {
var data = { _token: '{
{ csrf_token() }}' };
main.ajaxPost({url:$(this).attr('href'), data: data}, function(){
location.reload();
});
}
return false;
});
</script>
@endsection
(4)在routes\web.php文件中添加内容列表页的路由,具体代码如下:
Route::get('{id?}', 'ContentController@index');
6.编辑内容
(1)在内容列表页中为“编辑”按钮添加链接,具体代码如下:
<a href="{
{ url('content/edit', ['id' => $v->id ]) }}" style="margin-right:5px;">编辑</a>
(2)在Content控制器中添加edit()方法,具体代码如下:
public function edit(Request $request)
{
$id = $request->id;
$data = Category::orderBy('sort', 'asc')->get()->toArray();
$cate = new CategoryController();
$category = $cate->getTreeListCheckLeaf($data);
$content = Content::find($id);
return view('admin.content.edit', ['category' => $category, 'content' => $content]);
}
(3)在routes\web.php文件中添加内容列表页的路由,具体代码如下:
Route::get('edit/{id}', 'ContentController@edit');
7.删除内容
(1)在内容列表页为“删除”按钮添加链接,具体代码如下:
<a href="{
{ url('content/delete', ['id' => $v->id ]) }}" class="j-del text-danger">删除</a>
(2)在routes\web.php文件中添加删除内容的路由,具体代码如下:
Route::post('delete/{id}', 'ContentController@delete');
(3)在Content控制器中添加delete()方法,具体代码如下:
public function delete($id)
{
if (!$content = Content::find($id)) {
return response()->json(['code' => 0, 'msg' => '删除失败,记录不存在。' ]);
}
$content->delete();
return response()->json(['code' => 1, 'msg' => '删除成功' ]);
}
五.广告位管理
1.创建广告位表
(1)创建广告位表对应的迁移文件后,在迁移文件的up()方法中添加表结构信息,具体代码如下:
public function up()
{
Schema::create('adv', function (Blueprint $table) {
$table->increments('id')->comment('主键');
$table->string('name', 32)->comment('广告位名称');
$table->timestamps();
});
}
(2)创建广告位表对应的模型文件,具体代码如下:
php artisan make:model Adv
(3)执行上述命令后,会自动创建app\Adv.php文件,具体代码如下:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Adv extends Model
{
protected $table = "adv";
public $fillable = ['name'];
}
2.添加广告位
(1)创建Adv控制器,具体代码如下:
php artisan make:controller Admin\AdvController
(2)在控制器中添加add()方法用于实现添加广告位的功能,添加save()方法用于保存添加的广告位,具体代码如下:
public function add($id = 0){
$data = [];
if($id > 0){
$data = Adv::find($id);
}
return view('admin.adv.add', ['data' => $data]);
}
public function save(Request $request){
$data = $request->all();
$this->validate($request,[
'name'=>'required'
],[
'name.require'=>'名称不能为空'
]);
if(isset($data['id'])){
$id = $data['id'];
unset($data['id']);
unset($data['_token']);
$res = Adv::where('id',$id)->update($data);
$type = $res ? "message" : "tip";
$message = $res ? "修改成功" : "修改失败";
return redirect('adv')->with($type, $message);
}
$re = Adv::create($data);
if($re){
return redirect('adv')->with('message','添加成功');
}else{
return redirect('adv/add')->with('tip','添加失败');
}
}
(3)在控制器中引入Adv的命名空间。具体代码如下:
use App\Adv;
(4)在routes\web.php中添加广告位管理的路由组,具体代码如下:
//广告
Route::prefix('adv')->namespace('Admin')->middleware(['Admin'])->group(function () {
Route::get('add/{id?}', 'AdvController@add');
Route::post('save', 'AdvController@save');
});
3.显示、编辑、删除广告位列表
(1)修改admin.blade.php,为广告位菜单项添加链接,具体代码如下:
<a href="{
{url('adv')}}" data-name="adv">
<i class="fa fa-list fa-fw"></i>广告位</a>
(2)在routes\web.php中添加广告位列表的路由,具体代码如下:
Route::get('', 'AdvController@index');
route::post('delete/{id}','AdvController@delete');
(3)在Adv控制器中编写index()方法和delete()方法,具体代码如下:
public function index(){
$adv = Adv::all();
return view('admin.adv.index', ['adv' => $adv]);
}
public function delete($id){
if (!$content = Adv::find($id)) {
return response()->json(['code' => 0, 'msg' => '删除失败,记录不存在。' ]);
}
if(Advcontent::where('advid', '=', $id)->exists()){
return response()->json(['code' => 0, 'msg' => '该广告位下有广告记录,请先删除广告内容。' ]);
}
$content->delete();
return response()->json(['code' => 1, 'msg' => '删除成功' ]);
}
(4)创建index.blade.php文件,具体代码如下:
@extends('admin/layouts/admin')
@section('title', '广告位列表')
@section('main')
<div class="main-title"><h2>广告位管理</h2></div>
<div class="main-section form-inline">
<a href="{
{ url('adv/add') }}" class="btn btn-success">+ 新增</a>
</div>
<div class="main-section">
<table class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th width="75">序号</th><th>广告位名称</th><th width="100">操作</th>
</tr>
</thead>
<tbody>
<!-- 广告位列表-->
@foreach($adv as $v)
<tr class="j-pid-{
{ $v['pid'] }}">
<td><input type="text" value="{
{$v->id}}" class="form-control j-sort" maxlength="5" style="height:25px;font-size:12px;padding:0 5px;"></td>
<td>{
{$v->name}}</td>
<td>
<a href="{
{ url('adv/add', ['id' => $v->id]) }}" style="margin-right:5px;">编辑</a>
<a href="{
{ url('adv/delete', ['id' => $v->id]) }}" class="j-del text-danger">删除</a>
</td>
</tr>
@endforeach
@if(empty($adv))
<tr><td colspan="4" class="text-center">还没有添加广告位</td></tr>
@endif
</tbody>
</table>
</div>
<script>
main.menuActive('adv');
$('.j-del').click(function() {
if (confirm('您确定要删除此项?')) {
var data = { _token: '{
{ csrf_token() }}' };
main.ajaxPost({url:$(this).attr('href'), data: data}, function(){
location.reload();
});
}
return false;
});
</script>
@endsection
(5)在浏览器访问,其效果如下图:
(6)通过浏览器访问,单机“删除”按钮删除广告位,查看广告位是否删除成功。
六.广告内容管理
1.创建广告内容表
(1)创建广告内容表的迁移文件,在迁移文件的up()方法中添加表结构信息,具体代码如下:
public function up()
{
Schema::create('adcontent', function (Blueprint $table) {
$table->increments('id')->comment('主键');
$table->integer('advid')->comment('广告位id');
$table->integer('path')->comment('图片路径');
$table->timestamps();
});
}
(2)下面创建内容表对应的模型文件,具体代码如下:
php artisan make:model Advcontent
(3)执行上述命令后,会自动创建app\Advcontent.php文件,在文件中编写如下代码:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Advcontent extends Model
{
protected $table = "adcontent";
public $fillable = ['advid','path'];
}
2.添加、显示、编辑、删除广告
(1)创建Advcontent控制器,具体代码如下:
php artisan make:controller Admin\AdvcontentController
(2)在控制器中添加add()方法用于实现添加广告的功能,添加save()方法用于保存广告内容,添加upload()方法用于保存上传的广告图片,添加index()方法,添加delete()方法,具体代码如下:
public function add($id = 0){
$data = [];
if($id > 0){
$data = Advcontent::find($id);
if($data['path']){
$data['path'] = explode("|", $data['path']);
}else{
$data['path'] = [];
}
}
$position = Adv::all();
return view('admin.advcontent.add', ['data' => $data, 'position' => $position]);
}
public function save(Request $request){
$data = $request->all();
$path = '';
foreach($data['path'] as $v){
$path .= $v . "|";
}
$data['path'] = substr($path,0,-1);
if(isset($data['id'])){
$id = $data['id'];
unset($data['id']);
unset($data['_token']);
$res = Advcontent::where('id',$id)->update($data);
$type = $res ? "message" : "tip";
$message = $res ? "修改成功" : "修改失败";
return redirect('advcontent')->with($type, $message);
}
$re = Advcontent::create($data);
if($re){
return redirect('advcontent')->with('message','添加成功');
}else{
return redirect('advcontent/add')->with('tip','添加失败');
}
}
public function upload(Request $request){
if ($request->hasFile('image')) {
$image = $request->file('image');
if ($image->isValid()) {
$name = md5(microtime(true)) . '.' . $image->extension();
$image->move('static/upload', $name);
$path = '/static/upload/' . $name;
$returndata = array(
'filename' => $name,
'path' => $path
);
$result = [
'code' => 1,
'msg' => '上传成功',
'time' => time(),
'data' => $returndata,
];
return response()->json($result);
}
return $image->getErrorMessage();
}
return '文件上传失败';
}
public function index(){
$adv = Advcontent::all();
foreach($adv as $v){
if($v['path']){
$v['path'] = explode("|", $v['path']);
}else{
$v['path'] = [];
}
}
return view('admin.advcontent.index', ['adv' => $adv]);
}
public function delete($id){
if (!$content = Advcontent::find($id)) {
return response()->json(['code' => 0, 'msg' => '删除失败,记录不存在。' ]);
}
$content->delete();
return response()->json(['code' => 1, 'msg' => '删除成功' ]);
}
(3)在控制器中引入广告位的命名空间,具体代码如下:
use App\Advcontent;
use App\Adv;
(4)创建resources\views\admin\advcontent\add.blade.php视图文件,具体代码如下:
@extends('admin/layouts/admin')
@section('title', '添加广告')
@section('main')
<div class="main-title"><h2><div class="main-title"><h2>@if(!empty($data))编辑@else添加@endif广告</h2></div>
<div class="main-section">
<div style="width:543px">
<form method="post" action="{
{ url('/advcontent/save') }}">
<div class="form-group row">
<label class="col-sm-3 col-form-label">选择广告位</label>
<div class="col-sm-9">
<!-- 广告位列表 -->
<select name="advid" class="form-control" style="width:200px;">
@foreach ($position as $v)
<option value="{
{ $v->id }}" @if(isset($data->advposid) && $data->advposid == $v->id) selected @endif>
{
{ $v->name }}
</option>
@endforeach
</select>
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label">上传图片</label>
<div class="col-sm-9">
<input type="file" id="file1" name="path" value="上传图片">
</div>
<div class="col-sm-9 offset-sm-3">
<div class="upload-img-box" id="uploadImg">
@if(isset($data->path))
<div class="upload-pre-item" style="max-height:100%;">
@foreach ($data->path as $val)
<img src="/static/upload/{
{$val}}"
style="width:100px;height:100px"/>
<input type="hidden" name="path[]" value="{
{$val}}"
class="icon_banner"/>
@endforeach
</div>
@endif
</div>
</div>
</div>
<div class="form-group row">
<div class="col-sm-9">
{
{csrf_field()}}
@if(isset($data['id'])) <input type="hidden" name="id" value="{
{$data->id}}"> @endif
<button type="submit" class="btn btn-primary mr-2">提交表单</button>
<a href="{
{ url('advcontent') }}" class="btn btn-secondary">返回列表</a>
</div>
</div>
</form>
</div>
</div>
<link href="{
{asset('admin')}}/common/uploader/uploadifive.css" rel="stylesheet" />
<script src="{
{asset('admin')}}/common/uploader/jquery.uploadifive.js"></script>
<script>
main.menuActive('advcontent');
$(function(){
$('#file1').uploadifive({
'auto' : true,
'fileObjName' : 'image',
'fileType' : 'image',
'buttonText' : '上传图片',
'formData' : { '_token' : "{
{ csrf_token() }}" },
'method' : 'post',
'queueID' : 'uploadImg',
'removeCompleted' : true,
'uploadScript' : '{
{ url('advcontent/upload')}}',
'onUploadComplete' : uploadPicture_icon
});
});
function uploadPicture_icon(file, data) {
var obj = $.parseJSON(data);
var src = '';
if (obj.code) {
filename = obj.data.filename;
path = obj.data.path;
if ($('.upload-pre-item').length > 0) {
$('.upload-pre-item').append(
'<img src="' + path + '" style="width:100px;height:100px"/> <input type="hidden" name="path[]" value="'+filename+'" class="icon_banner"/>'
);
} else {
$('.upload-img-box').append(
'<div class="upload-pre-item" style="max-height:100%;"><img src="' + path + '" style="width:100px;height:100px"/> <input type="hidden" name="path[]" value="'+filename+'" class="icon_banner"/></div>'
);
}
} else {
alert(data.info);
}
}
</script>
@endsection
(5)创建index.php文件,具体代码如下:
@extends('admin/layouts/admin')
@section('title', '广告内容管理')
@section('main')
<div class="main-title"><h2>广告内容管理</h2></div>
<div class="main-section form-inline">
<a href="{
{ url('advcontent/add') }}" class="btn btn-success">+ 新增</a>
</div>
<div class="main-section">
<table class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th width="75">序号</th><th>广告位名称</th><th>广告图片</th><th width="100">操作</th>
</tr>
</thead>
<tbody>
<!-- 广告位列表 -->
@foreach($adv as $v)
<tr class="j-pid-{
{ $v['pid'] }}">
<td><input type="text" value="{
{$v->id}}" class="form-control j-sort" maxlength="5" style="height:25px;font-size:12px;padding:0 5px;"></td>
<td>{
{$v->position->name}}</td>
<td>
@foreach($v->path as $val)
<img src="/static/upload/{
{$val}}" style="height:40px;width: 50px">
@endforeach
</td>
<td><a href="{
{ url('advcontent/add', ['id' => $v->id]) }}" style="margin-right:5px;">编辑</a>
<a href="{
{ url('advcontent/delete', ['id' => $v->id]) }}" class="j-del text-danger">删除</a>
</td>
</tr>
@endforeach
@if(empty($adv))
<tr><td colspan="4" class="text-center">还没有添加广告内容</td></tr>
@endif
</tbody>
</table>
</div>
<script>
main.menuActive('advcontent');
$('.j-del').click(function() {
if (confirm('您确定要删除此项?')) {
var data = { _token: '{
{ csrf_token() }}' };
main.ajaxPost({url:$(this).attr('href'), data: data}, function(){
location.reload();
});
}
return false;
});
</script>
@endsection
(6)在routes\web.php中添加广告位管理的路由组,具体代码如下:
//广告列表
Route::prefix('advcontent')->namespace('Admin')->middleware(['Admin'])->group(function () {
Route::get('add/{id?}', 'AdvcontentController@add');
Route::post('save', 'AdvcontentController@save');
Route::post('upload','AdvcontentController@upload');
Route::get('', 'AdvcontentController@index');
route::post('delete/{id}','AdvcontentController@delete');
});
(7)修改app\Advcontent.php,设置关联模型,获取广告位信息,具体代码如下:
public function position()
{
return $this->belongsTo('App\Adv', 'advid', 'id');
}
(8)在Adv控制器中引入Advcontent的命名空间,具体代码如下:
use App\Content;
(9)通过浏览器访问,可以对广告内容进行显示、编辑、删除的操作。
结语
综上所述便是使用Laravel框架实现内容管理系统的后台功能。项目展示图片如下图:
前台首页
一、页面布局
(1)在resources\views目录下创建public目录,该目录用于保存公共文件,在该目录下创建static.blade.php,用于保存静态文件,具体代码如下:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{
{asset('home')}}/common/twitter-bootstrap/4.4.1/css/bootstrap.min.css">
<link rel="stylesheet" href="{
{asset('home')}}/common/font-awesome-4.2.0/css/font-awesome.min.css">
<link rel="stylesheet" href="{
{asset('home')}}/css/main.css">
<script src="{
{asset('home')}}/common/jquery/1.12.4/jquery.min.js"></script>
<script src="{
{asset('home')}}/common/twitter-bootstrap/4.4.1/js/bootstrap.min.js"></script>
(2)创建header.blade.php文件,具体代码如下:
<div class="header">
<header>
<div class="container">
<a href="{
{url("/")}}" style="color:#000000">
<div class="header-logo"><span>内容</span>管理系统</div>
</a>
<ul class="header-right">
@if(session()->has('users.name'))
<li>
<a href="#" class="j-layout-pwd">
<i class="fa fa-user fa-fw"></i>{
{ session()->get('users.name') }}
</a>
</li>
<li><a href="{
{ url('logout') }}"><i class="fa fa-power-off fa-fw"></i>退出</a></li>
@else
<li><a href="#" data-toggle="modal" data-target="#loginModal">登录</a></li>
<li><a href="#" data-toggle="modal" data-target="#registerModal">注册</a></li>
@endif
</ul>
</div>
</header>
<!-- 栏目列表 -->
<nav class="navbar navbar-expand-md navbar-dark">
<div class="container">
<div></div>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-expanded="false" aria-controls="navbarSupportedContent" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="/">首页</a>
</li>
@foreach($category as $v)
@if(isset($v['sub']))
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{
{$v['name']}}
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
@foreach($v['sub'] as $val)
<a class="dropdown-item" href="{
{url('lists', ['id' => $val['id']] )}}">{
{$val['name']}}</a>
@endforeach
</div>
</li>
@else
<li class="nav-item">
<a class="nav-link" href="{
{url('lists', ['id' => $v['id']] )}}">{
{$v['name']}}</a>
</li>
@endif
@endforeach
</ul>
</div>
</div>
</nav>
</div>
<!-- 登录表单 --->
<div class="modal fade" id="loginModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">登录</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="username">用户名</label>
<input type="text" name="name" class="form-control" id="username">
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" name="password" class="form-control" id="password">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
<button type="submit" class="btn btn-primary" id="login">登录
</button>
</div>
</div>
</div>
</div>
<!-- 注册表单 --->
<div class="modal fade" id="registerModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">注册</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="username1">用户名</label>
<input type="text" name="name" class="form-control" id="username1">
</div>
<div class="form-group">
<label for="email">邮箱</label>
<input type="email" name="email" class="form-control" id="email">
</div>
<div class="form-group">
<label for="password1">密码</label>
<input type="password" name="password" class="form-control" id="password1">
</div>
<div class="form-group">
<label for="confirm">确认密码</label>
<input type="password" class="form-control" id="confirm">
</div>
</div>
<div class="modal-footer">
{
{csrf_field()}}
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
<button type="submit" class="btn btn-primary" id="register">立即注册</button>
</div>
</div>
</div>
</div>
<script>
$("#login").bind("click",function(){
var data = {
'name' : $("#username").val(),
'password' : $("#password").val(),
'_token' : "{
{ csrf_token() }}"
};
$.post("{
{ url('login') }}", data, function(result){
if (result.status == 1) {
alert(result.msg);
window.location.reload();
} else {
alert(result.msg);
return;
}
});
});
$("#register").bind("click",function(){
var data = {
'name' : $("#username1").val(),
'email' : $("#email").val(),
'password' : $("#password1").val(),
' password_confirmation' : $("#confirm").val(),
'_token' : "{
{ csrf_token() }}"
};
$.post("{
{ url('register') }}", data, function(result){
if (result.status == 1) {
alert(result.msg);
$('#registerModal').modal('hide');
location.reload();
} else {
alert(result.msg);
return;
}
});
});
</script>
(3)创建resources\views\common\footer.blade.php文件,该文件用于保存页面底部的内容,具体代码如下:
<div class="footer">
<div class="container">内容管理系统</div>
</div>
二、首页、栏目导航、轮播图、广告位、栏目内容展示
(1)创建首页视图,在resources\views目录下创建index.blade.php,具体代码如下:
<!DOCTYPE html>
<html>
<head>
@include('public/static')
<title>首页</title>
</head>
<body>
@include('public/header')
<div class="main">
<div class="container">
<div class="row mt-4">
<!-- 轮播图 -->
<div class="col-md-6 main-carousel">
<div id="carouselExampleCaptions" class="carousel slide" data-ride="carousel">
<div class="carousel-inner">
@foreach($recommend as $k=>$con)
<div class="carousel-item @if($k==0) active @endif">
<img src="/static/upload/{
{$con->image}}" class="d-block w-100">
<a href="{
{url('detail', ['id'=> $con->id])}}">
<div class="carousel-caption d-none d-md-block">
<h5>{
{$con->title}}</h5>
<p></p>
</div>
</a>
</div>
@endforeach
</div>
<a class="carousel-control-prev" href="#carouselExampleCaptions" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#carouselExampleCaptions" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
</div>
<!-- 广告位 -->
<div class="col-md-6">
<div class="row main-imgbox">
@foreach($adv as $adval)
<div class="col-md-6">
<a href="#"><img class="img-fluid" src="/static/upload/{
{$adval}}"></a>
</div>
@endforeach
</div>
</div>
</div>
<div class="row">
<div class="col-md-9">
<div class="row">
<!-- 栏目内容 -->
@foreach($list as $value)
<div class="col-md-6 mb-4">
<div class="card main-card">
<div class="card-header">
<h2>{
{$value->name}}</h2>
<span class="float-right">
<a href="{
{ url('lists', ['id' => $value->id ])}}">[ 查看更多 ]</a>
</span>
</div>
@foreach($value->content as $val)
<div class="card-body">
<div class="main-card-pic">
<a href="{
{url('detail', ['id'=> $val->id])}}">
<img class="img-fluid" src="/static/upload/{
{$val->image}}">
<span><i class="fa fa-search"></i></span>
</a>
</div>
<div class="main-card-info">
<span><i class="fa fa-calendar"></i>
{
{ date('Y-m-d', strtotime($val->created_at)) }}</span>
</div>
<h3><a href="{
{url('detail', ['id'=> $val->id])}}">{
{$val->title}}</a></h3>
<div class="main-card-desc">{!!str_limit($val->content , 100)!!}</div>
</div>
@endforeach
</div>
</div>
@endforeach
</div>
</div>
<div class="col-md-3">
<!-- 侧边栏 -->
@include('public/sidebar')
</div>
</div>
</div>
</div>
@include('public/footer')
</body>
</html>
(2)创建Index控制器,具体代码如下:
php artisan make:controller IndexController
(3)在控制器中添加方法,具体代码如下:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Category;
use App\Content;
use App\Adv;
use App\Like;
use App\Comment;
use Illuminate\Support\Facades\DB;
class IndexController extends Controller
{
public function index()
{
$this->navBar();
$this->hotContent();
$recommend = Content::where('status', '2')->get(); // 新增代码
$advcontent = [];
$advlist = Adv::where('name', 'imgbox')->get();
foreach ($advlist as $key => $value) {
foreach ($value->content as $k => $v) {
$advcontent= explode('|', $v->path);
}
}
$list = Category::orderBy('id', 'desc')->get()->take(4);
return view('index', ['recommend' => $recommend, 'adv' => $advcontent, 'list' => $list]);
}
protected function navBar(){
$data = Category::orderBy('sort', 'asc')->get()->toArray();
$category = $sub = [];
foreach($data as $k=>$v){
if ($v['pid'] != 0) {
$sub[$v['id']] = $v;
}
}
foreach($data as $key=>$val){
if ($val['pid'] == 0) {
$category[$key] = $val;
}
foreach($sub as $subv) {
if ($subv['pid'] == $val['id']) {
$category[$key]['sub'][] = $subv;
}
}
}
return view()->share('category', $category);
}
public function lists($id)
{
if(!$id){
return redirect('/')->with('tip','缺少参数');
}
$this->navBar();
$this->hotContent();
$content = Content::where('cid', $id)->paginate(4);
return view('lists', ['id' => $id, 'content' => $content]);
}
public function detail($id)
{
if(!$id){
return redirect('/')->with('tip','缺少参数');
}
$this->navBar();
$this->hotContent();
$content = Content::find($id);
$count = Like::where('cid', $id)->get()->count();
$comments = Comment::where('cid', $id)->get();
return view('detail', ['id' => $content->id, 'cid' => $content->cid,
'content' => $content, 'count' => $count, 'comments' => $comments]);
}
public function like($id)
{
if(!$id){
return response()->json(['status'=>'2','msg'=>'缺少参数']);
}
@session_start();
$data = array(
'uid' => session()->get('users.id'),
'cid' => $id
);
$re = Like::create($data);
if($re){
$count = Like::where('cid', $id)->get()->count();
return response()->json(['status'=>'1', 'msg'=>'点赞成功', 'count'=>$count]);
}else{
return response()->json(['status'=>'2', 'msg'=>'点赞失败']);
}
}
public function comment(Request $request)
{
$cid = $request->input('cid');
$content = $request->input('content');
$uid = session()->get('users.id');
if(!$content){
return response()->json(['status'=>'2', 'msg'=>'缺少参数']);
}
$data = array(
'uid' => $uid,
'cid' => $cid,
'content' => $content,
);
$re = Comment::create($data);
if ($re) {
$theComment = Comment::where('cid', $cid)->where('uid', $uid)->orderBy('id','desc')->first();
$theComment->created_time = date('Y-m-d', strtotime($theComment->created_at));
$count = Comment::where('cid', $cid)->get()->count();
$theComment->count = $count;
$theComment->user = $theComment->user->name;
return response()->json(['status' => '1', 'msg' => '评论成功',
'data' => $theComment]);
} else {
return response()->json(['status' => '2', 'msg' => '评论失败']);
}
}
protected function hotContent(){
$hotContent = Like::select('cid',DB::raw('count(*) as num'))->orderBy('num', 'desc')->groupBy('cid')->get()->take(2);
return view()->share('hotContent', $hotContent);
}
}
(4)在routes\web.php文件中添加路由规则,具体代码如下:
// 首页
Route::get('/', 'IndexController@index');
Route::get('/lists/{id}', 'IndexController@lists');
Route::get('/detail/{id}', 'IndexController@detail');
Route::get('/like/{id}', 'IndexController@like');
Route::get('/comment', 'IndexController@comment');
Route::post('/register', 'UserController@register');
Route::post('/login', 'UserController@login');
Route::get('/logout', 'UserController@logout');
(5)修改app\Adv.php,设置关联模型,具体代码如下:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Adv extends Model
{
protected $table = "adv";
public $fillable = ['name'];
public function content()
{
return $this->hasMany('App\Advcontent', 'advid', 'id');
}
}
(6)修改app\Category.php,设置关联模型,具体代码如下:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
protected $table = "category";
public $fillable = ['pid', 'name', 'sort'];
public function content()
{
return $this->hasMany('App\Content', 'cid', 'id')->orderBy('id', 'desc')->limit(1);
}
}
(7)通过浏览器访问,看看是否完整显示。
前台用户管理
用户注册、用户登录和用户退出
(1)在header.blade.php视图中添加注册表单、登录表单,具体代码如下:
<div class="header">
<header>
<div class="container">
<a href="{
{url("/")}}" style="color:#000000">
<div class="header-logo"><span>内容</span>管理系统</div>
</a>
<ul class="header-right">
@if(session()->has('users.name'))
<li>
<a href="#" class="j-layout-pwd">
<i class="fa fa-user fa-fw"></i>{
{ session()->get('users.name') }}
</a>
</li>
<li><a href="{
{ url('logout') }}"><i class="fa fa-power-off fa-fw"></i>退出</a></li>
@else
<li><a href="#" data-toggle="modal" data-target="#loginModal">登录</a></li>
<li><a href="#" data-toggle="modal" data-target="#registerModal">注册</a></li>
@endif
</ul>
</div>
</header>
<!-- 栏目列表 -->
<nav class="navbar navbar-expand-md navbar-dark">
<div class="container">
<div></div>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-expanded="false" aria-controls="navbarSupportedContent" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="/">首页</a>
</li>
@foreach($category as $v)
@if(isset($v['sub']))
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{
{$v['name']}}
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
@foreach($v['sub'] as $val)
<a class="dropdown-item" href="{
{url('lists', ['id' => $val['id']] )}}">{
{$val['name']}}</a>
@endforeach
</div>
</li>
@else
<li class="nav-item">
<a class="nav-link" href="{
{url('lists', ['id' => $v['id']] )}}">{
{$v['name']}}</a>
</li>
@endif
@endforeach
</ul>
</div>
</div>
</nav>
</div>
<!-- 登录表单 --->
<div class="modal fade" id="loginModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">登录</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="username">用户名</label>
<input type="text" name="name" class="form-control" id="username">
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" name="password" class="form-control" id="password">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
<button type="submit" class="btn btn-primary" id="login">登录
</button>
</div>
</div>
</div>
</div>
<!-- 注册表单 --->
<div class="modal fade" id="registerModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">注册</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="username1">用户名</label>
<input type="text" name="name" class="form-control" id="username1">
</div>
<div class="form-group">
<label for="email">邮箱</label>
<input type="email" name="email" class="form-control" id="email">
</div>
<div class="form-group">
<label for="password1">密码</label>
<input type="password" name="password" class="form-control" id="password1">
</div>
<div class="form-group">
<label for="confirm">确认密码</label>
<input type="password" class="form-control" id="confirm">
</div>
</div>
<div class="modal-footer">
{
{csrf_field()}}
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
<button type="submit" class="btn btn-primary" id="register">立即注册</button>
</div>
</div>
</div>
</div>
<script>
$("#login").bind("click",function(){
var data = {
'name' : $("#username").val(),
'password' : $("#password").val(),
'_token' : "{
{ csrf_token() }}"
};
$.post("{
{ url('login') }}", data, function(result){
if (result.status == 1) {
alert(result.msg);
window.location.reload();
} else {
alert(result.msg);
return;
}
});
});
$("#register").bind("click",function(){
var data = {
'name' : $("#username1").val(),
'email' : $("#email").val(),
'password' : $("#password1").val(),
' password_confirmation' : $("#confirm").val(),
'_token' : "{
{ csrf_token() }}"
};
$.post("{
{ url('register') }}", data, function(result){
if (result.status == 1) {
alert(result.msg);
$('#registerModal').modal('hide');
location.reload();
} else {
alert(result.msg);
return;
}
});
});
</script>
(2)创建User控制器,具体代码如下:
php artisan make:controller UserController
(3)在User控制器中添加方法,具体代码如下:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use App\User;
use Illuminate\Support\Facades\Session;
class UserController extends Controller
{
public function register(Request $request)
{
$rule = [
'name' => 'required|unique:users',
'email' => 'required|email',
'password' => 'required|min:6',
'password_confirmation' => 'required'
];
$message = [
'name.require' => '用户名不能为空',
'name.unique' => '用户名不能重复',
'email.require' => '邮箱不能为空',
'email.email' => '邮箱格式不符合规范',
'password.require' => '密码不能为空',
'password.min' => '密码最少为6位',
'password.confirmed' => '密码和确认密码不一致'
];
$validator = Validator::make($request->all(), $rule, $message);
if ($validator->fails()) {
foreach ($validator->getMessageBag()->toArray() as $v) {
$msg = $v[0];
}
return response()->json(['status' => '2', 'msg' => $msg]);
}
$re = User::create($request->all());
if ($re) {
Session::put('users', ['id' => $re->id, 'name' => $re->name]); // 注册成功后保存登录状态
return response()->json(['status' => '1', 'msg' => '注册成功']);
} else {
return response()->json(['status' => '2', 'msg' => '注册失败']);
}
}
public function login(Request $request)
{
$rule = [
'name' => 'required|bail',
'password' => 'required|min:6'
];
$message = [
'name.required' => '用户名不能为空',
'password.required' => '密码不能为空',
'password.min' => '密码最少为6位'
];
$validator = Validator::make($request->all(), $rule, $message);
if ($validator->fails()) {
foreach ($validator->getMessageBag()->toArray() as $v) {
$msg = $v[0];
}
return response()->json(['status'=>'2', 'msg'=>$msg]);
}
$name = $request->get('name');
$password = $request->get('password');
$theUser = User::where('name', $name)->first();
if ($theUser) {
if ($password == $theUser->password) {
Session::put('users', ['id' => $theUser->id,'name' => $name]);
return response()->json(['status' => '1', 'msg' => '登录成功']);
} else {
return response()->json(['status' => '2', 'msg' => '密码错误']);
}
} else {
return response()->json(['status' => '2', 'msg' => '用户不存在']);
}
}
public function logout()
{
if (request()->session()->has('users')) {
request()->session()->pull('users', session('users'));
}
return redirect('/');
}
}
内容列表页
一、内容列表
(1)在resources\views目录下创建lists.blade.php,具体代码如下:
<!DOCTYPE html>
<html>
<head>
@include('public/static')
<title>列表页</title>
</head>
<body>
@include('public/header')
<div class="main">
<div class="main-crumb">
<div class="container">
<!-- 面包屑导航 -->
<nav aria-label="breadcrumb">
{!! Breadcrumbs::render('category', $id); !!}
</nav>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-9">
<div class="row">
<!-- 内容列表 -->
@foreach($content as $con)
<div class="col-md-6 mb-4">
<div class="card main-card">
<div class="main-card-pic">
<a href="{
{ url('detail', ['id' => $con->id ])}}">
<img class="img-fluid" src="@if($con->image)/static/upload/{
{$con->image}}@else {
{asset('admin')}}/img/noimg.png @endif">
<span><i class="fa fa-search"></i></span>
</a>
</div>
<div class="card-body">
<div class="main-card-info">
<span><i class="fa fa-calendar"></i>{
{ date('Y-m-d', strtotime($con->created_at)) }}</span>
<span><i class="fa fa-comments"></i>{
{$con->comments->count()}}</span>
</div>
<h3><a href="{
{ url('detail', ['id' => $con->id ])}}">{
{$con->title}}</a></h3>
<div class="main-card-desc">{
{str_limit(strip_tags($con->content),100)}}</div>
</div>
<a href="{
{ url('detail', ['id' => $con->id ])}}" class="main-card-btn">阅读更多</a>
</div>
</div>
@endforeach
</div>
{
{ $content->links()}}
</div>
<div class="col-md-3">
<!-- 侧边栏 -->
@include('public/sidebar')
</div>
</div>
</div>
</div>
@include('public/footer')
</body>
</html>
(2)通过浏览器访问内容列表页,可看到其效果。
二、面包屑导航
1.安装
(1)使用Composer载入laravel-breadcrumbs库,具体代码如下:
composer require davejamesmiller/laravel-breadcrumbs
(2)在config\app.php文件中将这个服务提供者注册到Laravel中,具体代码如下:
'providers' => [
...(原有代码)
DaveJamesMiller\Breadcrumbs\BreadcrumbsServiceProvider::class,
],
(3)在config\app.php文件中注册别名,以方便使用,具体代码如下:
'aliases' => [
...(原有代码)
'Breadcrumbs' => DaveJamesMiller\Breadcrumbs\Facades\Breadcrumbs::class,
],
2.配置导航
(1)配置首页的导航链接,创建routes\breadcrumbs.php文件,具体代码如下:
<?php
use DaveJamesMiller\Breadcrumbs\Facades\Breadcrumbs;
use App\Category;
use App\Content;
Breadcrumbs::register('home', function($breadcrumbs){
$breadcrumbs->push('首页', route('home'));
});
Breadcrumbs::register('category', function ($breadcrumbs, $id) {
$category = Category::find($id);
$breadcrumbs->parent('home');
$breadcrumbs->push($category->name, route('category', $id));
});
Breadcrumbs::register('detail', function ($breadcrumbs, $posts) {
$content = Content::find($posts['id']);
$breadcrumbs->parent('category', $posts['cid']);
$breadcrumbs->push($content->title, route('detail', $posts['id']));
});
(2)通过浏览器访问内容列表页,查看面包屑导航效果。
内容展示
一、内容详细页
在resources\views目录下创建detail.blade.php,具体代码如下:
<!DOCTYPE html>
<html>
<head>
@include('public/static')
<title>详细页</title>
</head>
<body>
@include('public/header')
<div class="main">
<div class="main-crumb">
<div class="container">
<!-- 面包屑导航 -->
<nav aria-label="breadcrumb">
{!! Breadcrumbs::render('detail', ['id'=>$id,'cid'=>$cid]); !!}
</nav>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-9">
<!-- 内容区域 -->
<article class="main-article">
<header>
<h1>{
{$content->title}}</h1>
<div>发表于{
{ date('Y-m-d', strtotime($content->create_time)) }}</div>
</header>
<div class="main-article-content">
<p><img class="img-fluid" src="/static/upload/{
{$content->image}}"></p>
<p>{!! $content->content !!}</p>
</div>
<!-- 点赞模块 -->
@if(session()->has('users'))
<div class="main-article-like">
<span>
<i class="fa fa-thumbs-up" aria-hidden="true">{
{$count}}</i>
</span>
</div>
@endif
</article>
<div class="main-comment">
<!-- 评论列表 -->
@if(!$comments->isEmpty())
<div class="main-comment-header">
<span id="count">{
{$comments->count()}}</span> 条评论
</div>
@foreach($comments as $val)
<div class="main-comment-item">
<div class="main-comment-name">{
{$val->user->name}}</div>
<div class="main-comment-date">
{
{ date('Y-m-d', strtotime($val->created_at)) }}</div>
<div class="main-comment-content">{
{$val->content}}</div>
</div>
@endforeach
@endif
</div>
<!-- 发表评论模块 -->
<div class="main-reply">
@if(session()->has('users'))
<div class="main-reply-header">发表评论</div>
<div class="main-reply-title">评论内容</div>
<div><textarea name="content" rows="8" id="content"></textarea></div>
<div>
<input type="hidden" id='c_id' value="{
{$id}}">
<input type="button" value="提交评论" id="publish">
</div>
@endif
</div>
</div>
<div class="col-md-3">
<!-- 侧边栏 -->
@include('public/sidebar')
</div>
</div>
</div>
</div>
@include('public/footer')
</body>
<script>
$(document).ready(function() {
$(".fa-thumbs-up").bind("click", function () {
$.get("{
{ url('like', $id) }}", {}, function (result) {
var count = result.count;
$(".fa-thumbs-up").html();
$(".fa-thumbs-up").html(count);
});
});
$('#publish').bind("click",function(){
var data = {
'cid' : $("#c_id").val(),
'content' : $("#content").val()
};
$.get("{
{ url('comment') }}",data, function(result){
var data = result.data;
var user = data.user;
var html = '<div class="main-comment-item">';
html += '<div class="main-comment-name">' + user['name'] + '</div>';
html += '<div class="main-comment-date">';
html += data['created_time'];
html += '</div>';
html += '<div class="main-comment-content">';
html += data['content'] + '</div>';
html += '</div>';
$(".main-comment").append(html);
$("#count").html();
$("#count").html(data['count']);
});
});
});
</script>
</html>