feat: migrate all files to typescript with strict false mode
This commit is contained in:
parent
b3d4e14409
commit
d56bca6692
@ -1,9 +1,9 @@
|
||||
import dayjs from "dayjs";
|
||||
import dayjs, { Dayjs } from "dayjs";
|
||||
import quarterOfYear from "dayjs/plugin/quarterOfYear";
|
||||
|
||||
dayjs.extend(quarterOfYear);
|
||||
|
||||
export const datePresets = [
|
||||
export const datePresets: Array<{ label: string; value: [Dayjs, Dayjs] }> = [
|
||||
{
|
||||
label: "本月",
|
||||
value: [dayjs().startOf("month"), dayjs().endOf("month")],
|
||||
@ -30,7 +30,7 @@ const authSlice = createSlice({
|
||||
state.roles = payload.roles;
|
||||
state.token = payload.token;
|
||||
|
||||
localStorage.setItem("userId", payload.userId);
|
||||
localStorage.setItem("userId", payload.userId.toString());
|
||||
localStorage.setItem("name", payload.name);
|
||||
localStorage.setItem("roles", JSON.stringify(payload.roles));
|
||||
localStorage.setItem("token", action.payload.token);
|
||||
@ -1,11 +0,0 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axiosInstance from "../../api/axios";
|
||||
|
||||
export const login = createAsyncThunk(
|
||||
"auth/login",
|
||||
async (values, thunkAPI) => {
|
||||
const res = await axiosInstance.post("/login", values);
|
||||
|
||||
return res;
|
||||
}
|
||||
);
|
||||
15
src/features/auth/authThunk.ts
Normal file
15
src/features/auth/authThunk.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axiosInstance from "../../api/axios";
|
||||
import { LoginResponse } from "./types";
|
||||
|
||||
export const login = createAsyncThunk<LoginResponse>(
|
||||
"auth/login",
|
||||
async (values) => {
|
||||
const res = await axiosInstance.post<LoginResponse, LoginResponse>(
|
||||
"/login",
|
||||
values
|
||||
);
|
||||
|
||||
return res;
|
||||
}
|
||||
);
|
||||
6
src/features/auth/types.ts
Normal file
6
src/features/auth/types.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export interface LoginResponse {
|
||||
userId: number;
|
||||
name: string;
|
||||
roles: string[];
|
||||
token: string;
|
||||
}
|
||||
@ -3,7 +3,7 @@ import { createRoot } from "react-dom/client";
|
||||
import { Provider } from "react-redux";
|
||||
import { RouterProvider } from "react-router-dom";
|
||||
import "./index.css";
|
||||
import router from "./router/index.jsx";
|
||||
import router from "./router/index.js";
|
||||
import { store } from "./store/index.js";
|
||||
import dayjs from "dayjs";
|
||||
import zhCN from "antd/locale/zh_CN";
|
||||
@ -4,9 +4,10 @@ import { useDispatch } from "react-redux";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { login } from "../features/auth/authThunk";
|
||||
import roleRoute from "../config/roleRouteConfig";
|
||||
import { store } from "store";
|
||||
|
||||
export default function Login() {
|
||||
const dispatch = useDispatch();
|
||||
const dispatch = useDispatch<typeof store.dispatch>();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const onFinish = async (values) => {
|
||||
@ -1,7 +1,14 @@
|
||||
import { message, Modal, Space, Spin, Table } from "antd";
|
||||
import { useEffect, useState } from "react";
|
||||
import { message, Modal, Spin, Table } from "antd";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import axiosInstance from "../../api/axios";
|
||||
|
||||
interface DeviceDetailStats {
|
||||
applicantName: string;
|
||||
applicantTeam: string;
|
||||
startDay: Date;
|
||||
endDay: Date;
|
||||
}
|
||||
|
||||
export default function DeviceDetailStatsModal({
|
||||
visible,
|
||||
record,
|
||||
@ -9,12 +16,15 @@ export default function DeviceDetailStatsModal({
|
||||
onClose,
|
||||
}) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [data, setData] = useState([]);
|
||||
const [data, setData] = useState<DeviceDetailStats[]>([]);
|
||||
|
||||
const fetchData = async () => {
|
||||
const fetchData = useCallback(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await axiosInstance.get("/device/detail-stats", {
|
||||
const res = await axiosInstance.get<
|
||||
DeviceDetailStats[],
|
||||
DeviceDetailStats[]
|
||||
>("/device/detail-stats", {
|
||||
params: {
|
||||
deviceId: record.deviceId,
|
||||
start: range[0].format("YYYY-MM-DD"),
|
||||
@ -22,12 +32,12 @@ export default function DeviceDetailStatsModal({
|
||||
},
|
||||
});
|
||||
setData(res);
|
||||
} catch (e) {
|
||||
} catch {
|
||||
message.error("获取数据失败");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
}, [record, range]);
|
||||
|
||||
const handleExport = async () => {
|
||||
setLoading(true);
|
||||
@ -73,7 +83,7 @@ export default function DeviceDetailStatsModal({
|
||||
if (visible) {
|
||||
fetchData();
|
||||
}
|
||||
}, [visible, record]);
|
||||
}, [visible, fetchData]);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
@ -1,41 +1,52 @@
|
||||
import { Button, DatePicker, Input, Space, Spin, Table, message } from "antd";
|
||||
import dayjs from "dayjs";
|
||||
import { useEffect, useState } from "react";
|
||||
import dayjs, { Dayjs } from "dayjs";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import axiosInstance from "../../api/axios";
|
||||
import { datePresets } from "../../config/datePresetsConfig";
|
||||
import DeviceDetailStatsModal from "./DeviceDetailStatsModal";
|
||||
|
||||
interface UsageStats {
|
||||
deviceId: string;
|
||||
deviceName: string;
|
||||
usageCount: number;
|
||||
totalUsageDays: number;
|
||||
}
|
||||
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
export default function DeviceStats() {
|
||||
const [data, setData] = useState([]);
|
||||
const [filteredData, setFilteredData] = useState([]);
|
||||
const [range, setRange] = useState([
|
||||
const [data, setData] = useState<UsageStats[]>([]);
|
||||
const [filteredData, setFilteredData] = useState<UsageStats[]>([]);
|
||||
const [range, setRange] = useState<[Dayjs, Dayjs]>([
|
||||
dayjs().startOf("month"),
|
||||
dayjs().endOf("month"),
|
||||
]);
|
||||
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
|
||||
const [search, setSearch] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [visiable, setVisiable] = useState(false);
|
||||
const [selectedRecord, setSelectedRecord] = useState(null);
|
||||
|
||||
const fetchData = async () => {
|
||||
const fetchData = useCallback(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await axiosInstance.get("/device/usage-stats", {
|
||||
const res = await axiosInstance.get<UsageStats[], UsageStats[]>(
|
||||
"/device/usage-stats",
|
||||
{
|
||||
params: {
|
||||
start: range[0].format("YYYY-MM-DD"),
|
||||
end: range[1].format("YYYY-MM-DD"),
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
setData(res);
|
||||
setFilteredData(res);
|
||||
} catch (e) {
|
||||
} catch {
|
||||
message.error("获取数据失败");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
}, [range]);
|
||||
|
||||
const handleSearch = (value) => {
|
||||
setSearch(value);
|
||||
@ -89,7 +100,7 @@ export default function DeviceStats() {
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, [range]);
|
||||
}, [fetchData]);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
@ -1,38 +1,50 @@
|
||||
import { Button, DatePicker, Input, Space, Spin, Table, message } from "antd";
|
||||
import dayjs from "dayjs";
|
||||
import { useEffect, useState } from "react";
|
||||
import dayjs, { Dayjs } from "dayjs";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import axiosInstance from "../../api/axios";
|
||||
import { datePresets } from "../../config/datePresetsConfig";
|
||||
|
||||
interface ReservationStat {
|
||||
deviceId: string;
|
||||
deviceName: string;
|
||||
applicantName: string;
|
||||
applicantTeam: string;
|
||||
usageCount: number;
|
||||
}
|
||||
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
export default function ReservationStats() {
|
||||
const [data, setData] = useState([]);
|
||||
const [filteredData, setFilteredData] = useState([]);
|
||||
const [range, setRange] = useState([
|
||||
const [data, setData] = useState<ReservationStat[]>([]);
|
||||
const [filteredData, setFilteredData] = useState<ReservationStat[]>([]);
|
||||
const [range, setRange] = useState<[Dayjs, Dayjs]>([
|
||||
dayjs().startOf("month"),
|
||||
dayjs().endOf("month"),
|
||||
]);
|
||||
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
|
||||
const [search, setSearch] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const fetchData = async () => {
|
||||
const fetchData = useCallback(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await axiosInstance.get("/reservation/stats", {
|
||||
const res = await axiosInstance.get<ReservationStat[], ReservationStat[]>(
|
||||
"/reservation/stats",
|
||||
{
|
||||
params: {
|
||||
start: range[0].format("YYYY-MM-DD"),
|
||||
end: range[1].format("YYYY-MM-DD"),
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
setData(res);
|
||||
setFilteredData(res);
|
||||
} catch (e) {
|
||||
} catch {
|
||||
message.error("获取数据失败");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
}, [range]);
|
||||
|
||||
const handleSearch = (value) => {
|
||||
setSearch(value);
|
||||
@ -86,7 +98,7 @@ export default function ReservationStats() {
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, [range]);
|
||||
}, [fetchData]);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
@ -1,20 +1,22 @@
|
||||
import { List, Modal, Typography } from "antd";
|
||||
import { useEffect, useState } from "react";
|
||||
import { List, Modal } from "antd";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import axiosInstance from "../../api/axios";
|
||||
|
||||
export default function TeamDetailModal({ open, team, onclose }) {
|
||||
const [data, setData] = useState([]);
|
||||
const [data, setData] = useState<string[]>([]);
|
||||
|
||||
const fetchData = async () => {
|
||||
const data = await axiosInstance.get(`/user-team/${team.id}`);
|
||||
const fetchData = useCallback(async () => {
|
||||
const data = await axiosInstance.get<string[], string[]>(
|
||||
`/user-team/${team.id}`
|
||||
);
|
||||
setData(data);
|
||||
};
|
||||
}, [team]);
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
fetchData();
|
||||
}
|
||||
}, [open, team]);
|
||||
}, [open, fetchData]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@ -4,19 +4,20 @@ import { useEffect, useState } from "react";
|
||||
import axiosInstance from "../../api/axios";
|
||||
import TeamDeleteButton from "../../components/TeamDeleteButton";
|
||||
import TeamDetailModal from "./TeamDetailModal";
|
||||
import { Team } from "types/model";
|
||||
|
||||
export default function TeamManage() {
|
||||
const [teams, setTeams] = useState([]);
|
||||
const [data, setData] = useState([]);
|
||||
const [searchName, setSearchName] = useState();
|
||||
const [teams, setTeams] = useState<Team[]>([]);
|
||||
const [data, setData] = useState<Team[]>([]);
|
||||
const [searchName, setSearchName] = useState<string>();
|
||||
const [editingId, setEditingId] = useState();
|
||||
const [editingName, setEditingName] = useState("");
|
||||
const [newTeamName, setNewTeamName] = useState();
|
||||
const [newTeamName, setNewTeamName] = useState("");
|
||||
const [open, setOpen] = useState(false);
|
||||
const [selectedTeam, setSelectedTeam] = useState(null);
|
||||
|
||||
const fetchData = async () => {
|
||||
const data = await axiosInstance.get("/teams");
|
||||
const data = await axiosInstance.get<Team[], Team[]>("/teams");
|
||||
setData(data);
|
||||
setTeams(data);
|
||||
setSearchName(null);
|
||||
@ -1,7 +1,15 @@
|
||||
import { Form, Input, message, Modal, Select } from "antd";
|
||||
import { useEffect, useState } from "react";
|
||||
import axiosInstance from "../../api/axios";
|
||||
import Password from "antd/es/input/Password";
|
||||
|
||||
interface UserDTO {
|
||||
username: string;
|
||||
name: string;
|
||||
phone: string;
|
||||
password?: string;
|
||||
teamId: string;
|
||||
roleId: string;
|
||||
}
|
||||
|
||||
export default function UserDetailModal({
|
||||
visiable,
|
||||
@ -12,11 +20,14 @@ export default function UserDetailModal({
|
||||
onSuccess,
|
||||
}) {
|
||||
const [form] = Form.useForm();
|
||||
const [initialValues, setInitialValues] = useState();
|
||||
const [teams, setTeams] = useState([]);
|
||||
const [initialValues, setInitialValues] = useState<UserDTO>();
|
||||
const [teams, setTeams] = useState<{ label: string; value: string }[]>();
|
||||
|
||||
const fetchTeams = async () => {
|
||||
const data = await axiosInstance.get("/team-label");
|
||||
const data = await axiosInstance.get<
|
||||
unknown,
|
||||
{ label: string; value: string }[]
|
||||
>("/team-label");
|
||||
setTeams(data);
|
||||
};
|
||||
|
||||
@ -27,7 +38,7 @@ export default function UserDetailModal({
|
||||
useEffect(() => {
|
||||
if (visiable) {
|
||||
if (mode === "edit") {
|
||||
const values = {
|
||||
const values: UserDTO = {
|
||||
username: user.username,
|
||||
name: user.name,
|
||||
phone: user.phone,
|
||||
@ -38,7 +49,7 @@ export default function UserDetailModal({
|
||||
setInitialValues(values);
|
||||
form.setFieldsValue(values);
|
||||
} else {
|
||||
const values = {
|
||||
const values: UserDTO = {
|
||||
username: undefined,
|
||||
password: undefined,
|
||||
name: undefined,
|
||||
@ -2,29 +2,33 @@ import { Button, Flex, Input, Popconfirm, Space, Table } from "antd";
|
||||
import Column from "antd/es/table/Column";
|
||||
import { useEffect, useState } from "react";
|
||||
import axiosInstance from "../../api/axios";
|
||||
import DeviceDetailModal from "../deviceAdmin/DeviceDetailModal";
|
||||
import UserDetailModal from "./UserDetailModal";
|
||||
import { PageResult, Pagination } from "types/common";
|
||||
import { UserVo } from "types/model";
|
||||
|
||||
export default function UserManage() {
|
||||
const [users, setUsers] = useState([]);
|
||||
const [teams, setTeams] = useState([]);
|
||||
const [modalMode, setModalMode] = useState();
|
||||
const [selectedUser, setSelectedUser] = useState();
|
||||
// const [teams, setTeams] = useState([]);
|
||||
const [modalMode, setModalMode] = useState<string>();
|
||||
const [selectedUser, setSelectedUser] = useState<UserVo>();
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const [roles, setRoles] = useState([]);
|
||||
const [pagination, setPagination] = useState({
|
||||
const [roles, setRoles] = useState<{ label: string; value: string }[]>([]);
|
||||
const [pagination, setPagination] = useState<Pagination>({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const fetchRoles = async () => {
|
||||
const data = await axiosInstance.get("/role");
|
||||
const data = await axiosInstance.get<
|
||||
unknown,
|
||||
{ label: string; value: string }[]
|
||||
>("/role");
|
||||
setRoles(data);
|
||||
};
|
||||
|
||||
const fetchData = async (pagination, name) => {
|
||||
const data = await axiosInstance.get("/user", {
|
||||
const fetchData = async (pagination: Pagination, name?: string) => {
|
||||
const data = await axiosInstance.get<unknown, PageResult<UserVo>>("/user", {
|
||||
params: {
|
||||
page: pagination.current,
|
||||
size: pagination.pageSize,
|
||||
@ -108,7 +112,7 @@ export default function UserManage() {
|
||||
/>
|
||||
<Column
|
||||
title="操作"
|
||||
render={(_, record) => {
|
||||
render={(_, record: UserVo) => {
|
||||
return (
|
||||
<Space>
|
||||
<Button
|
||||
@ -15,6 +15,7 @@ import { useSelector } from "react-redux";
|
||||
import axiosInstance, { baseURL } from "../../api/axios";
|
||||
import { deviceStatusOptions } from "../../config/DeviceStatusConfig";
|
||||
import { selectUserId } from "../../features/auth/authSlice";
|
||||
import { UploadFile } from "antd/lib";
|
||||
|
||||
export default function DeviceDetailModal({
|
||||
visiable,
|
||||
@ -26,7 +27,7 @@ export default function DeviceDetailModal({
|
||||
const [form] = Form.useForm();
|
||||
const [imageFile, setImageFile] = useState(null);
|
||||
const [initialValues, setInitialValues] = useState({});
|
||||
const [fileList, setFileList] = useState();
|
||||
const [fileList, setFileList] = useState<UploadFile[]>();
|
||||
const userId = useSelector(selectUserId);
|
||||
useEffect(() => {
|
||||
if (visiable) {
|
||||
@ -9,45 +9,61 @@ import {
|
||||
Tag,
|
||||
} from "antd";
|
||||
import Column from "antd/es/table/Column";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import axiosInstance from "../../api/axios";
|
||||
import { deviceStatusOptions } from "../../config/DeviceStatusConfig";
|
||||
import { selectUserId } from "../../features/auth/authSlice";
|
||||
import DeviceDetailModal from "./DeviceDetailModal";
|
||||
import { PageResult, Pagination } from "types/common";
|
||||
|
||||
interface DeviceAdminVO {
|
||||
deviceId: string;
|
||||
name: string;
|
||||
usageRequirement: string;
|
||||
location: string;
|
||||
imagePath: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export default function DeviceManage() {
|
||||
const [devices, setDevices] = useState([]);
|
||||
const [selectedDevice, setSelectedDevice] = useState(null);
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const [modalMode, setModalMode] = useState(null);
|
||||
const [searchName, setSearchName] = useState(null);
|
||||
const [pagination, setPagination] = useState({
|
||||
const [searchName, setSearchName] = useState<string>(null);
|
||||
const [pagination, setPagination] = useState<Pagination>({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const userId = useSelector(selectUserId);
|
||||
const fetchData = async (pagination, name = searchName) => {
|
||||
const data = await axiosInstance.get(`/device/${userId}`, {
|
||||
const fetchData = useCallback(
|
||||
async (pagination: Pagination, name: string = searchName) => {
|
||||
const data = await axiosInstance.get<unknown, PageResult<DeviceAdminVO>>(
|
||||
`/device/${userId}`,
|
||||
{
|
||||
params: {
|
||||
page: pagination.current,
|
||||
size: pagination.pageSize,
|
||||
name,
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
setDevices(data.records);
|
||||
setPagination({
|
||||
...pagination,
|
||||
total: data.total,
|
||||
});
|
||||
};
|
||||
},
|
||||
[userId, searchName]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData(pagination);
|
||||
}, []);
|
||||
}, [fetchData, pagination]);
|
||||
|
||||
const handlePageChange = async (pagination) => {
|
||||
await fetchData(pagination);
|
||||
@ -1,10 +1,22 @@
|
||||
import { Button, message, Space, Table } from "antd";
|
||||
import Column from "antd/es/table/Column";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import axiosInstance from "../../api/axios";
|
||||
import { selectUserId } from "../../features/auth/authSlice";
|
||||
import { selectUserRole } from "../../features/auth/authSlice";
|
||||
import { PageResult, Pagination } from "types/common";
|
||||
|
||||
interface ReservationVO {
|
||||
reservationId: string;
|
||||
applicantName: string;
|
||||
applicantTeam: string;
|
||||
applicantContact: string;
|
||||
deviceId: string;
|
||||
deviceName: string;
|
||||
startTime: Date;
|
||||
endTime: Date;
|
||||
}
|
||||
|
||||
export default function Approval() {
|
||||
const [reservations, setReservations] = useState([]);
|
||||
@ -21,24 +33,30 @@ export default function Approval() {
|
||||
showNeedAssist = true;
|
||||
}
|
||||
|
||||
const fetchData = async (pagination) => {
|
||||
const data = await axiosInstance.get(`/reservation/approval/${userId}`, {
|
||||
const fetchData = useCallback(
|
||||
async (pagination: Pagination) => {
|
||||
const data = await axiosInstance.get<unknown, PageResult<ReservationVO>>(
|
||||
`/reservation/approval/${userId}`,
|
||||
{
|
||||
params: {
|
||||
page: pagination.current,
|
||||
size: pagination.pageSize,
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
setReservations(data.records);
|
||||
setPagination({
|
||||
...pagination,
|
||||
total: data.total,
|
||||
});
|
||||
};
|
||||
},
|
||||
[userId]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData(pagination);
|
||||
}, []);
|
||||
}, [fetchData, pagination]);
|
||||
|
||||
const handlePageChange = async (pagination) => {
|
||||
await fetchData(pagination);
|
||||
@ -1,11 +1,25 @@
|
||||
import { Button, DatePicker, Form, Input, message, Table, Tag } from "antd";
|
||||
import { useForm } from "antd/es/form/Form";
|
||||
import Column from "antd/es/table/Column";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import axiosInstance from "../../api/axios";
|
||||
import { selectUserId, selectUserRole } from "../../features/auth/authSlice";
|
||||
import dayjs from "dayjs";
|
||||
import { PageResult, Pagination } from "types/common";
|
||||
|
||||
interface ApprovalVO {
|
||||
reservationId: string;
|
||||
approvalId: string;
|
||||
applicantName: string;
|
||||
applicantTeam: string;
|
||||
applicantContact: string;
|
||||
deviceName: string;
|
||||
startTime: Date;
|
||||
endTime: Date;
|
||||
decision: number;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export default function MyApproval() {
|
||||
const [approvals, setApprovals] = useState([]);
|
||||
@ -21,26 +35,35 @@ export default function MyApproval() {
|
||||
const userId = useSelector(selectUserId);
|
||||
const userRole = useSelector(selectUserRole);
|
||||
|
||||
const fetchData = async (pagination, searchParam) => {
|
||||
const data = await axiosInstance.get(`/approval/${userId}`, {
|
||||
const fetchData = useCallback(
|
||||
async (
|
||||
pagination: Pagination,
|
||||
searchParam?: { applicantName: string; deviceName: string }
|
||||
) => {
|
||||
const data = await axiosInstance.get<unknown, PageResult<ApprovalVO>>(
|
||||
`/approval/${userId}`,
|
||||
{
|
||||
params: {
|
||||
page: pagination.current,
|
||||
size: pagination.pageSize,
|
||||
applicantName: searchParam?.applicantName,
|
||||
deviceName: searchParam?.deviceName,
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
setApprovals(data.records);
|
||||
setPagination({
|
||||
...pagination,
|
||||
total: data.total,
|
||||
});
|
||||
};
|
||||
},
|
||||
[userId]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData(pagination);
|
||||
}, []);
|
||||
}, [fetchData, pagination]);
|
||||
|
||||
const handlePageChange = async (pagination) => {
|
||||
const values = await form.validateFields();
|
||||
@ -66,7 +89,7 @@ export default function MyApproval() {
|
||||
await fetchData(pagination, values);
|
||||
setEditingRow(null);
|
||||
message.success("修改成功");
|
||||
} catch (error) {
|
||||
} catch {
|
||||
message.error("修改失败");
|
||||
}
|
||||
};
|
||||
@ -1,14 +1,14 @@
|
||||
import { Button, Col, Form, Input, message, Row } from "antd";
|
||||
import { useForm } from "antd/es/form/Form";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import axiosInstance from "../../api/axios";
|
||||
import { selectUserId } from "../../features/auth/authSlice";
|
||||
import { UserVo } from "types/model";
|
||||
|
||||
export default function UserDetail() {
|
||||
const [form] = Form.useForm();
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const [user, setUser] = useState({
|
||||
const [user, setUser] = useState<UserVo>({
|
||||
userId: "",
|
||||
username: "",
|
||||
team: "",
|
||||
@ -17,15 +17,20 @@ export default function UserDetail() {
|
||||
});
|
||||
const userId = useSelector(selectUserId);
|
||||
|
||||
const fetchUser = async (userId) => {
|
||||
const user = await axiosInstance.get(`/userdetail/${userId}`);
|
||||
const fetchUser = useCallback(
|
||||
async (userId: string) => {
|
||||
const user = await axiosInstance.get<unknown, UserVo>(
|
||||
`/userdetail/${userId}`
|
||||
);
|
||||
setUser(user);
|
||||
form.setFieldsValue(user);
|
||||
};
|
||||
},
|
||||
[form]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
fetchUser(userId);
|
||||
}, []);
|
||||
}, [fetchUser, userId]);
|
||||
|
||||
const handleReset = () => {
|
||||
form.resetFields();
|
||||
@ -36,7 +41,7 @@ export default function UserDetail() {
|
||||
message.error("两次输入的密码不一致");
|
||||
return;
|
||||
}
|
||||
const changedFields = {};
|
||||
const changedFields: Record<string, string> = {};
|
||||
for (const key in values) {
|
||||
if (values[key] !== user[key] && values[key] !== undefined) {
|
||||
changedFields[key] = values[key];
|
||||
@ -44,7 +49,10 @@ export default function UserDetail() {
|
||||
}
|
||||
delete changedFields.confirmPassword;
|
||||
|
||||
const newUser = await axiosInstance.put(`/user/${userId}`, changedFields);
|
||||
const newUser = await axiosInstance.put<unknown, UserVo>(
|
||||
`/user/${userId}`,
|
||||
changedFields
|
||||
);
|
||||
setUser(newUser);
|
||||
form.setFieldsValue(newUser);
|
||||
message.success("修改成功");
|
||||
@ -10,21 +10,32 @@ import {
|
||||
Select,
|
||||
Space,
|
||||
} from "antd";
|
||||
import dayjs from "dayjs";
|
||||
import dayjs, { Dayjs } from "dayjs";
|
||||
import isBetween from "dayjs/plugin/isBetween";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import axiosInstance, { baseURL } from "../../api/axios";
|
||||
import { selectUserId } from "../../features/auth/authSlice";
|
||||
import { UserVo } from "types/model";
|
||||
|
||||
interface FormValue {
|
||||
name: string;
|
||||
phone: string;
|
||||
team: string;
|
||||
}
|
||||
|
||||
export default function DeviceDetailModal({ visiable, device, onclose }) {
|
||||
const [unavailableTimes, setUnavailableTims] = useState([]);
|
||||
const [unavailableTimes, setUnavailableTimes] = useState([]);
|
||||
const [form] = Form.useForm();
|
||||
const userId = useSelector((state) => state.auth.userId);
|
||||
const userId = useSelector(selectUserId);
|
||||
const [teams, setTeams] = useState([]);
|
||||
const [initialValues, setInitialValues] = useState();
|
||||
const [initialValues, setInitialValues] = useState<FormValue>();
|
||||
|
||||
const fetchTeams = async () => {
|
||||
const data = await axiosInstance.get("/team-label");
|
||||
const data = await axiosInstance.get<
|
||||
unknown,
|
||||
{ label: string; value: string }[]
|
||||
>("/team-label");
|
||||
const teams = data.map((item) => ({
|
||||
label: item.label,
|
||||
value: item.label,
|
||||
@ -32,8 +43,10 @@ export default function DeviceDetailModal({ visiable, device, onclose }) {
|
||||
setTeams(teams);
|
||||
};
|
||||
|
||||
const fetchUser = async () => {
|
||||
const data = await axiosInstance.get(`/userdetail/${userId}`);
|
||||
const fetchUser = useCallback(async () => {
|
||||
const data = await axiosInstance.get<unknown, UserVo>(
|
||||
`/userdetail/${userId}`
|
||||
);
|
||||
const values = {
|
||||
name: data.name,
|
||||
phone: data.phone,
|
||||
@ -41,7 +54,7 @@ export default function DeviceDetailModal({ visiable, device, onclose }) {
|
||||
};
|
||||
setInitialValues(values);
|
||||
form.setFieldsValue(values);
|
||||
};
|
||||
}, [userId, form]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchTeams();
|
||||
@ -49,20 +62,23 @@ export default function DeviceDetailModal({ visiable, device, onclose }) {
|
||||
|
||||
useEffect(() => {
|
||||
const fetchUnavailableTimes = async (id) => {
|
||||
const data = await axiosInstance.get(`/device/unavailable-times/${id}`);
|
||||
setUnavailableTims(data);
|
||||
const data = await axiosInstance.get<
|
||||
unknown,
|
||||
{ startTime: Date; endTime: Date }[]
|
||||
>(`/device/unavailable-times/${id}`);
|
||||
setUnavailableTimes(data);
|
||||
};
|
||||
|
||||
if (visiable && device?.deviceId) {
|
||||
fetchUnavailableTimes(device.deviceId);
|
||||
fetchUser();
|
||||
}
|
||||
}, [visiable, device?.deviceId]);
|
||||
}, [visiable, device?.deviceId, fetchUser]);
|
||||
|
||||
const { RangePicker } = DatePicker;
|
||||
const disabledDate = (current, { from } = {}) => {
|
||||
const disabledDate = (current: Dayjs, info: { from?: Dayjs } = {}) => {
|
||||
if (!current) return false;
|
||||
|
||||
const { from } = info;
|
||||
const today = dayjs().startOf("day");
|
||||
const currentDay = current.startOf("day");
|
||||
|
||||
@ -1,10 +1,24 @@
|
||||
import { Table, Tag } from "antd";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import axiosInstance from "../../api/axios";
|
||||
import { useSelector } from "react-redux";
|
||||
import Column from "antd/es/table/Column";
|
||||
import dayjs from "dayjs";
|
||||
import { selectUserId } from "../../features/auth/authSlice";
|
||||
import { PageResult } from "types/common";
|
||||
|
||||
interface UserReservationVO {
|
||||
reservationId: string;
|
||||
deviceName: string;
|
||||
startTime: Date;
|
||||
endTime: Date;
|
||||
statusLabel: string;
|
||||
deviceLeaderName: string;
|
||||
deviceLeaderContact: string;
|
||||
deviceAdminName: string;
|
||||
deviceAdminContact: string;
|
||||
createdTime: Date;
|
||||
}
|
||||
|
||||
export default function MyReservation() {
|
||||
const [reservations, setReservations] = useState([]);
|
||||
@ -16,8 +30,12 @@ export default function MyReservation() {
|
||||
|
||||
const userId = useSelector(selectUserId);
|
||||
|
||||
const fetchData = async (pagination) => {
|
||||
const data = await axiosInstance.get(`/reservation/${userId}`, {
|
||||
const fetchData = useCallback(
|
||||
async (pagination) => {
|
||||
const data = await axiosInstance.get<
|
||||
unknown,
|
||||
PageResult<UserReservationVO>
|
||||
>(`/reservation/${userId}`, {
|
||||
params: {
|
||||
page: pagination.current,
|
||||
size: pagination.pageSize,
|
||||
@ -28,11 +46,13 @@ export default function MyReservation() {
|
||||
...pagination,
|
||||
total: data.total,
|
||||
});
|
||||
};
|
||||
},
|
||||
[userId]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData(pagination);
|
||||
}, []);
|
||||
}, [fetchData, pagination]);
|
||||
|
||||
const handlePageChange = (pagination) => {
|
||||
fetchData(pagination);
|
||||
@ -1,8 +1,9 @@
|
||||
import { Input, Space, Table, Tag } from "antd";
|
||||
import Column from "antd/es/table/Column";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import axiosInstance from "../../api/axios";
|
||||
import DeviceDetailModal from "./DeviceDetailModal";
|
||||
import { PageResult } from "types/common";
|
||||
|
||||
const statusColorMap = {
|
||||
空闲: "green",
|
||||
@ -11,6 +12,15 @@ const statusColorMap = {
|
||||
维修中: "gray",
|
||||
};
|
||||
|
||||
interface DeviceVO {
|
||||
deviceId: string;
|
||||
name: string;
|
||||
usageRequirement: string;
|
||||
location: string;
|
||||
imagePath: string;
|
||||
state: string;
|
||||
}
|
||||
|
||||
export default function Reserve() {
|
||||
const [name, setName] = useState(null);
|
||||
const [pagination, setPagination] = useState({
|
||||
@ -20,24 +30,31 @@ export default function Reserve() {
|
||||
});
|
||||
const [devices, setDevices] = useState([]);
|
||||
|
||||
const fetchData = async (pagination, searchName = name) => {
|
||||
const data = await axiosInstance.get("/device", {
|
||||
const fetchData = useCallback(
|
||||
async (pagination, searchName = name) => {
|
||||
const data = await axiosInstance.get<unknown, PageResult<DeviceVO>>(
|
||||
"/device",
|
||||
{
|
||||
params: {
|
||||
page: pagination.current,
|
||||
size: pagination.pageSize,
|
||||
name: searchName,
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
setDevices(data.records);
|
||||
setPagination({
|
||||
...pagination,
|
||||
total: data.total,
|
||||
});
|
||||
};
|
||||
},
|
||||
[name]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData(pagination);
|
||||
}, []);
|
||||
}, [fetchData, pagination]);
|
||||
|
||||
const handlePageChange = (pagination) => {
|
||||
fetchData(pagination);
|
||||
@ -74,7 +91,7 @@ export default function Reserve() {
|
||||
title="使用要求"
|
||||
key="usageRequirement"
|
||||
dataIndex="usageRequirement"
|
||||
ellipsis="true"
|
||||
ellipsis={true}
|
||||
/>
|
||||
<Column title="位置" key="location" dataIndex="location" />
|
||||
<Column
|
||||
7
src/types/axios.d.ts
vendored
Normal file
7
src/types/axios.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
import "axios";
|
||||
|
||||
declare module "axios" {
|
||||
export interface AxiosRequestConfig {
|
||||
skipInterceptor?: boolean;
|
||||
}
|
||||
}
|
||||
12
src/types/common.ts
Normal file
12
src/types/common.ts
Normal file
@ -0,0 +1,12 @@
|
||||
export interface PageResult<T> {
|
||||
records: T[];
|
||||
total: number;
|
||||
size: number;
|
||||
current: number;
|
||||
}
|
||||
|
||||
export interface Pagination {
|
||||
current: number;
|
||||
pageSize: number;
|
||||
total?: number;
|
||||
}
|
||||
15
src/types/model.ts
Normal file
15
src/types/model.ts
Normal file
@ -0,0 +1,15 @@
|
||||
export interface Team {
|
||||
id: string;
|
||||
name: string;
|
||||
size: number;
|
||||
}
|
||||
|
||||
export interface UserVo {
|
||||
userId: string;
|
||||
username: string;
|
||||
team: string;
|
||||
teamId?: string;
|
||||
name: string;
|
||||
phone: string;
|
||||
roleId?: string;
|
||||
}
|
||||
1
src/vite-env.d.ts
vendored
Normal file
1
src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
Loading…
x
Reference in New Issue
Block a user