mirror of
https://github.com/PlayEdu/frontend.git
synced 2025-06-29 13:52:44 +08:00
个人信息修改和切花部门
This commit is contained in:
parent
e1ce7d8b47
commit
987c6e21ec
@ -18,3 +18,10 @@ export function courses(depId: number) {
|
|||||||
dep_id: depId,
|
dep_id: depId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 修改头像
|
||||||
|
export function avatar(file: any) {
|
||||||
|
return client.put("/api/v1/user/avatar", {
|
||||||
|
file: file,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import styles from "./index.module.scss";
|
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 { useDispatch, useSelector } from "react-redux";
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
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 { ChangePasswordModel } from "../change-password";
|
||||||
import { UserInfoModel } from "../user-info";
|
import { UserInfoModel } from "../user-info";
|
||||||
import { ExclamationCircleFilled } from "@ant-design/icons";
|
import { ExclamationCircleFilled } from "@ant-design/icons";
|
||||||
@ -20,6 +24,27 @@ export const Header: React.FC = () => {
|
|||||||
const [changePasswordVisiale, setChangePasswordVisiale] =
|
const [changePasswordVisiale, setChangePasswordVisiale] =
|
||||||
useState<boolean>(false);
|
useState<boolean>(false);
|
||||||
const [userInfoVisiale, setUserInfoVisiale] = 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 }) => {
|
const onClick: MenuProps["onClick"] = ({ key }) => {
|
||||||
if (key === "login_out") {
|
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 (
|
return (
|
||||||
<div className={styles["app-header"]}>
|
<div className={styles["app-header"]}>
|
||||||
<div className={styles["main-header"]}>
|
<div className={styles["main-header"]}>
|
||||||
@ -84,10 +135,15 @@ export const Header: React.FC = () => {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="d-flex">
|
<div className="d-flex">
|
||||||
{departments.length > 0 && (
|
{departments.length === 1 && (
|
||||||
<div className={styles["department-name"]}>
|
<div className={styles["department-name"]}>{currentDepartment}</div>
|
||||||
{departments[0].name}
|
)}
|
||||||
</div>
|
{departments.length > 1 && (
|
||||||
|
<Dropdown menu={{ items: depItems, onClick: onDepClick }}>
|
||||||
|
<div className={styles["department-name"]}>
|
||||||
|
{currentDepartment}
|
||||||
|
</div>
|
||||||
|
</Dropdown>
|
||||||
)}
|
)}
|
||||||
<Button.Group className={styles["button-group"]}>
|
<Button.Group className={styles["button-group"]}>
|
||||||
<Dropdown menu={{ items, onClick }} placement="bottomRight">
|
<Dropdown menu={{ items, onClick }} placement="bottomRight">
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
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 styles from "./index.module.less";
|
||||||
import { user } from "../../api/index";
|
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 {
|
interface PropInterface {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
@ -9,9 +14,12 @@ interface PropInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const UserInfoModel: React.FC<PropInterface> = ({ open, onCancel }) => {
|
export const UserInfoModel: React.FC<PropInterface> = ({ open, onCancel }) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [loading, setLoading] = useState<boolean>(true);
|
const [loading, setLoading] = useState<boolean>(true);
|
||||||
const [avatar, setAvatar] = useState<string>("");
|
const [avatar, setAvatar] = useState<string>("");
|
||||||
|
const [name, setName] = useState<string>("");
|
||||||
|
const [idCard, setIdCard] = useState<string>("");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getUser();
|
getUser();
|
||||||
@ -20,21 +28,41 @@ export const UserInfoModel: React.FC<PropInterface> = ({ open, onCancel }) => {
|
|||||||
const getUser = () => {
|
const getUser = () => {
|
||||||
user.detail().then((res: any) => {
|
user.detail().then((res: any) => {
|
||||||
setAvatar(res.data.user.avatar);
|
setAvatar(res.data.user.avatar);
|
||||||
form.setFieldsValue({
|
setName(res.data.user.name);
|
||||||
name: res.data.user.name,
|
setIdCard(res.data.user.id_card);
|
||||||
});
|
dispatch(loginAction(res.data));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onFinish = (values: any) => {
|
const props: UploadProps = {
|
||||||
user.password(avatar, values.name).then((res: any) => {
|
name: "file",
|
||||||
message.success("保存成功!");
|
multiple: false,
|
||||||
onCancel();
|
method: "PUT",
|
||||||
});
|
action: config.app_url + "/api/v1/user/avatar",
|
||||||
};
|
headers: {
|
||||||
|
Accept: "application/json",
|
||||||
const onFinishFailed = (errorInfo: any) => {
|
authorization: "Bearer " + getToken(),
|
||||||
console.log("Failed:", errorInfo);
|
},
|
||||||
|
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 (
|
return (
|
||||||
@ -45,25 +73,22 @@ export const UserInfoModel: React.FC<PropInterface> = ({ open, onCancel }) => {
|
|||||||
forceRender
|
forceRender
|
||||||
open={open}
|
open={open}
|
||||||
width={416}
|
width={416}
|
||||||
onOk={() => form.submit()}
|
|
||||||
onCancel={() => onCancel()}
|
onCancel={() => onCancel()}
|
||||||
maskClosable={false}
|
maskClosable={false}
|
||||||
|
footer={null}
|
||||||
>
|
>
|
||||||
<div className="float-left mt-24">
|
<div className="mt-24">
|
||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
name="user-info"
|
name="user-info"
|
||||||
labelCol={{ span: 8 }}
|
labelCol={{ span: 8 }}
|
||||||
wrapperCol={{ span: 16 }}
|
wrapperCol={{ span: 16 }}
|
||||||
initialValues={{ remember: true }}
|
initialValues={{ remember: true }}
|
||||||
onFinish={onFinish}
|
|
||||||
onFinishFailed={onFinishFailed}
|
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
>
|
>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="学员头像"
|
label="学员头像"
|
||||||
labelCol={{ style: { marginTop: 15, marginLeft: 52 } }}
|
labelCol={{ style: { marginTop: 15, marginLeft: 52 } }}
|
||||||
name="avatar"
|
|
||||||
>
|
>
|
||||||
<div className="d-flex">
|
<div className="d-flex">
|
||||||
{avatar && (
|
{avatar && (
|
||||||
@ -75,15 +100,18 @@ export const UserInfoModel: React.FC<PropInterface> = ({ open, onCancel }) => {
|
|||||||
preview={false}
|
preview={false}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className="d-flex ml-16">更换头像</div>
|
<div className="d-flex ml-16">
|
||||||
|
<Upload {...props} showUploadList={false}>
|
||||||
|
<Button>更换头像</Button>
|
||||||
|
</Upload>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="修改姓名" name="name">
|
<Form.Item label="学员姓名">
|
||||||
<Input
|
<div>{name}</div>
|
||||||
style={{ width: 200 }}
|
</Form.Item>
|
||||||
autoComplete="off"
|
<Form.Item label="身份证号" style={{ marginBottom: 16 }}>
|
||||||
placeholder="请输入姓名"
|
<div>{idCard}</div>
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
|
3
src/js/config.ts
Normal file
3
src/js/config.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default {
|
||||||
|
app_url: import.meta.env.VITE_APP_URL || "",
|
||||||
|
};
|
@ -19,14 +19,17 @@ const IndexPage = () => {
|
|||||||
const departments = useSelector(
|
const departments = useSelector(
|
||||||
(state: any) => state.loginUser.value.departments
|
(state: any) => state.loginUser.value.departments
|
||||||
);
|
);
|
||||||
|
const currentDepId = useSelector(
|
||||||
|
(state: any) => state.loginUser.value.currentDepId
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getData();
|
getData();
|
||||||
}, [tabKey]);
|
}, [tabKey, currentDepId]);
|
||||||
|
|
||||||
const getData = () => {
|
const getData = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
user.courses(departments[0].id).then((res: any) => {
|
user.courses(currentDepId).then((res: any) => {
|
||||||
const records = res.data.learn_course_records;
|
const records = res.data.learn_course_records;
|
||||||
setStats(res.data.stats);
|
setStats(res.data.stats);
|
||||||
setLearnCourseRecords(records);
|
setLearnCourseRecords(records);
|
||||||
|
@ -3,12 +3,14 @@ import { createSlice } from "@reduxjs/toolkit";
|
|||||||
type UserStoreInterface = {
|
type UserStoreInterface = {
|
||||||
user: null;
|
user: null;
|
||||||
departments: string[];
|
departments: string[];
|
||||||
|
currentDepId: number;
|
||||||
isLogin: boolean;
|
isLogin: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
let defaultValue: UserStoreInterface = {
|
let defaultValue: UserStoreInterface = {
|
||||||
user: null,
|
user: null,
|
||||||
departments: [],
|
departments: [],
|
||||||
|
currentDepId: 0,
|
||||||
isLogin: false,
|
isLogin: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -22,16 +24,23 @@ const loginUserSlice = createSlice({
|
|||||||
stage.value.user = e.payload.user;
|
stage.value.user = e.payload.user;
|
||||||
stage.value.departments = e.payload.departments;
|
stage.value.departments = e.payload.departments;
|
||||||
stage.value.isLogin = true;
|
stage.value.isLogin = true;
|
||||||
|
if (e.payload.departments.length > 0 && stage.value.currentDepId === 0) {
|
||||||
|
stage.value.currentDepId = e.payload.departments[0].id;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
logoutAction(stage) {
|
logoutAction(stage) {
|
||||||
stage.value.user = null;
|
stage.value.user = null;
|
||||||
stage.value.departments = [];
|
stage.value.departments = [];
|
||||||
stage.value.isLogin = false;
|
stage.value.isLogin = false;
|
||||||
},
|
},
|
||||||
|
saveCurrentDepId(stage, e) {
|
||||||
|
stage.value.currentDepId = e.payload;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default loginUserSlice.reducer;
|
export default loginUserSlice.reducer;
|
||||||
export const { loginAction, logoutAction } = loginUserSlice.actions;
|
export const { loginAction, logoutAction, saveCurrentDepId } =
|
||||||
|
loginUserSlice.actions;
|
||||||
|
|
||||||
export type { UserStoreInterface };
|
export type { UserStoreInterface };
|
||||||
|
Loading…
x
Reference in New Issue
Block a user