feat: 实现普通用户预约设备

This commit is contained in:
BenjaminNH 2025-06-24 17:27:50 +08:00
parent b0ea73befb
commit 4dfe6b491e
6 changed files with 123 additions and 6 deletions

1
package-lock.json generated
View File

@ -13,6 +13,7 @@
"@tailwindcss/vite": "^4.1.10",
"antd": "^5.26.1",
"axios": "^1.10.0",
"dayjs": "^1.11.13",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-redux": "^9.2.0",

View File

@ -15,6 +15,7 @@
"@tailwindcss/vite": "^4.1.10",
"antd": "^5.26.1",
"axios": "^1.10.0",
"dayjs": "^1.11.13",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-redux": "^9.2.0",

View File

@ -2,8 +2,10 @@ import { message } from "antd";
import axios from "axios";
import { logout } from "../features/auth/authSlice";
const baseURL = "http://127.0.0.1:8080";
const axiosInstance = axios.create({
baseURL: "http://127.0.0.1:8080",
baseURL: baseURL,
timeout: 2000, // 2秒
});
@ -42,4 +44,5 @@ axiosInstance.interceptors.response.use(
}
);
export { baseURL };
export default axiosInstance;

View File

@ -5,11 +5,18 @@ import { RouterProvider } from "react-router-dom";
import "./index.css";
import router from "./router/index.jsx";
import { store } from "./store/index.js";
import dayjs from "dayjs";
import zhCN from "antd/locale/zh_CN";
import { ConfigProvider } from "antd";
dayjs.locale("zh-cn");
createRoot(document.getElementById("root")).render(
<StrictMode>
<Provider store={store}>
<RouterProvider router={router} />
</Provider>
<ConfigProvider locale={zhCN}>
<Provider store={store}>
<RouterProvider router={router} />
</Provider>
</ConfigProvider>
</StrictMode>
);

View File

@ -0,0 +1,104 @@
import {
DatePicker,
Descriptions,
Form,
Image,
message,
Modal,
Space,
} from "antd";
import dayjs from "dayjs";
import axiosInstance, { baseURL } from "../../api/axios";
import { useEffect, useState } from "react";
import isBetween from "dayjs/plugin/isBetween";
import { store } from "../../store";
import { useSelector, useStore } from "react-redux";
export default function DeviceDetailModal({ visiable, device, onclose }) {
const [unavailableTimes, setUnavailableTims] = useState([]);
useEffect(() => {
const fetchUnavailableTimes = async (id) => {
const data = await axiosInstance.get(`/device/unavailable-times/${id}`);
setUnavailableTims(data);
};
if (visiable && device?.deviceId) {
fetchUnavailableTimes(device.deviceId);
}
}, [visiable, device?.deviceId]);
const { RangePicker } = DatePicker;
const disabledDate = (current) => {
if (!current) return false;
const today = dayjs().startOf("day");
const currentDay = current.startOf("day");
if (currentDay.isBefore(today)) {
return true;
}
dayjs.extend(isBetween);
return unavailableTimes.some(({ startTime, endTime }) => {
const start = dayjs(startTime).startOf("day");
const end = dayjs(endTime).endOf("day");
return currentDay.isBetween(start, end, null, "[]");
});
};
const [form] = Form.useForm();
const userId = useSelector((state) => state.auth.userId);
const handleOK = async () => {
const values = await form.validateFields();
const [startTime, endTime] = values.date;
const payload = {
deviceId: device.deviceId,
userId,
startTime: startTime.format("YYYY-MM-DD"),
endTime: endTime.format("YYYY-MM-DD"),
};
console.log(payload);
await axiosInstance.post("/reservation", payload);
message.success("预约成功");
form.resetFields();
onclose();
};
return (
<Modal
title="预约设备"
open={visiable}
onCancel={() => {
onclose();
}}
onOk={handleOK}
>
<Space direction="vertical">
<Descriptions column={1}>
<Descriptions.Item label="设备名称">{device?.name}</Descriptions.Item>
<Descriptions.Item label="使用要求">
{device?.usageRequirement}
</Descriptions.Item>
<Descriptions.Item label="设备位置">
{device?.location}
</Descriptions.Item>
<Descriptions.Item label="设备图片">
<Image src={`${baseURL}/${device?.imagePath}`} />
</Descriptions.Item>
</Descriptions>
<Form form={form} layout="inline" className="mt-14">
<Form.Item
name="date"
label="预约日期"
rules={[{ required: true, message: "请选择预约日期" }]}
>
<RangePicker disabledDate={disabledDate} />
</Form.Item>
</Form>
</Space>
</Modal>
);
}

View File

@ -2,6 +2,7 @@ import { Input, Space, Table, Tag } from "antd";
import Column from "antd/es/table/Column";
import { useEffect, useState } from "react";
import axiosInstance from "../../api/axios";
import DeviceDetailModal from "./DeviceDetailModal";
const statusColorMap = {
空闲: "green",
@ -100,11 +101,11 @@ export default function Reserve() {
)}
/>
</Table>
{/* <ReservationModal
<DeviceDetailModal
visiable={!!selectedDevice}
device={selectedDevice}
onclose={() => setSelectedDevice(null)}
/> */}
/>
</>
);
}