123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- <template>
- <div class="mod-demo__schedule">
- <div class="form-container">
- <el-form :inline="true" :model="state.dataForm" @keyup.enter="state.getDataList()">
- <el-form-item>
- <el-select v-model="state.dataForm.status" placeholder="排班确认状态" clearable>
- <el-option :label="item.dictLabel" :value="item.dictValue" v-for="item in state.getDictByKey('scheduleStatus')"></el-option>
- </el-select>
- </el-form-item>
- <el-form-item>
- <el-button @click="state.getDataList()">查询</el-button>
- </el-form-item>
- <el-form-item>
- <el-button v-if="state.hasPermission('emergency:schedule:save')" type="primary" @click="addHandle()">新增</el-button>
- </el-form-item>
- <el-form-item>
- <el-button v-if="state.hasPermission('emergency:schedule:delete')" type="danger" @click="customDeleteHandle()">删除</el-button>
- </el-form-item>
- <el-form-item>
- <el-button v-if="state.hasPermission('emergency:schedule:review')" type="danger" @click="reviewHandle()">审阅</el-button>
- </el-form-item>
- <el-form-item>
- <el-button v-if="state.hasPermission('emergency:inspection:export')" type="info" @click="state.exportHandle()">导出</el-button>
- </el-form-item>
- </el-form>
- </div>
- <!-- <el-calendar v-model="calendarValue" /> -->
- <el-calendar v-model="calendarValue">
- <template #date-cell="{ data }">
- <div class="calendar-cell" @dblclick="handleDayDblClick(data.day)">
- <div class="checkbox-status">
- <el-checkbox
- :label="formatMonthDay(data.day)"
- :checked="selectedDates.includes(data.day)"
- @change="(val) => handleDateToggle(data.day, val)"
- @click.stop
- />
- <el-tag
- v-if="getScheduleStatus(data.day) !== null"
- :type="getScheduleStatus(data.day) === 0 ? 'warning' : 'success'"
- size="small"
- class="status-tag"
- >
- {{ getScheduleStatus(data.day) === 0 ? '待确认' : '已确认' }}
- </el-tag>
- </div>
- <div class="employee-names">
- <div
- v-for="(name, index) in getScheduleNames(data.day)"
- :key="index"
- class="employee-name"
- @dblclick.stop
- >
- {{ name }}
- </div>
- </div>
- </div>
- </template>
- </el-calendar>
- <el-pagination :current-page="state.page" :page-sizes="[10, 20, 50, 100]" :page-size="state.limit" :total="state.total" layout="total, sizes, prev, pager, next, jumper" @size-change="state.pageSizeChangeHandle" @current-change="state.pageCurrentChangeHandle"> </el-pagination>
- <!-- 弹窗, 新增 / 修改 -->
- <add-or-update ref="addOrUpdateRef" @refreshDataList="refreshAfterAdd">确定</add-or-update>
- </div>
- </template>
- <script lang="ts" setup>
- import useView from "@/hooks/useView";
- import { reactive, ref, toRefs } from "vue";
- import baseService from "@/service/baseService";
- import { ElMessage, ElMessageBox } from "element-plus";
- import { IObject } from "@/types/interface";
- import AddOrUpdate from "./schedule-add-or-update.vue";
- const view = reactive({
- deleteIsBatch: true,
- getDataListURL: "/emergency/schedule/page",
- getDataListIsPage: true,
- exportURL: "/emergency/schedule/export",
- deleteURL: "/emergency/schedule",
- });
- const state = reactive({ ...useView(view), ...toRefs(view) });
- //日历
- const calendarValue = ref(new Date())
- const selectedDates = ref<string[]>([]);
- const formatMonthDay = (fullDate: string): string => {
- const parts = fullDate.split("-");
- return `${parts[1]}-${parts[2]}`;
- };
- const getScheduleByDate = (date: string) => {
- return state.dataList?.find(item => item.scheduleDate === date) || null;
- };
- const getScheduleStatus = (date: string): number | null => {
- const item = getScheduleByDate(date);
- return item?.status ?? null;
- };
- const getScheduleNames = (date: string): string[] => {
- const item = getScheduleByDate(date);
- return item?.employeeNames || [];
- };
- const addHandle = () => {
- if (!selectedDates.value || selectedDates.value.length === 0) {
- ElMessage({
- message: '请选择操作项',
- type: 'warning',
- duration: 500,
- });
- return;
- }
- const existingDates = selectedDates.value.filter(date =>
- state.dataList?.some(item => item.scheduleDate === date)
- );
- if (existingDates.length > 0) {
- ElMessageBox.confirm(
- `以下日期已有排班数据:\n${existingDates.join('、')}\n,是否继续新增?`,
- '提示',
- {
- confirmButtonText: '继续',
- cancelButtonText: '取消',
- type: 'warning',
- }
- )
- .then(() => {
- addOrUpdateHandle(undefined, undefined, selectedDates.value);
- })
- .catch(() => {
- // 用户取消,无需处理
- });
- } else {
- // 无冲突,直接新增
- addOrUpdateHandle(undefined, undefined, selectedDates.value);
- }
- };
- const refreshAfterAdd = async () => {
- selectedDates.value = [];
- state.getDataList();
- };
- const addOrUpdateRef = ref();
- const addOrUpdateHandle = (id?: number, date?: string, dates?: string[]) => {
- addOrUpdateRef.value.init(id, date, dates);
- };
- const handleDayDblClick = (day: string) => {
- const schedule = state.dataList?.find(item => item.scheduleDate === day);
- if (schedule && schedule.id) {
- // 已有排班记录,修改
- addOrUpdateHandle(schedule.id);
- } else {
- // 不存在,调用“新增”
- addOrUpdateHandle(undefined, day);
- }
- };
- const handleDateToggle = (day: string, checked: boolean) => {
- const index = selectedDates.value.indexOf(day);
- if (checked && index === -1) {
- selectedDates.value.push(day);
- } else if (!checked && index !== -1) {
- selectedDates.value.splice(index, 1);
- }
- };
- //删除
- const customDeleteHandle = () => {
- if (selectedDates.value.length === 0) {
- return ElMessage.warning("请先选择要删除的日期");
- }
- const idsToDelete = selectedDates.value
- .map(date => {
- const match = state.dataList.find(item => item.scheduleDate === date);
- return match?.id;
- })
- .filter(Boolean) as string[];
- if (idsToDelete.length === 0) {
- return ElMessage.warning("选中日期中暂无排班数据");
- }
- ElMessageBox.confirm(`确认要删除选中的 ${idsToDelete.length} 条排班记录吗?`, "提示", {
- confirmButtonText: "删除",
- cancelButtonText: "取消",
- type: "warning"
- }).then(() => {
- baseService.delete(state.deleteURL, idsToDelete);
- ElMessage.success({
- message: "删除成功",
- duration: 500,
- onClose: () => {
- state.getDataList();
- selectedDates.value = [];
- }
- });
- }).catch(() => {
- // 取消删除
- });
- };
- // 审阅
- const reviewHandle = (id?: string) => {
- if (selectedDates.value.length === 0) {
- return ElMessage({
- message: "请选择操作项",
- type: "warning",
- duration: 500
- });
- }
- const reviewData = selectedDates.value
- .map(date => {
- const item = state.dataList.find((i: any) => i.scheduleDate === date);
- return item?.id;
- })
- .filter(Boolean);
- if (reviewData.length === 0) {
- return ElMessage.warning("选中日期中暂无排班数据");
- }
- ElMessageBox.confirm("确定进行[审阅]操作?", "提示", {
- confirmButtonText: "确定",
- cancelButtonText: "取消",
- type: "warning"
- })
- .then(() => {
- baseService.put("/emergency/schedule/review", reviewData).then((res) => {
- ElMessage.success({
- message: "审阅成功",
- duration: 500,
- onClose: () => {
- state.getDataList();
- state.dataListSelections = [];
- }
- });
- });
- })
- .catch(() => {
- //
- });
- };
- </script>
- <style>
- .calendar-cell {
- width: 100%;
- height: 100%;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: flex-start;
- padding-top: 6px;
- box-sizing: border-box;
- padding: 4px;
- cursor: pointer;
- }
- .employee-name {
- user-select: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- }
- .checkbox-status {
- display: flex;
- align-items: center;
- gap: 4px;
- margin-bottom: 2px;
- }
- .status-tag {
- font-size: 10px;
- padding: 0 4px;
- height: 20px;
- user-select: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- }
- ::v-deep(.el-calendar-day) {
- display: flex !important;
- flex-direction: column;
- align-items: flex-start;
- justify-content: flex-start;
- padding: 4px;
- box-sizing: border-box;
- }
- </style>
|