This commit is contained in:
2026-05-06 20:36:52 +08:00
parent 056eb4798d
commit 1d5f0b4bc0
6 changed files with 114 additions and 16 deletions
@@ -15,7 +15,7 @@
* 或者作为组件使用 v-model:
* <ConfirmDialog v-model="show" @confirm="..." @cancel="..." />
*/
import { ref, watch } from "vue";
import { ref, watch, onMounted, getCurrentInstance } from "vue";
import { useI18n } from "vue-i18n";
const props = defineProps({
@@ -47,7 +47,11 @@ const props = defineProps({
const emit = defineEmits(["update:modelValue", "confirm", "cancel"]);
const { t } = useI18n();
// 优先用组件内 i18n,Teleport 场景下可能为空,从全局补足
const instance = getCurrentInstance();
const { t: componentT } = useI18n();
const globalT = instance?.appContext?.config?.globalProperties?.$i18n?.t;
const t = (key, ...args) => componentT(key, ...args) || globalT?.(key, ...args) || key;
function close() {
emit("update:modelValue", false);
+3
View File
@@ -1,4 +1,6 @@
{
"delete": "Delete",
"cancel": "Cancel",
"common": {
"actions": "Actions",
"search": "Search",
@@ -625,6 +627,7 @@
"update_success": "Calendar updated successfully",
"delete_success": "Calendar deleted successfully",
"confirm_delete": "Are you sure you want to delete this calendar?",
"confirm_delete_message": "Are you sure you want to delete calendar '{name}'? This action cannot be undone.",
"loading": "Loading...",
"add_event": "Add Event",
"edit_event": "Edit Event",
+3
View File
@@ -1,4 +1,6 @@
{
"delete": "删除",
"cancel": "取消",
"common": {
"actions": "操作",
"search": "搜索",
@@ -625,6 +627,7 @@
"update_success": "更新成功",
"delete_success": "删除成功",
"confirm_delete": "确定要删除此日历吗?",
"confirm_delete_message": "确定要删除日历「{name}」吗?此操作不可撤销。",
"loading": "加载中...",
"add_event": "添加事件",
"edit_event": "编辑事件",
@@ -13,6 +13,7 @@ import { useUserStore } from "@/stores/user"
import { calendarApi } from "@/api/calendar"
import { useDateUtils } from "@/composables/useDateUtils"
import DatatimePickerForFullCalendar from "@/components/datatimePickerForFullCalendar.vue"
import ConfirmDialog from "@/components/ConfirmDialog.vue"
const route = useRoute()
const router = useRouter()
@@ -62,6 +63,8 @@ const pageData = ref({
lastEventsSnapshot: null,
})
const showDeleteModal = ref(false)
// 选中/取消选中事件
function unseleEvent(eventID) {
const target = calendarOptions.value.events.find(item => item.id === eventID)
@@ -187,19 +190,23 @@ async function saveEvent() {
}
async function deleteEvent() {
if (!confirm(t('calendar.confirm_delete_event'))) return
showDeleteModal.value = true
}
async function confirmDeleteEvent() {
try {
const result = await calendarApi.deleteEvent(eventData.value.id)
if (result.errCode === 0) {
toast.success(t('calendar.event_delete_success'))
toast.success(t("calendar.event_delete_success"))
closeEventModal()
getEvents()
} else {
toast.error(t('message.server_error'))
toast.error(t("message.server_error"))
}
} catch {
// 拦截器已处理
} finally {
showDeleteModal.value = false
}
}
@@ -319,12 +326,20 @@ const calendarOptions = ref({
},
headerToolbar: {
left: "prevYear,prev,today,next,nextYear",
center: "title",
right: "",
left: "backToList,prevYear,prev,today,next,nextYear",
center: "myTitle",
right: "title",
},
customButtons: {
backToList: {
text: t("calendar.calendars"),
click() { router.push("/calendars") },
},
myTitle: {
text: calendarInfo.value?.Name || "",
disabled: true,
},
prevYear: {
text: t("schedule.previous_year"),
click() { calendarRef.value.getApi().prevYear(); getEvents() },
@@ -439,9 +454,15 @@ const calendarOptions = ref({
},
})
// 监听日历信息变化
watch(calendarInfo, () => {
calendarOptions.value.customButtons.myTitle.text = calendarInfo.value?.Name || ""
})
// 监听语言变化
watch(locale, () => {
calendarOptions.value.locale = locale.value
calendarOptions.value.customButtons.backToList.text = t("calendar.calendars")
calendarOptions.value.customButtons.prevYear.text = t("schedule.previous_year")
calendarOptions.value.customButtons.nextYear.text = t("schedule.next_year")
calendarOptions.value.customButtons.prev.text = t("schedule.previous_month")
@@ -674,9 +695,35 @@ onMounted(() => {
</div>
</div>
</div>
<!-- Delete Confirm Dialog -->
<ConfirmDialog
v-model="showDeleteModal"
:title="t('calendar.delete_event')"
:message="t('calendar.confirm_delete_event')"
:confirm-text="t('delete')"
:cancel-text="t('cancel')"
danger
@confirm="confirmDeleteEvent"
/>
</template>
<style scoped>
/* 日历名称按钮样式 */
:deep(.fc-myTitle-button) {
background: none !important;
border: none !important;
box-shadow: none !important;
cursor: default !important;
font-size: 1.1rem;
font-weight: 600;
color: #374151;
padding: 0 8px;
}
:deep(.fc-myTitle-button:disabled) {
opacity: 1 !important;
}
/* 父容器作为裁剪视口 */
:deep(.fc-daygrid-event .fc-event-title-container) {
overflow: hidden !important;
@@ -5,20 +5,21 @@ import { useI18n } from 'vue-i18n'
import { useToastStore } from '@/stores/toast'
import { usePageTitle } from '@/composables/usePageTitle'
import { calendarApi } from '@/api/calendar'
import { useUserStore } from '@/stores/user'
import { IconPlus, IconCalendar, IconTrash, IconEdit } from '@tabler/icons-vue'
import ConfirmDialog from '@/components/ConfirmDialog.vue'
usePageTitle('appname.calendar')
const { t } = useI18n()
const router = useRouter()
const toast = useToastStore()
const userStore = useUserStore()
const calendars = ref([])
const loading = ref(false)
const showCreateModal = ref(false)
const showEditModal = ref(false)
const showDeleteModal = ref(false)
const editingCalendar = ref(null)
const deletingCalendar = ref(null)
const form = ref({
name: '',
@@ -112,12 +113,14 @@ async function updateCalendar() {
}
async function deleteCalendar(calendar) {
if (!confirm(t('calendar.confirm_delete'))) {
return
}
deletingCalendar.value = calendar
showDeleteModal.value = true
}
async function confirmDelete() {
if (!deletingCalendar.value) return
try {
const { errCode } = await calendarApi.deleteCalendar(calendar.ID)
const { errCode } = await calendarApi.deleteCalendar(deletingCalendar.value.ID)
if (errCode === 0) {
toast.success(t('calendar.delete_success'))
fetchCalendars()
@@ -126,6 +129,9 @@ async function deleteCalendar(calendar) {
}
} catch {
// 拦截器已处理
} finally {
showDeleteModal.value = false
deletingCalendar.value = null
}
}
@@ -188,14 +194,14 @@ onMounted(fetchCalendars)
<div class="flex items-center gap-1" @click.stop>
<button
v-if="calendar.UserID === userStore.userInfo?.ID"
v-if="calendar.canEdit"
@click="openEditModal(calendar)"
class="rounded p-1 text-gray-400 transition-colors hover:bg-gray-100 hover:text-gray-600 dark:hover:bg-dk-muted"
>
<IconEdit :size="16" />
</button>
<button
v-if="calendar.UserID === userStore.userInfo?.ID"
v-if="calendar.canEdit"
@click="deleteCalendar(calendar)"
class="rounded p-1 text-gray-400 transition-colors hover:bg-red-50 hover:text-red-600 dark:hover:bg-dk-muted"
>
@@ -373,4 +379,15 @@ onMounted(fetchCalendars)
</div>
</div>
</div>
<!-- Delete Confirm Dialog -->
<ConfirmDialog
v-model="showDeleteModal"
:title="t('calendar.confirm_delete')"
:message="t('calendar.confirm_delete_message', { name: deletingCalendar?.Name || '' })"
:confirm-text="t('delete')"
:cancel-text="t('cancel')"
danger
@confirm="confirmDelete"
/>
</template>