Files
admin-web/src/modules/appointment-calendar/AppointmentCancellationDialog.vue
T
2026-10-20 14:52:06 +08:00

50 lines
3.0 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.
<script setup lang="ts">
import { inject, onBeforeUnmount, ref } from 'vue'
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
import { ElMessage } from 'element-plus'
import AppDialog from '@/shared/components/AppDialog.vue'
import LoadErrorState from '@/shared/components/LoadErrorState.vue'
import { getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http'
import { useAccessPreviewStore } from '@/core/access/accessPreview'
import { deleteAppointment } from './api'
const props = defineProps<{ appointmentNo: string; version: number; selectedCount: number }>()
const emit = defineEmits<{ close: []; cancelled: [] }>()
const access = useAccessPreviewStore()
const reason = ref(''), saving = ref(false), error = ref<ApiErrorDetails | null>(null)
const pending = ref<{number: string; version: number; reason: string} | null>(null)
function canLeave() {
if (saving.value || pending.value) { ElMessage.warning('请先核实本次取消结果,再关闭或切换'); return false }
return true
}
function beforeClose(done: () => void) { if (canLeave()) done() }
function close() { if (canLeave()) emit('close') }
const register = inject<((guard: () => boolean) => () => void) | undefined>('appointment-register-leave-guard', undefined)
const unregister = register?.(canLeave)
onBeforeUnmount(() => unregister?.())
onBeforeRouteLeave(canLeave)
onBeforeRouteUpdate(canLeave)
async function save() {
if (!access.can('platform:appointment:delete') || saving.value) return
if (!pending.value && !reason.value.trim()) { ElMessage.warning('请填写实际取消原因'); return }
pending.value ||= {number: props.appointmentNo, version: props.version, reason: reason.value.trim()}
saving.value = true; error.value = null
try {
await deleteAppointment(pending.value.number, pending.value.version, pending.value.reason)
pending.value = null; emit('cancelled')
} catch (cause) {
error.value = getApiErrorDetails(cause, '取消结果待核实,请重试本次取消')
if (['400','403','404','409','A0400','A0403','A0404','A0409'].includes(error.value.code || '')) pending.value = null
} finally { saving.value = false }
}
</script>
<template>
<AppDialog :model-value="true" title="取消预约" width="min(600px, calc(100vw - 48px))" class="admin-density-dialog" confirm-type="danger" :confirm-text="pending ? '重试本次取消' : '确认取消预约'" :show-confirm="access.can('platform:appointment:delete')" :confirm-loading="saving" :before-close="beforeClose" @update:model-value="close" @confirm="save">
<p>{{ appointmentNo }} · {{ selectedCount }} 票货物</p>
<p>取消后释放货物占用,保留原备注、时间及取消历史;不会回退库存或取消车次。</p>
<LoadErrorState v-if="error" title="取消未完成" :message="error.message" :show-retry="false" />
<el-form label-position="top" :disabled="saving || !!pending">
<el-form-item label="取消原因" required><el-input v-model="reason" type="textarea" maxlength="1000" show-word-limit /></el-form-item>
</el-form>
</AppDialog>
</template>