提交 3a37af3f authored 作者: 王鹏飞's avatar 王鹏飞

feat: 新增个人信息模块

上级 f369ccc8
差异被折叠。
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
}, },
"dependencies": { "dependencies": {
"axios": "^0.21.1", "axios": "^0.21.1",
"blueimp-md5": "^2.18.0",
"clipboard": "^2.0.8", "clipboard": "^2.0.8",
"element-ui": "^2.15.5", "element-ui": "^2.15.5",
"qrcode.vue": "^1.7.0", "qrcode.vue": "^1.7.0",
...@@ -20,6 +21,7 @@ ...@@ -20,6 +21,7 @@
"vant": "^2.12.26", "vant": "^2.12.26",
"vue": "^2.6.14", "vue": "^2.6.14",
"vue-router": "^3.5.2", "vue-router": "^3.5.2",
"vuedraggable": "^2.24.3",
"vuex": "^3.6.2" "vuex": "^3.6.2"
}, },
"devDependencies": { "devDependencies": {
......
<template>
<div class="app-card">
<div class="app-card-hd">
<slot name="header">
<h2 class="app-card-hd__title" v-if="title">{{ title }}</h2>
<slot name="header-aside"></slot>
</slot>
</div>
<div class="app-card-bd">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: 'AppCard',
props: { title: String }
}
</script>
<style>
.app-card {
background-color: #fff;
border-radius: 8px;
border: 1px solid #dadce0;
box-sizing: border-box;
overflow: hidden;
margin-top: 24px;
}
.app-card-hd {
display: flex;
padding: 24px;
}
.app-card-hd__title {
flex: 1;
font-size: 1.375rem;
font-weight: 400;
letter-spacing: 0;
line-height: 1.75rem;
word-break: break-word;
word-wrap: break-word;
color: #202124;
}
</style>
<template>
<header class="app-header">
<div class="logo">
<router-link to="/"><img src="https://zws-imgs-pub.ezijing.com/pc/base/ezijing-logo.svg" /></router-link>
</div>
<div class="app-header-right">
<el-dropdown>
<div class="avatar">
<img :src="user.avatar || 'https://webapp-pub.ezijing.com/website/base/images/avatar.svg'" />
</div>
<el-dropdown-menu slot="dropdown" style="width: 354px">
<div class="app-header-user">
<div class="app-header-user-avatar">
<img :src="user.avatar || 'https://webapp-pub.ezijing.com/website/base/images/avatar.svg'" />
</div>
<div class="app-header-user-main">
<h3>{{ user.realname || user.nickname }}</h3>
<p>{{ user.email || user.mobile }}</p>
</div>
<div class="app-header-user-buttons">
<router-link to="/settings">
<el-button size="medium" round>个人中心</el-button>
</router-link>
</div>
</div>
<ul>
<li class="app-header-dropwodn-item">
<router-link to="/payment"><i class="el-icon-money"></i><span>支付记录</span></router-link>
</li>
</ul>
<div class="app-header-buttons">
<el-button size="medium" @click="logout">退出</el-button>
</div>
</el-dropdown-menu>
</el-dropdown>
</div>
</header>
</template>
<script>
export default {
name: 'AppHeader',
computed: {
user() {
return this.$store.state.user.user
}
},
methods: {
logout() {
this.$store.dispatch('logout').then(() => {
window.location.href = `${import.meta.env.VITE_LOGIN_URL}?rd=${encodeURIComponent(window.location.href)}`
})
}
}
}
</script>
<style lang="scss">
.app-header {
padding: 0 20px;
display: flex;
align-items: center;
justify-content: space-between;
height: 64px;
background-color: #fff;
color: #fff;
// box-shadow: 0px 1px 2px 0px rgb(60 64 67 / 30%), 0px 2px 6px 2px rgb(60 64 67 / 15%);
.logo {
width: 120px;
}
}
.app-header-right {
display: flex;
.avatar {
width: 32px;
height: 32px;
border-radius: 50%;
overflow: hidden;
padding: 4px;
img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 50%;
overflow: hidden;
}
&:hover {
background-color: rgba(60, 64, 67, 0.08);
}
}
}
.app-header-user {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
padding: 16px;
}
.app-header-user-avatar {
margin-bottom: 6px;
width: 80px;
height: 80px;
border-radius: 50%;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.app-header-user-main {
h3 {
color: #202124;
font: 500 16px/22px Helvetica, Arial, sans-serif;
letter-spacing: 0.29px;
margin: 0;
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
}
p {
color: #5f6368;
font: 400 14px/19px Helvetica, Arial, sans-serif;
letter-spacing: normal;
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
}
}
.app-header-user-buttons {
padding: 16px 0;
}
.app-header-dropwodn-item {
border-bottom: 1px solid #e8eaed;
border-top: 1px solid #e8eaed;
a {
display: flex;
align-items: center;
background-color: #ffffff;
color: #3c4043;
font: 500 14px/16px Helvetica, Arial, sans-serif;
letter-spacing: 0.25px;
padding: 14px 40px;
box-sizing: border-box;
&:hover {
background-color: #ebf1ff;
}
}
span {
padding-left: 16px;
white-space: normal;
}
}
.app-header-buttons {
text-align: center;
padding-top: 14px;
}
</style>
<template>
<div class="app-layout">
<app-header></app-header>
<div class="app-layout-container">
<app-main></app-main>
</div>
</div>
</template>
<script>
import AppHeader from './Header.vue'
import AppMain from './Main.vue'
export default {
name: 'AppLayout',
components: { AppHeader, AppMain }
}
</script>
<style>
.app-layout {
display: flex;
flex-direction: column;
min-height: 100vh;
/* background-color: #f0f2f5; */
}
.app-layout-container {
flex: 1;
display: flex;
}
</style>
<template>
<section class="app-main">
<div class="app-main-inner">
<div class="app-main-container">
<router-view></router-view>
</div>
</div>
</section>
</template>
<script>
export default {
name: 'AppMain'
}
</script>
<style>
.app-main {
position: relative;
flex: 1;
padding: 20px;
}
.app-main-inner {
margin: 0 auto;
}
.app-main-container::after {
content: '';
display: table;
clear: both;
}
.el-form--label-top .el-form-item__label {
padding-bottom: 0;
}
</style>
<template>
<div class="app-upload">
<draggable
v-model="fileList"
group="people"
class="file-list el-upload-list--picture-card"
@end="onEnd"
v-if="showFileList"
>
<div class="file-item" v-for="(file, index) in fileList" :key="index">
<!-- <el-image style="width: 100%; height: 100%" :src="file.url" :preview-src-list="fileList.map(item => item.url)"> -->
<img :src="file.url" />
<span class="el-upload-list__item-actions">
<span class="el-upload-list__item-preview" @click="handlePreview(file)">
<i class="el-icon-zoom-in"></i>
</span>
<span v-if="!$attrs.disabled" class="el-upload-list__item-delete" @click="handleRemove(index)">
<i class="el-icon-delete"></i>
</span>
</span>
</div>
</draggable>
<el-upload
action="https://webapp-pub.oss-cn-beijing.aliyuncs.com"
type="drag"
:before-upload="beforeUpload"
:on-success="handleSuccess"
:show-file-list="false"
:on-exceed="handleExceed"
:data="data"
v-bind="$attrs"
v-on="$listeners"
style="display: inline"
>
<slot>
<i class="el-icon-plus"></i>
</slot>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="previewFile.url" />
</el-dialog>
</div>
</template>
<script>
import { getSignature } from '@/api/base'
import md5 from 'blueimp-md5'
import draggable from 'vuedraggable'
export default {
name: 'AppUpload',
components: { draggable },
props: {
value: { type: [String, Array] },
prefix: { type: String, default: 'upload/accounts/' },
showFileList: { type: Boolean, default: true }
},
data() {
return {
data: {}, // 请求参数
fileList: [], // 文件列表
dialogVisible: false,
previewFile: {},
message: null
}
},
watch: {
value: {
immediate: true,
handler(value) {
if (!value) {
return
}
let fileList = []
if (this.isMultiple) {
fileList = value.map(item => {
return { name: item.name || item, url: item.url || item }
})
} else {
fileList.push({ name: '附件', url: value })
}
this.fileList = [...fileList]
}
}
},
computed: {
isMultiple() {
return Array.isArray(this.value)
}
},
methods: {
beforeUpload(file) {
const limit = this.$attrs.limit
if (limit && this.fileList.length >= limit) {
this.message && this.message.close()
this.message = this.$message({ type: 'error', message: '文件超出个数限制' })
return false
}
const fileName = file.name
const key = this.prefix + md5(fileName + new Date().getTime()) + fileName.substr(fileName.lastIndexOf('.'))
return new Promise((resolve, reject) => {
getSignature()
.then(response => {
const { accessid, policy, signature, host } = response
this.data = { key, OSSAccessKeyId: accessid, policy, signature, success_action_status: '200' }
file.url = `${host}/${key}`
resolve(true)
})
.catch(err => {
console.log(err)
reject(err)
})
})
},
handleSuccess(response, file) {
let value = null
if (this.isMultiple) {
const limit = this.$attrs.limit
if (limit && this.fileList.length >= limit) {
return
}
this.fileList.push({ name: file.name, url: file.raw.url })
value = this.fileList
} else {
this.fileList = [file.raw.url]
value = file.raw.url
}
this.$emit('input', value)
this.dispatch('ElFormItem', 'el.form.change', value)
},
// 删除
handleRemove(index) {
this.fileList.splice(index, 1)
this.$emit('input', this.fileList)
this.dispatch('ElFormItem', 'el.form.change', this.fileList)
},
// 预览
handlePreview(file) {
this.previewFile = file
this.dialogVisible = true
},
handleExceed() {
this.$message({ type: 'error', message: '文件超出个数限制' })
},
onEnd() {
this.$emit('input', this.fileList)
},
dispatch(componentName, eventName, params) {
let parent = this.$parent || this.$root
let name = parent.$options.componentName
while (parent && (!name || name !== componentName)) {
parent = parent.$parent
if (parent) {
name = parent.$options.componentName
}
}
if (parent) {
parent.$emit.apply(parent, [eventName].concat(params))
}
}
}
}
</script>
<style lang="scss">
.el-upload-list--picture-card .el-upload-list__item-thumbnail {
object-fit: cover;
}
.el-upload-list__item {
transition: none !important;
}
.file-list {
margin: 0;
display: inline;
vertical-align: top;
}
.file-item {
position: relative;
overflow: hidden;
background-color: #fff;
border: 1px solid #c0ccda;
border-radius: 6px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 148px;
height: 148px;
margin: 0 8px 8px 0;
display: inline-block;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
</style>
<template>
<app-upload class="avatar-uploader" accept="image/*" :show-file-list="false" v-bind="$attrs" v-on="$listeners">
<img v-if="imageUrl" :src="imageUrl" class="avatar" />
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</app-upload>
</template>
<script>
import AppUpload from './Upload.vue'
export default {
name: 'AppUploadImage',
components: { AppUpload },
data() {
return {}
},
computed: {
imageUrl() {
return this.$attrs.value
}
}
}
</script>
<style lang="scss">
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
width: 148px;
height: 148px;
}
.avatar-uploader .el-upload:hover {
border-color: #409eff;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
line-height: 148px;
text-align: center;
}
.avatar {
width: 100%;
height: 100%;
display: block;
object-fit: cover;
}
</style>
<template>
<app-upload class="video-uploader" accept="video/*" :show-file-list="false" v-bind="$attrs" v-on="$listeners">
<img v-if="videoUrl" :src="`${videoUrl}?x-oss-process=video/snapshot,t_10,f_jpg,w_0,h_0,m_fast`" class="avatar" />
<i v-else class="el-icon-plus video-uploader-icon"></i>
</app-upload>
</template>
<script>
import AppUpload from './Upload.vue'
export default {
name: 'AppUploadVideo',
components: { AppUpload },
data() {
return {}
},
computed: {
videoUrl() {
return this.$attrs.value
}
}
}
</script>
<style lang="scss">
.video-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
width: 148px;
height: 148px;
}
.video-uploader .el-upload:hover {
border-color: #409eff;
}
.video-uploader-icon {
font-size: 28px;
color: #8c939d;
line-height: 148px;
text-align: center;
}
.avatar {
width: 100%;
height: 100%;
display: block;
object-fit: cover;
}
</style>
import httpRequest from '@/utils/axios'
// 获取用户信息
export function updateUser(data) {
return httpRequest.post('/api/usercenter/user/update-user', data)
}
// 获取用户信息
export function updatePassword(data) {
return httpRequest.post('/api/usercenter/user/change-pwd-by-cookie', data)
}
<template>
<app-card title="基本信息">
<ul class="app-card-list">
<li class="app-card-item" @click="avatarDialogVisible = true">
<div class="app-card-item-label">照片</div>
<div class="app-card-item-content"></div>
<div class="app-card-item-aside">
<div class="avatar">
<img :src="user.avatar || 'https://webapp-pub.ezijing.com/website/base/images/avatar.svg'" />
<div class="cover">
<i class="el-icon-camera-solid"></i>
</div>
</div>
</div>
</li>
<li class="app-card-item">
<div class="app-card-item-label">账号</div>
<div class="app-card-item-content">{{ user.username }}</div>
<div class="app-card-item-aside"></div>
</li>
<li class="app-card-item" @click="showUpdateInfo">
<div class="app-card-item-label">昵称</div>
<div class="app-card-item-content">{{ user.nickname }}</div>
<div class="app-card-item-aside"><i class="el-icon-arrow-right"></i></div>
</li>
<li class="app-card-item" @click="showUpdateInfo">
<div class="app-card-item-label">真实姓名</div>
<div class="app-card-item-content">{{ user.realname }}</div>
<div class="app-card-item-aside"><i class="el-icon-arrow-right"></i></div>
</li>
<li class="app-card-item" @click="showUpdateInfo">
<div class="app-card-item-label">生日</div>
<div class="app-card-item-content">{{ user.birthday }}</div>
<div class="app-card-item-aside"><i class="el-icon-arrow-right"></i></div>
</li>
<li class="app-card-item" @click="showUpdateInfo">
<div class="app-card-item-label">性别</div>
<div class="app-card-item-content">{{ genderText(user.gender) }}</div>
<div class="app-card-item-aside"><i class="el-icon-arrow-right"></i></div>
</li>
</ul>
<!-- 头像修改 -->
<el-dialog
class="avatar-dialog"
:visible.sync="avatarDialogVisible"
:close-on-click-modal="false"
@close="resetFormData"
>
<div class="avatar-dialog-body">
<upload-image v-model="form.avatar"></upload-image>
<h2>个人资料照片</h2>
<p>照片可帮助他人认出您,并可让您了解自己已登录帐号</p>
</div>
<div slot="footer" class="avatar-dialog-footer">
<el-button size="medium" icon="el-icon-delete" @click="handleUpdateAvatar('')">移除</el-button>
<el-button type="primary" size="medium" icon="el-icon-edit" @click="handleUpdateAvatar(form.avatar)"
>更改</el-button
>
</div>
</el-dialog>
<!-- 基本信息修改 -->
<el-dialog title="基本信息" :visible.sync="dialogVisible" :close-on-click-modal="false" @close="resetFormData">
<el-form ref="form" :model="form" :rules="rules" :hide-required-asterisk="true" label-position="top">
<el-form-item label="昵称" prop="nickname">
<el-input v-model="form.nickname" clearable></el-input>
</el-form-item>
<el-form-item label="真实姓名" prop="realname">
<el-input v-model="form.realname" clearable></el-input>
</el-form-item>
<el-form-item label="出生日期" prop="birthday">
<el-date-picker v-model="form.birthday" type="date" value-format="yyyy-MM-dd" placeholder="选择出生日期">
</el-date-picker>
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-radio-group v-model="form.gender">
<el-radio :label="1"></el-radio>
<el-radio :label="2"></el-radio>
<el-radio :label="0">不便透露</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="handleCancelUpdateInfo">取消</el-button>
<el-button type="primary" size="medium" @click="handlePrimaryUpdateInfo">保存</el-button>
</div>
</el-dialog>
</app-card>
</template>
<script>
import AppCard from '@/components/base/AppCard.vue'
import UploadImage from '@/components/upload/UploadImage.vue'
import { updateUser } from '../api.js'
export default {
components: { AppCard, UploadImage },
data() {
return {
form: {},
rules: {
nickname: [{ required: true, message: '请输入昵称', trigger: 'blur' }],
realname: [{ required: true, message: '请输入真实姓名', trigger: 'blur' }]
},
dialogVisible: false,
avatarDialogVisible: false
}
},
computed: {
user() {
return this.$store.state.user.user
}
},
watch: {
user: {
deep: true,
immediate: true,
handler(user) {
this.form = Object.assign({}, user)
}
}
},
methods: {
genderText(value) {
const map = {
0: '不方便透露',
1: '男',
2: '女'
}
return map[value]
},
showUpadeAvatar() {
this.avatarDialogVisible = true
},
handleUpdateAvatar(url) {
this.form.avatar = url
this.updateHandler({ avatar: url })
},
showUpdateInfo() {
this.dialogVisible = true
},
handleCancelUpdateInfo() {
this.dialogVisible = false
},
handlePrimaryUpdateInfo() {
this.$refs.form.validate().then(() => {
const params = {
nickname: this.form.nickname,
real_name: this.form.realname,
birthday: this.form.birthday,
gender: this.form.gender
}
this.updateHandler(params, () => {
this.dialogVisible = false
})
})
},
updateHandler(params, callback) {
return updateUser(params)
.then(resp => {
this.$store.dispatch('getUser')
callback && callback(resp)
})
.catch(resp => this.$message.error(resp.msg))
},
resetFormData() {
this.form = Object.assign({}, this.user)
this.$refs.form && this.$refs.form.resetFields()
}
}
}
</script>
<style lang="scss" scoped>
.app-card-item {
position: relative;
margin-left: 24px;
display: flex;
align-items: center;
padding: 16px 24px 16px 0;
border-top: 1px solid #dadce0;
cursor: pointer;
&:hover {
margin-left: 0;
padding-left: 24px;
background-color: rgba(128, 134, 139, 0.04);
&::after {
content: '';
position: absolute;
left: 0;
right: 0;
bottom: -1px;
border-top: 1px solid #dadce0;
}
}
}
.app-card-item-label {
flex-basis: 156px;
margin-right: 24px;
font-weight: 500;
color: #5f6368;
}
.app-card-item-content {
flex: 1;
}
.avatar {
position: relative;
width: 60px;
height: 60px;
border-radius: 50%;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
.cover {
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 20px;
background-color: rgba(32, 33, 36, 0.6);
color: #fff;
text-align: center;
}
}
::v-deep .el-dialog {
max-width: 490px;
}
.avatar-dialog-body {
text-align: center;
::v-deep .el-upload {
width: 288px;
height: 288px;
border-radius: 50%;
}
::v-deep .avatar-uploader-icon {
font-size: 40px;
line-height: 288px;
}
h2 {
margin-top: 24px;
line-height: 2rem;
font-size: 1.5rem;
letter-spacing: 0;
font-weight: 400;
}
p {
margin-top: 4px;
line-height: 1.5rem;
font-size: 1rem;
letter-spacing: 0.00625em;
font-weight: 400;
}
}
.avatar-dialog-footer {
display: flex;
::v-deep .el-button {
flex: 1;
}
}
</style>
<template>
<app-card title="联系信息">
<ul class="app-card-list">
<li class="app-card-item" @click="showUpdate">
<div class="app-card-item-label">电子邮件</div>
<div class="app-card-item-content">{{ user.email }}</div>
<div class="app-card-item-aside"><i class="el-icon-arrow-right"></i></div>
</li>
<li class="app-card-item" @click="showUpdate">
<div class="app-card-item-label">电话</div>
<div class="app-card-item-content">{{ user.mobile }}</div>
<div class="app-card-item-aside"><i class="el-icon-arrow-right"></i></div>
</li>
</ul>
<!-- 联系信息修改 -->
<el-dialog title="联系信息" :visible.sync="dialogVisible" :close-on-click-modal="false" @close="resetFormData">
<el-form ref="form" :model="form" :rules="rules" :hide-required-asterisk="true" label-position="top">
<el-form-item label="电子邮件" prop="email">
<el-input v-model="form.email" clearable></el-input>
</el-form-item>
<el-form-item label="电话" prop="mobile">
<el-input v-model="form.mobile" clearable></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="handleCancelUpdate">取消</el-button>
<el-button type="primary" size="medium" @click="handlePrimaryUpdate">保存</el-button>
</div>
</el-dialog>
</app-card>
</template>
<script>
import AppCard from '@/components/base/AppCard.vue'
import { updateUser } from '../api.js'
export default {
components: { AppCard },
data() {
return {
form: {},
rules: {
email: [{ required: true, type: 'email', message: '请输入电子邮件', trigger: 'blur' }],
mobile: [{ required: true, pattern: /^1[3-9]\d{9}$/, message: '请输入手机号', trigger: 'blur' }]
},
dialogVisible: false
}
},
computed: {
user() {
return this.$store.state.user.user
}
},
watch: {
user: {
deep: true,
immediate: true,
handler(user) {
this.form = Object.assign({}, user)
}
}
},
methods: {
showUpdate() {
this.dialogVisible = true
},
handleCancelUpdate() {
this.dialogVisible = false
},
handlePrimaryUpdate() {
this.$refs.form.validate().then(() => {
const params = { email: this.form.email, mobile: this.form.mobile }
this.updateHandler(params, () => {
this.dialogVisible = false
})
})
},
updateHandler(params, callback) {
return updateUser(params)
.then(resp => {
this.$store.dispatch('getUser')
callback && callback(resp)
})
.catch(resp => this.$message.error(resp.msg))
},
resetFormData() {
this.form = Object.assign({}, this.user)
this.$refs.form && this.$refs.form.resetFields()
}
}
}
</script>
<style lang="scss" scoped>
.app-card-item {
position: relative;
margin-left: 24px;
display: flex;
align-items: center;
padding: 16px 24px 16px 0;
border-top: 1px solid #dadce0;
cursor: pointer;
&:hover {
margin-left: 0;
padding-left: 24px;
background-color: rgba(128, 134, 139, 0.04);
&::after {
content: '';
position: absolute;
left: 0;
right: 0;
bottom: -1px;
border-top: 1px solid #dadce0;
}
}
}
.app-card-item-label {
flex-basis: 156px;
margin-right: 24px;
font-weight: 500;
color: #5f6368;
}
.app-card-item-content {
flex: 1;
}
::v-deep .el-dialog {
max-width: 490px;
}
</style>
<template>
<app-card title="密码">
<ul class="app-card-list">
<li class="app-card-item" @click="showUpdate">
<div class="app-card-item-content">••••••••</div>
<div class="app-card-item-aside"><i class="el-icon-arrow-right"></i></div>
</li>
</ul>
<!-- 密码修改 -->
<el-dialog title="密码" :visible.sync="dialogVisible" :close-on-click-modal="false" @close="resetFormData">
<el-form ref="form" :model="form" :rules="rules" :hide-required-asterisk="true" label-position="top">
<el-form-item label="旧密码" prop="old_password">
<el-input type="password" v-model="form.old_password"></el-input>
</el-form-item>
<el-form-item label="新密码" prop="password">
<el-input type="password" v-model="form.password"></el-input>
</el-form-item>
<el-form-item label="确认新密码" prop="passwordR">
<el-input type="password" v-model="form.passwordR"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="handleCancelUpdate">取消</el-button>
<el-button type="primary" size="medium" @click="handlePrimaryUpdate">保存</el-button>
</div>
</el-dialog>
</app-card>
</template>
<script>
import AppCard from '@/components/base/AppCard.vue'
import { updatePassword } from '../api.js'
export default {
components: { AppCard },
data() {
const validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入新密码'))
} else if (value !== this.form.password) {
callback(new Error('密码不一致'))
} else {
callback()
}
}
return {
form: {},
rules: {
old_password: [{ required: true, message: '请输入旧密码', trigger: 'blur' }],
password: [
{ required: true, message: '请输入新密码', trigger: 'blur' },
{ min: 6, max: 20, message: '长度为6-20个字符', trigger: 'blur' }
],
passwordR: [
{ required: true, message: '请输入新密码', trigger: 'blur' },
{ validator: validatePass, trigger: 'blur' }
]
},
dialogVisible: false
}
},
computed: {
user() {
return this.$store.state.user
}
},
methods: {
showUpdate() {
this.dialogVisible = true
},
handleCancelUpdate() {
this.dialogVisible = false
},
handlePrimaryUpdate() {
this.$refs.form.validate().then(() => {
this.updateHandler(this.form, () => {
this.dialogVisible = false
})
})
},
updateHandler(params, callback) {
return updatePassword(params)
.then(resp => {
this.$store.dispatch('getUser')
callback && callback(resp)
})
.catch(resp => this.$message.error(resp.msg))
},
resetFormData() {
this.form = {}
this.$refs.form && this.$refs.form.resetFields()
}
}
}
</script>
<style lang="scss" scoped>
.app-card-item {
position: relative;
margin-left: 24px;
display: flex;
align-items: center;
padding: 16px 24px 16px 0;
border-top: 1px solid #dadce0;
cursor: pointer;
&:hover {
margin-left: 0;
padding-left: 24px;
background-color: rgba(128, 134, 139, 0.04);
&::after {
content: '';
position: absolute;
left: 0;
right: 0;
bottom: -1px;
border-top: 1px solid #dadce0;
}
}
}
.app-card-item-label {
flex-basis: 156px;
margin-right: 24px;
font-weight: 500;
color: #5f6368;
}
.app-card-item-content {
flex: 1;
}
::v-deep .el-dialog {
max-width: 490px;
}
</style>
const routes = [
{
path: '/settings',
component: () => import('@/components/layout/Index.vue'),
children: [
{
path: '',
component: () => import('./views/Index.vue')
}
]
}
]
export { routes }
<template>
<div class="settings">
<h1 class="title">个人信息</h1>
<p class="tips">您在各种紫荆服务中的个人信息和偏好设置</p>
<settings-base></settings-base>
<settings-contact></settings-contact>
<settings-password></settings-password>
</div>
</template>
<script>
import SettingsBase from '../components/Base.vue'
import SettingsPassword from '../components/Password.vue'
import SettingsContact from '../components/Contact.vue'
export default {
metaInfo: {
title: '个人信息'
},
components: { SettingsBase, SettingsPassword, SettingsContact }
}
</script>
<style lang="scss" scoped>
.settings {
max-width: 838px;
margin: 0 auto;
}
.title {
margin-bottom: 8px;
font-size: 1.75rem;
font-weight: 400;
letter-spacing: 0;
line-height: 2.25rem;
word-break: break-word;
word-wrap: break-word;
color: #202124;
text-align: center;
}
.tips {
letter-spacing: 0.00625em;
font-family: Roboto, Arial, sans-serif;
font-size: 1rem;
font-weight: 400;
line-height: 1.5rem;
hyphens: auto;
word-break: break-word;
word-wrap: break-word;
color: #5f6368;
margin-left: auto;
margin-right: auto;
max-width: 600px;
text-align: center;
}
</style>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论