个人信息修改和切花部门

This commit is contained in:
禺狨 2023-03-27 12:15:31 +08:00
parent e1ce7d8b47
commit 987c6e21ec
6 changed files with 141 additions and 35 deletions

View File

@ -18,3 +18,10 @@ export function courses(depId: number) {
dep_id: depId,
});
}
// 修改头像
export function avatar(file: any) {
return client.put("/api/v1/user/avatar", {
file: file,
});
}

View File

@ -1,9 +1,13 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import styles from "./index.module.scss";
import { Modal, Button, Dropdown, MenuProps } from "antd";
import { Modal, Button, Dropdown } from "antd";
import type { MenuProps } from "antd";
import { useDispatch, useSelector } from "react-redux";
import { Link, useNavigate } from "react-router-dom";
import { logoutAction } from "../../store/user/loginUserSlice";
import {
logoutAction,
saveCurrentDepId,
} from "../../store/user/loginUserSlice";
import { ChangePasswordModel } from "../change-password";
import { UserInfoModel } from "../user-info";
import { ExclamationCircleFilled } from "@ant-design/icons";
@ -20,6 +24,27 @@ export const Header: React.FC = () => {
const [changePasswordVisiale, setChangePasswordVisiale] =
useState<boolean>(false);
const [userInfoVisiale, setUserInfoVisiale] = useState<boolean>(false);
const [departmentsMenu, setDepartmentsMenu] = useState<any>([]);
const [currentDepartment, setCurrentDepartment] = useState<string>("");
useEffect(() => {
setCurrentDepartment(departments[0].name);
const arr: any = [
{
key: "1",
type: "group",
label: "部门",
children: [],
},
];
departments.map((item: any) => {
arr[0].children.push({
key: item.id,
label: item.name,
});
});
setDepartmentsMenu(arr);
}, [departments]);
const onClick: MenuProps["onClick"] = ({ key }) => {
if (key === "login_out") {
@ -75,6 +100,32 @@ export const Header: React.FC = () => {
},
];
const depItems: MenuProps["items"] = departmentsMenu;
const onDepClick: MenuProps["onClick"] = ({ key }) => {
let name: string = "";
departments.map((item: any) => {
if (Number(key) === item.id) {
name = item.name;
}
});
confirm({
title: "操作确认",
icon: <ExclamationCircleFilled />,
content: "确认切换部门?",
centered: true,
okText: "确认",
cancelText: "取消",
onOk() {
setCurrentDepartment(name);
dispatch(saveCurrentDepId(Number(key)));
},
onCancel() {
console.log("Cancel");
},
});
};
return (
<div className={styles["app-header"]}>
<div className={styles["main-header"]}>
@ -84,10 +135,15 @@ export const Header: React.FC = () => {
</Link>
</div>
<div className="d-flex">
{departments.length > 0 && (
{departments.length === 1 && (
<div className={styles["department-name"]}>{currentDepartment}</div>
)}
{departments.length > 1 && (
<Dropdown menu={{ items: depItems, onClick: onDepClick }}>
<div className={styles["department-name"]}>
{departments[0].name}
{currentDepartment}
</div>
</Dropdown>
)}
<Button.Group className={styles["button-group"]}>
<Dropdown menu={{ items, onClick }} placement="bottomRight">

View File

@ -1,7 +1,12 @@
import React, { useState, useEffect } from "react";
import { Modal, Image, Form, Input, message } from "antd";
import { Modal, Image, Form, message, Upload, Button } from "antd";
import styles from "./index.module.less";
import { user } from "../../api/index";
import { useDispatch } from "react-redux";
import { loginAction } from "../../store/user/loginUserSlice";
import type { UploadProps } from "antd";
import config from "../../js/config";
import { getToken } from "../../utils/index";
interface PropInterface {
open: boolean;
@ -9,9 +14,12 @@ interface PropInterface {
}
export const UserInfoModel: React.FC<PropInterface> = ({ open, onCancel }) => {
const dispatch = useDispatch();
const [form] = Form.useForm();
const [loading, setLoading] = useState<boolean>(true);
const [avatar, setAvatar] = useState<string>("");
const [name, setName] = useState<string>("");
const [idCard, setIdCard] = useState<string>("");
useEffect(() => {
getUser();
@ -20,21 +28,41 @@ export const UserInfoModel: React.FC<PropInterface> = ({ open, onCancel }) => {
const getUser = () => {
user.detail().then((res: any) => {
setAvatar(res.data.user.avatar);
form.setFieldsValue({
name: res.data.user.name,
});
setName(res.data.user.name);
setIdCard(res.data.user.id_card);
dispatch(loginAction(res.data));
});
};
const onFinish = (values: any) => {
user.password(avatar, values.name).then((res: any) => {
message.success("保存成功!");
onCancel();
});
};
const onFinishFailed = (errorInfo: any) => {
console.log("Failed:", errorInfo);
const props: UploadProps = {
name: "file",
multiple: false,
method: "PUT",
action: config.app_url + "/api/v1/user/avatar",
headers: {
Accept: "application/json",
authorization: "Bearer " + getToken(),
},
beforeUpload: (file) => {
const isPNG = file.type === ("image/png" || "image/jpg");
if (!isPNG) {
message.error(`${file.name}不是图片文件`);
}
return isPNG || Upload.LIST_IGNORE;
},
onChange(info: any) {
const { status, response } = info.file;
if (status === "done") {
if (response.code === 0) {
message.success(`${info.file.name} 上传成功`);
getUser();
} else {
message.error(response.msg);
}
} else if (status === "error") {
message.error(`${info.file.name} 上传失败`);
}
},
};
return (
@ -45,25 +73,22 @@ export const UserInfoModel: React.FC<PropInterface> = ({ open, onCancel }) => {
forceRender
open={open}
width={416}
onOk={() => form.submit()}
onCancel={() => onCancel()}
maskClosable={false}
footer={null}
>
<div className="float-left mt-24">
<div className="mt-24">
<Form
form={form}
name="user-info"
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
initialValues={{ remember: true }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
>
<Form.Item
label="学员头像"
labelCol={{ style: { marginTop: 15, marginLeft: 52 } }}
name="avatar"
>
<div className="d-flex">
{avatar && (
@ -75,15 +100,18 @@ export const UserInfoModel: React.FC<PropInterface> = ({ open, onCancel }) => {
preview={false}
/>
)}
<div className="d-flex ml-16"></div>
<div className="d-flex ml-16">
<Upload {...props} showUploadList={false}>
<Button></Button>
</Upload>
</div>
</div>
</Form.Item>
<Form.Item label="修改姓名" name="name">
<Input
style={{ width: 200 }}
autoComplete="off"
placeholder="请输入姓名"
/>
<Form.Item label="学员姓名">
<div>{name}</div>
</Form.Item>
<Form.Item label="身份证号" style={{ marginBottom: 16 }}>
<div>{idCard}</div>
</Form.Item>
</Form>
</div>

3
src/js/config.ts Normal file
View File

@ -0,0 +1,3 @@
export default {
app_url: import.meta.env.VITE_APP_URL || "",
};

View File

@ -19,14 +19,17 @@ const IndexPage = () => {
const departments = useSelector(
(state: any) => state.loginUser.value.departments
);
const currentDepId = useSelector(
(state: any) => state.loginUser.value.currentDepId
);
useEffect(() => {
getData();
}, [tabKey]);
}, [tabKey, currentDepId]);
const getData = () => {
setLoading(true);
user.courses(departments[0].id).then((res: any) => {
user.courses(currentDepId).then((res: any) => {
const records = res.data.learn_course_records;
setStats(res.data.stats);
setLearnCourseRecords(records);

View File

@ -3,12 +3,14 @@ import { createSlice } from "@reduxjs/toolkit";
type UserStoreInterface = {
user: null;
departments: string[];
currentDepId: number;
isLogin: boolean;
};
let defaultValue: UserStoreInterface = {
user: null,
departments: [],
currentDepId: 0,
isLogin: false,
};
@ -22,16 +24,23 @@ const loginUserSlice = createSlice({
stage.value.user = e.payload.user;
stage.value.departments = e.payload.departments;
stage.value.isLogin = true;
if (e.payload.departments.length > 0 && stage.value.currentDepId === 0) {
stage.value.currentDepId = e.payload.departments[0].id;
}
},
logoutAction(stage) {
stage.value.user = null;
stage.value.departments = [];
stage.value.isLogin = false;
},
saveCurrentDepId(stage, e) {
stage.value.currentDepId = e.payload;
},
},
});
export default loginUserSlice.reducer;
export const { loginAction, logoutAction } = loginUserSlice.actions;
export const { loginAction, logoutAction, saveCurrentDepId } =
loginUserSlice.actions;
export type { UserStoreInterface };