fastadmin表格右侧操作栏增加审核成功和审核失败按钮,点击提交ajax到后端

'# fastadmin表格右侧操作栏增加审核成功和审核失败按钮,点击提交ajax到后端

一、背景与问题

在内容管理系统中,审核操作是常见需求。传统FastAdmin框架中,表格右侧操作栏默认提供"编辑/删除"按钮,但缺少灵活的审核状态切换功能。当需要实现"审核通过"和"审核失败"两种操作时,传统方案存在以下痛点:

  1. 需要动态生成按钮并绑定不同操作
  2. 需要处理不同状态的AJAX请求
  3. 需要更新前端展示状态
  4. 需要保证操作的原子性
  5. 需要防范安全漏洞

本文将深入探讨如何通过AJAX实现审核状态切换的完整解决方案,并分析其适用场景和注意事项。

二、基本原理

FastAdmin基于ThinkPHP框架和Vue.js实现,其表格操作栏的实现原理如下:

  1. 前端通过Vue模板渲染表格行
  2. 使用v-for遍历数据源生成表格行
  3. 使用v-if或v-show控制操作栏显示
  4. 使用@click绑定点击事件
  5. 通过AJAX请求与后端交互
  6. 后端处理审核状态变更逻辑
  7. 前端根据返回结果更新界面状态

核心技术点包括:Vue事件绑定、AJAX通信、状态管理、权限控制和安全防护。

三、环境准备

  1. 开发环境要求:

    • PHP 7.4+
    • MySQL 5.7+
    • Node.js 16+
    • FastAdmin 1.8.0+(确保支持Vue3)
  2. 代码结构:

    ├── application
    │   └── admin
    │       └── controller
    │           └── ArticleController.php
    │       └── view
    │           └── article
    │               └── index.html
  3. 数据库准备:

    CREATE TABLE `think_article` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `title` varchar(255) NOT NULL,
      `status` tinyint NOT NULL DEFAULT 0,
      `create_time` datetime NOT NULL,
      PRIMARY KEY (`id`)
    );

四、核心实现

1. 前端模板改造(index.html)

<!-- 原始代码 -->
<th width="180">操作</th>
<td>
  <a href="javascript:;" class="layui-btn layui-btn-xs" lay-options="{type: 'edit', url: '{:url('admin/article/edit')}'}" lay-filter="edit">编辑</a>
  <a href="javascript:;" class="layui-btn layui-btn-danger layui-btn-xs" lay-options="{type: 'delete', url: '{:url('admin/article/delete')}'}" lay-filter="del">删除</a>
</td>

<!-- 修改后代码 -->
<th width="180">操作</th>
<td>
  <!-- 审核按钮 -->
  <div class="layui-btn-group">
    <a href="javascript:;" class="layui-btn layui-btn-sm" @click="audit(1, '{{ $vo['id'] }}')">审核通过</a>
    <a href="javascript:;" class="layui-btn layui-btn-sm layui-btn-danger" @click="audit(2, '{{ $vo['id'] }}')">审核失败</a>
  </div>
  
  <!-- 原有编辑删除按钮 -->
  <a href="javascript:;" class="layui-btn layui-btn-xs" lay-options="{type: 'edit', url: '{:url('admin/article/edit')}'}" lay-filter="edit">编辑</a>
  <a href="javascript:;" class="layui-btn layui-btn-danger layui-btn-xs" lay-options="{type: 'delete', url: '{:url('admin/article/delete')}'}" lay-filter="del">删除</a>
</td>

关键点说明:

  • 使用@click绑定自定义方法
  • 传递审核状态(1为通过,2为失败)和记录ID
  • 使用layui-btn-sm控制按钮尺寸

2. 前端JS逻辑(index.js)

// 原始代码(未修改)
var edit = {
  init: function() {
    // 初始化代码
  }
};

// 修改后代码
var edit = {
  init: function() {
    // 绑定审核按钮点击事件
    this.auditBtn();
  },
  
  auditBtn: function() {
    const that = this;
    // 绑定审核按钮点击事件
    $(document).on('click', '.layui-btn-sm', function() {
      const status = $(this).hasClass('layui-btn-success') ? 1 : 2;
      const id = $(this).data('id');
      that.audit(id, status);
    });
  },
  
  audit: function(id, status) {
    this.$axios.post('/admin/article/audit', {
      id: id,
      status: status
    }).then(response => {
      if (response.data.code === 0) {
        // 成功提示
        layer.msg('审核成功');
        // 刷新当前行
        this.$nextTick(() => {
          this.$refs.table.refresh();
        });
      } else {
        layer.msg('审核失败: ' + response.data.msg);
      }
    }).catch(error => {
      console.error('审核失败:', error);
      layer.msg('系统错误');
    });
  }
};

关键点说明:

  • 使用axios发送POST请求
  • 使用data-id属性传递记录ID(需在模板中添加)
  • 使用layer.msg显示提示信息
  • 使用$nextTick刷新表格

3. 后端接口实现(ArticleController.php)

namespace app\admin\controller;

use think\Request;
use app\common\controller\Backend;

class Article extends Backend
{
    public function audit()
    {
        $id = $this->request->post('id');
        $status = $this->request->post('status');

        // 验证请求合法性
        if (!$this->request->isPost() || !isset($id) || !isset($status)) {
            return json(['code' => 1, 'msg' => '请求非法']);
        }

        // 验证权限
        if (!$this->auth->check('audit', 'article')) {
            return json(['code' => 1, 'msg' => '无权限操作']);
        }

        // 更新审核状态
        $result = $this->model->where(['id' => $id])->update(['status' => $status]);

        if ($result) {
            return json(['code' => 0, 'msg' => '操作成功']);
        } else {
            return json(['code' => 1, 'msg' => '操作失败']);
        }
    }
}

关键点说明:

  • 验证请求类型和参数
  • 验证用户权限
  • 使用模型进行数据更新
  • 返回JSON格式响应

五、完整案例:文章审核系统

1. 项目结构

├── application
│   └── admin
│       └── controller
│           └── ArticleController.php
│       └── view
│           └── article
│               ├── index.html
│               └── index.js

2. 前端完整代码(index.html)

<!-- 基础模板 -->
<template>
  <div>
    <table class="layui-table">
      <thead>
        <tr>
          <th>标题</th>
          <th>状态</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="item in articles" :key="item.id">
          <td>{{ item.title }}</td>
          <td>{{ statusMap[item.status] }}</td>
          <td>
            <!-- 审核按钮 -->
            <div class="layui-btn-group">
              <a href="javascript:;" class="layui-btn layui-btn-sm" @click="audit(1, item.id)">审核通过</a>
              <a href="javascript:;" class="layui-btn layui-btn-sm layui-btn-danger" @click="audit(2, item.id)">审核失败</a>
            </div>
            
            <!-- 原有操作 -->
            <a href="javascript:;" class="layui-btn layui-btn-xs" lay-options="{type: 'edit', url: '{:url('admin/article/edit')}'}" lay-filter="edit">编辑</a>
            <a href="javascript:;" class="layui-btn layui-btn-danger layui-btn-xs" lay-options="{type: 'delete', url: '{:url('admin/article/delete')}'}" lay-filter="del">删除</a>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      articles: [],
      statusMap: {
        0: '未审核',
        1: '已通过',
        2: '已拒绝'
      }
    };
  },
  mounted() {
    this.fetchData();
  },
  methods: {
    fetchData() {
      // 模拟数据获取
      this.articles = [
        { id: 1, title: '测试文章1', status: 0 },
        { id: 2, title: '测试文章2', status: 1 },
        { id: 3, title: '测试文章3', status: 2 }
      ];
    },
    audit(status, id) {
      // 模拟AJAX请求
      setTimeout(() => {
        this.articles = this.articles.map(item => 
          item.id === id ? { ...item, status } : item
        );
        layer.msg('审核成功');
      }, 500);
    }
  }
};
</script>

3. 后端完整代码(ArticleController.php)

namespace app\admin\controller;

use think\Request;
use app\common\controller\Backend;

class Article extends Backend
{
    public function index()
    {
        // 简化示例,实际应从数据库获取数据
        $this->assign('articles', [
            ['id' => 1, 'title' => '测试文章1', 'status' => 0],
            ['id' => 2, 'title' => '测试文章2', 'status' => 1],
            ['id' => 3, 'title' => '测试文章3', 'status' => 2]
        ]);
        return $this->fetch();
    }

    public function audit()
    {
        $id = $this->request->post('id');
        $status = $this->request->post('status');

        // 验证请求合法性
        if (!$this->request->isPost() || !isset($id) || !isset($status)) {
            return json(['code' => 1, 'msg' => '请求非法']);
        }

        // 验证权限
        if (!$this->auth->check('audit', 'article')) {
            return json(['code' => 1, 'msg' => '无权限操作']);
        }

        // 模拟数据库更新
        $result = $this->model->where(['id' => $id])->update(['status' => $status]);

        if ($result) {
            return json(['code' => 0, 'msg' => '操作成功']);
        } else {
            return json(['code' => 1, 'msg' => '操作失败']);
        }
    }
}

六、源码解析

1. 前端源码解析

  1. 模板语法:

    • 使用Vue的v-for遍历数据
    • 使用@click绑定点击事件
    • 使用{{ }}进行数据绑定
  2. 状态管理:

    • 使用statusMap进行状态转换
    • 使用this.articles保存数据
    • 使用this.fetchData()初始化数据
  3. AJAX请求:

    • 使用setTimeout模拟AJAX请求
    • 使用layer.msg显示提示信息
    • 使用this.articles更新状态

2. 后端源码解析

  1. 接口验证:

    • 验证请求类型
    • 验证参数存在性
    • 验证用户权限
  2. 数据更新:

    • 使用$this->model进行数据库操作
    • 使用update()方法更新数据
    • 返回JSON格式响应

七、进阶使用

1. 权限控制增强

// 在audit方法中增加权限验证
if (!$this->auth->check('audit', 'article') || !$this->auth->check('edit', 'article', $id)) {
    return json(['code' => 1, 'msg' => '无权限操作']);
}

2. 防止重复提交

// 前端添加防重锁
audit: function(id, status) {
  if (this.isProcessing) return;
  this.isProcessing = true;
  
  setTimeout(() => {
    this.isProcessing = false;
    this.articles = this.articles.map(item => 
      item.id === id ? { ...item, status } : item
    );
    layer.msg('审核成功');
  }, 500);
}

3. 异步审核处理

// 在audit方法中进行异步处理
public function audit()
{
    $id = $this->request->post('id');
    $status = $this->request->post('status');

    // 模拟异步处理
    $this->model->where(['id' => $id])->update(['status' => $status]);

    // 记录日志
    $this->log->save([
        'user_id' => $this->user->id,
        'action' => 'audit',
        'record_id' => $id,
        'status' => $status
    ]);

    return json(['code' => 0, 'msg' => '操作成功']);
}

八、性能与工程实践

1. 性能优化

  1. 批量处理:对于大量审核操作,使用批量处理减少数据库查询
  2. 缓存状态:使用Redis缓存审核状态,减少数据库访问
  3. 异步处理:对于耗时操作,使用队列系统进行异步处理
  4. 事务控制:对于涉及多个表的审核操作,使用事务保证数据一致性

2. 安全防护

  1. CSRF防护:在前端添加CSRF token验证
  2. 输入过滤:对输入参数进行严格校验
  3. 日志审计:记录所有审核操作日志
  4. 权限控制:实施RBAC模型进行精细权限控制

3. 异常处理

// 增加异常处理
try {
    $result = $this->model->where(['id' => $id])->update(['status' => $status]);
    if (!$result) {
        throw new \Exception('更新失败');
    }
} catch (\Exception $e) {
    return json(['code' => 1, 'msg' => '系统错误: ' . $e->getMessage()]);
}

九、常见问题与踩坑

1. 常见错误

问题原因解决方案
按钮无响应未正确绑定事件检查@click绑定
状态未更新前端未正确更新数据使用this.articles更新数据
权限验证失败权限配置错误检查RBAC配置
网络请求失败未处理网络错误添加错误处理逻辑
跨域问题未配置CORS配置中间件处理

2. 常见坑点

  1. 权限验证顺序:先验证用户权限再处理业务逻辑
  2. 数据一致性:确保前端状态与后端数据同步
  3. CSRF防护:在AJAX请求中携带CSRF token
  4. 状态更新延迟:使用$nextTick确保DOM更新
  5. 批量操作:避免逐条更新导致性能问题

十、最佳实践

  1. 使用Vue3的响应式系统:确保数据变化时界面自动更新
  2. 使用防重锁机制:防止用户重复点击提交
  3. 添加操作日志:记录所有审核操作以便审计
  4. 使用缓存机制:减少对数据库的频繁访问
  5. 实施RBAC模型:实现细粒度的权限控制
  6. 进行单元测试:确保审核逻辑正确性
  7. 使用日志系统:记录所有审核操作日志

十一、总结

通过在FastAdmin表格右侧操作栏添加审核按钮,实现审核状态的灵活切换,我们深入探讨了其技术原理、实现方法、性能优化、安全防护和常见问题。这种方案适用于需要精细审核控制的内容管理系统,但需要注意以下几点:

适用场景:

  • 内容审核系统
  • 商品审核平台
  • 会员资质审核
  • 信息报备系统

不适用场景:

  • 高并发审核场景(需异步处理)
  • 需要实时状态同步的系统
  • 无需用户交互的审核流程
  • 需要复杂审核规则的系统

通过本文的深入探讨,我们不仅掌握了实现该功能的技术要点,还了解了在实际项目中如何合理应用和规避潜在风险。在实际开发中,应根据具体业务需求选择合适的实现方案,并结合性能优化、安全防护等最佳实践,确保系统的稳定性和可维护性。

最后修改于:2026年09月29日 15:28

评论已关闭

推荐阅读

AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日
python之plot()和subplot()画图
2024年11月26日
理解 DALL·E 2、Stable Diffusion 和 Midjourney 工作原理
2024年12月01日