基于 Laravel + Swoole + Vue 搭建实时在线聊天室(十五):实现用户头像上传功能

头像上传页面入口

之前遗漏了头像上传功能,这里补充一下,头像上传入口位于我的->修改头像里面:

用户个人中心页面

用户头像上传页面

我们只需要在头像上传页面点击上传头像,进行裁剪后,保存头像,即可将其上传并保存到用户表。

调整 mu-icon-button 组件

不过目前这个页面还在报错:

mu-icon-button组件报错

还是 Muse UI 3.0 版本移除对 mu-icon-button 元素支持的原因,下面我们将其调整为为 mu-button 组件。

打开头像上传页面组件 resources/js/pages/Avatar.vuemu-icon-button 的引入位于 Header 子组件中:

<Header></Header>

打开定义该组件的文件 resources/js/components/Header/index.vue,找到下面这段模板代码:

<mu-appbar title="Title">
    <mu-icon-button icon="chevron_left" slot="left" @click="goback"/>
    <div class="center">
    </div>
    <mu-icon-button icon="expand_more" slot="right"/>
</mu-appbar>

将所有 mu-icon-button 组件调整为 mu-button 组件:

<mu-appbar title="Title">
    <mu-button icon slot="left" @click="goback">
        <mu-icon value="chevron_left"></mu-icon>
    </mu-button>
    <div class="center">
    </div>
    <mu-button icon slot="right">
        <mu-icon value="expand_more"></mu-icon>
    </mu-button>
</mu-appbar>

然后重新编译前端资源:

npm run dev

这样再次访问头像上传页面就不会报错了。

前端页面头像上传逻辑

回到 resources/js/pages/Avatar.vue,上传头像文件到后端的逻辑定义在 postAvatar() 方法中的如下这段代码(点击“保存头像”按钮时才会执行,而上传和裁剪操作都是纯前端行为):

let files = new window.File([data], this.name, {type: this.type});
const formdata = new window.FormData();
formdata.append('file', files);
formdata.append('username', getItem('userid'));
const res = await this.$store.dispatch('uploadAvatar', formdata);

和之前定义的很多其它前后端交互逻辑一样,这里我们将表单字段中的 username 调整为 api_token,以便后端 API 接口可以通过它实现自动认证:

formdata.append('api_token', this.auth_token);

相应的,需要在计算属性中新增 auth_token 并从 localStorage 中读取对应的 token 字段值:

computed: {
  ...mapState({
    userid: state => state.userInfo.userid,
    src: state => state.userInfo.src,
    auth_token: state => state.userInfo.token
  })
}

然后基于 Vuex 定义的 uploadAvatar 动作对后端头像上传接口发起请求,对应的接口调用定义在 resources/js/api/server.js 中:

// 上传头像
postUploadAvatar: data => Axios.post('/file/avatar', data, {
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
}),

目前在后端还没有实现这个接口,接下来,我们到 Laravel 后端补齐这个接口。

头像上传后端接口实现

routes/api.php 中新增路由 file/avatar

Route::middleware('auth:api')->group(function () {
    ...
    Route::post('/file/avatar', 'FileController@avatar');
}

然后在 FileController 控制器中编写 avatar 方法实现:

public function avatar(Request $request)
{
    if (!$request->hasFile('file') || !$request->file('file')->isValid()) {
        return response()->json([
            'errno' => 500,
            'msg'   => '无效的参数(头像图片为空或者无效)'
        ]);
    }
    $image = $request->file('file');
    $time = time();
    $filename = md5($time . mt_rand(0, 10000)) . '.' . $image->extension();
    $path = $image->storeAs('images/avatars/' . date('Y/m/d', $time), $filename, ['disk' => 'public']);
    if ($path) {
        // 保存用户头像信息到数据库
        $user = auth('api')->user();
        $user->avatar = Storage::disk('public')->url($path);
        $user->save();
        return response()->json([
            'errno' => 0,
            'data' => [
                'url' => $path
            ],
            'msg'   => '保存成功'
        ]);
    } else {
        return response()->json([
            'errno' => 500,
            'msg'   => '文件上传失败,请重试'
        ]);
    }
}

上篇教程编写的消息图片上传接口类似,只是这里是将头像保存到了 images/avatars 目录,然后将完整路径信息保存到用户表的 avatar 字段,从而完成用户头像的更新。

重新编译前端资源并重启 Swoole HTTP 服务器让前后端代码修改生效。

测试头像上传功能

最后,我们来测试下头像上传功能,强制刷新头像上传页面,上传新的用户头像,然后保存头像调用上传头像接口,保存成功后,会弹出如下提示框:

测试用户头像上传功能

点击确定后,页面会跳转到用户个人中心页面,并显示新的用户头像:

头像上传成功跳转到个人主页

至此,用户头像上传功能完成。

这样我们就完成了聊天室项目的所有前端页面交互功能,接下来,学院君会花两三个篇幅的教程对后端 Websocket 服务器实现代码进行优化,从而完结掉 Laravel + Swoole 聊天室项目的开发,进入下一段 Laravel 旅程。

上一篇: 基于 Laravel + Swoole + Vue 搭建实时在线聊天室(十四):发送图片消息

下一篇: 基于 Laravel + Swoole + Vue 搭建实时在线聊天室(十六):轮询保持长连接优化