Laravel Vuejs 实战:开发知乎 (28-29)私信功能
1.数据库迁移:
1 php artisan make:model Message –m
****_create_messages_table:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <?php 2 3 use Illuminate\Database\Migrations\Migration; 4 use Illuminate\Database\Schema\Blueprint; 5 use Illuminate\Support\Facades\Schema; 6 7 class CreateMessagesTable extends Migration 8 { 9 /** 10 * Run the migrations. 11 * 12 * @return void 13 */ 14 public function up() 15 { 16 Schema::create('messages', function (Blueprint $table) { 17 $table->bigIncrements('id'); 18 $table->unsignedBigInteger('from_user_id')->comment("发送私信的用户的id"); 19 $table->unsignedBigInteger('to_user_id')->comment("接受私信的用户的id"); 20 $table->text('content')->comment("私信的内容"); 21 $table->timestamp('read_at')->nullable()->comment("接收方阅读的时间"); 22 $table->timestamps(); 23 }); 24 } 25 26 /** 27 * Reverse the migrations. 28 * 29 * @return void 30 */ 31 public function down() 32 { 33 Schema::dropIfExists('messages'); 34 } 35 } 36 37
2.模型关联:
Message.php
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <?php 2 3 namespace App; 4 5 use Illuminate\Database\Eloquent\Model; 6 7 class Message extends Model 8 { 9 // 10 11 protected $table = 'messages'; 12 13 protected $fillable = ['from_user_id', 'to_user_id', 'content']; 14 15 public function fromUser() 16 { 17 return $this->belongsTo(User::class, 'from_user_id'); 18 } 19 20 public function toUser() 21 { 22 return $this->belongsTo(User::class, 'to_user_id'); 23 } 24 } 25 26
User.php
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <?php 2 3 namespace App; 4 5 use App\Models\Question; 6 use Illuminate\Contracts\Auth\MustVerifyEmail; 7 use Illuminate\Database\Eloquent\SoftDeletes; 8 use Illuminate\Foundation\Auth\User as Authenticatable; 9 use Illuminate\Notifications\Notifiable; 10 11 class User extends Authenticatable implements MustVerifyEmail 12 { 13 use Notifiable; 14 #region 支持软删除 15 use SoftDeletes; 16 protected $dates = ['deleted_at']; 17 #endregion 18 /** 19 * The attributes that are mass assignable. 20 * 21 * @var array 22 */ 23 protected $fillable = [ 24 'name', 'email', 'password', 'avatar', 'activation_token', 'api_token' 25 ]; 26 27 /** 28 * The attributes that should be hidden for arrays. 29 * 30 * @var array 31 */ 32 protected $hidden = [ 33 'password', 'remember_token', 34 ]; 35 36 /** 37 * The attributes that should be cast to native types. 38 * 39 * @var array 40 */ 41 protected $casts = [ 42 'email_verified_at' => 'datetime', 43 ]; 44 45 46 /**添加用户模型和问题模型的模型关联 47 * @return \Illuminate\Database\Eloquent\Relations\HasMany 48 */ 49 public function questions() 50 { 51 return $this->hasMany(Question::class); 52 } 53 54 55 /** 添加用户模型和回答模型的模型关联 一个用户可以有多个回答 56 * @return \Illuminate\Database\Eloquent\Relations\HasMany 57 */ 58 public function answers() 59 { 60 return $this->hasMany(Answer::class); 61 } 62 63 64 public function followQuestions() 65 { 66 //默认表名 可以不设置后面三个参数,自定义表名需要设置 67 return $this->belongsToMany(Question::class, 'users_questions', 'question_id', 'user_id')->withTimestamps(); 68 } 69 70 71 /** 用户的粉丝 72 * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany 73 */ 74 public function followers() 75 { 76 77 return $this->belongsToMany 78 ( 79 self::class, 80 'followers', 81 'user_id', //foreignPivotKey:当前模型在中间表的字段(当前模型类的外键) //【当前模型是leader】的外键id 82 'follower_id'//relatedPivotKey:另一模型在中间表的字段(另一模型类的外键) 83 )->withTimestamps(); 84 } 85 86 87 /** 用户关注的作者 88 * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany 89 */ 90 public function followings() 91 { 92 return $this->belongsToMany 93 ( 94 self::class, 95 'followers', 96 'follower_id',//foreignPivotKey:当前模型在中间表的字段(当前模型类的外键) //【当前模型是粉丝】的外键id 97 'user_id'//relatedPivotKey:另一模型在中间表的字段(另一模型类的外键) 98 ) 99 ->withTimestamps(); 100 } 101 102 103 /** 104 * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany 105 */ 106 public function votes() 107 { 108 return $this->belongsToMany(Answer::class, 'votes')->withTimestamps(); 109 } 110 111 112 /** 113 * @param $answer_id 114 * @return array 115 */ 116 public function voteAnswer($answer_id) 117 { 118 return $this->votes()->toggle($answer_id); 119 } 120 121 122 public function messages() 123 { 124 return $this->hasMany(Message::class, 'to_user_id'); 125 } 126 127 128 } 129 130
3.执行迁移
1 php artisan migrate
4.view层 vue
vue层:【要点击按钮弹出一个对话框,点击发送按钮,发送数据】
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <template> 2 <div> 3 <button class="btn btn-sm btn-secondary ml-2" 4 @click="showMessageForm">私信 5 </button> 6 7 <div class="modal fade" id="model-send-message" tabindex="-1" role="dialog"> 8 <div class="modal-dialog"> 9 <div class="modal-content"> 10 <div class="modal-header"> 11 <h4 class="modal-title"> 12 编辑并发送私信 13 </h4> 14 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> 15 </div> 16 17 <div class="modal-body"> 18 <textarea class="form-control" rows="10" v-model="message" v-if="!success"></textarea> 19 <div class="alert alert-success" v-if="success">私信发送成功!</div> 20 </div> 21 22 <!-- Modal Actions --> 23 <div class="modal-footer"> 24 <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button> 25 <button type="button" class="btn btn-success" @click="send" v-if="!success">发送</button> 26 </div> 27 </div> 28 </div> 29 </div> 30 </div> 31 </template> 32 33 <script> 34 export default { 35 props: ['user'], 36 name: "SendMessage", 37 data() { 38 return { 39 voteable: true, 40 message: '', 41 success: false, 42 } 43 }, 44 computed: {}, 45 mounted: function () { 46 47 }, 48 methods: { 49 send() { 50 let currentObj = this; 51 axios.post('/api/messages/send', {'user': this.user, 'message': this.message}) 52 .then(function (response) { 53 currentObj.message = ''; 54 currentObj.success = response.data.success; 55 //两秒钟后关闭弹窗 56 if (currentObj.success) { 57 setTimeout(function () { 58 $('#model-send-message').modal('hide'); 59 }, 2000); 60 } 61 } 62 ) 63 .catch(function (e) { 64 console.log(e); 65 }); 66 }, 67 showMessageForm() { 68 $('#model-send-message').modal('show');//显示发送编辑框 69 } 70 } 71 } 72 </script> 73 74 <style scoped> 75 76 </style> 77 78
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <div> 2 <img src="{{ $userable->user->avatar }}" class="card-img img-thumbnail imgWrap " 3 style="width: 50px" alt="{{ $userable->user->name }}"> 4 <span class="text text-info">{{ $userable->user->name }}</span> 5 </div> 6 <div class="float-left mt-2"> 7 <user-follow-button user="{{ $userable->user->id }}"user->id }}"></user-follow-button> 8 @if(auth()->check()) 9 @if(auth()->user()->id!==$userable->user->id) 10 <div class="float-right"> 11 <send-message user="{{ $userable->user->id }}"user->id }}"></send-message> 12 </div> 13 @endif 14 @endif 15 </div> 16 17
路由:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <?php 2 3 use Illuminate\Http\Request; 4 5 /* 6 |-------------------------------------------------------------------------- 7 | API Routes 8 |-------------------------------------------------------------------------- 9 | 10 | Here is where you can register API routes for your application. These 11 | routes are loaded by the RouteServiceProvider within a group which 12 | is assigned the "api" middleware group. Enjoy building your API! 13 | 14 */ 15 16 Route::middleware('auth:api')->get('/user', function (Request $request) { 17 return $request->user(); 18 }); 19 20 Route::middleware('api')->get('/topics', function (Request $request) { 21 $query = $request->query('q'); 22 return \App\Topic::query()->where('name', 'like', '%' . $query . '%')->get(); 23 }); 24 #region 问题关注 25 //加载页面时取关注状态 26 Route::middleware('auth:api')->post('/questions/follow/stats', 'QuestionController@getFollowStats'); 27 //执行关注/取关操作 28 Route::middleware('auth:api')->post('/questions/follow', 'QuestionController@followThroughApi'); 29 #endregion 30 31 #region 用户关注 32 //加载页面时取关注状态 33 Route::middleware('auth:api')->post('/users/follow/stats', 'FollowerController@getFollowStats'); 34 //执行关注/取关操作 35 Route::middleware('auth:api')->post('/users/follow', 'FollowerController@followThroughApi'); 36 37 #endregion 38 39 40 #region 41 //加载页面时取赞状态 42 Route::middleware('auth:api')->post('/answers/vote/stats', 'VoteController@getVoteStats'); 43 //执行赞/取消赞操作 44 Route::middleware('auth:api')->post('/answers/vote/up', 'VoteController@voteUpThroughApi'); 45 #endregion 46 47 48 #region 49 50 Route::middleware('auth:api')->post('/messages/send', 'MessageController@store'); 51 52 #endregion 53 54
控制器:
1 php artisan make:controller MessageController
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <?php 2 3 namespace App\Http\Controllers; 4 5 use App\Message; 6 use App\User; 7 use Illuminate\Http\Request; 8 9 class MessageController extends Controller 10 { 11 // 12 13 public function __construct() 14 { 15 $this->middleware('auth'); 16 } 17 18 public function store(Request $request) 19 { 20 $toUser = $request->get('user'); 21 22 $currentUser = auth()->user()->id; 23 24 $content = $request->get('message'); 25 26 if ($content) { 27 $data = [ 28 'from_user_id' => $currentUser, 29 'to_user_id' => $toUser, 30 'content' => $content, 31 ]; 32 $message = Message::create($data); 33 if ($message) { 34 return response()->json(['success' => true]); 35 } 36 } 37 return response()->json(['success' => false]); 38 } 39 } 40 41