(十一:完结)Vue项目——轻社区:完成回复操作—发表回复+修改、删除回复

本文详细介绍了如何在论坛应用中实现回复功能,包括创建回复表的数据库迁移,发表回复的前端组件及API接口,加载和显示回复列表,以及编辑和删除回复的操作。涉及到的技术栈包括ThinkPHP框架、Vue.js和前端交互。
摘要由CSDN通过智能技术生成

目录

回复操作

1.创建回复表

2.发表回复

3.回复列表

4.修改回复

5.删除回复

6.删除主题时隐藏关联的回复


回复操作

1.创建回复表

执行命令。

php think migrate:create Reply

打开database\migrations\…_reply.php,编写change()方法。

public function change()

{

    $table = $this->table(

        'reply',

        ['engine' => 'InnoDB', 'collation' => 'utf8mb4_general_ci']

    );

    $table->addColumn(

        'topic_id',

        'integer',

        ['null' => false, 'default' => 0, 'comment' => '分类id']

    )

    ->addColumn(

        'user_id',

        'integer',

        ['null' => false, 'default' => 0, 'comment' => '用户id']

    )

    ->addColumn(

        'content',

        'text',

        ['null' => false, 'comment' => '回复内容']

    )

    ->addColumn(

        'is_show',

        'boolean',

        ['null' => false, 'default' => 0, 'comment' => '是否显示']

    )

    ->addTimestamps()

    ->create();

}

执行迁移。

php think migrate:run

2.发表回复

编写src\components\topic\Reply.vue。

<template>

  <div class="reply">

    <div class="add-reply mt-4">

      <div class="row mb-1">

        <div class="col-md-8">

          <textarea ref="reply" maxlength="10000" v-model="reply.content"></textarea>

        </div>

      </div>

      <input type="button" class="btn btn-primary" @click="sendReply" value="发布评论" />

    </div>

  </div>

</template>

<script>

export default {

  data () {

    return {

      topic_id: this.$route.params.id,

      reply: {

        content: ''

      },

    }

  },

  methods: {

    sendReply () {

      // 发布评论

    }

  }

}

</script>

<style scoped>

.add-reply textarea {

  width: 100%;

  height: 80px;

  border-radius: 3px;

  padding: 5px;

  font-size: 14px;

  border: 1px solid #ccc;

}

.add-reply button {

  margin-top: 10px;

}

</style>

页面效果如下。

编写sendReply()方法。

sendReply () {

  var data = { topic_id: this.topic_id, content: this.reply.content }

  this.$http.post('reply/save', data).then(res => {

    if (res.data.code === 0) {

      this.$toastr.e(res.data.msg)

    } else if (res.data.code === 1) {

      this.$toastr.s(res.data.msg)

    }

  }).catch(() => {

    this.$toastr.e('服务器异常。')

  })

},

route\route.php,编写服务器端路由。

Route::post('reply/save', 'api/Reply/save');

创建application\api\controller\Reply.php

<?php

namespace app\api\controller;

class Reply extends Common

{

    protected $checkActive = ['save', 'del'];

    public function save()

    {

        $id = $this->request->post('id/d', 0);

        $data = [

            'topic_id' => $this->request->post('topic_id/d', 0),

            'content' => $this->request->post('content/s', '')

        ];

    }

}

创建application\api\validate\Reply.php

<?php

namespace app\api\validate;

use think\Validate;

class Reply extends Validate

{

    protected $rule = [

        'content' => 'checkText:65535'

    ];

    protected $message = [

    ];

    protected function checkText($value, $rule)

    {

        return strlen($value) <= $rule ? true : '内容最多65535个字节';

    }

}

创建application\api\model\Reply.php。

<?php

namespace app\api\model;

use think\Model;

class Reply extends Model

{

}

导入命名空间。

use app\api\validate\Reply as ReplyValidate;

use app\api\model\Reply as ReplyModel;

打开application\api\controller\Reply.php,继续编写save()方法。

public function save()

{

    ……(原有代码)

    $validate = new ReplyValidate();

    if (!$validate->check($data)) {

        $this->error('操作失败,' . $validate->getError() . '');

    }

    if ($id) {

        if (!$reply = ReplyModel::get($id)) {

            $this->error('修改失败,记录不存在。');

        }

        if ($this->user->role !== 'admin' && $this->user->id !== $reply->user_id) {

            $this->error('修改失败,您没有权限修改此内容。');

        }

        $reply->save($data);

        $this->success('修改成功。', null, ['id' => $id]);

    } else {

        $data['is_show'] = true;

        $data['user_id'] = $this->user->id;

        $reply = ReplyModel::create($data);

        $this->success('添加成功。', null, ['id' => $reply->id]);

    }

}

测试程序。

3.回复列表

修改src\components\topic\Reply.vue,在页面打开后加载回复列表。

<script>

import Pagination from '../../components/Pagination'

export default {

  data () {

    return {

      ……(原有代码)

      replies: [],

      page: {

        current: parseInt(this.$route.params.page) || 1,

        total: 0,

        size: 7

      }

    }

  },

  created () {

    this.getReply()

  },

  methods: {

    getReply () {

      var params = { topic_id: this.topic_id, page: this.page.current, size: this.page.size }

      this.$http.get('reply/index', { params: params }).then(res => {

        if (res.data.code === 1) {

          this.replies = res.data.data.data

          this.page.current = res.data.data.page

          this.page.total = res.data.data.total

        }

      }).catch(() => {

        this.$toastr.e('加载失败,服务器异常。')

      })

    },

    pageChange (page) {

      this.page.current = page

      this.getReply()

    },

    ……(原有代码)

  },

  components: { Pagination }

}

打开src\components\topic\Reply.vue,在页面中输出。

<div class="reply">

  <ul class="list-group list-group-flush mb-4">

    <li class="list-group-item bg-light" v-for="(reply,index) in replies" :key="index">

      <div class="row">

        <div clas="col">

          <img :src="reply.user.img_url" class="rounded-circle reply-img">

        </div>

        <div clas="col">

          <div class="row">

            <span>

              <strong>{{ reply.user.name }}</strong>

              <span class="small text-muted">

                <span class="d-none d-md-inline"> 创建于 {{ reply.create_time }} </span>

                <span>更新于 {{ reply.update_time }}</span>

              </span>

            </span>

          </div>

          <div class="row card-text">{{ reply.content }}</div>

        </div>

      </div>

    </li>

  </ul>

  <Pagination :current="page.current" :total="page.total" :size="page.size" @change="pageChange"></Pagination>

  ……(原有代码)

</div>

添加样式。

<style scoped>

……(原有代码)

.reply {

  font-size: 14px;

  margin-top: 20px;

  margin-bottom: 20px;

}

.reply span {

  color: #385f8a;

}

.reply-img {

  width: 44px;

  height: 44px;

  margin-right: 25px;

}

</style>

打开route\route.php,添加服务器端路由。

Route::get('reply/index', 'api/Reply/index');

打开application\api\model\Reply.php,编写user()方法。

public function user()

{

    return $this->belongsTo('User', 'user_id');

}

打开application\api\controller\Reply.php,编写index()方法。

public function index()

{

    $topic_id = $this->request->get('topic_id/d', 0);

    $page = max($this->request->get('page/d', 1), 1);

    $size = max(min($this->request->get('size/d', 10), 50), 1);

    $where = ['is_show' => 1, 'topic_id' => $topic_id];

    $total = ReplyModel::where($where)->count();

    $data = ReplyModel::with(['user' => function ($query) {

        $query->field('id,name,img_url');

    }])->where($where)->order('id', 'desc')->limit(($page - 1) * $size, $size)->select();

    $data = array_map(function ($v) {

        $v['user']['img_url'] = $this->avatarUrl($v['user']['img_url']);

        return $v;

    }, $data->toArray());

    $this->success('', null, [

        'data' => $data,

        'total' => $total,

        'page' => $page

    ]);

}

在发表回复成功后,更新列表,并重置表单。

sendReply () {

  var data = { topic_id: this.topic_id, content: this.reply.content }

  this.$http.post('reply/save', data).then(res => {

    if (res.data.code === 0) {

      this.$toastr.e(res.data.msg)

    } else if (res.data.code === 1) {

      this.$toastr.s(res.data.msg)

      this.resetReply()

      this.getReply()

    }

  }).catch(() => {

    this.$toastr.e('服务器异常。')

  })

},

resetReply () {

  this.reply.content = ''

},

页面效果如下。

4.修改回复

打开src\components\topic\Reply.vue。

<script>

import { mapState } from 'vuex'

import Pagination from '../../components/Pagination'

export default {

  data () {

    ……(原有代码)

  },

  computed: {

    ...mapState(['user'])

  },

  ……(原有代码)

}

</script>

在回复的旁边放上“编辑”按钮。

<span>

  <strong>{{ reply.user.name }}</strong>

  ……(原有代码)

  <span v-if="user.role === 'admin' || user.id == reply.user_id">

    <button class="btn btn-link opt" @click="editReply(reply)">编辑</button>

  </span>

</span>

在data中给reply增加一个id,表示当前编辑的回复的id。

reply: {

  id: 0,

  content: ''

},

在methods中增加editReply()方法。

methods: {

  ……(原有代码)

  editReply (reply) {

    this.reply.id = reply.id

    this.reply.content = reply.content

    this.$refs.reply.focus()

  },

}

当设置了回复的id以后,将“发布评论”按钮改为“修改评论”,并提供一个“取消”按钮。

<div class="add-reply mt-4">

  ……(原有代码)

  <input type="button" class="btn btn-primary" @click="sendReply" :value="reply.id ? '修改评论' : '发布评论'" />

  <input type="button" v-if="reply.id" class="btn btn-default ml-1" @click="resetReply" value="取消" />

</div>

修改sendReply()方法,将id放入data中发送。

sendReply () {

  var data = { topic_id: this.topic_id, content: this.reply.content, id: this.reply.id }

  ……(原有代码)

},

修改resetReply()方法,将id设为0。

resetReply () {

  this.reply.id = 0

  this.reply.content = ''

},

添加样式。

<style scoped>

……(原有代码)

.opt {

  color: #adadad;

  font-size: 12px;

}

.opt:hover {

  text-decoration: none;

  color: #666;

}

</style>

页面效果如下。

单击“编辑”后,效果如下。

5.删除回复

打开src\components\topic\Reply.vue,添加“删除”按钮。

<span v-if="user.role === 'admin' || user.id == reply.user_id">

  ……(原有代码)

  <button class="btn btn-link opt" @click="delReply(index, reply.id)">删除</button>

</span>

在methods中编写delReply()方法。

methods: {

  ……(原有代码)

  delReply (index, id) {

    this.replies.splice(index, 1)

    this.$http.post('reply/del', { id: id }).then(res => {

      if (res.data.code === 0) {

        this.$toastr.e(res.data.msg)

      } else if (res.data.code === 1) {

        this.$toastr.s(res.data.msg)

      }

    })

  }

}

打开route\route.php,编写服务器端路由。

Route::post('reply/del', 'api/Reply/del');

打开application\api\controller\Reply.php,编写del()方法。

public function del()

{

    $id = $this->request->post('id/d', 0);

    $reply = ReplyModel::where([

        'is_show' => true

    ])->get($id);

    if (!$reply) {

        $this->error('删除失败,记录不存在。');

    }

    if ($this->user->role !== 'admin' && $reply->user_id !== $this->user->id) {

        $this->error('删除失败,您没有权限执行此操作。');

    }

    $reply->is_show = false;

    $reply->save();

    $this->success('删除成功。', null, []);

}

测试程序。

6.删除主题时隐藏关联的回复

打开application\api\controller\Topic.php,先导入命名空间。

use app\api\model\Reply as ReplyModel;

找到del()方法,进行修改。

public function del()

{

    ……(原有代码)

    ReplyModel::where(['topic_id' => $id, 'is_show' => true])->update(['is_show' => false]);

    $this->success('删除成功。', null, []);

}

测试程序。

大功告成啦、、嘿嘿~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值