之前写过一篇文章关于vue3+antd
的框架模板,链接如下:http://t.csdn.cn/9dZMS
首先感谢大神提供的后台管理系统的模板,在此基础上改动要简单很多,主要是自己有很多内容不太敢随意改动。。。
直接看【个人中心】页面的效果图:
个人中心的内容要跟框架头部的信息保持同步,因此需要用到vuex
,此框架中的vuex
是使用的pinia
。
下面介绍详细代码:
1.个人中心的页面代码
1.1html
代码
<template>
<a-spin :spinning="loading">
<a-card>
<a-tabs v-model="activeKey">
<a-tab-pane key="1" tab="修改信息">
<a-form
:model="form"
:rules="rules"
style="height: calc(100vh - 200px); width: 60%; overflow: auto"
ref="ruleForm"
:label-col="labelCol"
:wrapper-col="wrapperCol"
@finish="handleOk"
>
<a-form-item label="用户名" ref="userName" name="userName">
<a-input v-model:value="form.userName" placeholder="请输入角色名称" />
</a-form-item>
<a-form-item label="工号">
<a-input v-model:value="form.jobNo" />
</a-form-item>
<a-form-item label="名">
<a-input v-model:value="form.name" />
</a-form-item>
<a-form-item label="姓">
<a-input v-model:value="form.surname" />
</a-form-item>
<a-form-item label="性别">
<a-radio-group v-model:value="form.sex">
<a-radio :value="1">男</a-radio>
<a-radio :value="2">女</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="头像">
<uploadPic
v-model:value="form.headPhoto"
listType="picture-card"
:limit="1"
:showFile="showFile"
ref="upload"
@getFile="headPhotoInput"
></uploadPic>
</a-form-item>
<a-form-item label="邮箱地址" ref="email" name="email">
<a-input v-model:value="form.email" />
</a-form-item>
<a-form-item label="手机号码">
<a-input v-model:value="form.phoneNumber" />
</a-form-item>
<a-button type="primary" style="margin-left: 20%" html-type="submit">保存</a-button>
</a-form>
</a-tab-pane>
<a-tab-pane key="2" tab="修改密码">
<a-form
:model="form2"
:rules="rules2"
style="height: calc(100vh - 200px); width: 60%; overflow: auto"
ref="ruleForm2"
:label-col="labelCol"
:wrapper-col="wrapperCol"
@finish="handleOk2"
>
<a-form-item label="当前密码" name="currentPassword">
<a-input v-model:value="form2.currentPassword" type="password" />
</a-form-item>
<a-form-item label="新密码" name="newPassword">
<a-input v-model:value="form2.newPassword" type="password" />
</a-form-item>
<a-form-item label="确认新密码" name="newPasswordConfirm">
<a-input v-model:value="form2.newPasswordConfirm" type="password" />
</a-form-item>
<a-button type="primary" style="margin-left: 20%" html-type="submit">保存</a-button>
</a-form>
</a-tab-pane>
</a-tabs>
</a-card>
</a-spin>
</template>
1.2 js
代码
<script lang="ts">
import { GetUserInfo } from '@/services/storehouse/common';
import { useAccountStore } from '@/store';
import { createUpdate, postChangePassword } from '@/services/identity/user';
import uploadPic from '@/components/upload/UploadPic.vue';
export default {
components: { uploadPic },
data() {
let validatePass = (rule, value) => {
if (value === '') {
return Promise.reject('请输入密码');
} else if (value.length < 6) {
return Promise.reject('密码长度不能少于6位');
} else {
return Promise.resolve();
}
};
let validatePass1 = (rule, value) => {
if (value === '') {
return Promise.reject('请输入密码');
} else if (value.length < 6) {
return Promise.reject('密码长度不能少于6位');
} else {
return Promise.resolve();
}
};
let validatePass2 = (rule, value) => {
if (value === '') {
return Promise.reject('请输入密码');
} else if (value.length < 6) {
return Promise.reject('密码长度不能少于6位');
} else {
return Promise.resolve();
}
};
return {
showFile: [],
loading: false,
activeKey: '1',
labelCol: { span: 6 },
wrapperCol: { span: 18 },
form: {
userName: null,
jobNo: null,
name: null,
surname: null,
sex: null,
headPhoto: null,
email: null,
phoneNumber: null,
},
form2: {
currentPassword: null,
newPassword: null,
newPasswordConfirm: null,
},
rules2: {
currentPassword: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ validator: validatePass, trigger: 'change' },
],
newPassword: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ validator: validatePass1, trigger: 'change' },
],
newPasswordConfirm: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ validator: validatePass2, trigger: 'change' },
],
},
rules: {
userName: [{ required: true, message: '用户名必须填写', trigger: 'blur' }],
email: [
{
type: 'email',
required: true,
message: '请填写正确的邮箱地址',
trigger: 'blur',
},
],
},
};
},
methods: {
headPhotoInput(imgs) {
this.form.headPhoto = imgs;
this.$forceUpdate();
},
getUserInfo(flag) {
this.loading = true;
GetUserInfo()
.then((res: any) => {
if (res.code == 1) {
this.form = {
...res.data,
headPhoto: res.data?.extraProperties?.HeadPhoto,
jobNo: res.data?.extraProperties?.JobNo,
};
if (flag) {
const { setUser } = useAccountStore();
setUser({ ...this.form });
}
this.form2 = {
id: res.data.id,
};
if (this.form.headPhoto) {
this.showFile = [
{
name: this.form.headPhoto,
url: this.form.headPhoto,
uid: this.form.headPhoto,
},
];
} else {
this.showFile = [];
}
}
})
.finally(() => {
this.loading = false;
});
},
handleOk2() {
this.loading = true;
postChangePassword(this.form2)
.then((res) => {
this.$message.success('操作成功');
this.getUserInfo();
})
.finally(() => {
this.loading = false;
});
},
handleOk() {
this.loading = true;
let values = {
...this.form,
extraProperties: {
JobNo: this.form.jobNo,
HeadPhoto: this.form.headPhoto,
},
};
createUpdate(values)
.then((res) => {
this.$message.success('操作成功');
this.getUserInfo(true);
})
.finally(() => {
this.loading = false;
});
},
},
activated() {
this.getUserInfo();
},
};
</script>
重点在于:修改个人信息后,需要触发account.js
中的setUser
方法,然后将内容同步到头部。
也就是再handleOk
的函数调用成功后,要重新获取用户信息getUserInfo
的方法,在此方法中要进行account.ts
中的setUser
方法。
1.3 account.ts
中的setUser
方法——重要代码!!!
export const useAccountStore = defineStore('account', {
state: () => ({
account: null,
}),
actions: {
setUser(userInfo) {
this.account = userInfo;
},
},
});
获取account.ts
中的方法如下:
import { useAccountStore } from '@/store';
在getUserInfo
中的方法如下:
if (flag) {
const { setUser } = useAccountStore();
setUser({ ...this.form });
}
此时就实现了个人信息修改后与后台管理系统头部信息的同步。
2.上传头像
的组件——uploadPic
2.1 html
代码:
<template>
<div>
<a-upload
class="upload-demo"
:customRequest="uploadFile"
@remove="handleRemove"
:file-list="fileList"
:multiple="multiple"
:limit="limit"
:list-type="listType"
>
<a-button v-if="showBtn" size="small" type="primary">点击上传</a-button>
<plus-outlined v-if="!showBtn && fileList.length < limit" />
<template v-slot:tip>
<div class="cloud-upload"></div>
</template>
</a-upload>
<a-modal title="图片预览" :visible="dialogVisible" :append-to-body="true">
<img width="100%" :src="dialogImageUrl" alt="" />
</a-modal>
</div>
</template>
2.2 js
代码
<script lang="ts">
import { Upload } from '@/services/storehouse/common.js';
export default {
name: 'UploadPic',
props: {
multiple: {
type: Boolean,
default: false,
},
showFile: Array,
limit: Number,
showBtn: {
type: Boolean,
default: false,
},
listType: String,
},
data() {
return {
fileList: [],
dialogVisible: false,
dialogImageUrl: '',
};
},
watch: {
showFile: {
handler(newVal) {
this.fileList = newVal ? newVal : [];
},
deep: true,
immediate: true,
},
},
methods: {
uploadFile(req) {
let that = this;
let formData = new FormData();
formData.append('files', req.file);
Upload({ module: 'IQC' }, formData).then((response: any) => {
if (response.code == 0) return false;
that.fileList.push({
uid: req.file.uid,
name: req.file.name,
url: response.data,
});
let imgs = that.fileList.map((s) => s.url).join(',');
this.$emit('getFile', imgs);
});
},
beforeUpload() {},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
},
handleRemove(file) {
let index = this.fileList.findIndex((item) => {
return item.uid === file.uid;
});
this.fileList.splice(index, 1);
let imgs = this.fileList.map((s) => s.url).join(',');
this.$emit('getFile', imgs);
},
beforeRemove(file, fileList) {
return this.$confirm(`确定移除文件?`);
},
handleExceed(files, fileList) {
this.$message.warning(
`当前限制选择${this.limit}个文件,本次选择了 ${files.length} 个文件,共选择了 ${
files.length + fileList.length
} 个文件`
);
},
},
};
</script>
2.3 Upload
接口——要根据实际情况来处理
//上传图片
export async function Upload(params, data) {
return request(`/api/app/bussiness-smt/upload-file?${qs.stringify(params)}`, METHOD.POST, data, {
headers: {
AppSecret: 'xxxxxxxxx',
},
});
}