| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- <template>
- <div class="admin-order-detail">
- <el-button text @click="router.back()">← 返回</el-button>
- <el-card v-if="order" class="detail-card">
- <h2>订单详情</h2>
- <el-descriptions :column="2" border>
- <el-descriptions-item label="订单编号">{{ order.id }}</el-descriptions-item>
- <el-descriptions-item label="状态">
- <el-tag :type="statusTag(order.status)">{{ statusLabel(order.status) }}</el-tag>
- </el-descriptions-item>
- <el-descriptions-item label="用户">{{ order.userId }}</el-descriptions-item>
- <el-descriptions-item label="服务类型">{{ order.type }}</el-descriptions-item>
- <el-descriptions-item label="总价">¥{{ order.totalPrice }}</el-descriptions-item>
- <el-descriptions-item label="定金">¥{{ order.deposit }} {{ order.depositPaid ? '(已支付)' : '(未支付)' }}</el-descriptions-item>
- <el-descriptions-item label="创建时间">{{ order.createdAt }}</el-descriptions-item>
- </el-descriptions>
- <div class="actions">
- <el-button v-if="order.status === 'PENDING'" type="primary" @click="openReview">审核</el-button>
- <el-button v-if="order.status === 'CANCEL_REQUESTED'" type="warning" @click="openCancelHandle">处理取消</el-button>
- </div>
- </el-card>
- <el-dialog v-model="reviewVisible" title="订单审核" width="400px">
- <el-form>
- <el-form-item label="审核结果">
- <el-radio-group v-model="reviewAction">
- <el-radio value="CONFIRMED">通过</el-radio>
- <el-radio value="CANCELLED">拒绝</el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="原因">
- <el-input v-model="reviewReason" type="textarea" :rows="3" />
- </el-form-item>
- </el-form>
- <template #footer>
- <el-button @click="reviewVisible = false">取消</el-button>
- <el-button type="primary" @click="submitReview">确认</el-button>
- </template>
- </el-dialog>
- <el-dialog v-model="cancelVisible" title="处理取消申请" width="400px">
- <p>取消原因:{{ order?.cancelReason }}</p>
- <el-form>
- <el-form-item label="处理结果">
- <el-radio-group v-model="cancelAction">
- <el-radio value="CANCELLED">同意取消</el-radio>
- <el-radio value="CONFIRMED">拒绝取消</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-form>
- <template #footer>
- <el-button @click="cancelVisible = false">取消</el-button>
- <el-button type="primary" @click="submitCancel">确认</el-button>
- </template>
- </el-dialog>
- </div>
- </template>
- <script setup lang="ts">
- import { ref, onMounted } from 'vue'
- import { useRoute, useRouter } from 'vue-router'
- import { ElMessage } from 'element-plus'
- import type { Appointment } from '@/type'
- import { getAppointmentController } from '@/api/appointment-controller'
- import { getAdminAppointmentController } from '@/api/admin-appointment-controller'
- import type { ReviewDto, HandleCancelDto } from '@/api/models'
- const route = useRoute()
- const router = useRouter()
- const order = ref<Appointment | null>(null)
- const loading = ref(false)
- const reviewVisible = ref(false)
- const reviewAction = ref('CONFIRMED')
- const reviewReason = ref('')
- const cancelVisible = ref(false)
- const cancelAction = ref('CANCELLED')
- const loadOrder = async () => {
- loading.value = true
- try {
- const api = getAppointmentController()
- const res = await api.getById2(Number(route.params.id))
- if (res.code === 200 && res.data) {
- const a = res.data
- order.value = {
- id: String(a.id ?? ''),
- userId: String(a.userId ?? ''),
- petId: String(a.petId ?? ''),
- packageId: String(a.packageId ?? ''),
- roomId: a.roomId ? String(a.roomId) : undefined,
- type: (a.type as Appointment['type']) ?? 'GROOMING',
- startDate: a.startDate,
- endDate: a.endDate,
- status: (a.status as Appointment['status']) ?? 'PENDING',
- deposit: a.deposit ?? 0,
- depositPaid: a.depositPaid ?? false,
- totalPrice: a.totalPrice ?? 0,
- cancelReason: a.cancelReason,
- rejectReason: a.rejectReason,
- createdAt: a.createdAt ?? ''
- }
- }
- } catch (err: any) {
- ElMessage.error(err.message || '加载失败')
- } finally {
- loading.value = false
- }
- }
- const openReview = () => {
- reviewAction.value = 'CONFIRMED'
- reviewReason.value = ''
- reviewVisible.value = true
- }
- const submitReview = async () => {
- if (!order.value) return
- try {
- const api = getAdminAppointmentController()
- const dto: ReviewDto = {
- action: reviewAction.value,
- rejectReason: reviewAction.value === 'CANCELLED' ? reviewReason.value : undefined
- }
- const res = await api.review(Number(order.value.id), dto)
- if (res.code === 200) {
- ElMessage.success('审核完成')
- reviewVisible.value = false
- await loadOrder()
- } else {
- ElMessage.error(res.message || '操作失败')
- }
- } catch (err: any) {
- ElMessage.error(err.message || '操作失败')
- }
- }
- const openCancelHandle = () => {
- cancelAction.value = 'CANCELLED'
- cancelVisible.value = true
- }
- const submitCancel = async () => {
- if (!order.value) return
- try {
- const api = getAdminAppointmentController()
- const dto: HandleCancelDto = { action: cancelAction.value }
- const res = await api.handleCancel(Number(order.value.id), dto)
- if (res.code === 200) {
- ElMessage.success('处理完成')
- cancelVisible.value = false
- await loadOrder()
- } else {
- ElMessage.error(res.message || '操作失败')
- }
- } catch (err: any) {
- ElMessage.error(err.message || '操作失败')
- }
- }
- const statusLabel = (status: string) => {
- const map: Record<string, string> = {
- PENDING: '待审核', CONFIRMED: '已确认', CANCELLED: '已取消',
- COMPLETED: '已完成', CANCEL_REQUESTED: '取消申请'
- }
- return map[status] || status
- }
- const statusTag = (status: string) => {
- const map: Record<string, string> = {
- PENDING: 'warning', CONFIRMED: 'success', CANCELLED: 'info',
- COMPLETED: 'primary', CANCEL_REQUESTED: 'danger'
- }
- return map[status] || 'info'
- }
- onMounted(loadOrder)
- </script>
- <style scoped>
- .admin-order-detail {
- max-width: 800px;
- padding: 20px;
- }
- .detail-card {
- margin-top: 16px;
- }
- .actions {
- margin-top: 24px;
- display: flex;
- gap: 12px;
- }
- </style>
|