之前写过一篇文章关于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',
    },
  });
}

完成!!!多多积累,多多收获!!!

下面的内容跟文章相关不大,仅为了凑字数,可忽略!!!

pinia的基本概念

pinia基本概念,相比于vuex有什么样的优点,为什么官方推荐使用pinia?

pinia,是一个vue阵营的新的状态管理库,现在vue官方已经推荐使用Pinia来代替vuex,或者你可以把pinia看作vuex的最新的版本。
pinia是一个西班牙语,表示菠萝的意思。因为菠萝是一小块一小块组成的,这个和pinia的思想就非常的吻合,在pinia中,每个store仓库都是单独的扁平化存在的。
pinia是由vue官方团队中的一个成员开发的,最早是在2019年11月作为一项实验性工作所提出的,当时的目的是将组合API融入到vuex中,探索新版本的vuex应有的形态,随着探索的进行,最终发现pinia已经实现了vuex5大部分的提案,因此pinia就作为了最新版本的vuex,但是为了尊重作者本人,名字保持不变,仍然叫做pinia.
相比vuex,pinia的API更好而且简单,还支持组合式API,还可以和typescript一起推断类型使用

pinia优势

1.在pinia不存在mutations,只有state,getters,actions
在创建仓库中,提供了三个选项,分别是state,getters,actions
2.actions支持同步和异步来修改store,相当于将之前的mutationsactions合并

Logo

前往低代码交流专区

更多推荐