阿里百秀后台管理项目笔记 ---- Day03

来吧展示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

step1:所有文章数据展示

  1. 引入 functions.php 文件执行数据库查询以及判断用户登录状态
require_once '../functions.php';
get_userinfo();
  1. 查询文章数据
$posts = mysql_all('select * from posts;');
  1. 文章数据渲染
    在表格中将多余的 tr 标记移除,通过 foreach 遍历查询到的 $posts 变量,绑定数据
<tbody>
        <?php foreach ($posts as $item): ?>
         <tr>
            <td class="text-center"><input type="checkbox"></td>
            <td><?php echo $item['title']; ?></td>
            <td><?php echo $item['user_id']?></td>
            <td><?php echo $item['category_id']?></td>
            <td class="text-center"><?php echo $item['created']?></td>
            <td class="text-center"><?php echo $item['status']?></td>
            <td class="text-center">
              <a href="javascript:;" class="btn btn-default btn-xs">编辑</a>
              <a href="javascript:;" class="btn btn-danger btn-xs">删除</a>
            </td>
          </tr>
        <?php endforeach?>
        </tbody>

step2:函数处理所有文章页面中的时间显示

1.用函数去格式化时间

// 用函数去处理时间
function convert_date ($created) {
  // 数据库中存储的时间 '2017-07-01 08:08:00' 
  //格式化成 => '2017年07月01日 08:08:00
  // 如果配置文件没有配置时区
  // date_default_timezone_set('PRC');
  $timestamp = strtotime($created);
  return date('Y年m月d日<b\r>H:i:s', $timestamp);
}
  1. 在时间的标签中用函数的方式去显示对应的时间
<td class="text-center"><?php echo convert_date($item['created']); ?></td>

step3:函数处理所有文章页面中的状态显示

  1. 用函数去处理状态
// 用函数去处理状态
function convert_status($status){
  $dict = array(
    'published' => '已发布',
    'drafted' => '草稿',
    'trashed' => '回收站'
    );
  return isset($dict[$status]) ? $dict[$status] : '未知';
}
  1. 在状态的标签中用函数的方式去显示对应的状态
<td class="text-center"><?php echo convert_status($item['status']); ?></td>

step4:函数处理所有文章页面中的作者和分类显示

  1. 用函数去处理作者和分类
//php部分
//用函数去处理作者和分类方法一
function get_user($user_id){
   return mysql_one ("select nickname from users where id = {$user_id}['nickname']");
 }
 function get_category($category_id){
   return mysql_one ("select name from categories where id = {$category_id}['name']");
 }
  1. 在分类和作者的标签中用函数的方式去显示对应的作者和分类
//Html部分
//用函数去处理作者和状态
<td><?php  echo get_user($item['user_id']); ?></td>
<td><?php  echo get_category($item['category_id']); ?></td> 

step5:用关联数据库的方式去处理所有文章页面中的作者和分类显示(减少数据库的查询次数)

  1. 关联查询的方式介绍
    1.1 关联查询 posts 表与 categories
    查询总条数 = posts的总条数 * categories的总条数
    24 = 4 * 6
    在这里插入图片描述
    1.2 带有条件的关联查询
    在这里插入图片描述
    1.3 带有多个条件的关联查询
    在这里插入图片描述
    1.4 带有多个条件并查询多张表
    在这里插入图片描述
    1.5
    如果这几个表中有相同名称的字段,在查询过后转换为关联数组就会有问题(关联数组 的键是不能重复的),所以我们需要指定需要查询的字段,同时还可以给每一个字段起一个别名,避免冲突分别给 users.nickname categories.name 起别名
    users.nickname ==> user_name
    categoies.name == > category_name
    在这里插入图片描述
  2. 关联查询的方式使用
    2.1 将之前的查询语句改更改成关联查询的语句
//php部分
$posts = mysql_all('select 
posts.id,
posts.title,
posts.created,
posts.status,
users.nickname as user_name,
categories.name as category_name
from posts
inner join categories on posts.category_id = categories.id
inner join users on posts.user_id = users.id');

2.2 更改html部分

//html部分
 <td><?php echo $item['user_name']; ?></td>
 <td><?php echo $item['category_name']; ?></td>

step6: 实现页面呈现多页数据

想要是实现分页的话,posts表中的数据显然不够做这个功能,所以需要导入更多的测试数据

  1. 复制 post-test-data.sql 文件代码 在数据库新建查询中粘贴,在代码末尾加上 commit; 然后点击运行
    在这里插入图片描述
    可以看到 posts 表中新增了很多数据
    在这里插入图片描述

step7 : 分页加载文章数据

  1. 查询一部分数据
    1.1 当数据过多过后,如果还是按照以上操作每次查询全部数据,页面就显得十分臃肿,加载起来也非常慢,所以必须 要通过分页加载的方式改善(每次只显示一部分数据)。
    操作方式也非常简单,就是在原有 SQL 语句的基础之上加上 limit order by 子句
    在这里插入图片描述
    1.2 imit 用法:limit [offset, ]rows
    limit 10 -----只取前 10 条数据
    limit 5, 10 ----- 从第 5 条之后,第 6 条开始,向后取 10 条数据

step8 : 分页参数计算

limit 子句中的 0 和 10 不是一成不变的,应该跟着页码的变化而变化,具体的规则就是:
第 1 页 limit 0, 10
第 2 页 limit 10, 10
第 3 页 limit 20, 10
第 4 页 limit 30, 10 ...
根据以上规则得出公式: offset = (page - 1) * size

// 处理分页参数
$size = 5;
// // 计算越过多少条
$offset = ($page - 1) * $size;
// 用关联数据中方式去查询数据库
// 获取全部数据
$posts = mysql_all("select
  posts.id,
  posts.title,
  users.nickname as user_name,
  categories.name as category_name,
  posts.created,
  posts.status
  from posts
  inner join categories on posts.category_id = categories.id
  inner join users on posts.user_id = users.id
  order by posts.created desc
  limit {$offset}, {$size};
  ");

step9 : 获取当前页码

一般分页都是通过 URL 传递一个页码参数
也就是说,我们应该在页面开始执行的时候获取这个 URL 参数

//// 获取分页参数 没有或传过来的不是数字的话默认为 1 $page = isset($_GET['p']) && is_numeric($_GET['p'
$page = empty($_GET['page']) ? 1 : (int)$_GET['page'];

step 10 : 处理页面页码显示高亮并与地址栏同步

//Php部分
// 计算页码
$visiables = 5;
$region = ($visiables -1) / 2;
$begin = $page - $region;
$end = $page + $region;
//Html部分
   <ul class="pagination pagination-sm pull-right">
          <li><a href="#">上一页</a></li>
          <?php for ($i = $begin; $i <= $end; $i++): ?>
          <li<?php echo $i === $page ? ' class="active"' : '' ?>><a href="?page=<?php echo $i ;?>"><?php echo $i; ?></a></li>
          <?php endfor ?>
          <li><a href="#">下一页</a></li>
   </ul>

step 11. 处理页面分页最大和最小页码限制


// 计算页码开始
$visiables = 5;
$region = ($visiables - 1) / 2; // 左右区间
$begin = $page - $region; // 开始页码
// $end = $page + $region;
$end = $begin + $visiables; // 结束页码 + 1
//出现$begin不合理的情况处理
//$begin必须大于1
if ($begin < 1) {
  $begin = 1;
  // begin 修改意味着必须要改 end
  $end = $begin + $visiables;
}
//$end不得超过最大page
//求出最大页码
$total_count = (int)mysql_one('select count(1) as num from posts;')['num'];
$total_pages = (int)ceil($total_count / $size);
// 判断
if ($end > $total_pages + 1) {
  // end 超出范围
  $end = $total_pages + 1;
  // end 修改意味着必须要改 begin
  $begin = $end - $visiables;
  if ($begin < 1) {
    $begin = 1;
  }
}
//html部分,与上面不同的是
//将for ($i = $begin; $i <= $end; $i++)更改成 for ($i = $begin; $i < $end; $i++)
<li>
<a href="#">上一页</a></li>
<?php for ($i = $begin; $i < $end; $i++): ?>
<li<?php echo $i === $page ? ' class="active"' : ''; ?>><a href="?page=<?php echo $i; ?>"><?php echo $i; ?></a></li>
<?php endfor ?>
<li><a href="#">下一页</a>
</li>

step 12 : 解决step11中的bug

  1. bug1 : 到50的时候就不能显示高亮(原因,因为50以后就是小数float,要取整数)
    解决办法一:将小数类型强制转换成整数类型
    之前代码
$total_pages = ceil($total_count / $size);

修改后的代码

$total_pages = (int)ceil($total_count / $size);

解决办法二:将三个 === 更改成 两个 == (让它变得没有那么严谨)

<li<?php echo $i == $page ? ' class="active"' : ''; ?>><a href="?page=<?php echo $i; ?>"><?php echo $i; ?></a></li>
  1. bug2 : 当点击最后一个页码时,会报错
    在这里插入图片描述
    解决办法:
    将:
//$end不得超过最大page
//求出最大页码
$total_count = (int)mysql_one('select count(1) as num from posts;')['num'];
$total_pages = (int)ceil($total_count / $size);

更改成:

//$end不得超过最大page
//求出最大页码
$total_count = (int)mysql_one('select count(1) as num 
  from posts
  inner join categories on posts.category_id = categories.id
  inner join users on posts.user_id = users.id;')['num'];
$total_pages = (int)ceil($total_count / $size);

step 13 : 处理筛选分类,显示对应的分类页面

// 分类筛选
 if(!empty($_GET['category'])){
  $where .= ' and posts.category_id = ' . $_GET['category'];
}
//防止category=all时报错,所以更改成
if (isset($_GET['category']) && $_GET['category'] !== 'all') {
  $where .= ' and posts.category_id = ' . $_GET['category'];
}

//HTML部分 利用foreach遍历循环得到的categories表中的数据并呈现在页面上
//给form表单设置action,表单自动默认method = "get",此处应该使用get方式
//所以可以不用设置method
<form class="form-inline" action="<?php echo $_SERVER['PHP_SELF']; ?>">
//给select加上name属性
<select  name="category" class="form-control input-sm">
   //给所有分类添加一个value="all",用来默认显示所有分类
   <option value="all">所有分类</option>
   //将未分类删掉,遍历循环categories表中数据
   //<option value="">未分类</option>
   <?php foreach ($categories as $item): ?>
   //给分类的option添加value = "id" ,用来作为筛选的标识
   //再加上一个判断当前是否存在$_GET['category'],用来判断当前所选项,记住筛选状态,并展示在框内
   <option value="<?php echo $item['id']; ?>"<?php echo isset($_GET['category']) && $_GET['category'] == $item['id'] ? ' selected' : '' ?>>
    <?php echo $item['name']; ?>
    </option>
    <?php endforeach ?>  
 </select>

step 14 : 处理筛选状态,显示对应的状态页面

//PHP部分
//筛选状态
if (isset($_GET['status']) && $_GET['status'] !== 'all') {
  $where .= " and posts.status = '{$_GET['status']}'";
}

//HTML部分
//给每一个option标签都加上对应的value属性
//并且判断是否存在$_GET['status'],用来判断当前所选项,记住筛选状态,并展示在框内
<select name="status" class="form-control input-sm">
    <option value="all">所有状态</option>
    <option value="drafted"<?php echo isset($_GET['status']) && $_GET['status'] == 'drafted' ? ' selected' : '' ?>>草稿</option>
    <option value="published"<?php echo isset($_GET['status']) && $_GET['status'] == 'published' ? ' selected' : '' ?>>已发布</option>
    <option value="trashed"<?php echo isset($_GET['status']) && $_GET['status'] == 'trashed' ? ' selected' : '' ?>>回收站</option>
</select>

step 15 : 根据筛选的参数,显示筛选数据的页面

当我们加上 where 语句时,可实现数据的筛选,where语句筛选数据都是根据数据的唯一标识(也就是id)来进行筛选

在这里插入图片描述
所以,在之前的每一项查询中添加 where 子句

//sql语句的注入
// 数据库查询筛选条件(默认为 1 = 1,相当于没有条件) 
$where = '1 = 1';
$posts = mysql_all("select
  posts.id,
  posts.title,
  users.nickname as user_name,
  categories.name as category_name,
  posts.created,
  posts.status
  from posts
  inner join categories on posts.category_id = categories.id
  inner join users on posts.user_id = users.id
  where {$where}
  order by posts.created desc
  limit {$offset}, {$size};
  ");
$total_count = (int)mysql_one("select count(1) as num from posts
inner join categories on posts.category_id = categories.id
inner join users on posts.user_id = users.id
where {$where};")['num'];
$total_pages = (int)ceil($total_count / $size);

step 16 : 根据筛选的数据显示完整的 url 地址

///Php部分
//定义一个serch 
$search = '';
//在每个筛选下加上serch
// 分类筛选
 // if(!empty($_GET['category'])){
if (isset($_GET['category']) && $_GET['category'] !== 'all') {
  $where .= ' and posts.category_id = ' . $_GET['category'];
  $search .= '&category=' . $_GET['category'];
}
//筛选状态
if (isset($_GET['status']) && $_GET['status'] !== 'all') {
  $where .= " and posts.status = '{$_GET['status']}'";
  $search .= '&status=' . $_GET['status'];
}

//Html部分
//没有处理分类和状态显示所有分类和状态之前
<li><a href="#">上一页</a></li>
    <?php for ($i = $begin; $i < $end; $i++): ?>
    <li<?php echo $i === $page ? ' class="active"' : ''; ?>><a href="?page=<?php echo $i; ?>">
    <?php echo $i; ?></a></li>
     <?php endfor ?>
<li><a href="#">下一页</a></li>-->
//处理分类和状态显示所有分类和状态之后
<li><a href="#">上一页</a></li>
    <?php for ($i = $begin; $i < $end; $i++): ?>
     <li<?php echo $i == $page ? ' class="active"' : '' ?>><a href="?page=<?php echo $i . $search; ?>"><?php echo $i; ?></a></li>
    <?php endfor ?>
<li><a href="#">下一页</a></li>

step 17 : 如果用户在url地址中输入大于总页数的页码,则跳到最大页码

if ($page > $total_pages) {
  // 跳转到第最后页
  header('Location: /admin/posts.php?page=' . $total_pages . $search);
}

step 18 : 文章中单条数据删除功能

//Html部分
<a href="/admin/post-delete.php?id=<?php echo $item['id']; ?>" class="btn btn-danger btn-xs">删除</a>

新增一个 post-delete.php 文件与 category-delete.php 类似

post-delete.php

<?php
/**
 * 根据客户端传递过来的ID删除对应数据
 */
require_once '../functions.php';
if (empty($_GET['id'])) {
  exit('缺少必要参数');
}
// $id = (int)$_GET['id'];
$id = $_GET['id'];
$rows = mysql_change('delete from posts where id in (' . $id . ');');
header('Location: ' . $_SERVER['HTTP_REFERER']);

// http 中的 referer 用来标识当前请求的来源
//末尾这句话的作用是为了当用户删除最后一页数据时,不会报错,返回的是倒数第二页,显示正确

posts.php完整代码

<?php
header("Content-Type: text/html;charset=utf-8");
require_once '../functions.php';
get_userinfo();
// 处理分页参数
$page = empty($_GET['page']) ? 1 : (int)$_GET['page'];
$size = 20;
// 计算出越过多少条
$offset = ($page - 1) * $size;
// 接收筛选数据
$where = '1 = 1';
$search = '';
// 分类筛选
if (isset($_GET['category']) && $_GET['category'] !== 'all') {
  $where .= ' and posts.category_id = ' . $_GET['category'];
  $search .= '&category=' . $_GET['category'];
}
//筛选状态
if (isset($_GET['status']) && $_GET['status'] !== 'all') {
  $where .= " and posts.status = '{$_GET['status']}'";
  $search .= '&status=' . $_GET['status'];
}
// 用关联数据中方式去查询数据库
// 获取全部数据
$posts = mysql_all("select
  posts.id,
  posts.title,
  users.nickname as user_name,
  categories.name as category_name,
  posts.created,
  posts.status
  from posts
  inner join categories on posts.category_id = categories.id
  inner join users on posts.user_id = users.id
  where {$where}
  order by posts.created desc
  limit {$offset}, {$size};
  ");

// 处理分页页码===============================
// 计算页码
// 计算页码开始
$visiables = 5;
$region = ($visiables - 1) / 2; // 左右区间
$begin = $page - $region; // 开始页码
$end = $begin + $visiables; // 结束页码 + 1

//出现$begin不合理的情况处理
//$begin必须大于1
if ($begin < 1) {
  $begin = 1;
  // begin 修改意味着必须要改 end
  $end = $begin + $visiables;
}

//$end不得超过最大page
//求出最大页码
$total_count = (int)mysql_one("select count(1) as num from posts
inner join categories on posts.category_id = categories.id
inner join users on posts.user_id = users.id
where {$where};")['num'];
$total_pages = (int)ceil($total_count / $size);
// 判断
if ($end > $total_pages + 1) {
  // end 超出范围
  $end = $total_pages + 1;
  // end 修改意味着必须要改 begin
  $begin = $end - $visiables;
  if ($begin < 1) {
    $begin = 1;
  }
}
if ($page > $total_pages) {
  // 跳转到第最后页
  header('Location: /admin/posts.php?page=' . $total_pages . $search);
}

// 用函数去处理状态
function convert_status($status){
  $dict = array(
    'published' => '已发布',
    'drafted' => '草稿',
    'trashed' => '回收站'
    );
  return isset($dict[$status]) ? $dict[$status] : '未知';
}
// 用函数去处理时间,格式化时间
function convert_date ($created) {
  // 如果配置文件没有配置时区
  // date_default_timezone_set('PRC');
  $timestamp = strtotime($created);
  return date('Y年m月d日<b\r>H:i:s', $timestamp);
}
$categories = mysql_all('select * from categories;');
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8">
  <title>Posts &laquo; Admin</title>
  <link rel="stylesheet" href="/static/assets/vendors/bootstrap/css/bootstrap.css">
  <link rel="stylesheet" href="/static/assets/vendors/font-awesome/css/font-awesome.css">
  <link rel="stylesheet" href="/static/assets/vendors/nprogress/nprogress.css">
  <link rel="stylesheet" href="/static/assets/css/admin.css">
  <script src="/static/assets/vendors/nprogress/nprogress.js"></script>
</head>
<body>
  <script>NProgress.start()</script>
  <div class="main">
    <?php include 'com/nav.php';?>
    <div class="container-fluid">
      <div class="page-title">
        <h1>所有文章</h1>
        <a href="post-add.php" class="btn btn-primary btn-xs">写文章</a>
      </div>
      <div class="page-action">
        <!-- show when multiple checked -->
        <a class="btn btn-danger btn-sm" href="javascript:;" style="display: none">批量删除</a>
        <form class="form-inline" action="<?php echo $_SERVER['PHP_SELF']; ?>" >
          <select  name="category" class="form-control input-sm">
            <option value="all">所有分类</option>
            <!-- <option value="">未分类</option> -->
            <?php foreach ($categories as $item): ?>
            <option value="<?php echo $item['id']; ?>"<?php echo isset($_GET['category']) && $_GET['category'] == $item['id'] ? ' selected' : '' ?>>
              <?php echo $item['name']; ?>
            </option>
            <?php endforeach ?>
           
          </select>
          <select name="status" class="form-control input-sm">
            <option value="all">所有状态</option>
            <option value="drafted"<?php echo isset($_GET['status']) && $_GET['status'] == 'drafted' ? ' selected' : '' ?>>草稿</option>
            <option value="published"<?php echo isset($_GET['status']) && $_GET['status'] == 'published' ? ' selected' : '' ?>>已发布</option>
            <option value="trashed"<?php echo isset($_GET['status']) && $_GET['status'] == 'trashed' ? ' selected' : '' ?>>回收站</option>
          </select>
          <button class="btn btn-default btn-sm">筛选</button>
        </form>
        <ul class="pagination pagination-sm pull-right">
          <li><a href="#">上一页</a></li>
          <?php for ($i = $begin; $i < $end; $i++): ?>
          <li<?php echo $i == $page ? ' class="active"' : '' ?>><a href="?page=<?php echo $i . $search; ?>"><?php echo $i; ?></a></li>
          <?php endfor ?>
          <li><a href="#">下一页</a></li>
        </ul>
      </div>
      <table class="table table-striped table-bordered table-hover">
        <thead>
          <tr>
            <th class="text-center" width="40"><input type="checkbox"></th>
            <th>标题</th>
            <th>作者</th>
            <th>分类</th>
            <th class="text-center">发表时间</th>
            <th class="text-center">状态</th>
            <th class="text-center" width="100">操作</th>
          </tr>
        </thead>
        <tbody>
        <?php foreach ($posts as $item): ?>
         <tr>
            <td class="text-center"><input type="checkbox"></td>
            <td><?php echo $item['title']; ?></td>
            //用关联数据库的方式去处理作者和状态
            <td><?php echo $item['user_name']; ?></td>
            <td><?php echo $item['category_name']; ?></td>
            //用函数去处理时间
            <td class="text-center"><?php echo convert_date($item['created']); ?></td>
            // 用函数处理后显示状态 
            <td class="text-center"><?php echo convert_status($item['status']); ?></td>
            <td class="text-center">
              <a href="javascript:;" class="btn btn-default btn-xs">编辑</a>
              <!-- <a href="javascript:;" class="btn btn-danger btn-xs">删除</a> -->
            <a href="/admin/post-delete.php?id=<?php echo $item['id']; ?>" class="btn btn-danger btn-xs">删除</a>
            </td>
          </tr>

        <?php endforeach?>
        </tbody>
      </table>
    </div>
  </div>
 <?php $current_page='posts';?>
 <?php include 'com/sidebar.php';?>
  <script src="/static/assets/vendors/jquery/jquery.js"></script>
  <script src="/static/assets/vendors/bootstrap/js/bootstrap.js"></script>
  <script>NProgress.done()</script>
</body>
</html>

posted @ 2020-10-15 20:47  杨芋可可  阅读(129)  评论(0编辑  收藏  举报