Files
violin-home/src/view/calendar/index.vue
T
2026-06-30 07:56:09 +08:00

246 lines
7.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<el-calendar v-model="value" v-if="isComponentActive" v-loading="isComponentLoading"
element-loading-text="主人别着急我在努力加载中^_^">
<template #date-cell="{ data }">
<div class="date-cell-holiday"
v-if="Object.keys(holidays).includes(data.day)"
@click="onclick(data.date)"
style="cursor: pointer;">
<span style="color: red;">{{ data.day.split('-')[2] }}</span><br>
<span>{{ holidays[data.day] }}</span>
</div>
<div class="date-cell" v-else @click="onclick(data.date)" style="cursor: pointer;">
<span style="color: red;" v-if="data.date.getDay() == 0 || data.date.getDay() == 6">
{{ data.day.split('-')[2] }}
</span>
<span v-else> {{ data.day.split('-')[2] }}</span>
</div>
<div class="date-cell-event" v-if="Object.keys(eventDataObject).includes(data.day)">
<span>{{ eventDataObject[data.day] }}</span>
</div>
</template>
</el-calendar>
<div class="toolbar">
<span class="toolbar-label">待办事项</span>
<el-select v-model="pageSize" size="small" style="width: 110px">
<el-option label="10 条/页" :value="10" />
<el-option label="20 条/页" :value="20" />
<el-option label="50 条/页" :value="50" />
<el-option label="100 条/页" :value="100" />
</el-select>
</div>
<el-table :data="eventDataList" v-loading="isComponentLoading">
<el-table-column property="eventDate" label="Date" width="150" />
<el-table-column property="title" label="title" width="200" />
<el-table-column property="eventInfo" label="eventInfo" />
<el-table-column label="操作" width="120">
<template #default="{ row }">
<el-button size="small" type="danger" @click="onDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
class="pagination"
background
layout="prev, pager, next, total"
:total="pagination.total"
:page-size="pageSize"
:current-page="pagination.page"
@current-change="onPageChange"
/>
<el-dialog v-model="dialogFormVisible" title="待办事项">
<el-form :model="form">
<el-form-item label="日期" :label-width="formLabelWidth">
<span>{{ form.eventDate }}</span>
</el-form-item>
<el-form-item label="title" :label-width="formLabelWidth">
<el-input v-model="form.title" autocomplete="off" />
</el-form-item>
<el-form-item label="eventInfo" :label-width="formLabelWidth">
<el-input v-model="form.eventInfo" autocomplete="off" type="textarea" />
</el-form-item>
<el-form-item label="alert" :label-width="formLabelWidth">
<el-checkbox-group v-model="checkedalerts" :min="0" :max="2">
<el-checkbox v-for="city in alerts" :key="city" :value="city">{{
city
}}</el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogFormVisible = false">Cancel</el-button>
<el-button type="primary" @click="confirm">
Confirm
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { get_holiday } from '@/service/calendar'
import { toLocalDate } from '@/utils/date'
import { get_event, post_event, delete_event } from '@/api/calendar'
import { Event } from '@/entity/index'
import { settingsStore } from '@/store/modules/settings'
// -- IMPORT --
const useSettingsStore = settingsStore()
// -- REACTIVE OBJECT --
const holidays = reactive<Record<string, string>>({})
const eventDataList = reactive<Event[]>([])
const eventDataObject = reactive<Record<string, string>>({})
const form = reactive({
// 与后端 CalendarEventRequest 对齐(camelCase
eventDate: '',
title: '',
eventInfo: '',
})
// -- REF OBJECT --
const value = ref(new Date())
const dialogFormVisible = ref(false)
const formLabelWidth = '140px'
const isComponentActive = ref(false)
const isComponentLoading = ref(true)
const checkedalerts = ref([])
const alerts = ['email', 'messageBox', '手机短信', '微信通知']
// 分页
const pageSize = ref(10)
const pagination = reactive({ page: 1, total: 0 })
// 当前选中的月份(yyyy-MM
const monthStr = computed(() => {
const d = value.value
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`
})
// -- EVENT DEFINITION
const onclick = (date: Date) => {
form.eventDate = toLocalDate(date)
dialogFormVisible.value = true
}
const confirm = async () => {
await post_event({
eventDate: form.eventDate,
title: form.title,
eventInfo: form.eventInfo,
})
dialogFormVisible.value = false
handleCommand('refresh')
}
const handleCommand = (command: string) => {
if (command === 'refresh') {
useSettingsStore.settings.isLoading = true
useSettingsStore.settings.isRouterAlive = false
nextTick(() => {
useSettingsStore.settings.isRouterAlive = true
useSettingsStore.settings.isLoading = false
})
}
}
const onPageChange = (p: number) => {
pagination.page = p
reloadEvents()
}
const reloadEvents = async () => {
isComponentLoading.value = true
try {
const res = await get_event({
month: monthStr.value,
page: pagination.page,
pageSize: pageSize.value
})
// 后端 ApiResponse 结构:{code, message, data: {items, total, page, pageSize}}
const pageResp = res.data?.data ?? res.data
const items = Array.isArray(pageResp) ? pageResp : (pageResp?.items ?? [])
pagination.total = pageResp?.total ?? items.length
pagination.page = pageResp?.page ?? pagination.page
eventDataList.length = 0
eventDataObject.value = {}
items.forEach((record: Event) => {
eventDataList.push(record)
eventDataObject[record.eventDate] = record.title
})
} catch {
// 错误已由 axios 拦截器处理
} finally {
isComponentLoading.value = false
}
}
const onDelete = async (row: Event) => {
if (!row.id) return
try {
await ElMessageBox.confirm(`确认删除 "${row.title}"`, '提示', { type: 'warning' })
} catch {
return // 用户取消
}
await delete_event(row.id)
ElMessage.success('删除成功')
reloadEvents()
}
// 切换月份 / 改变 pageSize → 重新加载
watch([monthStr, pageSize], () => {
pagination.page = 1
reloadEvents()
}, { deep: true })
/**
* AUTO INVOKE FUNCTION
*/
onMounted(async () => {
isComponentActive.value = true
await get_holiday().then((resp) => {
Object.keys(resp.data).forEach(element => {
holidays[element] = resp.data[element]
})
}).catch(() => { /* 节假日失败不影响 */ })
await reloadEvents()
})
</script>
<style lang="scss" scoped>
.date-cell-holiday {
background: #dfd;
}
.date-cell-event {
background: yellow;
}
.toolbar {
display: flex;
justify-content: space-between;
align-items: center;
margin: 16px 0 8px;
}
.toolbar-label {
font-size: 16px;
font-weight: 500;
}
.pagination {
margin: 16px 0;
justify-content: flex-end;
}
</style>