add
This commit is contained in:
@@ -162,6 +162,14 @@ public class AdminController {
|
|||||||
return ApiResponse.success(scheduleMapper.listByDate(java.time.LocalDate.parse(date)));
|
return ApiResponse.success(scheduleMapper.listByDate(java.time.LocalDate.parse(date)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/schedules/range")
|
||||||
|
public ApiResponse<List<Schedule>> listSchedulesRange(@RequestParam String start, @RequestParam String end) {
|
||||||
|
return ApiResponse.success(scheduleMapper.listByDateRange(
|
||||||
|
java.time.LocalDate.parse(start),
|
||||||
|
java.time.LocalDate.parse(end)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/schedules")
|
@PostMapping("/schedules")
|
||||||
public ApiResponse<Schedule> createSchedule(@RequestBody ScheduleRequest request) {
|
public ApiResponse<Schedule> createSchedule(@RequestBody ScheduleRequest request) {
|
||||||
Schedule schedule = new Schedule();
|
Schedule schedule = new Schedule();
|
||||||
|
|||||||
@@ -40,6 +40,16 @@ public class NurseController {
|
|||||||
return ApiResponse.success(scheduleMapper.listByNurseAndDate(nurseId, java.time.LocalDate.parse(date)));
|
return ApiResponse.success(scheduleMapper.listByNurseAndDate(nurseId, java.time.LocalDate.parse(date)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/schedules/range")
|
||||||
|
public ApiResponse<List<Schedule>> listSchedulesRange(@RequestParam String start, @RequestParam String end) {
|
||||||
|
Long nurseId = Long.valueOf(StpUtil.getLoginId().toString());
|
||||||
|
return ApiResponse.success(scheduleMapper.listByNurseAndDateRange(
|
||||||
|
nurseId,
|
||||||
|
java.time.LocalDate.parse(start),
|
||||||
|
java.time.LocalDate.parse(end)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/care-records")
|
@PostMapping("/care-records")
|
||||||
public ApiResponse<CareRecord> createCare(@RequestBody CareRecordRequest request) {
|
public ApiResponse<CareRecord> createCare(@RequestBody CareRecordRequest request) {
|
||||||
CareRecord record = new CareRecord();
|
CareRecord record = new CareRecord();
|
||||||
|
|||||||
@@ -14,6 +14,12 @@ public interface ScheduleMapper {
|
|||||||
@Select("SELECT * FROM schedule WHERE date = #{date} ORDER BY id DESC")
|
@Select("SELECT * FROM schedule WHERE date = #{date} ORDER BY id DESC")
|
||||||
List<Schedule> listByDate(LocalDate date);
|
List<Schedule> listByDate(LocalDate date);
|
||||||
|
|
||||||
|
@Select("SELECT * FROM schedule WHERE date BETWEEN #{start} AND #{end} ORDER BY date ASC")
|
||||||
|
List<Schedule> listByDateRange(@Param("start") LocalDate start, @Param("end") LocalDate end);
|
||||||
|
|
||||||
|
@Select("SELECT * FROM schedule WHERE nurse_id = #{nurseId} AND date BETWEEN #{start} AND #{end} ORDER BY date ASC")
|
||||||
|
List<Schedule> listByNurseAndDateRange(@Param("nurseId") Long nurseId, @Param("start") LocalDate start, @Param("end") LocalDate end);
|
||||||
|
|
||||||
@Insert("INSERT INTO schedule(nurse_id, date, shift, task, created_at, updated_at) VALUES(#{nurseId}, #{date}, #{shift}, #{task}, NOW(), NOW())")
|
@Insert("INSERT INTO schedule(nurse_id, date, shift, task, created_at, updated_at) VALUES(#{nurseId}, #{date}, #{shift}, #{task}, NOW(), NOW())")
|
||||||
@Options(useGeneratedKeys = true, keyProperty = "id")
|
@Options(useGeneratedKeys = true, keyProperty = "id")
|
||||||
int insert(Schedule schedule);
|
int insert(Schedule schedule);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export const eldersUpdate = (payload) => http.put("/admin/elders", payload);
|
|||||||
export const eldersDelete = (id) => http.delete(`/admin/elders/${id}`);
|
export const eldersDelete = (id) => http.delete(`/admin/elders/${id}`);
|
||||||
|
|
||||||
export const schedulesByDate = (date) => http.get("/admin/schedules", { params: { date } });
|
export const schedulesByDate = (date) => http.get("/admin/schedules", { params: { date } });
|
||||||
|
export const schedulesByRange = (start, end) => http.get("/admin/schedules/range", { params: { start, end } });
|
||||||
export const scheduleCreate = (payload) => http.post("/admin/schedules", payload);
|
export const scheduleCreate = (payload) => http.post("/admin/schedules", payload);
|
||||||
export const scheduleUpdate = (payload) => http.put("/admin/schedules", payload);
|
export const scheduleUpdate = (payload) => http.put("/admin/schedules", payload);
|
||||||
export const scheduleDelete = (id) => http.delete(`/admin/schedules/${id}`);
|
export const scheduleDelete = (id) => http.delete(`/admin/schedules/${id}`);
|
||||||
@@ -31,6 +32,7 @@ export const noticeCreate = (payload) => http.post("/admin/notices", payload);
|
|||||||
export const noticeList = (role, userId) => http.get("/admin/notices", { params: { role, userId } });
|
export const noticeList = (role, userId) => http.get("/admin/notices", { params: { role, userId } });
|
||||||
|
|
||||||
export const nurseSchedules = (date) => http.get("/nurse/schedules", { params: { date } });
|
export const nurseSchedules = (date) => http.get("/nurse/schedules", { params: { date } });
|
||||||
|
export const nurseSchedulesRange = (start, end) => http.get("/nurse/schedules/range", { params: { start, end } });
|
||||||
export const nurseCareCreate = (payload) => http.post("/nurse/care-records", payload);
|
export const nurseCareCreate = (payload) => http.post("/nurse/care-records", payload);
|
||||||
export const nurseCareList = (elderId) => http.get("/nurse/care-records", { params: { elderId } });
|
export const nurseCareList = (elderId) => http.get("/nurse/care-records", { params: { elderId } });
|
||||||
export const nurseHealthCreate = (payload) => http.post("/nurse/health-records", payload);
|
export const nurseHealthCreate = (payload) => http.post("/nurse/health-records", payload);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import Vue from "vue";
|
import Vue from "vue";
|
||||||
import ElementUI from "element-ui";
|
import ElementUI from "element-ui";
|
||||||
import "element-ui/lib/theme-chalk/index.css";
|
import "element-ui/lib/theme-chalk/index.css";
|
||||||
import "./assets/theme.css";
|
import "./assets/theme.css";
|
||||||
|
|||||||
@@ -1,108 +1,244 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="page-card">
|
<div class="page-card">
|
||||||
<h3>排班管理</h3>
|
<div style="display:flex; justify-content: space-between; align-items:center;">
|
||||||
<div style="margin: 12px 0; display:flex; gap: 12px;">
|
<h3>排班管理</h3>
|
||||||
<el-date-picker v-model="date" type="date" placeholder="选择日期" />
|
<el-button type="primary" @click="openCreate">新增排班</el-button>
|
||||||
<el-button type="primary" @click="load">查询</el-button>
|
|
||||||
<el-button @click="showCreate = true">新增排班</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="schedules" stripe>
|
<div class="schedule-toolbar">
|
||||||
<el-table-column prop="id" label="编号" width="80" />
|
<el-date-picker v-model="monthPicker" type="month" placeholder="选择月份" @change="handleMonthChange" />
|
||||||
<el-table-column prop="nurseId" label="护工ID" width="100" />
|
<el-button @click="jumpToday">回到今天</el-button>
|
||||||
<el-table-column prop="date" label="日期" />
|
</div>
|
||||||
<el-table-column prop="shift" label="班次" />
|
<el-row :gutter="16">
|
||||||
<el-table-column prop="task" label="任务" />
|
<el-col :span="16">
|
||||||
<el-table-column label="操作" width="200">
|
<el-calendar v-model="calendarDate" @input="handleDateChange">
|
||||||
<template slot-scope="scope">
|
<template slot="dateCell" slot-scope="{ data }">
|
||||||
<el-button size="mini" @click="edit(scope.row)">编辑</el-button>
|
<div class="calendar-cell">
|
||||||
<el-button size="mini" type="danger" @click="remove(scope.row)">删除</el-button>
|
<div class="cell-date">{{ data.day.split('-')[2] }}</div>
|
||||||
</template>
|
<div class="cell-badges">
|
||||||
</el-table-column>
|
<span v-for="item in getDaySchedules(data.day).slice(0, 2)" :key="item.id" class="badge">
|
||||||
</el-table>
|
{{ formatBadge(item) }}
|
||||||
|
</span>
|
||||||
|
<span v-if="getDaySchedules(data.day).length > 2" class="more">
|
||||||
|
+{{ getDaySchedules(data.day).length - 2 }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-calendar>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<div class="schedule-panel">
|
||||||
|
<div class="schedule-title">当天排班:{{ selectedDate }}</div>
|
||||||
|
<el-table :data="daySchedules" stripe>
|
||||||
|
<el-table-column label="护工" width="120">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ nurseName(scope.row.nurseId) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="shift" label="班次" width="90" />
|
||||||
|
<el-table-column prop="task" label="任务" />
|
||||||
|
<el-table-column label="操作" width="160" class-name="action-col">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<div class="action-inline">
|
||||||
|
<el-button size="mini" @click="openEdit(scope.row)">编辑</el-button>
|
||||||
|
<el-button size="mini" type="danger" @click="remove(scope.row)">删除</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
<el-dialog title="新增排班" :visible.sync="showCreate">
|
<el-dialog title="排班信息" :visible.sync="showDialog">
|
||||||
<el-form :model="form" label-width="120px">
|
<el-form :model="form" label-width="120px">
|
||||||
<el-form-item label="护工ID"><el-input v-model="form.nurseId"/></el-form-item>
|
<el-form-item label="护工">
|
||||||
|
<el-select v-model="form.nurseId" placeholder="选择护工">
|
||||||
|
<el-option v-for="nurse in nurses" :key="nurse.id" :label="nurse.name" :value="nurse.id" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="日期"><el-date-picker v-model="form.date" type="date"/></el-form-item>
|
<el-form-item label="日期"><el-date-picker v-model="form.date" type="date"/></el-form-item>
|
||||||
<el-form-item label="班次"><el-input v-model="form.shift"/></el-form-item>
|
<el-form-item label="班次">
|
||||||
|
<el-select v-model="form.shift" placeholder="选择班次">
|
||||||
|
<el-option label="早班" value="早班" />
|
||||||
|
<el-option label="中班" value="中班" />
|
||||||
|
<el-option label="晚班" value="晚班" />
|
||||||
|
<el-option label="夜班" value="夜班" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="任务"><el-input v-model="form.task"/></el-form-item>
|
<el-form-item label="任务"><el-input v-model="form.task"/></el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<span slot="footer">
|
<span slot="footer">
|
||||||
<el-button @click="showCreate = false">取消</el-button>
|
<el-button @click="showDialog = false">取消</el-button>
|
||||||
<el-button type="primary" @click="create">保存</el-button>
|
<el-button type="primary" @click="save">保存</el-button>
|
||||||
</span>
|
|
||||||
</el-dialog>
|
|
||||||
|
|
||||||
<el-dialog title="编辑排班" :visible.sync="showEdit">
|
|
||||||
<el-form :model="editForm" label-width="120px">
|
|
||||||
<el-form-item label="护工ID"><el-input v-model="editForm.nurseId"/></el-form-item>
|
|
||||||
<el-form-item label="日期"><el-date-picker v-model="editForm.date" type="date"/></el-form-item>
|
|
||||||
<el-form-item label="班次"><el-input v-model="editForm.shift"/></el-form-item>
|
|
||||||
<el-form-item label="任务"><el-input v-model="editForm.task"/></el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<span slot="footer">
|
|
||||||
<el-button @click="showEdit = false">取消</el-button>
|
|
||||||
<el-button type="primary" @click="update">保存</el-button>
|
|
||||||
</span>
|
</span>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { schedulesByDate, scheduleCreate, scheduleUpdate, scheduleDelete } from "../../api";
|
import { schedulesByRange, scheduleCreate, scheduleUpdate, scheduleDelete, adminUsers } from "../../api";
|
||||||
import { formatDate } from "../../utils/date";
|
import { formatDate } from "../../utils/date";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
|
const today = new Date();
|
||||||
return {
|
return {
|
||||||
date: "",
|
calendarDate: today,
|
||||||
schedules: [],
|
monthPicker: today,
|
||||||
showCreate: false,
|
selectedDate: formatDate(today),
|
||||||
showEdit: false,
|
daySchedules: [],
|
||||||
form: { nurseId: "", date: "", shift: "", task: "" },
|
scheduleMap: {},
|
||||||
editForm: {}
|
nurses: [],
|
||||||
|
nurseMap: {},
|
||||||
|
showDialog: false,
|
||||||
|
form: { id: null, nurseId: "", date: "", shift: "", task: "" }
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
created() {
|
||||||
|
this.loadMonth(this.monthPicker);
|
||||||
|
this.loadNurses();
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async load() {
|
async loadNurses() {
|
||||||
if (!this.date) return;
|
|
||||||
try {
|
try {
|
||||||
const res = await schedulesByDate(formatDate(this.date));
|
const res = await adminUsers("NURSE");
|
||||||
this.schedules = res.data.data;
|
this.nurses = res.data.data;
|
||||||
|
const map = {};
|
||||||
|
this.nurses.forEach((nurse) => {
|
||||||
|
map[nurse.id] = nurse.name;
|
||||||
|
});
|
||||||
|
this.nurseMap = map;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$message.error(e.message || "load failed");
|
this.$message.error(e.message || "加载护工失败");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async create() {
|
nurseName(id) {
|
||||||
|
return this.nurseMap[id] || `护工${id}`;
|
||||||
|
},
|
||||||
|
formatBadge(item) {
|
||||||
|
const shift = item.shift || "班次";
|
||||||
|
const name = this.nurseName(item.nurseId);
|
||||||
|
return `${shift}·${name}`;
|
||||||
|
},
|
||||||
|
handleMonthChange() {
|
||||||
|
if (!this.monthPicker) return;
|
||||||
|
const firstDay = new Date(this.monthPicker.getFullYear(), this.monthPicker.getMonth(), 1);
|
||||||
|
this.calendarDate = firstDay;
|
||||||
|
this.loadMonth(this.monthPicker);
|
||||||
|
},
|
||||||
|
handleDateChange(date) {
|
||||||
|
this.selectedDate = formatDate(date);
|
||||||
|
this.daySchedules = this.getDaySchedules(this.selectedDate);
|
||||||
|
},
|
||||||
|
getDaySchedules(dayStr) {
|
||||||
|
return this.scheduleMap[dayStr] || [];
|
||||||
|
},
|
||||||
|
async loadMonth(date) {
|
||||||
|
const year = date.getFullYear();
|
||||||
|
const month = date.getMonth();
|
||||||
|
const start = new Date(year, month, 1);
|
||||||
|
const end = new Date(year, month + 1, 0);
|
||||||
try {
|
try {
|
||||||
await scheduleCreate({ ...this.form, date: formatDate(this.form.date) });
|
const res = await schedulesByRange(formatDate(start), formatDate(end));
|
||||||
this.showCreate = false;
|
const map = {};
|
||||||
this.load();
|
res.data.data.forEach((item) => {
|
||||||
|
if (!map[item.date]) {
|
||||||
|
map[item.date] = [];
|
||||||
|
}
|
||||||
|
map[item.date].push(item);
|
||||||
|
});
|
||||||
|
this.scheduleMap = map;
|
||||||
|
this.daySchedules = this.getDaySchedules(this.selectedDate);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$message.error(e.message || "create failed");
|
this.$message.error(e.message || "加载失败");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
edit(row) {
|
openCreate() {
|
||||||
this.editForm = { ...row };
|
this.form = { id: null, nurseId: "", date: new Date(this.selectedDate), shift: "", task: "" };
|
||||||
this.showEdit = true;
|
this.showDialog = true;
|
||||||
},
|
},
|
||||||
async update() {
|
openEdit(row) {
|
||||||
|
this.form = { ...row, date: new Date(row.date) };
|
||||||
|
this.showDialog = true;
|
||||||
|
},
|
||||||
|
async save() {
|
||||||
try {
|
try {
|
||||||
await scheduleUpdate({ ...this.editForm, date: formatDate(this.editForm.date) });
|
const payload = { ...this.form, date: formatDate(this.form.date) };
|
||||||
this.showEdit = false;
|
if (payload.id) {
|
||||||
this.load();
|
await scheduleUpdate(payload);
|
||||||
|
} else {
|
||||||
|
await scheduleCreate(payload);
|
||||||
|
}
|
||||||
|
this.showDialog = false;
|
||||||
|
this.loadMonth(this.monthPicker);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$message.error(e.message || "update failed");
|
this.$message.error(e.message || "保存失败");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async remove(row) {
|
async remove(row) {
|
||||||
try {
|
try {
|
||||||
await scheduleDelete(row.id);
|
await scheduleDelete(row.id);
|
||||||
this.load();
|
this.loadMonth(this.monthPicker);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$message.error(e.message || "delete failed");
|
this.$message.error(e.message || "删除失败");
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
jumpToday() {
|
||||||
|
const today = new Date();
|
||||||
|
this.monthPicker = today;
|
||||||
|
this.calendarDate = today;
|
||||||
|
this.selectedDate = formatDate(today);
|
||||||
|
this.loadMonth(today);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.schedule-toolbar {
|
||||||
|
margin: 12px 0 16px;
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.schedule-panel {
|
||||||
|
background: #f6fbf7;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
border: 1px solid #d9efe3;
|
||||||
|
}
|
||||||
|
.schedule-title {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.action-inline {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
.calendar-cell {
|
||||||
|
min-height: 58px;
|
||||||
|
}
|
||||||
|
.cell-date {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #6b7b6f;
|
||||||
|
}
|
||||||
|
.cell-badges {
|
||||||
|
margin-top: 4px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
.badge {
|
||||||
|
background: #e1f3ea;
|
||||||
|
color: #2f7d59;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
.more {
|
||||||
|
color: #7b8b7f;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,36 +1,145 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="page-card">
|
<div class="page-card">
|
||||||
<h3>我的排班</h3>
|
<div style="display:flex; justify-content: space-between; align-items:center;">
|
||||||
<div style="margin-bottom: 12px; display:flex; gap: 12px;">
|
<h3>我的排班</h3>
|
||||||
<el-date-picker v-model="date" type="date" placeholder="选择日期" />
|
<el-button @click="jumpToday">回到今天</el-button>
|
||||||
<el-button type="primary" @click="load">查询</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="items" stripe>
|
<div class="schedule-toolbar">
|
||||||
<el-table-column prop="date" label="日期" />
|
<el-date-picker v-model="monthPicker" type="month" placeholder="选择月份" @change="handleMonthChange" />
|
||||||
<el-table-column prop="shift" label="班次" />
|
</div>
|
||||||
<el-table-column prop="task" label="任务" />
|
<el-row :gutter="16">
|
||||||
</el-table>
|
<el-col :span="16">
|
||||||
|
<el-calendar v-model="calendarDate" @input="handleDateChange">
|
||||||
|
<template slot="dateCell" slot-scope="{ data }">
|
||||||
|
<div class="calendar-cell">
|
||||||
|
<div class="cell-date">{{ data.day.split('-')[2] }}</div>
|
||||||
|
<div class="cell-badges">
|
||||||
|
<span v-for="item in getDaySchedules(data.day).slice(0, 2)" :key="item.id" class="badge">
|
||||||
|
{{ item.shift || "班次" }}
|
||||||
|
</span>
|
||||||
|
<span v-if="getDaySchedules(data.day).length > 2" class="more">
|
||||||
|
+{{ getDaySchedules(data.day).length - 2 }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-calendar>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<div class="schedule-panel">
|
||||||
|
<div class="schedule-title">当天排班:{{ selectedDate }}</div>
|
||||||
|
<el-table :data="daySchedules" stripe>
|
||||||
|
<el-table-column prop="shift" label="班次" width="100" />
|
||||||
|
<el-table-column prop="task" label="任务" />
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { nurseSchedules } from "../../api";
|
import { nurseSchedulesRange } from "../../api";
|
||||||
import { formatDate } from "../../utils/date";
|
import { formatDate } from "../../utils/date";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return { date: "", items: [] };
|
const today = new Date();
|
||||||
|
return {
|
||||||
|
calendarDate: today,
|
||||||
|
monthPicker: today,
|
||||||
|
selectedDate: formatDate(today),
|
||||||
|
daySchedules: [],
|
||||||
|
scheduleMap: {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.loadMonth(this.monthPicker);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async load() {
|
handleMonthChange() {
|
||||||
if (!this.date) return;
|
if (!this.monthPicker) return;
|
||||||
|
const firstDay = new Date(this.monthPicker.getFullYear(), this.monthPicker.getMonth(), 1);
|
||||||
|
this.calendarDate = firstDay;
|
||||||
|
this.loadMonth(this.monthPicker);
|
||||||
|
},
|
||||||
|
handleDateChange(date) {
|
||||||
|
this.selectedDate = formatDate(date);
|
||||||
|
this.daySchedules = this.getDaySchedules(this.selectedDate);
|
||||||
|
},
|
||||||
|
getDaySchedules(dayStr) {
|
||||||
|
return this.scheduleMap[dayStr] || [];
|
||||||
|
},
|
||||||
|
async loadMonth(date) {
|
||||||
|
const year = date.getFullYear();
|
||||||
|
const month = date.getMonth();
|
||||||
|
const start = new Date(year, month, 1);
|
||||||
|
const end = new Date(year, month + 1, 0);
|
||||||
try {
|
try {
|
||||||
const res = await nurseSchedules(formatDate(this.date));
|
const res = await nurseSchedulesRange(formatDate(start), formatDate(end));
|
||||||
this.items = res.data.data;
|
const map = {};
|
||||||
|
res.data.data.forEach((item) => {
|
||||||
|
if (!map[item.date]) {
|
||||||
|
map[item.date] = [];
|
||||||
|
}
|
||||||
|
map[item.date].push(item);
|
||||||
|
});
|
||||||
|
this.scheduleMap = map;
|
||||||
|
this.daySchedules = this.getDaySchedules(this.selectedDate);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$message.error(e.message || "load failed");
|
this.$message.error(e.message || "加载失败");
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
jumpToday() {
|
||||||
|
const today = new Date();
|
||||||
|
this.monthPicker = today;
|
||||||
|
this.calendarDate = today;
|
||||||
|
this.selectedDate = formatDate(today);
|
||||||
|
this.loadMonth(today);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.schedule-toolbar {
|
||||||
|
margin: 12px 0 16px;
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.schedule-panel {
|
||||||
|
background: #f6fbf7;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
border: 1px solid #d9efe3;
|
||||||
|
}
|
||||||
|
.schedule-title {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.calendar-cell {
|
||||||
|
min-height: 58px;
|
||||||
|
}
|
||||||
|
.cell-date {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #6b7b6f;
|
||||||
|
}
|
||||||
|
.cell-badges {
|
||||||
|
margin-top: 4px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
.badge {
|
||||||
|
background: #e1f3ea;
|
||||||
|
color: #2f7d59;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
.more {
|
||||||
|
color: #7b8b7f;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user