需要实现的大致效果
这里大致需要实现4个页面,一个个人中心的主页面,另外还有3个子页面,用户信息修改页,重置密码页,关于我们页。这里关于我们页,就不写了。重点实现一下用户信息修改以及重置密码页面功能。下面样式部分的代码就不粘贴了,有需要的参考我这篇,里面有我学习的项目地址:https://kaimo313.blog.csdn.net/article/details/122586455

实现过程
1.联调问题以及路由添加
一个问题是上传的时候有问题,该问题由Lweilve提出https://blog.csdn.net/kaimo313/article/details/122689960#comments_20557507
 所以首先需要改动一下后端服务的问题:

第二个问题就是获取头像的时候,获取参数有点问题:应该改成query去获取,这个是get请求。

路由添加:在 router.js 文件里添加路由
import Login from '@/container/Login'
import Home from '@/container/Home'
import Data from '@/container/Data'
import User from '@/container/User'
import Detail from '@/container/Detail'
import UserInfo from '@/container/UserInfo'
import Account from '@/container/Account'
const routes = [
{
path: "/login",
component: Login
},{
path: "/",
component: Home
},{
path: "/data",
component: Data
},{
path: "/user",
component: User
},{
path: "/userInfo",
component: UserInfo
},{
path: "/detail",
component: Detail
},{
path: "/account",
component: Account
}
];
export default routes
2.实现个人中心页面:退出登录
实现的效果如下:

我们在按照下面的结构新建文件,分别添加代码:

import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { Cell, Button, Toast } from 'zarm';
import { userInfo, getAvatar } from './api/index.js';
import geqian from "@/assets/images/geqian.png";
import gxqm from "@/assets/images/gxqm.png";
import zhaq from "@/assets/images/zhaq.png";
import lianxi from "@/assets/images/lianxi.png";
import defaultAvatar from "@/assets/images/default.jpg";
import s from './style.module.less';
const User = () => {
const navigate = useNavigate();
const [avatarUrl, setAvatarUrl] = useState(defaultAvatar);
const [user, setUser] = useState({});
useEffect(() => {
getUserInfo();
}, []);
const getUserInfo = async () => {
const { status, desc, data } = await userInfo({});
if(status === 200) {
setUser(data);
if(data.avatar) {
const res = await getAvatar({picname: data.avatar});
console.log(res);
if(res.status === 200) {
setAvatarUrl(res.data);
}else{
Toast.show(res.desc);
}
}
}else{
Toast.show(desc);
}
};
const logout = async () => {
localStorage.removeItem('token');
navigate('/login');
};
return <div className={s.user}>
<div className={s.head}>
<div className={s.info}>
<span>昵称:{user.username || '--'}</span>
<span>
<img style={{ width: 30, height: 30, verticalAlign: '-10px' }} src={geqian} alt="" />
<b>{user.signature || '这个人很懒,暂无个签'}</b>
</span>
</div>
<img className={s.avatar} style={{ width: 60, height: 60, borderRadius: 8 }} src={avatarUrl} alt="" />
</div>
<div className={s.content}>
<Cell
hasArrow
title="用户信息修改"
onClick={() => navigate('/userinfo')}
icon={<img style={{ width: 20, verticalAlign: '-7px' }} src={gxqm} alt="" />}
/>
<Cell
hasArrow
title="重制密码"
onClick={() => navigate('/account')}
icon={<img style={{ width: 20, verticalAlign: '-7px' }} src={zhaq} alt="" />}
/>
<Cell
hasArrow
title="关于我们"
onClick={() => navigate('/about')}
icon={<img style={{ width: 20, verticalAlign: '-7px' }} src={lianxi} alt="" />}
/>
</div>
<Button className={s.logout} block theme="danger" onClick={logout}>退出登录</Button>
</div>
}
export default User
import { fetchData } from "@/utils/axios.js";
export function userInfo(data) {
return fetchData('/api/user/getUserInfo', 'get', data);
}
export function getAvatar(data) {
return fetchData('/api/upload/getAvatar', 'get', data);
}
3.实现用户信息修改页:上传头像
这里需要注意的是需要用表单方式上传, 通过 axios 传 forms 设置 'Content-Type': 'multipart/form-data' , 进行文件上传
if (ajaxType === 'get') {
config.url = url + '?r=' + Math.random() * 1000;
config.params = data;
} else if (ajaxType === 'post') {
if(data.forms) {
config.data = data.forms;
config.headers['Content-Type'] = 'multipart/form-data;charset=UTF-8';
}else{
config.data = data;
config.headers['Content-Type'] = 'application/json;charset=UTF-8';
}
}
我们在按照下面的结构新建文件,分别添加代码:

import React, { useEffect, useState } from 'react';
import { Button, FilePicker, Input, Toast } from 'zarm';
import { useNavigate } from 'react-router-dom';
import Header from '@/components/Header';
import { getAvatar, userInfo, uploadAvatar, updateUserInfo } from './api/index.js';
import defaultAvatar from "@/assets/images/default.jpg";
import s from './style.module.less';
const UserInfo = () => {
const navigate = useNavigate();;
const [avatarUrl, setAvatarUrl] = useState(defaultAvatar);
const [avatar, setAvatar] = useState('');
const [signature, setSignature] = useState('');
useEffect(() => {
getUserInfo();
}, []);
useEffect(async () => {
if(avatar) {
const { status, data, desc } = await getAvatar({picname: avatar});
if(status === 200) {
setAvatarUrl(data);
}else{
Toast.show(desc);
}
}
}, [avatar]);
const getUserInfo = async () => {
const { status, desc, data } = await userInfo({});
if(status === 200) {
setAvatar(data.avatar)
setSignature(data.signature)
}else{
Toast.show(desc);
}
};
const handleSelect = async (file) => {
console.log('file.file', file.file)
if (file && file.file.size > 200 * 1024) {
Toast.show('上传头像不得超过 200 KB!')
return
}
let formData = new FormData()
formData.append('file', file.file)
const { status, desc, data } = await uploadAvatar({
forms: formData
});
if(status === 200) {
setAvatar(data)
}else{
Toast.show(desc);
}
}
const save = async () => {
if (signature && signature.length > 36) {
Toast.show('个性签名不能超过36个字!')
return
}
const { status, desc } = await updateUserInfo({
signature,
avatar
});
if(status === 200) {
Toast.show('修改成功')
navigate(-1)
}else{
Toast.show(desc);
}
}
return <>
<Header title='用户信息修改' />
<div className={s.userinfo}>
<div className={s.item}>
<div className={s.title}>头像</div>
<div className={s.avatar}>
<img className={s.avatarUrl} src={avatarUrl} alt=""/>
<div className={s.desc}>
<span>支持 jpg、png、jpeg 格式大小 200KB 以内的图片</span>
<FilePicker className={s.filePicker} onChange={handleSelect} accept="image/*">
<Button className={s.upload} theme='primary' size='xs'>点击上传</Button>
</FilePicker>
</div>
</div>
</div>
<div className={s.item}>
<div className={s.title}>个性签名</div>
<div className={s.signature}>
<Input
clearable
type="text"
value={signature}
placeholder="个性签名不能超过36个字"
onChange={(value) => setSignature(value)}
/>
</div>
</div>
<Button onClick={save} style={{ marginTop: 50 }} block theme='primary'>保存</Button>
</div>
</>
};
export default UserInfo;
import { fetchData } from "@/utils/axios.js";
export function getAvatar(data) {
return fetchData('/api/upload/getAvatar', 'get', data);
}
export function userInfo(data) {
return fetchData('/api/user/getUserInfo', 'get', data);
}
export function updateUserInfo(data) {
return fetchData('/api/user/updateUserInfo', 'post', data);
}
export function uploadAvatar(data) {
return fetchData('/api/upload/avatar', 'post', data);
}
写完测试一下:点击用户信息修改进入
 我们可以通过下面的地方修改信息: 
比如修改头像:
 我们发现就上传成功了
 我们可以查看本地的盘里是有该图片的:

修改个签:
 成功之后就会跳转到个人中心。 
4.安装依赖 rc-form、crypto-js
npm i rc-form -S

用法:参考https://github.com/react-component/form
import { createForm, formShape } from 'rc-form';
class Form extends React.Component {
static propTypes = {
form: formShape,
};
submit = () => {
this.props.form.validateFields((error, value) => {
console.log(error, value);
});
}
render() {
let errors;
const { getFieldProps, getFieldError } = this.props.form;
return (
<div>
<input {...getFieldProps('normal')}/>
<input {...getFieldProps('required', {
onChange(){},
rules: [{required: true}],
})}/>
{(errors = getFieldError('required')) ? errors.join(',') : null}
<button onClick={this.submit}>submit</button>
</div>
);
}
}
export createForm()(Form);

安装 crypto-js,用法请参考:crypto-js:加密标准的JavaScript库
npm install crypto-js -S

5.实现重置密码页
在下面文件里添加相应的代码:

import React from 'react';
import { Cell, Input, Button, Toast } from 'zarm';
import { useNavigate } from 'react-router-dom';
import { createForm } from 'rc-form';
import Header from '@/components/Header'
import { resetPassword } from './api/index'
import CryptoJS from "crypto-js";
import s from './style.module.less'
const Account = (props) => {
const navigate = useNavigate();
console.log('Account 通过 createForm 高阶组件包裹之后', props)
const { getFieldProps, validateFields } = props.form;
const DES_encrypt = (hashStr) => {
return CryptoJS.DES.encrypt(
hashStr,
CryptoJS.enc.Utf8.parse("ABF"),
{
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
}
).ciphertext.toString();
}
const submit = () => {
validateFields(async (error, value) => {
if (!error) {
console.log(value)
if (value.newPassword != value.newPassword2) {
Toast.show('新密码输入不一致');
return
}
const {status, desc} = await resetPassword({
oldPassword: DES_encrypt(value.oldPassword),
newPassword: DES_encrypt(value.newPassword)
})
if(status === 200) {
Toast.show('修改成功');
localStorage.removeItem("token");
navigate('/login')
}else{
Toast.show(desc)
}
}else{
Toast.show('参数校验不通过,请填写完整!')
}
});
}
return <>
<Header title="重制密码" />
<div className={s.account}>
<div className={s.form}>
<Cell title="原密码">
<Input
clearable
type="text"
placeholder="请输入原密码"
{...getFieldProps('oldPassword', { rules: [{ required: true }] })}
/>
</Cell>
<Cell title="新密码">
<Input
clearable
type="text"
placeholder="请输入新密码"
{...getFieldProps('newPassword', { rules: [{ required: true }] })}
/>
</Cell>
<Cell title="确认密码">
<Input
clearable
type="text"
placeholder="请确认新密码"
{...getFieldProps('newPassword2', { rules: [{ required: true }] })}
/>
</Cell>
</div>
<Button className={s.btn} block theme="primary" onClick={submit}>提交</Button>
</div>
</>
};
export default createForm()(Account);
import { fetchData } from "@/utils/axios.js";
export function resetPassword(data) {
return fetchData('/api/user/resetPassword', 'post', data);
}
测试一下效果:点击重置密码进去
 填写好修改的信息  提交成功之后就会回到首页

输入之前的密码
 就会提示密码错误
 改成新的密码
 发现可以登录成功了

参考资料
|