Forráskód Böngészése

fix:修复我的订单显示信息不全的问题

yangyi 4 hónapja
szülő
commit
d5e2569408

+ 3 - 0
src/type/index.ts

@@ -48,8 +48,11 @@ export interface Appointment {
     id: string
     userId: string
     petId: string
+    petName?: string
     packageId: string
+    packageName?: string
     roomId?: string
+    roomName?: string
     type: 'BOARDING' | 'GROOMING'
     startDate?: string
     endDate?: string

+ 37 - 7
src/view/admin/AdminOrderDetailView.vue

@@ -8,11 +8,17 @@
         <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="用户 ID">{{ order.userId }}</el-descriptions-item>
+        <el-descriptions-item label="宠物">{{ order.petName || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="服务类型">{{ typeLabel(order.type) }}</el-descriptions-item>
+        <el-descriptions-item label="服务套餐">{{ order.packageName || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="房间">{{ order.roomName || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="服务日期">{{ formatDate(order.startDate) }} ~ {{ formatDate(order.endDate) }}</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-item label="创建时间">{{ formatDate(order.createdAt) }}</el-descriptions-item>
+        <el-descriptions-item v-if="order.cancelReason" label="取消原因">{{ order.cancelReason }}</el-descriptions-item>
+        <el-descriptions-item v-if="order.rejectReason" label="拒绝原因">{{ order.rejectReason }}</el-descriptions-item>
       </el-descriptions>
 
       <div class="actions">
@@ -64,6 +70,8 @@ import { ElMessage } from 'element-plus'
 import type { Appointment } from '@/type'
 import { getAppointmentController } from '@/api/appointment-controller'
 import { getAdminAppointmentController } from '@/api/admin-appointment-controller'
+import { getPetController } from '@/api/pet-controller'
+import { getPackageController } from '@/api/package-controller'
 import type { ReviewDto, HandleCancelDto } from '@/api/models'
 
 const route = useRoute()
@@ -81,16 +89,29 @@ 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
+    const [orderRes, petRes, pkgRes] = await Promise.all([
+      getAppointmentController().getById2(Number(route.params.id)),
+      getPetController().list(),
+      getPackageController().list4()
+    ])
+
+    const petMap = new Map<number, string>()
+    petRes.data?.forEach(p => { if (p.id != null && p.name) petMap.set(p.id, p.name) })
+
+    const pkgMap = new Map<number, string>()
+    pkgRes.data?.forEach(p => { if (p.id != null && p.name) pkgMap.set(p.id, p.name) })
+
+    if (orderRes.code === 200 && orderRes.data) {
+      const a = orderRes.data
       order.value = {
         id: String(a.id ?? ''),
         userId: String(a.userId ?? ''),
         petId: String(a.petId ?? ''),
+        petName: a.petName || (a.petId != null ? petMap.get(a.petId) : undefined),
         packageId: String(a.packageId ?? ''),
+        packageName: a.packageName || (a.packageId != null ? pkgMap.get(a.packageId) : undefined),
         roomId: a.roomId ? String(a.roomId) : undefined,
+        roomName: a.roomName,
         type: (a.type as Appointment['type']) ?? 'GROOMING',
         startDate: a.startDate,
         endDate: a.endDate,
@@ -160,6 +181,15 @@ const submitCancel = async () => {
   }
 }
 
+const typeLabel = (type: string) => {
+  return type === 'BOARDING' ? '寄养' : '美容'
+}
+
+const formatDate = (date?: string) => {
+  if (!date) return '-'
+  return date.replace('T', ' ').substring(0, 16)
+}
+
 const statusLabel = (status: string) => {
   const map: Record<string, string> = {
     PENDING: '待审核', CONFIRMED: '已确认', CANCELLED: '已取消',

+ 48 - 7
src/view/order/OrderDetailView.vue

@@ -9,15 +9,21 @@
       <el-descriptions :column="2" border>
         <el-descriptions-item label="订单编号">{{ order.id }}</el-descriptions-item>
         <el-descriptions-item label="状态">
-          <el-tag :type="statusTag(order.status)">{{ order.status }}</el-tag>
+          <el-tag :type="statusTag(order.status)">{{ statusLabel(order.status) }}</el-tag>
         </el-descriptions-item>
-        <el-descriptions-item label="服务类型">{{ order.type }}</el-descriptions-item>
+        <el-descriptions-item label="宠物">{{ order.petName || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="服务类型">{{ typeLabel(order.type) }}</el-descriptions-item>
+        <el-descriptions-item label="服务套餐">{{ order.packageName || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="房间">{{ order.roomName || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="服务日期">{{ formatDate(order.startDate) }} ~ {{ formatDate(order.endDate) }}</el-descriptions-item>
         <el-descriptions-item label="总价">¥{{ order.totalPrice }}</el-descriptions-item>
         <el-descriptions-item label="定金">¥{{ order.deposit }}</el-descriptions-item>
         <el-descriptions-item label="定金支付">
           {{ order.depositPaid ? '已支付' : '未支付' }}
         </el-descriptions-item>
-        <el-descriptions-item label="创建时间">{{ order.createdAt }}</el-descriptions-item>
+        <el-descriptions-item label="创建时间">{{ formatDate(order.createdAt) }}</el-descriptions-item>
+        <el-descriptions-item v-if="order.cancelReason" label="取消原因">{{ order.cancelReason }}</el-descriptions-item>
+        <el-descriptions-item v-if="order.rejectReason" label="拒绝原因">{{ order.rejectReason }}</el-descriptions-item>
       </el-descriptions>
 
       <div class="detail-actions">
@@ -34,6 +40,8 @@ import { useRouter, useRoute } from 'vue-router'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import type { Appointment } from '@/type'
 import { getAppointmentController } from '@/api/appointment-controller'
+import { getPetController } from '@/api/pet-controller'
+import { getPackageController } from '@/api/package-controller'
 
 const router = useRouter()
 const route = useRoute()
@@ -43,16 +51,29 @@ const loading = ref(false)
 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
+    const [orderRes, petRes, pkgRes] = await Promise.all([
+      getAppointmentController().getById2(Number(route.params.id)),
+      getPetController().list(),
+      getPackageController().list4()
+    ])
+
+    const petMap = new Map<number, string>()
+    petRes.data?.forEach(p => { if (p.id != null && p.name) petMap.set(p.id, p.name) })
+
+    const pkgMap = new Map<number, string>()
+    pkgRes.data?.forEach(p => { if (p.id != null && p.name) pkgMap.set(p.id, p.name) })
+
+    if (orderRes.code === 200 && orderRes.data) {
+      const a = orderRes.data
       order.value = {
         id: String(a.id ?? ''),
         userId: String(a.userId ?? ''),
         petId: String(a.petId ?? ''),
+        petName: a.petName || (a.petId != null ? petMap.get(a.petId) : undefined),
         packageId: String(a.packageId ?? ''),
+        packageName: a.packageName || (a.packageId != null ? pkgMap.get(a.packageId) : undefined),
         roomId: a.roomId ? String(a.roomId) : undefined,
+        roomName: a.roomName,
         type: (a.type as Appointment['type']) ?? 'GROOMING',
         startDate: a.startDate,
         endDate: a.endDate,
@@ -116,6 +137,26 @@ const handleCancel = async () => {
   }
 }
 
+const typeLabel = (type: string) => {
+  return type === 'BOARDING' ? '寄养' : '美容'
+}
+
+const statusLabel = (status: string) => {
+  const map: Record<string, string> = {
+    PENDING: '待审核',
+    CONFIRMED: '已确认',
+    CANCELLED: '已取消',
+    COMPLETED: '已完成',
+    CANCEL_REQUESTED: '取消申请'
+  }
+  return map[status] || status
+}
+
+const formatDate = (date?: string) => {
+  if (!date) return '-'
+  return date.replace('T', ' ').substring(0, 16)
+}
+
 const statusTag = (status: string) => {
   const map: Record<string, string> = {
     PENDING: 'warning',

+ 109 - 14
src/view/order/OrderListView.vue

@@ -15,12 +15,39 @@
     </div>
 
     <div v-else class="order-cards">
-      <el-card v-for="order in orders" :key="order.id" class="order-card">
-        <div class="order-info">
-          <p>订单 ID: {{ order.id }}</p>
-          <el-tag :type="statusTag(order.status)">{{ statusLabel(order.status) }}</el-tag>
+      <el-card v-for="order in orders" :key="order.id" class="order-card" shadow="hover">
+        <div class="order-header">
+          <span class="order-id">#{{ order.id }}</span>
+          <el-tag :type="statusTag(order.status)" size="small">{{ statusLabel(order.status) }}</el-tag>
         </div>
-        <div class="order-actions">
+        <div class="order-body">
+          <div class="order-field">
+            <span class="field-label">宠物</span>
+            <span>{{ order.petName || '-' }}</span>
+          </div>
+          <div class="order-field">
+            <span class="field-label">服务类型</span>
+            <span>{{ typeLabel(order.type) }}</span>
+          </div>
+          <div class="order-field">
+            <span class="field-label">服务套餐</span>
+            <span>{{ order.packageName || '-' }}</span>
+          </div>
+          <div class="order-field">
+            <span class="field-label">服务日期</span>
+            <span>{{ formatDate(order.startDate) }} ~ {{ formatDate(order.endDate) }}</span>
+          </div>
+          <div class="order-field">
+            <span class="field-label">总价</span>
+            <span class="price">¥{{ order.totalPrice }}</span>
+          </div>
+          <div class="order-field">
+            <span class="field-label">定金</span>
+            <span>¥{{ order.deposit }} ({{ order.depositPaid ? '已付' : '未付' }})</span>
+          </div>
+        </div>
+        <div class="order-footer">
+          <span class="order-time">创建时间: {{ formatDate(order.createdAt) }}</span>
           <el-button size="small" @click="viewDetail(order.id)">查看详情</el-button>
         </div>
       </el-card>
@@ -34,6 +61,8 @@ import { useRouter } from 'vue-router'
 import { ElMessage } from 'element-plus'
 import type { Appointment } from '@/type'
 import { getAppointmentController } from '@/api/appointment-controller'
+import { getPetController } from '@/api/pet-controller'
+import { getPackageController } from '@/api/package-controller'
 
 const router = useRouter()
 const activeStatus = ref('')
@@ -43,15 +72,28 @@ const loading = ref(false)
 const loadOrders = async () => {
   loading.value = true
   try {
-    const api = getAppointmentController()
-    const res = await api.list1()
-    if (res.code === 200 && res.data) {
-      let list = res.data.map(a => ({
+    const [orderRes, petRes, pkgRes] = await Promise.all([
+      getAppointmentController().list1(),
+      getPetController().list(),
+      getPackageController().list4()
+    ])
+
+    const petMap = new Map<number, string>()
+    petRes.data?.forEach(p => { if (p.id != null && p.name) petMap.set(p.id, p.name) })
+
+    const pkgMap = new Map<number, string>()
+    pkgRes.data?.forEach(p => { if (p.id != null && p.name) pkgMap.set(p.id, p.name) })
+
+    if (orderRes.code === 200 && orderRes.data) {
+      let list = orderRes.data.map(a => ({
         id: String(a.id ?? ''),
         userId: String(a.userId ?? ''),
         petId: String(a.petId ?? ''),
+        petName: a.petName || (a.petId != null ? petMap.get(a.petId) : undefined),
         packageId: String(a.packageId ?? ''),
+        packageName: a.packageName || (a.packageId != null ? pkgMap.get(a.packageId) : undefined),
         roomId: a.roomId ? String(a.roomId) : undefined,
+        roomName: a.roomName,
         type: (a.type as Appointment['type']) ?? 'GROOMING',
         startDate: a.startDate,
         endDate: a.endDate,
@@ -90,6 +132,15 @@ const statusLabel = (status: string) => {
   return map[status] || status
 }
 
+const typeLabel = (type: string) => {
+  return type === 'BOARDING' ? '寄养' : '美容'
+}
+
+const formatDate = (date?: string) => {
+  if (!date) return '-'
+  return date.replace('T', ' ').substring(0, 16)
+}
+
 const statusTag = (status: string) => {
   const map: Record<string, string> = {
     PENDING: 'warning',
@@ -117,18 +168,62 @@ onMounted(loadOrders)
 
 .order-card {
   margin-bottom: 16px;
+  cursor: pointer;
+  transition: box-shadow 0.2s;
 }
 
-.order-info {
+.order-header {
   display: flex;
   justify-content: space-between;
   align-items: center;
+  padding-bottom: 12px;
+  border-bottom: 1px solid #f0f0f0;
+}
+
+.order-id {
+  font-weight: 600;
+  color: var(--el-color-primary);
+}
+
+.order-body {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 10px 24px;
+  padding: 12px 0;
+}
+
+.order-field {
+  display: flex;
+  flex-direction: column;
+  gap: 2px;
+}
+
+.field-label {
+  font-size: 12px;
+  color: #999;
 }
 
-.order-actions {
-  margin-top: 12px;
+.price {
+  color: var(--el-color-danger);
+  font-weight: 600;
+}
+
+.order-footer {
   display: flex;
-  gap: 8px;
-  justify-content: flex-end;
+  justify-content: space-between;
+  align-items: center;
+  padding-top: 12px;
+  border-top: 1px solid #f0f0f0;
+}
+
+.order-time {
+  font-size: 12px;
+  color: #999;
+}
+
+@media (max-width: 480px) {
+  .order-body {
+    grid-template-columns: 1fr;
+  }
 }
 </style>