feat: 实现普通用户预约设备
This commit is contained in:
parent
b0ea73befb
commit
4dfe6b491e
1
package-lock.json
generated
1
package-lock.json
generated
@ -13,6 +13,7 @@
|
|||||||
"@tailwindcss/vite": "^4.1.10",
|
"@tailwindcss/vite": "^4.1.10",
|
||||||
"antd": "^5.26.1",
|
"antd": "^5.26.1",
|
||||||
"axios": "^1.10.0",
|
"axios": "^1.10.0",
|
||||||
|
"dayjs": "^1.11.13",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-redux": "^9.2.0",
|
"react-redux": "^9.2.0",
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
"@tailwindcss/vite": "^4.1.10",
|
"@tailwindcss/vite": "^4.1.10",
|
||||||
"antd": "^5.26.1",
|
"antd": "^5.26.1",
|
||||||
"axios": "^1.10.0",
|
"axios": "^1.10.0",
|
||||||
|
"dayjs": "^1.11.13",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-redux": "^9.2.0",
|
"react-redux": "^9.2.0",
|
||||||
|
@ -2,8 +2,10 @@ import { message } from "antd";
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { logout } from "../features/auth/authSlice";
|
import { logout } from "../features/auth/authSlice";
|
||||||
|
|
||||||
|
const baseURL = "http://127.0.0.1:8080";
|
||||||
|
|
||||||
const axiosInstance = axios.create({
|
const axiosInstance = axios.create({
|
||||||
baseURL: "http://127.0.0.1:8080",
|
baseURL: baseURL,
|
||||||
timeout: 2000, // 2秒
|
timeout: 2000, // 2秒
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -42,4 +44,5 @@ axiosInstance.interceptors.response.use(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export { baseURL };
|
||||||
export default axiosInstance;
|
export default axiosInstance;
|
||||||
|
13
src/main.jsx
13
src/main.jsx
@ -5,11 +5,18 @@ import { RouterProvider } from "react-router-dom";
|
|||||||
import "./index.css";
|
import "./index.css";
|
||||||
import router from "./router/index.jsx";
|
import router from "./router/index.jsx";
|
||||||
import { store } from "./store/index.js";
|
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(
|
createRoot(document.getElementById("root")).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<Provider store={store}>
|
<ConfigProvider locale={zhCN}>
|
||||||
<RouterProvider router={router} />
|
<Provider store={store}>
|
||||||
</Provider>
|
<RouterProvider router={router} />
|
||||||
|
</Provider>
|
||||||
|
</ConfigProvider>
|
||||||
</StrictMode>
|
</StrictMode>
|
||||||
);
|
);
|
||||||
|
104
src/pages/user/DeviceDetailModal.jsx
Normal file
104
src/pages/user/DeviceDetailModal.jsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
@ -2,6 +2,7 @@ import { Input, Space, Table, Tag } from "antd";
|
|||||||
import Column from "antd/es/table/Column";
|
import Column from "antd/es/table/Column";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import axiosInstance from "../../api/axios";
|
import axiosInstance from "../../api/axios";
|
||||||
|
import DeviceDetailModal from "./DeviceDetailModal";
|
||||||
|
|
||||||
const statusColorMap = {
|
const statusColorMap = {
|
||||||
空闲: "green",
|
空闲: "green",
|
||||||
@ -100,11 +101,11 @@ export default function Reserve() {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Table>
|
</Table>
|
||||||
{/* <ReservationModal
|
<DeviceDetailModal
|
||||||
visiable={!!selectedDevice}
|
visiable={!!selectedDevice}
|
||||||
device={selectedDevice}
|
device={selectedDevice}
|
||||||
onclose={() => setSelectedDevice(null)}
|
onclose={() => setSelectedDevice(null)}
|
||||||
/> */}
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user