上节回顾
-
JWT
相关
工作内容
- 更新用户数据
准备工作
无
业务逻辑
页面调用用户信息
//更新文件:client/src/views/personal-panel/index.vue
...
<script>
import http from '@/utils/http'
export default {
data () {
return {
loginer: {}
}
},
async created () {
const { id } = this.$store.state.loginer
const res = await http.get(`/users/${id}`)
this.loginer = res.data
}
}
</script>
在登录的时候,已经将登录用户信息存储到vuex
中,通过用户ID查询用户详细信息。
服务端查询用户服务
// 更新文件: server/router/users.js
...
const { list, get, register, login, update } = require('../control/users');
...
{
path: '/:id',
method: 'GET',
handle: get
},
...
// 更新文件:server/control/users.js
async function get (ctx) {
const { id } = ctx.params;
try {
const user = await userModel.findOne({
_id: id
}).select('+telephone +email'); //新增查询除默认外的字段
if (user) {
ctx.body = {
code: '200',
data: user,
msg: '成功'
}
return;
}
throw('请核对参数')
} catch (err) {
ctx.body = {
code: '403',
data: null,
msg: err.message
}
}
}
...
module.exports = {
...
get,
...
}
- 其中,
userModel.findOne({_id: id})
默认查出的是Schema
没有设置select: false
的字段,如果需要其它字段的话,需要userModel.findOne({_id: id}).select('+telephone +email');
新增字段 - 通过
ctx.params
获取匹配路由:id
参数。
前端展示布局
// 更新文件:client/src/views/personal-panel/index.vue
<template>
<div class="panel-container">
<div class="panel-avatar">
<el-upload
class="avatar-uploader"
v-bind="uploadForm">
<img v-if="imageUrl" :src="imageUrl" class="avatar">
<i v-else class="el-icon-user"></i>
</el-upload>
</div>
<div class="panel-main">
<h3 class="panel-title">{{loginer.alias || loginer.account}}</h3>
<ul class="panel-content">
<li class="panel-item">
<label class="panel-item-lanel">帐号:</label>
<span class="panel-item-value">{{loginer.account}}</span>
</li>
<li class="panel-item">
<label class="panel-item-lanel">邮箱:</label>
<span class="panel-item-value">{{loginer.email}}</span>
</li>
<li class="panel-item">
<label class="panel-item-lanel">电话:</label>
<span class="panel-item-value">{{loginer.telephone}}</span>
</li>
</ul>
<div class="panel-controls">
<el-button class="btn-edit" type="default" @click="openFormDialog">编辑</el-button>
</div>
</div>
</div>
</template>
<script>
import http from '@/utils/http'
export default {
methods: {
openFormDialog () {
}
},
data () {
return {
uploadForm: {
action: ''
},
imageUrl: '',
loginer: {}
}
},
async created () {
const { id } = this.$store.state.loginer
const res = await http.get(`/users/${id}`)
this.loginer = res.data
}
}
</script>
<style lang="scss" scoped>
@import '~@/stylesheets/layout.scss';
@import './index.scss';
</style>
// 新建文件:client/src/views/personal-panel/index.scss
.panel-container {
@include flex($item: flex-start);
.panel-avatar {
width: 160px;
}
.panel-main {
flex: 1;
color: #525975;
line-height: 2;
padding: 0 40px;
font-size: 14px;
.panel-title {
color: #2e3242;
font-size: 24px;
}
}
.panel-controls {
margin-top: 20px;
}
}
.avatar-uploader{
/deep/ {
.el-upload {
border: 1px dashed #d9d9d9;
border-radius: 100px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.el-upload:hover {
border-color: #409EFF;
}
.el-icon-user {
font-size: 70px;
color: #8c939d;
width: 160px;
height: 160px;
line-height: 160px;
text-align: center;
}
.avatar {
width: 160px;
height: 160px;
display: block;
}
}
}
展示效果
前端编辑用户信息
// 更新文件:client/src/views/personal-panel/index.vue
<template>
<div class="panel-container">
<div class="panel-avatar">
<el-upload
class="avatar-uploader"
v-bind="uploadForm">
<img v-if="imageUrl" :src="imageUrl" class="avatar">
<i v-else class="el-icon-user"></i>
</el-upload>
</div>
<div class="panel-main">
<h3 class="panel-title">{{loginer.alias || loginer.account}}</h3>
<ul class="panel-content">
<li class="panel-item">
<label class="panel-item-lanel">帐号:</label>
<span class="panel-item-value">{{loginer.account}}</span>
</li>
<li class="panel-item">
<label class="panel-item-lanel">邮箱:</label>
<span class="panel-item-value">{{loginer.email}}</span>
</li>
<li class="panel-item">
<label class="panel-item-lanel">电话:</label>
<span class="panel-item-value">{{loginer.telephone}}</span>
</li>
</ul>
<div class="panel-controls">
<el-button class="btn-edit" type="default" @click="openFormDialog">编辑</el-button>
</div>
</div>
<el-dialog :title="dialogForm.title" :visible.sync="dialogForm.visible">
<el-form :ref="dialogForm.formRef" :model="dialogForm.form" :rules="dialogForm.rules">
<el-form-item label="帐号" prop="account">
<el-input v-model="dialogForm.form.account"></el-input>
</el-form-item>
<el-form-item label="昵称" prop="alias">
<el-input v-model="dialogForm.form.alias"></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input type="email" v-model="dialogForm.form.email"></el-input>
</el-form-item>
<el-form-item label="电话" prop="telephone">
<el-input type="telephone" v-model="dialogForm.form.telephone"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogForm.visible = false">取 消</el-button>
<el-button type="primary" @click="submitForm">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import http from '@/utils/http'
export default {
methods: {
openFormDialog () {
this.dialogForm.visible = true
},
async submitForm () {
try {
const valid = await this.$refs[this.dialogForm.formRef].validate()
if (valid) {
const res = await http.patch(
`/users/${this.userId}`,
{
...this.dialogForm.form
}
)
if (res.code === '200') {
const { account, alias } = res.data
this.$store.commit(
'putLoginer',
{
account,
alias
}
) // 更新vuex状态
this.loginer = Object.assign(
{},
this.loginer,
{
...res.data
}
) // 更新展示的默认值
this.$set(this.dialogForm, 'form', Object.assign(
{},
this.dialogForm.form,
{
...res.data
}
)) // 更新弹窗默认值
this.dialogForm.visible = false
} else {
this.$message({
type: 'error',
message: res.msg
})
}
}
} catch (err) {
console.error(err)
}
}
},
data () {
return {
uploadForm: {
action: ''
},
imageUrl: '',
loginer: {},
dialogForm: {
visible: false,
title: '编辑',
formRef: 'dialogForm',
form: {
account: '',
alias: '',
email: '',
telephone: ''
},
rules: {
account: [
{ required: true, message: '请输入帐号', trigger: 'blur' },
{ min: 5, message: '长度至少5个字符', trigger: 'blur' }
],
alias: [
{ required: true, message: '请输入昵称', trigger: 'blur' },
{ min: 1, max: 15, message: '长度不能超过十五个字符', trigger: 'blur'}
],
email: [
{ type: 'email', required: true, message: '请输入邮箱', trigger: 'blur' }
],
telephone: [
{ required: true, message: '请输入手机号码', trigger: 'blur' },
{
validator: (rule, value, cb) => {
if (/^1[0-9]{10}$/.test(value)) {
cb()
} else {
cb(new Error('手机号码格式错误'))
}
},
trigger: 'blur'
}
]
}
}
}
},
computed: {
userId () {
return this.$store.state.loginer.id
}
},
async created () {
// 调用完初始化接口时,需要赋展示初始值
const res = await http.get(`/users/${this.userId}`)
if (res.code === '200') {
this.loginer = res.data
this.dialogForm.form = {...res.data}
this.imageUrl = res.data.avatar
} else {
this.$message({
type: 'error',
message: '获取用户信息失败'
})
}
}
}
</script>
-
get
方法调用/users/:id
接口后,需要给用户设初始值。 -
patch
方法调用/users/:id
接口,更新用户信息后,要更新vuex
存储的状态,更新展示的用户信息,更新弹窗初始值。
展示效果:
服务端更新用户服务
// 更新文件:server/control/users.js
...
async function update (ctx) {
const { id } = ctx.params;
const payload = ctx.request.body;
try {
await userModel.updateOne(
{
_id: id
},
{
...payload
}
);
ctx.body = {
code: '200',
data: {
id,
...payload
},
msg: '更新成功'
}
} catch (err) {
ctx.body = {
code: '403',
data: null,
msg: '请核查参数'
}
}
}
...
测试结果:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。