feat(mes): 优化排班日历查询逻辑,支持批量班组查询

重构排班日历查询功能,简化代码实现,支持一次性查询多个班组的排班记录。
新增班组编号集合字段,提升查询效率和可读性。
pull/871/MERGE
YunaiV 2026-04-02 19:54:18 +08:00
parent f8553abcdd
commit 1b3a41da14
5 changed files with 139 additions and 189 deletions

View File

@ -33,26 +33,16 @@
</template>
<script setup lang="ts">
import { CalCalendarApi, CalCalendarDayVO } from '@/api/mes/cal/calendar'
import { CalTeamApi, CalTeamVO } from '@/api/mes/cal/team'
import { CalHolidayApi, CalHolidayVO } from '@/api/mes/cal/holiday'
import { formatDate } from '@/utils/formatTime'
import { HolidayType } from '@/views/mes/utils/constants'
import CalendarDateCell from './CalendarDateCell.vue'
import CalendarLegend from './CalendarLegend.vue'
import dayjs from 'dayjs'
import 'dayjs/locale/zh-cn'
import PluginLunar from 'dayjs-plugin-lunar'
import { useCalendar } from './useCalendar'
dayjs.locale('zh-cn')
dayjs.extend(PluginLunar)
const { loading, currentDate, calendarDayMap, holidaySet, loadHolidays, fetchCalendar, watchMonth } =
useCalendar()
const loading = ref(false)
const currentDate = ref(new Date()) //
const selectedTeamId = ref<number>() //
const teamList = ref<CalTeamVO[]>([]) //
const calendarDayMap = ref<Map<string, CalCalendarDayVO>>(new Map()) // key: yyyy-MM-dd
const holidaySet = ref(new Set<string>()) // key: yyyy-MM-dd
/** 获取班组列表,并默认选中第一个 */
const getTeamList = async () => {
@ -62,71 +52,28 @@ const getTeamList = async () => {
}
}
/** 获取节假日列表,构建节假日日期集合 */
const getHolidayList = async () => {
holidaySet.value.clear()
const list = await CalHolidayApi.getHolidayList()
if (!list) {
return
}
list.forEach((item: CalHolidayVO) => {
const day = item.day ? formatDate(item.day as any, 'YYYY-MM-DD') : ''
if (day && item.type === HolidayType.HOLIDAY) {
holidaySet.value.add(day)
}
})
}
/** 查询当前月份的排班日历,按选中班组过滤 */
const fetchCalendar = async () => {
const doFetch = () => {
if (!selectedTeamId.value) return
loading.value = true
try {
//
const date = currentDate.value
const year = date.getFullYear()
const month = date.getMonth()
const startDay = new Date(year, month, 1)
const endDay = new Date(year, month + 1, 0, 23, 59, 59)
const list = await CalCalendarApi.getCalendarList({
queryType: 'TEAM',
teamId: selectedTeamId.value,
startDay: formatDate(startDay, 'YYYY-MM-DD HH:mm:ss'),
endDay: formatDate(endDay, 'YYYY-MM-DD HH:mm:ss')
})
// Map 便
calendarDayMap.value.clear()
if (!list) {
return
}
list.forEach((item: CalCalendarDayVO) => {
// day long yyyy-MM-dd Map key
const day = item.day ? formatDate(item.day as any, 'YYYY-MM-DD') : ''
if (day) {
calendarDayMap.value.set(day, { ...item, day })
}
})
} finally {
loading.value = false
}
fetchCalendar({ queryType: 'TEAM', teamId: selectedTeamId.value })
}
/** 点击左侧班组后切换并刷新日历 */
const onSelectTeam = (id: number) => {
selectedTeamId.value = id
fetchCalendar()
doFetch()
}
/** 监听月份切换,重新加载当月排班 */
watch(currentDate, () => {
watchMonth(() => {
if (selectedTeamId.value) {
fetchCalendar()
doFetch()
}
})
/** 初始化 */
onMounted(() => {
getTeamList()
getHolidayList()
loadHolidays()
})
</script>

View File

@ -33,91 +33,38 @@
</template>
<script setup lang="ts">
import { CalCalendarApi, CalCalendarDayVO } from '@/api/mes/cal/calendar'
import { CalHolidayApi, CalHolidayVO } from '@/api/mes/cal/holiday'
import { formatDate } from '@/utils/formatTime'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { HolidayType } from '@/views/mes/utils/constants'
import CalendarDateCell from './CalendarDateCell.vue'
import CalendarLegend from './CalendarLegend.vue'
import dayjs from 'dayjs'
import 'dayjs/locale/zh-cn'
import PluginLunar from 'dayjs-plugin-lunar'
import { useCalendar } from './useCalendar'
dayjs.locale('zh-cn')
dayjs.extend(PluginLunar)
const { loading, currentDate, calendarDayMap, holidaySet, loadHolidays, fetchCalendar, watchMonth } =
useCalendar()
const loading = ref(false)
const currentDate = ref(new Date()) //
const selectedType = ref<number>() // MES_CAL_CALENDAR_TYPE
const calendarDayMap = ref<Map<string, CalCalendarDayVO>>(new Map()) // key: yyyy-MM-dd
const holidaySet = ref(new Set<string>()) // key: yyyy-MM-dd
/** 获取节假日列表,构建节假日日期集合 */
const getHolidayList = async () => {
holidaySet.value.clear()
const list = await CalHolidayApi.getHolidayList()
if (!list) {
return
}
list.forEach((item: CalHolidayVO) => {
const day = item.day ? formatDate(item.day as any, 'YYYY-MM-DD') : ''
if (day && item.type === HolidayType.HOLIDAY) {
holidaySet.value.add(day)
}
})
}
/** 查询当前月份的排班日历,按选中分类过滤 */
const fetchCalendar = async () => {
const doFetch = () => {
if (!selectedType.value) return
loading.value = true
try {
//
const date = currentDate.value
const year = date.getFullYear()
const month = date.getMonth()
const startDay = new Date(year, month, 1)
const endDay = new Date(year, month + 1, 0, 23, 59, 59)
const list = await CalCalendarApi.getCalendarList({
queryType: 'TYPE',
calendarType: selectedType.value,
startDay: formatDate(startDay, 'YYYY-MM-DD HH:mm:ss'),
endDay: formatDate(endDay, 'YYYY-MM-DD HH:mm:ss')
})
// Map 便
calendarDayMap.value.clear()
if (!list) {
return
}
list.forEach((item: CalCalendarDayVO) => {
// day long yyyy-MM-dd Map key
const day = item.day ? formatDate(item.day as any, 'YYYY-MM-DD') : ''
if (day) {
calendarDayMap.value.set(day, { ...item, day })
}
})
} finally {
loading.value = false
}
fetchCalendar({ queryType: 'TYPE', calendarType: selectedType.value })
}
/** 点击左侧分类后切换并刷新日历 */
const onSelectType = (value: number) => {
selectedType.value = value
fetchCalendar()
doFetch()
}
/** 监听月份切换,重新加载当月排班 */
watch(currentDate, () => {
watchMonth(() => {
if (selectedType.value) {
fetchCalendar()
doFetch()
}
})
/** 初始化:加载节假日,并默认选中第一个分类 */
onMounted(() => {
getHolidayList()
loadHolidays()
const opts = getIntDictOptions(DICT_TYPE.MES_CAL_CALENDAR_TYPE)
if (opts.length > 0) {
onSelectType(opts[0].value as number)

View File

@ -7,7 +7,10 @@
<el-select
v-model="userId"
filterable
placeholder="请选择人员"
remote
:remote-method="remoteSearchUser"
:loading="userSearchLoading"
placeholder="请输入人员姓名搜索"
class="!w-200px"
@change="onUserQuery"
>
@ -41,91 +44,54 @@
</template>
<script setup lang="ts">
import { CalCalendarApi, CalCalendarDayVO } from '@/api/mes/cal/calendar'
import { CalHolidayApi, CalHolidayVO } from '@/api/mes/cal/holiday'
import { getSimpleUserList, UserVO } from '@/api/system/user'
import { formatDate } from '@/utils/formatTime'
import { HolidayType } from '@/views/mes/utils/constants'
import CalendarDateCell from './CalendarDateCell.vue'
import CalendarLegend from './CalendarLegend.vue'
import dayjs from 'dayjs'
import 'dayjs/locale/zh-cn'
import PluginLunar from 'dayjs-plugin-lunar'
import { useCalendar } from './useCalendar'
dayjs.locale('zh-cn')
dayjs.extend(PluginLunar)
const { loading, currentDate, calendarDayMap, holidaySet, loadHolidays, fetchCalendar, watchMonth } =
useCalendar()
const loading = ref(false)
const currentDate = ref(new Date()) //
const userId = ref<number>() //
const userList = ref<UserVO[]>([]) //
const calendarDayMap = ref<Map<string, CalCalendarDayVO>>(new Map()) // key: yyyy-MM-dd
const holidaySet = ref(new Set<string>()) // key: yyyy-MM-dd
const userList = ref<UserVO[]>([]) //
const userSearchLoading = ref(false) //
let allUserList: UserVO[] = [] //
/** 获取节假日列表,构建节假日日期集合 */
const getHolidayList = async () => {
holidaySet.value.clear()
const list = await CalHolidayApi.getHolidayList()
if (!list) {
return
/** 远程搜索用户 */
const remoteSearchUser = (query: string) => {
if (query) {
userSearchLoading.value = true
//
userList.value = allUserList.filter((user) =>
user.nickname?.toLowerCase().includes(query.toLowerCase())
)
userSearchLoading.value = false
} else {
userList.value = []
}
list.forEach((item: CalHolidayVO) => {
const day = item.day ? formatDate(item.day as any, 'YYYY-MM-DD') : ''
if (day && item.type === HolidayType.HOLIDAY) {
holidaySet.value.add(day)
}
})
}
/** 查询当前月份的排班日历,按选中人员过滤 */
const fetchCalendar = async () => {
const doFetch = () => {
if (!userId.value) return
loading.value = true
try {
//
const date = currentDate.value
const year = date.getFullYear()
const month = date.getMonth()
const startDay = new Date(year, month, 1)
const endDay = new Date(year, month + 1, 0, 23, 59, 59)
const list = await CalCalendarApi.getCalendarList({
queryType: 'USER',
userId: userId.value,
startDay: formatDate(startDay, 'YYYY-MM-DD HH:mm:ss'),
endDay: formatDate(endDay, 'YYYY-MM-DD HH:mm:ss')
})
// Map 便
calendarDayMap.value.clear()
if (!list) {
return
}
list.forEach((item: CalCalendarDayVO) => {
// day long yyyy-MM-dd Map key
const day = item.day ? formatDate(item.day as any, 'YYYY-MM-DD') : ''
if (day) {
calendarDayMap.value.set(day, { ...item, day })
}
})
} finally {
loading.value = false
}
fetchCalendar({ queryType: 'USER', userId: userId.value })
}
/** 查询按钮 / 下拉选人后刷新日历 */
const onUserQuery = () => {
fetchCalendar()
doFetch()
}
/** 监听月份切换,重新加载当月排班 */
watch(currentDate, () => {
watchMonth(() => {
if (userId.value) {
fetchCalendar()
doFetch()
}
})
/** 初始化 */
onMounted(async () => {
userList.value = await getSimpleUserList()
await getHolidayList()
allUserList = await getSimpleUserList()
await loadHolidays()
})
</script>

View File

@ -0,0 +1,90 @@
import { ref, watch } from 'vue'
import { CalCalendarApi, CalCalendarDayVO } from '@/api/mes/cal/calendar'
import { CalHolidayApi, CalHolidayVO } from '@/api/mes/cal/holiday'
import { formatDate } from '@/utils/formatTime'
import { HolidayType } from '@/views/mes/utils/constants'
/**
* composable
*
*
*/
export function useCalendar() {
const loading = ref(false)
const currentDate = ref(new Date())
const calendarDayMap = ref<Map<string, CalCalendarDayVO>>(new Map())
const holidaySet = ref(new Set<string>())
/** 获取节假日列表,按当前月份范围加载 */
const loadHolidays = async () => {
holidaySet.value.clear()
const { startDay, endDay } = getMonthRange()
const list = await CalHolidayApi.getHolidayList({
startDay: formatDate(startDay, 'YYYY-MM-DD HH:mm:ss'),
endDay: formatDate(endDay, 'YYYY-MM-DD HH:mm:ss')
})
if (!list) {
return
}
list.forEach((item: CalHolidayVO) => {
const day = item.day ? formatDate(item.day as any, 'YYYY-MM-DD') : ''
if (day && item.type === HolidayType.HOLIDAY) {
holidaySet.value.add(day)
}
})
}
/** 查询排班日历params 由调用方提供 queryType 相关参数 */
const fetchCalendar = async (params: Record<string, any>) => {
loading.value = true
try {
const { startDay, endDay } = getMonthRange()
const list = await CalCalendarApi.getCalendarList({
...params,
startDay: formatDate(startDay, 'YYYY-MM-DD HH:mm:ss'),
endDay: formatDate(endDay, 'YYYY-MM-DD HH:mm:ss')
})
calendarDayMap.value.clear()
if (!list) {
return
}
list.forEach((item: CalCalendarDayVO) => {
const day = item.day ? formatDate(item.day as any, 'YYYY-MM-DD') : ''
if (day) {
calendarDayMap.value.set(day, { ...item, day })
}
})
} finally {
loading.value = false
}
}
/** 计算当前月份的起止时间 */
const getMonthRange = () => {
const date = currentDate.value
const year = date.getFullYear()
const month = date.getMonth()
return {
startDay: new Date(year, month, 1),
endDay: new Date(year, month + 1, 0, 23, 59, 59)
}
}
/** 监听月份切换,调用回调刷新数据 */
const watchMonth = (callback: () => void) => {
watch(currentDate, () => {
loadHolidays().then()
callback()
})
}
return {
loading,
currentDate,
calendarDayMap,
holidaySet,
loadHolidays,
fetchCalendar,
watchMonth
}
}

View File

@ -19,8 +19,9 @@
class="w-1/1"
/>
</el-form-item>
<el-form-item label="设备类型编码" prop="code">
<el-input v-model="formData.code" placeholder="请输入类型编码" />
<el-form-item label="设备类型编码" prop="code" v-if="formType === 'update'">
<!-- TODO @AI点击后生成不要这里自动生成 -->
<el-input v-model="formData.code" placeholder="系统自动生成" disabled />
</el-form-item>
<el-form-item label="设备类型名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入类型名称" />
@ -75,7 +76,6 @@ const formData = ref({
})
const formRules = reactive({
parentId: [{ required: true, message: '上级类型不能为空', trigger: 'blur' }],
code: [{ required: true, message: '类型编码不能为空', trigger: 'blur' }],
name: [{ required: true, message: '类型名称不能为空', trigger: 'blur' }],
sort: [{ required: true, message: '显示排序不能为空', trigger: 'blur' }],
status: [{ required: true, message: '状态不能为空', trigger: 'blur' }]