|
@@ -0,0 +1,258 @@
|
|
|
+<script setup lang="tsx">
|
|
|
+import {
|
|
|
+ createByMonthApi,
|
|
|
+ getByMonth,
|
|
|
+ getCodes,
|
|
|
+ getSortAndName,
|
|
|
+ saveSort,
|
|
|
+ updateById,
|
|
|
+} from "@/api/settings/schedulingClassApi";
|
|
|
+import XcElOption from "@/components/xiao-chan/xc-el-option/XcElOption.vue";
|
|
|
+import Sortable from "sortablejs";
|
|
|
+import dayjs from "dayjs";
|
|
|
+import { stringNotBlank } from "@/utils/blank-utils";
|
|
|
+import ExportTrueExcel from "@/views/settings/scheduling-class/ExportTrueExcel.vue";
|
|
|
+import { useCompShallowRef } from "@/utils/useCompRef";
|
|
|
+import ExportFalseExcel from "@/views/settings/scheduling-class/ExportFalseExcel.vue";
|
|
|
+
|
|
|
+const store = reactive({
|
|
|
+ codes: [],
|
|
|
+ sortName: [],
|
|
|
+
|
|
|
+ currentCalendar: new Date(),
|
|
|
+ currentCodes: "",
|
|
|
+
|
|
|
+ months: {} as {
|
|
|
+ [key: string]: { id: string; code: string; schedulingDate: string }[];
|
|
|
+ },
|
|
|
+});
|
|
|
+
|
|
|
+const trueExcelRef = useCompShallowRef(ExportTrueExcel);
|
|
|
+const falseExcelRef = useCompShallowRef(ExportFalseExcel);
|
|
|
+
|
|
|
+const sortRef = ref<HTMLDivElement>();
|
|
|
+
|
|
|
+const currentData = computed(() => {
|
|
|
+ const month = dayjs(store.currentCalendar).format("YYYY-MM");
|
|
|
+ if (store.months[month]) {
|
|
|
+ const tmp = {};
|
|
|
+ store.months[month].forEach(i => {
|
|
|
+ tmp[i.schedulingDate] = i;
|
|
|
+ });
|
|
|
+ return tmp;
|
|
|
+ }
|
|
|
+ return {};
|
|
|
+});
|
|
|
+
|
|
|
+const handleSort = () => {
|
|
|
+ const tmp = store.sortName.map(i => {
|
|
|
+ return {
|
|
|
+ name: i.name,
|
|
|
+ code: i.code,
|
|
|
+ };
|
|
|
+ });
|
|
|
+ saveSort({ data: JSON.stringify(tmp) });
|
|
|
+};
|
|
|
+
|
|
|
+function handleSelectChange(value) {
|
|
|
+ const number = store.sortName.findIndex(i => i.code === value);
|
|
|
+ if (number === -1) {
|
|
|
+ store.sortName.push({
|
|
|
+ code: value,
|
|
|
+ name: store.codes.find(i => i.code === value).name,
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function createByMonth() {
|
|
|
+ const month = dayjs(store.currentCalendar).format("YYYY-MM");
|
|
|
+ createByMonthApi(month);
|
|
|
+}
|
|
|
+
|
|
|
+function handleGetByMonth() {
|
|
|
+ const month = dayjs(store.currentCalendar).format("YYYY-MM");
|
|
|
+ if (store.months[month]) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ getByMonth(month).then(res => {
|
|
|
+ store.months[month] = res;
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+function renderTemplate(data) {
|
|
|
+ const user = toRef<{
|
|
|
+ falseCode: string;
|
|
|
+ id: string;
|
|
|
+ }>(currentData.value[data.day]);
|
|
|
+ const tmpCode = ref(user.value?.changeClass ?? user.value?.code);
|
|
|
+ const tmpFalseCode = ref<string[]>(
|
|
|
+ stringNotBlank(user?.value?.falseCode)
|
|
|
+ ? user?.value?.falseCode?.split(",") || []
|
|
|
+ : []
|
|
|
+ );
|
|
|
+
|
|
|
+ const oldData = {};
|
|
|
+
|
|
|
+ return () => (
|
|
|
+ <div>
|
|
|
+ <div>{dayjs(data.day).format("MM-DD")}</div>
|
|
|
+ <div>
|
|
|
+ {user.value?.code ? (
|
|
|
+ <div>
|
|
|
+ <div>
|
|
|
+ 主要:
|
|
|
+ <el-select
|
|
|
+ style={{ width: "120px" }}
|
|
|
+ model-value={tmpCode.value}
|
|
|
+ onUpdate:model-value={value => {
|
|
|
+ tmpCode.value = value;
|
|
|
+ }}
|
|
|
+ onFocus={() => {
|
|
|
+ oldData["code"] = tmpCode.value;
|
|
|
+ }}
|
|
|
+ onBlur={() => {
|
|
|
+ if (tmpCode.value !== oldData["code"]) {
|
|
|
+ updateById({
|
|
|
+ id: user.value.id,
|
|
|
+ changeClass: tmpCode.value,
|
|
|
+ }).catch(() => {
|
|
|
+ tmpCode.value = oldData["code"];
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <XcElOption data={store.codes} />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ 次要:
|
|
|
+ <el-select
|
|
|
+ style={{ width: "120px" }}
|
|
|
+ model-value={tmpFalseCode.value}
|
|
|
+ onUpdate:model-value={value => {
|
|
|
+ tmpFalseCode.value = value;
|
|
|
+ if ((value as string[]).length === 0) {
|
|
|
+ updateById({
|
|
|
+ id: user.value.id,
|
|
|
+ falseCode: "",
|
|
|
+ }).catch(() => {
|
|
|
+ tmpFalseCode.value = oldData["falseCode"];
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ multiple
|
|
|
+ clearable
|
|
|
+ onFocus={() => {
|
|
|
+ oldData["falseCode"] = tmpFalseCode.value;
|
|
|
+ }}
|
|
|
+ onBlur={() => {
|
|
|
+ if (tmpFalseCode.value == oldData["falseCode"]) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ updateById({
|
|
|
+ id: user.value.id,
|
|
|
+ falseCode: tmpFalseCode.value.join(","),
|
|
|
+ }).catch(() => {
|
|
|
+ tmpFalseCode.value = oldData["falseCode"];
|
|
|
+ });
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <XcElOption data={store.codes} />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ ) : null}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+function exportExcel() {
|
|
|
+ const month = dayjs(store.currentCalendar).format("YYYY-MM");
|
|
|
+
|
|
|
+ getByMonth(month).then(res => {
|
|
|
+ store.months[month] = res;
|
|
|
+ trueExcelRef.value.exportExcel(`${month}信息中心值班表`, res);
|
|
|
+ falseExcelRef.value.exportExcel(month, res);
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(async () => {
|
|
|
+ getCodes().then(res => {
|
|
|
+ store.codes = res;
|
|
|
+ });
|
|
|
+ getSortAndName().then(res => {
|
|
|
+ store.sortName = res;
|
|
|
+ });
|
|
|
+
|
|
|
+ await nextTick();
|
|
|
+
|
|
|
+ Sortable.create(sortRef.value, {
|
|
|
+ handle: ".scheduling_class_sort-item",
|
|
|
+ onEnd({ newIndex, oldIndex }) {
|
|
|
+ const current = store.sortName.splice(oldIndex, 1)[0];
|
|
|
+ store.sortName.splice(newIndex, 0, current);
|
|
|
+ },
|
|
|
+ });
|
|
|
+
|
|
|
+ handleGetByMonth();
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div class="layout_container">
|
|
|
+ <ExportTrueExcel ref="trueExcelRef" />
|
|
|
+ <ExportFalseExcel ref="falseExcelRef" :dept-list="store.codes" />
|
|
|
+ <header>
|
|
|
+ <el-select
|
|
|
+ v-model="store.currentCodes"
|
|
|
+ style="width: 120px"
|
|
|
+ @change="handleSelectChange"
|
|
|
+ >
|
|
|
+ <xc-el-option :data="store.codes" />
|
|
|
+ </el-select>
|
|
|
+
|
|
|
+ <el-button @click="handleSort">保存排序</el-button>
|
|
|
+ <el-button @click="createByMonth"
|
|
|
+ >生成 {{ dayjs(store.currentCalendar).format("YYYY-MM") }}排班
|
|
|
+ </el-button>
|
|
|
+
|
|
|
+ <el-button @click="exportExcel">导出excel</el-button>
|
|
|
+ <div style="margin: 5px" ref="sortRef">
|
|
|
+ <el-tag
|
|
|
+ class="scheduling_class_sort-item"
|
|
|
+ v-for="(item, index) in store.sortName"
|
|
|
+ :key="item.code"
|
|
|
+ closable
|
|
|
+ style="margin: 0 2px"
|
|
|
+ @close="store.sortName.splice(index, 1)"
|
|
|
+ >
|
|
|
+ {{ item.name }}
|
|
|
+ </el-tag>
|
|
|
+ </div>
|
|
|
+ </header>
|
|
|
+ <div class="layout_main">
|
|
|
+ <el-calendar
|
|
|
+ v-model="store.currentCalendar"
|
|
|
+ class="scheduling_class_calendar"
|
|
|
+ >
|
|
|
+ <template #date-cell="{ data }">
|
|
|
+ <component :is="renderTemplate(data)" />
|
|
|
+ </template>
|
|
|
+ </el-calendar>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style lang="scss">
|
|
|
+.scheduling_class_calendar {
|
|
|
+ .el-calendar-day {
|
|
|
+ height: max-content !important;
|
|
|
+ min-height: 85px !important;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.scheduling_class_sort-item {
|
|
|
+ cursor: move;
|
|
|
+}
|
|
|
+</style>
|