Huanyi пре 1 месец
родитељ
комит
466176b90a

+ 18 - 0
src/api/system/merchant/index.ts

@@ -0,0 +1,18 @@
+import request from '@/utils/request';
+import { MerchantIndexCountVO } from './types';
+
+// 获取商户首页统计数据
+export const getMerchantIndexCount = () => {
+  return request<any, any>({
+    url: '/system/merchant/index/count',
+    method: 'get'
+  });
+};
+
+// 获取商户首页订单列表动态图表数据来源
+export const listMerchantOrder = () => {
+  return request<any, any>({
+    url: '/system/merchant/index/listOrder',
+    method: 'get'
+  });
+};

+ 16 - 0
src/api/system/merchant/types.ts

@@ -0,0 +1,16 @@
+export interface MerchantIndexCountVO {
+  orderCountToday: number;
+  costToday: number;
+  costLastday: number;
+  orderCompletedThisMonth: number;
+  pendingDispatchCount: number;
+}
+
+export interface MerchantIndexListOrderVO {
+  id: number;
+  code: string;
+  service: number;
+  serviceTime: string;
+  status: number;
+  createTime: string;
+}

+ 34 - 13
src/views/archieves/customer/index.vue

@@ -670,26 +670,45 @@ const handleDetail = (row) => {
 
 // 移除不需要的方法
 
+const remarkTargetType = ref('customer')
+
 const handleRemark = (row) => {
   currentUser.value = row
-  remarkForm.content = ''
+  remarkTargetType.value = 'customer'
+  remarkForm.content = row.remark || ''
   remarkDialogVisible.value = true
 }
 
 const saveRemark = () => {
   if (!remarkForm.content) return ElMessage.warning('请输入内容')
-  // For now, update customer remark via API
-  const data = {
-    id: currentUser.value.id,
-    name: currentUser.value.name,
-    phone: currentUser.value.phone,
-    remark: remarkForm.content
+  
+  if (remarkTargetType.value === 'customer') {
+    const data = {
+      id: currentUser.value.id,
+      name: currentUser.value.name,
+      phone: currentUser.value.phone,
+      remark: remarkForm.content
+    }
+    updateCustomer(data).then(() => {
+      ElMessage.success('备注添加成功')
+      remarkDialogVisible.value = false
+      getList()
+    })
+  } else {
+    const data = {
+      id: currentUser.value.id,
+      name: currentUser.value.name,
+      remark: remarkForm.content
+    }
+    updatePet(data).then(() => {
+      ElMessage.success('宠物备注添加成功')
+      remarkDialogVisible.value = false
+      if (customerDetailRef.value) {
+        customerDetailRef.value.refresh()
+      }
+      getList()
+    })
   }
-  updateCustomer(data).then(() => {
-    ElMessage.success('备注添加成功')
-    remarkDialogVisible.value = false
-    getList()
-  })
 }
 
 const saveUser = () => {
@@ -855,7 +874,9 @@ const handlePetEdit = (row) => {
 }
 
 const handlePetRemark = (row) => {
-  remarkForm.content = `[宠物:${row.name}] `
+  currentUser.value = row
+  remarkTargetType.value = 'pet'
+  remarkForm.content = row.remark || ''
   remarkDialogVisible.value = true
 }
 

+ 494 - 133
src/views/index.vue

@@ -1,179 +1,540 @@
 <template>
-  <div class="home">
-    <div class="coming-soon-container">
-      <div class="coming-soon-content">
-        <div class="icon-wrapper">
-          <svg class="icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
-            <path
-              d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z"
-              stroke="currentColor"
-              stroke-width="2"
-              stroke-linecap="round"
-              stroke-linejoin="round"
-            />
-            <path d="M9 12L11 14L15 10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
-          </svg>
+  <div class="dashboard-container">
+    <el-row :gutter="20">
+      <!-- 今日新增订单 -->
+      <el-col :span="6">
+        <div class="data-card bg-blue">
+          <div class="card-title">今日新增订单</div>
+          <div class="card-value">
+            <span class="num">{{ countData.orderCountToday || 0 }}</span>
+            <span class="unit">单</span>
+          </div>
+          <div class="card-footer">
+            <div class="footer-left">较昨日</div>
+            <div class="footer-right">-</div>
+          </div>
         </div>
-        <h2 class="coming-soon-title">部分功能待开发中</h2>
-        <p class="coming-soon-subtitle">请直接进行入驻、新增和下单等流程</p>
-
-        <div class="process-guide">
-          <div class="guide-item">
-            <div class="guide-info">
-              <span class="dot"></span>
-              <span>履约入驻流程</span>
-            </div>
+      </el-col>
+      
+      <!-- 今日订单支出 -->
+      <el-col :span="6">
+        <div class="data-card bg-orange">
+          <div class="card-title">今日订单支出</div>
+          <div class="card-value">
+            <span style="font-size: 14px; margin-right: 2px;">¥</span>
+            <span class="num">{{ formatMoney(countData.costToday) }}</span>
           </div>
-          <div class="guide-item">
-            <div class="guide-info">
-              <span class="dot"></span>
-              <span>数据新增与修改</span>
+          <div class="card-footer">
+            <div class="footer-left">较昨日</div>
+            <div class="footer-right">
+              <span v-if="costRate > 0">↑ {{ costRate }}%</span>
+              <span v-else-if="costRate < 0">↓ {{ Math.abs(costRate) }}%</span>
+              <span v-else>-</span>
             </div>
           </div>
-          <div class="guide-item">
-            <div class="guide-info">
-              <span class="dot"></span>
-              <span>核心下单业务流</span>
-            </div>
+        </div>
+      </el-col>
+      
+      <!-- 本月累计完成 -->
+      <el-col :span="6">
+        <div class="data-card bg-green">
+          <div class="card-title">本月累计完成</div>
+          <div class="card-value">
+            <span class="num">{{ countData.orderCompletedThisMonth || 0 }}</span>
+            <span class="unit">单</span>
+          </div>
+          <div class="card-footer linkable" @click="goTo('/order/management')">
+            <div class="footer-left">查看订单明细</div>
+          </div>
+        </div>
+      </el-col>
+      
+      <!-- 待派单 -->
+      <el-col :span="6">
+        <div class="data-card bg-purple">
+          <div class="card-title">待派单</div>
+          <div class="card-value">
+            <span class="num">{{ countData.pendingDispatchCount || 0 }}</span>
+            <span class="unit">项</span>
+          </div>
+          <div class="card-footer linkable" @click="goTo('/order/management')">
+            <div class="footer-left">前往处理</div>
           </div>
         </div>
-      </div>
-    </div>
+      </el-col>
+    </el-row>
+
+    <!-- 图表区域 -->
+    <el-row :gutter="20" class="mt-4">
+      <!-- 趋势分析 -->
+      <el-col :span="16">
+        <el-card shadow="never" class="dashboard-card">
+          <template #header>
+            <div class="card-title-header">
+              <span class="indicator-bar"></span>
+              <span>近7日订单趋势分析</span>
+            </div>
+          </template>
+          <div ref="lineChartRef" style="height: 320px; width: 100%;"></div>
+        </el-card>
+      </el-col>
+
+      <!-- 订单类型占比 -->
+      <el-col :span="8">
+        <el-card shadow="never" class="dashboard-card">
+          <template #header>
+            <div class="card-title-header">
+              <span class="indicator-bar"></span>
+              <span>服务订单占比</span>
+            </div>
+          </template>
+          <div ref="pieChartRef" style="height: 320px; width: 100%;"></div>
+        </el-card>
+      </el-col>
+    </el-row>
+
+    <!-- 订单动态 -->
+    <el-row :gutter="20" class="mt-4">
+      <el-col :span="24">
+        <el-card shadow="never" class="dashboard-card no-padding-body">
+          <template #header>
+            <div style="display: flex; justify-content: space-between; align-items: center;">
+              <div class="card-title-header">
+                <span class="indicator-bar"></span>
+                <span>今日关注订单动态</span>
+                <el-tag size="small" type="info" style="margin-left: 10px;" effect="plain">全部门店</el-tag>
+              </div>
+              <el-button link type="primary" @click="goTo('/order/management')" style="font-size: 13px;">查看全部订单</el-button>
+            </div>
+          </template>
+          <el-table :data="tableOrders" style="width: 100%" :header-cell-style="{ background: '#f8f9fb', color: '#606266' }">
+            <el-table-column prop="code" label="订单号" min-width="180" />
+            <el-table-column prop="service" label="服务项目" min-width="120">
+              <template #default="scope">
+                <el-tag :color="getServiceColor(scope.row.service, true)" 
+                        :style="{ color: getServiceColor(scope.row.service), borderColor: getServiceColor(scope.row.service, true) }" 
+                        size="small">
+                  {{ getServiceName(scope.row.service) }}
+                </el-tag>
+              </template>
+            </el-table-column>
+            <el-table-column label="服务宠物" min-width="120">
+              <template #default> 
+                <!-- API无宠物数据时默认显示暂无 -->
+                <span style="color: #909399;">暂无数据</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="serviceTime" label="今日预约时间" min-width="150" />
+            <el-table-column prop="status" label="订单状态" min-width="120">
+              <template #default="scope">
+                <el-tag :type="getStatusType(scope.row.status)" effect="dark" size="small">{{ getStatusLabel(scope.row.status) }}</el-tag>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-card>
+      </el-col>
+    </el-row>
   </div>
 </template>
 
-<script setup name="Index" lang="ts">
-// 首页逻辑组件
-</script>
+<script setup lang="ts">
+import { ref, onMounted, computed, onUnmounted, nextTick } from 'vue';
+import { useRouter } from 'vue-router';
+import * as echarts from 'echarts';
+import { getMerchantIndexCount, listMerchantOrder } from '@/api/system/merchant';
+import { MerchantIndexCountVO } from '@/api/system/merchant/types';
+import { listAllService } from '@/api/service/list';
 
-<style lang="scss" scoped>
-.home {
-  min-height: 100vh;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
-  font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
-  overflow-x: hidden;
-}
+const router = useRouter();
 
-.coming-soon-container {
-  width: 100%;
-  max-width: 600px;
-  padding: 40px;
-}
+const countData = ref<MerchantIndexCountVO>({
+  orderCountToday: 0,
+  costToday: 0,
+  costLastday: 0,
+  orderCompletedThisMonth: 0,
+  pendingDispatchCount: 0
+});
 
-.coming-soon-content {
-  background: rgba(255, 255, 255, 0.95);
-  border-radius: 20px;
-  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.08);
-  backdrop-filter: blur(10px);
-  -webkit-backdrop-filter: blur(10px);
-  border: 1px solid rgba(255, 255, 255, 0.3);
-  padding: 60px 40px;
-  text-align: center;
-  transition: all 0.3s ease;
+const serviceList = ref<any[]>([]);
+const orderList = ref<any[]>([]);
 
-  &:hover {
-    transform: translateY(-5px);
-    box-shadow: 0 25px 70px rgba(0, 0, 0, 0.12);
+const lineChartRef = ref();
+const pieChartRef = ref();
+let lineChart: echarts.ECharts | null = null;
+let pieChart: echarts.ECharts | null = null;
+
+const tableOrders = computed(() => {
+  return orderList.value.slice(0, 5); // 仅显示今天最新的几条关注动态
+});
+
+const getCount = async () => {
+  try {
+    const res: any = await getMerchantIndexCount();
+    if (res.code === 200 && res.data) {
+      countData.value = Object.assign(countData.value, res.data);
+    }
+  } catch (error) {
+    console.error('获取统计数据失败', error);
   }
-}
+};
 
-.icon-wrapper {
-  margin-bottom: 30px;
-  animation: float 3s ease-in-out infinite;
+const getOrders = async () => {
+  try {
+    const res: any = await listMerchantOrder();
+    if (res.code === 200 && res.data) {
+      orderList.value = res.data || [];
+      initCharts();
+    }
+  } catch (error) {
+    console.error('获取订单列表失败', error);
+  }
+};
 
-  .icon {
-    width: 80px;
-    height: 80px;
-    color: #409eff;
+const getServices = async () => {
+  try {
+    const res: any = await listAllService();
+    serviceList.value = res.data || res || [];
+  } catch (error) {
+    console.error('获取服务项失败', error);
   }
-}
+};
 
-.coming-soon-title {
-  font-size: 32px;
-  font-weight: 600;
-  color: #303133;
-  margin: 0 0 15px 0;
-  letter-spacing: 1px;
-}
+const getServiceName = (id: number) => {
+  const s = serviceList.value.find(item => String(item.id) === String(id));
+  return s ? s.name : String(id);
+};
 
-.coming-soon-subtitle {
-  font-size: 18px;
-  color: #606266;
-  margin: 0 0 40px 0;
-  font-weight: 400;
-}
+// 构造服务标签伪随机色彩
+const COLORS = ['#409eff', '#e6a23c', '#67c23a', '#f56c6c', '#9c27b0', '#19d4ae'];
+const OPACITY_COLORS = ['#ecf5ff', '#fdf6ec', '#f0f9eb', '#fef0f0', '#f9ebfb', '#e5fbf7'];
 
-.process-guide {
-  display: flex;
-  flex-direction: column;
-  gap: 15px;
-  max-width: 320px;
-  margin: 0 auto;
-  text-align: left;
+const getServiceColor = (id: number, isBg = false) => {
+  const index = Number(id || 0) % COLORS.length;
+  return isBg ? OPACITY_COLORS[index] : COLORS[index];
+};
+
+const getStatusLabel = (status: number) => {
+  const map: any = { 0: '待派单', 1: '待接单', 2: '待服务', 3: '服务中', 4: '已完成', 5: '已取消' };
+  return map[status] || '未知状态';
+};
+
+const getStatusType = (status: number) => {
+  const map: any = { 0: 'danger', 1: 'warning', 2: 'primary', 3: 'warning', 4: 'success', 5: 'info' };
+  return map[status] || 'info';
+};
+
+const formatMoney = (val: number) => {
+  if (!val) return '0';
+  return (val / 100).toString();
+};
+
+const costRate = computed(() => {
+  const today = countData.value.costToday || 0;
+  const lastday = countData.value.costLastday || 0;
+  if (lastday === 0) {
+    return today > 0 ? 100 : 0;
+  }
+  return Number((((today - lastday) / lastday) * 100).toFixed(1));
+});
+
+const goTo = (path: string) => {
+  router.push(path);
+};
+
+// 生成过去7天的日期数组, 例如 "03-14"
+const getLast7Days = () => {
+  const dates = [];
+  for (let i = 6; i >= 0; i--) {
+    const d = new Date();
+    d.setDate(d.getDate() - i);
+    const m = (d.getMonth() + 1).toString().padStart(2, '0');
+    const day = d.getDate().toString().padStart(2, '0');
+    dates.push(`${m}-${day}`);
+  }
+  return dates;
+};
+
+const initCharts = () => {
+  if (!lineChartRef.value || !pieChartRef.value) return;
+
+  // ==== 1. 趋势分析折线图 ====
+  const dates = getLast7Days();
+  const newOrderCounts = new Array(7).fill(0);
+  const completedOrderCounts = new Array(7).fill(0);
+
+  // 根据返回的 orderList 聚合数据
+  orderList.value.forEach(order => {
+    if (order.createTime) {
+      // 提取 MM-DD
+      let dateMatch = order.createTime.match(/\d{4}-(\d{2}-\d{2})/);
+      if (!dateMatch) return;
+      let md = dateMatch[1];
+      const index = dates.indexOf(md);
+      if (index !== -1) {
+        newOrderCounts[index]++;
+        if (order.status === 4) {
+          completedOrderCounts[index]++;
+        }
+      }
+    }
+  });
+
+  lineChart = echarts.init(lineChartRef.value);
+  lineChart.setOption({
+    tooltip: {
+      trigger: 'axis',
+      backgroundColor: 'rgba(255, 255, 255, 0.9)',
+      padding: [10, 15],
+      textStyle: { color: '#333' },
+      axisPointer: { type: 'line', lineStyle: { color: '#ddd' } },
+      extraCssText: 'box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);'
+    },
+    legend: {
+      data: ['新增订单', '完成订单'],
+      top: '0',
+      icon: 'emptyCircle'
+    },
+    grid: { left: '3%', right: '4%', bottom: '5%', containLabel: true },
+    xAxis: {
+      type: 'category',
+      boundaryGap: false,
+      data: dates,
+      axisLine: { lineStyle: { color: '#E4E7ED' } },
+      axisLabel: { color: '#909399' }
+    },
+    yAxis: {
+      type: 'value',
+      axisLine: { show: false },
+      axisTick: { show: false },
+      splitLine: { lineStyle: { type: 'dashed', color: '#ebeef5' } },
+      axisLabel: { color: '#909399' }
+    },
+    series: [
+      {
+        name: '新增订单',
+        type: 'line',
+        smooth: true,
+        symbolSize: 8,
+        itemStyle: { color: '#409EFF', borderWidth: 2, borderColor: '#fff' },
+        lineStyle: { color: '#409EFF', width: 3 },
+        areaStyle: {
+          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+            { offset: 0, color: 'rgba(64,158,255,0.2)' },
+            { offset: 1, color: 'rgba(64,158,255,0)' }
+          ])
+        },
+        data: newOrderCounts
+      },
+      {
+        name: '完成订单',
+        type: 'line',
+        smooth: true,
+        symbolSize: 8,
+        itemStyle: { color: '#67C23A', borderWidth: 2, borderColor: '#fff' },
+        lineStyle: { color: '#67C23A', width: 3 },
+        data: completedOrderCounts
+      }
+    ]
+  });
+
+  // ==== 2. 服务订单占比饼图 ====
+  // 聚合分类数据
+  const serviceCounts: Record<string, number> = {};
+  let totalOrder = orderList.value.length || 1; // 防止/0
+  
+  orderList.value.forEach(order => {
+    let sName = getServiceName(order.service);
+    if (!serviceCounts[sName]) serviceCounts[sName] = 0;
+    serviceCounts[sName]++;
+  });
+
+  const pieData = Object.keys(serviceCounts).map(name => {
+    return { name: name, value: serviceCounts[name] };
+  });
+  
+  // 处理空数据展示
+  if(pieData.length === 0) pieData.push({name: '暂无数据', value: 0});
+
+  pieChart = echarts.init(pieChartRef.value);
+  pieChart.setOption({
+    title: {
+      text: 'Total\n100%',
+      left: '34%',
+      top: 'center',
+      textAlign: 'center',
+      textStyle: {
+        fontSize: 13,
+        fontWeight: 'bold',
+        color: '#303133',
+        lineHeight: 18
+      }
+    },
+    tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' },
+    legend: {
+      orient: 'vertical',
+      right: '5%',
+      top: 'center',
+      itemWidth: 10,
+      itemHeight: 10,
+      textStyle: { color: '#606266' },
+      formatter: (name: string) => {
+        const item = pieData.find(i => i.name === name);
+        const val = item ? item.value : 0;
+        const percent = ((val / totalOrder) * 100).toFixed(0);
+        return `${name}  ${percent}%`;
+      }
+    },
+    color: ['#409EFF', '#E6A23C', '#67C23A', '#F56C6C', '#9C27B0'],
+    series: [
+      {
+        name: '服务占比',
+        type: 'pie',
+        radius: ['50%', '75%'],
+        center: ['35%', '50%'],
+        avoidLabelOverlap: false,
+        itemStyle: {
+          borderRadius: 4,
+          borderColor: '#fff',
+          borderWidth: 2
+        },
+        label: { show: false, position: 'center' },
+        emphasis: {
+          label: {
+            show: true,
+            fontSize: '16',
+            fontWeight: 'bold',
+            formatter: '{b}\n{c}'
+          }
+        },
+        labelLine: { show: false },
+        data: pieData
+      }
+    ]
+  });
+};
+
+const resizeCharts = () => {
+  if (lineChart) lineChart.resize();
+  if (pieChart) pieChart.resize();
+};
+
+onMounted(async () => {
+  await getServices(); // 先拉取字典,这样聚合时才有正确名字
+  getCount();
+  getOrders(); // 拉取完进行图表渲染
+  window.addEventListener('resize', resizeCharts);
+});
+
+onUnmounted(() => {
+  window.removeEventListener('resize', resizeCharts);
+  if (lineChart) lineChart.dispose();
+  if (pieChart) pieChart.dispose();
+});
+</script>
+
+<style lang="scss" scoped>
+.dashboard-container {
+  padding: 20px;
+  min-height: calc(100vh - 84px);
+  background-color: #f5f7f9;
 }
 
-.guide-item {
-  padding: 12px 20px;
-  background: #f8faff;
-  border-radius: 10px;
-  border: 1px border-color(#e4e7ed);
-  transition: all 0.2s ease;
+.mt-4 { margin-top: 20px; }
 
+.data-card {
+  border-radius: 8px;
+  padding: 20px;
+  color: #fff;
+  height: 140px;
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
+  transition: transform 0.3s ease;
+  
   &:hover {
-    background: #ecf5ff;
-    transform: scale(1.02);
+    transform: translateY(-5px);
   }
 
-  .guide-info {
+  &.bg-blue { background: linear-gradient(135deg, #409EFF 0%, #66b1ff 100%); }
+  &.bg-orange { background: linear-gradient(135deg, #E6A23C 0%, #f3d19e 100%); }
+  &.bg-green { background: linear-gradient(135deg, #67C23A 0%, #85ce61 100%); }
+  &.bg-purple { background: linear-gradient(135deg, #9C27B0 0%, #b05da6 100%); }
+
+  .card-title { font-size: 14px; font-weight: 500; opacity: 0.9; }
+
+  .card-value {
+    margin-top: 10px;
+    margin-bottom: 20px;
     display: flex;
-    align-items: center;
-    gap: 12px;
-    color: #409eff;
-    font-size: 16px;
-    font-weight: 500;
+    align-items: baseline;
+    
+    .num { font-size: 36px; font-weight: bold; line-height: 1; margin-right: 2px;}
+    .unit { font-size: 14px; margin-left: 2px; opacity: 0.8; }
   }
 
-  .dot {
-    width: 8px;
-    height: 8px;
-    background-color: #409eff;
-    border-radius: 50%;
+  .card-footer {
+    border-top: 1px solid rgba(255, 255, 255, 0.2);
+    padding-top: 10px;
+    display: flex;
+    justify-content: space-between;
+    font-size: 13px;
+    opacity: 0.85;
+
+    &.linkable {
+      cursor: pointer;
+      display: flex;
+      &:hover { opacity: 1; }
+    }
   }
 }
 
-@keyframes float {
-  0%,
-  100% {
-    transform: translateY(0);
-  }
-  50% {
-    transform: translateY(-10px);
+.dashboard-card {
+  border-radius: 8px;
+  border: none;
+  box-shadow: 0 1px 4px rgba(0,21,41,.04);
+
+  :deep(.el-card__header) {
+    padding: 16px 20px;
+    border-bottom: 1px solid #ebeef5;
   }
 }
 
-@media (max-width: 768px) {
-  .coming-soon-container {
-    padding: 20px;
-  }
+.card-title-header {
+  font-size: 16px;
+  font-weight: 600;
+  color: #303133;
+  display: flex;
+  align-items: center;
 
-  .coming-soon-content {
-    padding: 40px 20px;
+  .indicator-bar {
+    display: inline-block;
+    width: 4px;
+    height: 16px;
+    background-color: #409EFF;
+    border-radius: 2px;
+    margin-right: 10px;
   }
+}
 
-  .icon-wrapper .icon {
-    width: 60px;
-    height: 60px;
+.no-padding-body {
+  :deep(.el-card__body) {
+    padding: 0;
   }
 
-  .coming-soon-title {
-    font-size: 24px;
+  :deep(.el-table__inner-wrapper::before) {
+    display: none;
+  }
+  
+  :deep(.el-table th.el-table__cell) {
+    background-color: #f8f9fb;
+    padding: 12px 20px;
+    font-weight: 600;
+    color: #606266;
   }
 
-  .coming-soon-subtitle {
-    font-size: 16px;
+  :deep(.el-table td.el-table__cell) {
+    padding: 16px 20px;
   }
 }
 </style>

+ 35 - 5
src/views/merchant/storeManagement/index.vue

@@ -70,7 +70,7 @@
         <el-table-column label="归属区域/站点" align="left" width="180">
           <template #default="scope">
             <div class="location-info">
-              <div class="area-name">{{ scope.row.regionName || '未知区域' }}</div>
+              <div class="area-name">{{ getRegionNameBySite(scope.row.site) }}</div>
               <div class="station-name">
                 <el-icon class="loc-icon"><Location /></el-icon>
                 <span>{{ scope.row.siteName }}</span>
@@ -130,9 +130,9 @@
                 </span>
                 <template #dropdown>
                   <el-dropdown-menu>
-                    <el-dropdown-item v-hasPermi="['merchant:storeManagement:renew']" command="renew">续期</el-dropdown-item>
-                    <el-dropdown-item v-if="scope.row.status === 1" v-hasPermi="['merchant:storeManagement:disable']" command="ban">禁用</el-dropdown-item>
-                    <el-dropdown-item v-if="scope.row.status === 3" v-hasPermi="['merchant:storeManagement:enable']" command="enable">启用</el-dropdown-item>
+                    <el-dropdown-item v-if="checkPermi(['merchant:storeManagement:renew'])" command="renew">续期</el-dropdown-item>
+                    <el-dropdown-item v-if="scope.row.status === 1 && checkPermi(['merchant:storeManagement:disable'])" command="ban">禁用</el-dropdown-item>
+                    <el-dropdown-item v-if="scope.row.status === 3 && checkPermi(['merchant:storeManagement:enable'])" command="enable">启用</el-dropdown-item>
                   </el-dropdown-menu>
                 </template>
               </el-dropdown>
@@ -260,7 +260,8 @@
             <el-descriptions-item label="有效期至">{{ parseTime(detailData.validity, '{y}-{m}-{d}') }}</el-descriptions-item>
             <el-descriptions-item label="联系人">{{ detailData.contact }}</el-descriptions-item>
             <el-descriptions-item label="联系电话">{{ detailData.contactNumber }}</el-descriptions-item>
-            <el-descriptions-item label="所在区域">{{ detailData.regionName || '北京市朝阳区' }}</el-descriptions-item>
+            <el-descriptions-item label="所在区域">{{ getRegionNameBySite(detailData.site) }}</el-descriptions-item>
+            <el-descriptions-item label="归属站点">{{ detailData.siteName }}</el-descriptions-item>
             <el-descriptions-item label="详细地址">{{ detailData.detailAddress }}</el-descriptions-item>
             <el-descriptions-item label="营业执照">
               <image-preview v-if="detailData.businessLicenseUrl" :src="detailData.businessLicenseUrl" :width="80" :height="60" />
@@ -338,6 +339,7 @@ import { SysAreaStationOnStoreVo } from '@/api/system/areaStation/types';
 import { regionData, codeToText, textToCode } from 'element-china-area-data';
 import PageSelect from '@/components/PageSelect/index.vue';
 import { useUserStore } from '@/store/modules/user';
+import { checkPermi } from '@/utils/permission';
 
 const userStore = useUserStore();
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -654,6 +656,10 @@ const handleSelectionChange = (selection: StoreVO[]) => {
 
 /** 新增按钮操作 */
 const handleAdd = () => {
+  if (!areaOptions.value || areaOptions.value.length === 0) {
+    proxy?.$modal.msgWarning("请先配置区域站点");
+    return;
+  }
   reset();
   if (userStore.tenantId) {
     form.value.tenantId = userStore.tenantId;
@@ -940,6 +946,30 @@ const getServiceName = (serviceId: number): string => {
   return service ? service.name : String(serviceId);
 };
 
+/** 根据站点ID获取区域全称(向上遍历树形关系) */
+const getRegionNameBySite = (siteId: string | number): string => {
+  if (!siteId || areaStationList.value.length === 0) return '未知区域';
+
+  const site = areaStationList.value.find((item: any) => String(item.id) === String(siteId));
+  if (!site) return '未知区域';
+
+  let parentNames: string[] = [];
+  let currentParentId = site.parentId;
+
+  // 向上遍历直到父级ID为0或没找到父级
+  while (currentParentId && String(currentParentId) !== '0') {
+    const parent = areaStationList.value.find((item: any) => String(item.id) === String(currentParentId));
+    if (parent) {
+      parentNames.unshift(parent.name);
+      currentParentId = parent.parentId;
+    } else {
+      break;
+    }
+  }
+
+  return parentNames.length > 0 ? parentNames.join('/') : '未知区域';
+};
+
 /** 获取状态列表 */
 const getStatusList = async () => {
   try {

+ 0 - 256
src/views/order/management-bak/components/CareSummaryDrawer.vue

@@ -1,256 +0,0 @@
-<template>
-  <el-drawer
-    :model-value="visible"
-    @update:model-value="updateVisible"
-    title="宠物护理工作小结"
-    direction="rtl"
-    size="750px"
-    destroy-on-close
-    class="care-summary-drawer"
-  >
-    <div class="care-summary-container" v-if="order">
-      <!-- Pet Header -->
-      <div class="summary-header">
-        <div class="avatar-wrapper">
-          <el-avatar :size="80" :src="order.petAvatar" shape="circle" class="pet-summary-avatar">{{ order.petName?.charAt(0) }}</el-avatar>
-        </div>
-        <div class="pet-summary-info">
-          <div class="summary-name-row">
-            <span class="name">{{ order.petName }}</span>
-            <div class="tags-group">
-              <el-tag :type="order.petGender==='male'?'':'danger'" effect="light" round>
-                <el-icon><component :is="order.petGender==='male'?'Male':'Female'" /></el-icon>
-                {{ order.petAge }}
-              </el-tag>
-              <el-tag v-for="tag in (order.petTags||[])" :key="tag" type="warning" effect="plain" round>{{ tag }}</el-tag>
-            </div>
-          </div>
-          <div class="summary-sub-row">
-            <div class="info-item">
-              <span class="lbl">品种</span>
-              <span class="val">{{ order.petBreed || '未知' }}</span>
-            </div>
-            <div class="divider-v"></div>
-            <div class="info-item">
-              <span class="lbl">体重</span>
-              <span class="val">{{ order.petWeight }}</span>
-            </div>
-            <div class="divider-v"></div>
-            <div class="info-item">
-              <span class="lbl">主人</span>
-              <span class="val">{{ order.userName || '未知' }}</span>
-            </div>
-          </div>
-        </div>
-      </div>
-
-      <!-- Info Groups -->
-      <div class="summary-section">
-        <div class="sec-title">
-          <span class="icon-box"><el-icon><List /></el-icon></span>
-          基本信息
-        </div>
-        <el-descriptions :column="2" border class="spacious-desc">
-          <el-descriptions-item label="性格关键词">{{ order.petPersonality }}</el-descriptions-item>
-          <el-descriptions-item label="健康状况">
-            <el-tag :type="order.healthStatus==='健康'?'success':'danger'" effect="light" size="small">{{ order.healthStatus }}</el-tag>
-          </el-descriptions-item>
-          <el-descriptions-item label="疫苗情况">
-            <div class="flex-align">
-              <span style="color:#67c23a; margin-right:8px;" v-if="order.vaccineImg"><el-icon><CircleCheckFilled /></el-icon> 已接种</span>
-              <span v-else style="color:#909399;">未接种</span>
-              <el-image
-                v-if="order.vaccineImg"
-                style="width: 24px; height: 24px; border-radius:4px; vertical-align:middle; cursor:zoom-in;"
-                :src="order.vaccineImg"
-                :preview-src-list="[order.vaccineImg]"
-                :preview-teleported="true"
-              />
-            </div>
-          </el-descriptions-item>
-          <el-descriptions-item label="过敏史">
-            <span :style="{color: order.allergy ? '#f56c6c' : 'inherit'}">{{ order.allergy || '无' }}</span>
-          </el-descriptions-item>
-        </el-descriptions>
-      </div>
-
-      <div class="summary-section">
-        <div class="sec-title">
-          <span class="icon-box text-blue"><el-icon><HomeFilled /></el-icon></span>
-          服务环境
-        </div>
-        <el-descriptions :column="2" border class="spacious-desc">
-          <el-descriptions-item label="到家时间">{{ order.homeTime }}</el-descriptions-item>
-          <el-descriptions-item label="房屋类型">{{ order.houseType }}</el-descriptions-item>
-          <el-descriptions-item label="入户方式" :span="2">
-            <span style="font-weight:bold;">{{ order.entryMethod }}</span>
-            <span style="margin-left:8px; color:#909399;">({{ order.entryDetail }})</span>
-          </el-descriptions-item>
-        </el-descriptions>
-      </div>
-
-      <!-- Service Log -->
-      <div class="summary-section main-log">
-        <div class="sec-title" style="border:none; padding-left:0; margin-bottom:16px;">
-          <div class="left">
-            <span class="icon-box text-orange"><el-icon><Notebook /></el-icon></span>
-            服务内容记录
-          </div>
-          <el-button v-if="!isEditingSummary" type="primary" link icon="Edit" @click="isEditingSummary = true">编辑</el-button>
-        </div>
-
-        <div v-if="isEditingSummary" class="edit-area">
-          <el-input
-            v-model="careSummaryText"
-            type="textarea"
-            :rows="12"
-            placeholder="请输入详细的护理服务小结..."
-            resize="none"
-          />
-          <div class="edit-actions">
-            <el-button @click="isEditingSummary = false">取消</el-button>
-            <el-button type="primary" @click="saveCareSummary">保存内容</el-button>
-          </div>
-        </div>
-        <div v-else class="log-content-box">
-          <pre class="log-text">{{ careSummaryText }}</pre>
-        </div>
-      </div>
-
-      <!-- Footer Info -->
-      <div class="summary-footer">
-        <div class="footer-info">
-          <div class="f-row">
-            <span class="lbl">护宠师</span>
-            <span class="val user-active">{{ order.fulfillerName || '当前履约者' }}</span>
-          </div>
-          <div class="f-row">
-            <span class="lbl">提交时间</span>
-            <span class="val">{{ order.summaryTime || '2024-02-04 17:00' }}</span>
-          </div>
-        </div>
-        <div class="footer-action">
-          <el-button size="large" @click="updateVisible(false)">关闭</el-button>
-        </div>
-      </div>
-    </div>
-  </el-drawer>
-</template>
-
-<script setup>
-import { ref, watch } from 'vue'
-import { ElMessage } from 'element-plus'
-
-const props = defineProps({
-  visible: Boolean,
-  order: Object
-})
-
-const emit = defineEmits(['update:visible', 'success'])
-
-const isEditingSummary = ref(false)
-const careSummaryText = ref('')
-
-watch(() => props.visible, (val) => {
-  if (val && props.order) {
-    isEditingSummary.value = false
-    if (!props.order.careSummary) {
-      careSummaryText.value = `1. 精神/身体状态:${props.order.petName}精神状态良好,愿意互动。
-2. 进食/饮水:食欲正常,饮水适当,已清洗碗具。
-3. 排泄情况:排便正常,颜色形状正常,已清理。
-4. 卫生情况:猫砂盆/地面已清理干净,无异味。
-5. 互动情况:陪玩了20分钟,${props.order.petName}很开心。
-6. 特殊情况/备注:无特殊异常。`
-    } else {
-      careSummaryText.value = props.order.careSummary
-    }
-  }
-})
-
-const updateVisible = (val) => {
-  emit('update:visible', val)
-}
-
-const saveCareSummary = () => {
-  if (props.order) {
-    props.order.careSummary = careSummaryText.value
-    if (!props.order.summaryTime) {
-      props.order.summaryTime = '2024-02-04 17:00'
-    }
-    ElMessage.success('护理小结已保存')
-    isEditingSummary.value = false
-    emit('success', careSummaryText.value)
-  }
-}
-</script>
-
-<style scoped>
-/* Enhanced Care Summary Styles */
-.care-summary-drawer :deep(.el-drawer__header) { margin-bottom: 0; padding: 20px 24px; border-bottom: 1px solid #f0f0f0; }
-.care-summary-drawer :deep(.el-drawer__body) { padding: 0; overflow-y: auto; background: #fff; }
-
-.care-summary-container { padding: 32px 40px; }
-
-/* 1. Header */
-.summary-header { display: flex; gap: 24px; align-items: flex-start; margin-bottom: 32px; padding-bottom: 24px; border-bottom: 1px dashed #e4e7ed; }
-.avatar-wrapper { border: 4px solid #f2f6fc; border-radius: 50%; }
-.pet-summary-info { flex: 1; display:flex; flex-direction:column; gap:12px; padding-top: 4px; }
-
-.summary-name-row { display: flex; align-items: center; gap: 16px; margin-bottom: 4px; }
-.summary-name-row .name { font-size: 24px; font-weight: 800; color: #303133; letter-spacing: 0.5px; }
-.tags-group { display: flex; gap: 8px; align-items: center; }
-
-.summary-sub-row { display: flex; align-items: center; background: #f9fafe; padding: 10px 16px; border-radius: 8px; align-self: flex-start; }
-.info-item { display: flex; flex-direction: column; gap: 2px; }
-.info-item .lbl { font-size: 11px; color: #909399; text-transform: uppercase; }
-.info-item .val { font-size: 14px; font-weight: bold; color: #606266; }
-.divider-v { width: 1px; height: 24px; background: #ebeef5; margin: 0 16px; }
-
-/* 2. Sections */
-.summary-section { margin-bottom: 40px; }
-.sec-title {
-  font-size: 16px; font-weight: 700; color: #303133; margin-bottom: 16px;
-  display:flex; align-items:center; gap:8px;
-  justify-content: space-between;
-}
-.sec-title .left { display: flex; align-items: center; gap: 8px; }
-.icon-box {
-  width: 28px; height: 28px; background: #ecf5ff; color: #409eff; border-radius: 6px;
-  display: flex; align-items: center; justify-content: center; font-size: 16px;
-}
-.icon-box.text-blue { background: #ecf5ff; color: #409eff; }
-.icon-box.text-orange { background: #fdf6ec; color: #e6a23c; }
-
-/* 3. Descriptions */
-.spacious-desc :deep(.el-descriptions__cell) { padding: 12px 16px!important; }
-.spacious-desc :deep(.el-descriptions__label) { width: 100px; color: #606266; font-weight: 500; background: #fafafa; }
-.flex-align { display: flex; align-items: center; }
-
-/* 4. Log Area */
-.main-log { background: #fff; }
-.log-content-box {
-  background: #fff;
-  border: 1px solid #ebeef5; border-radius: 8px;
-  padding: 24px;
-  box-shadow: 0 2px 12px rgba(0,0,0,0.02);
-  position: relative;
-}
-.log-content-box::before {
-  content: ''; position: absolute; top: 0; left: 0; width: 4px; height: 100%; background: #e6a23c; border-top-left-radius: 8px; border-bottom-left-radius: 8px;
-}
-.log-text {
-  white-space: pre-wrap; font-family: 'Inter', system-ui, sans-serif; margin: 0; line-height: 1.8; font-size: 15px; color: #303133; text-align: justify;
-}
-.edit-actions { display: flex; justify-content: flex-end; gap: 12px; margin-top: 12px; }
-
-/* 5. Footer */
-.summary-footer {
-  margin-top: 60px; padding-top: 24px; border-top: 1px solid #ebeef5;
-  display: flex; justify-content: space-between; align-items: center;
-}
-.footer-info { display: flex; gap: 32px; }
-.f-row { display: flex; flex-direction: column; gap: 4px; }
-.f-row .lbl { font-size: 12px; color: #909399; }
-.f-row .val { font-size: 15px; font-weight: 600; color: #303133; }
-.f-row .val.user-active { color: #409eff; }
-</style>

+ 0 - 942
src/views/order/management-bak/components/OrderDetailDrawer.vue

@@ -1,942 +0,0 @@
-<template>
-    <el-drawer v-model="drawerVisible" title="订单详情" direction="rtl" size="60%" class="order-detail-drawer">
-        <div class="detail-container" v-if="order">
-            <!-- 1. Header Status -->
-            <div class="detail-header">
-                <div class="left-head">
-                    <span class="order-no">{{ order.orderNo }}</span>
-                    <el-tag :type="getStatusTag(order.status)" effect="dark" class="status-tag">{{
-                        getStatusName(order.status) }}</el-tag>
-                    <el-tag effect="plain" class="type-tag"
-                        :type="order.type === 'transport' ? '' : (order.type === 'feeding' ? 'warning' : 'danger')">
-                        {{ getTypeName(order.type) }}
-                    </el-tag>
-                </div>
-                <div class="right-head">
-                    <!-- Action Buttons Group -->
-                    <div class="detail-actions">
-                        <template v-if="[0, 1, 2].includes(order.status)">
-                            <el-button type="success" icon="Bicycle" @click="emit('dispatch', order)">
-                                {{ order.fulfiller || order.fulfillerName ? '重新派单' : '立即派单' }}
-                            </el-button>
-                        </template>
-
-                        <template v-if="order.status === 0">
-                            <el-button type="danger" plain icon="CircleClose"
-                                @click="emit('cancel', order)">取消订单</el-button>
-                        </template>
-
-                        <template v-if="order.status === 3">
-                            <el-button type="primary" icon="CircleCheck"
-                                @click="emit('command', 'complete', order)">确认完成</el-button>
-                        </template>
-
-                        <template v-if="[3, 4].includes(order.status)">
-                            <el-button icon="Notebook" @click="emit('care-summary', order)">护理小结</el-button>
-                        </template>
-
-                        <el-dropdown trigger="click" @command="(cmd) => emit('command', cmd, order)"
-                            style="margin-left: 12px;">
-                            <el-button icon="More">更多操作</el-button>
-                            <template #dropdown>
-                                <el-dropdown-menu>
-                                    <el-dropdown-item command="reward" icon="Trophy">奖惩操作</el-dropdown-item>
-                                    <el-dropdown-item command="remark" icon="EditPen">订单备注</el-dropdown-item>
-                                    <el-dropdown-item command="delete" v-if="[5, 4].includes(order.status)" divided
-                                        icon="Delete" style="color: #f56c6c;">删除订单</el-dropdown-item>
-                                </el-dropdown-menu>
-                            </template>
-                        </el-dropdown>
-                    </div>
-                </div>
-            </div>
-
-            <div class="detail-scroll-area">
-                <!-- 2. Progress Section -->
-                <div class="progress-section">
-                    <el-steps :active="currentOrderSteps.active" finish-status="success" align-center
-                        class="custom-steps">
-                        <el-step v-for="(step, index) in currentOrderSteps.steps" :key="index" :title="step.title"
-                            :description="step.time" />
-                    </el-steps>
-                </div>
-
-                <!-- 3. Top Info: Pet & User -->
-                <div class="top-info-row">
-                    <!-- Left: Pet Info -->
-                    <div class="info-section pet-section">
-                        <div class="sec-header">
-                            <span class="label">宠物档案</span>
-                            <el-tag size="small" effect="plain">{{ order.petBreed }}</el-tag>
-                        </div>
-                        <div class="pet-basic-row">
-                            <el-avatar :size="50" :src="order.petAvatar" shape="square" class="pet-avatar-lg">{{
-                                (order.petName || '').charAt(0) }}</el-avatar>
-                            <div class="pet-names">
-                                <div class="b-name">{{ order.petName }}
-                                    <el-icon v-if="order.petGender === 'male'" color="#409eff">
-                                        <Male />
-                                    </el-icon>
-                                    <el-icon v-else color="#f56c6c">
-                                        <Female />
-                                    </el-icon>
-                                </div>
-                                <div class="b-tags">
-                                    <el-tag size="small" type="info">{{ order.petAge || '未知年龄' }}</el-tag>
-                                    <el-tag size="small" type="info">{{ order.petWeight || '未知体重' }}</el-tag>
-                                </div>
-                            </div>
-                        </div>
-                        <el-descriptions :column="2" size="small" class="pet-desc" border>
-                            <el-descriptions-item label="绝育状态">{{ order.petSterilized ? '已绝育' : '未绝育'
-                            }}</el-descriptions-item>
-                            <el-descriptions-item label="疫苗状态"><span style="color:#67c23a">{{ order.petVaccine || '未知'
-                            }}</span></el-descriptions-item>
-                            <el-descriptions-item label="性格特点">{{ order.petCharacter || '温顺' }}</el-descriptions-item>
-                            <el-descriptions-item label="健康状况">{{ order.petHealth || '健康' }}</el-descriptions-item>
-                        </el-descriptions>
-                    </div>
-
-                    <!-- Right: User Info -->
-                    <div class="info-section user-section">
-                        <div class="sec-header">
-                            <span class="label">用户信息</span>
-                        </div>
-                        <div class="user-content">
-                            <div class="u-row">
-                                <el-avatar :size="40" :src="order.userAvatar">{{ (order.userName || '').charAt(0)
-                                }}</el-avatar>
-                                <div class="u-info">
-                                    <div class="nm">{{ order.userName }}</div>
-                                    <div class="ph">{{ order.contactPhone }}</div>
-                                </div>
-                            </div>
-                            <div class="addr-box">
-                                <div class="addr-label">服务地址</div>
-                                <div class="addr-txt">{{ order.city }}{{ order.district }} {{ order.address || '' }}
-                                </div>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-
-                <!-- 4. Bottom Tabs -->
-                <el-tabs v-model="activeDetailTab" class="detail-tabs type-card">
-                    <!-- Tab 1: Basic Info -->
-                    <el-tab-pane label="订单基础信息" name="basic">
-                        <div class="tab-pane-content">
-                            <div class="section-block">
-                                <div class="sec-title-bar">基础业务信息</div>
-                                <el-descriptions :column="3" border size="default" class="custom-desc">
-                                    <el-descriptions-item label="系统单号">{{ order.orderNo }}</el-descriptions-item>
-                                    <el-descriptions-item label="服务类型">
-                                        {{ getTypeName(order.type) }}
-                                        <el-tag size="small" v-if="order.type === 'transport'" style="margin-left:5px"
-                                            effect="light">{{ getTransportModeName(order.transportType) }}</el-tag>
-                                    </el-descriptions-item>
-
-                                    <el-descriptions-item label="归属门店">{{ order.merchantName }}
-                                        ({{ Number(order.platformId) === 1 ? '门店下单' : '平台代下单' }})</el-descriptions-item>
-                                    <el-descriptions-item label="宠主信息">{{ order.userName }} / {{ order.contactPhone
-                                    }}</el-descriptions-item>
-                                    <el-descriptions-item label="服务费用" label-class-name="money-label">
-                                        <span style="color:#f56c6c; font-weight:bold;">¥ {{ order.fulfillerFee }}</span>
-                                    </el-descriptions-item>
-
-                                    <el-descriptions-item label="预约时间">{{ getServiceTimeRange(order.serviceTime)
-                                    }}</el-descriptions-item>
-                                    <el-descriptions-item label="团购套餐">{{ order.groupBuyPackage || '未使用团购套餐'
-                                    }}</el-descriptions-item>
-                                    <el-descriptions-item label="创建时间">{{ order.createTime }}</el-descriptions-item>
-
-                                    <el-descriptions-item label="订单备注" :span="3">
-                                        {{ order.remark || '暂无备注' }}
-                                    </el-descriptions-item>
-                                </el-descriptions>
-                            </div>
-
-                            <div v-if="order.type === 'transport'" class="section-block transport-split-block">
-                                <div class="sec-title-bar">接送任务详情</div>
-                                <div class="transport-one">
-                                    <div class="t-row">
-                                        <el-tag size="small" effect="plain" class="sub-badge">{{
-                                            getTransportLabel(order.subOrderType) }}</el-tag>
-                                        <span class="time">{{ order.serviceTime }}</span>
-                                    </div>
-                                    <div class="t-row">
-                                        <span class="t-k">起点</span>
-                                        <span class="t-v">{{ order.detail?.fromAddress || order.detail?.pickAddr || '--'
-                                            }}</span>
-                                    </div>
-                                    <div class="t-row">
-                                        <span class="t-k">终点</span>
-                                        <span class="t-v">{{ order.detail?.toAddress || order.detail?.dropAddr ||
-                                            order.toAddress ||
-                                            '--' }}</span>
-                                    </div>
-                                    <div class="t-row sub">
-                                        <span class="t-v">{{ order.contact || order.userName || '--' }} {{
-                                            order.contactPhoneNumber
-                                            || order.contactPhone || '--' }}</span>
-                                    </div>
-                                </div>
-                            </div>
-
-                            <div v-if="['feeding', 'washing'].includes(order.type)" class="section-block">
-                                <div class="sec-title-bar">服务执行要求</div>
-                                <el-descriptions :column="2" border size="default" class="custom-desc">
-                                    <el-descriptions-item label="服务地址" :span="2">{{ order.detail.area || order.address
-                                    }}</el-descriptions-item>
-                                </el-descriptions>
-                            </div>
-                        </div>
-                    </el-tab-pane>
-
-                    <!-- Tab 2: Fulfiller Info -->
-                    <el-tab-pane label="指派履约者" name="fulfiller">
-                        <div class="tab-pane-content">
-                            <div v-if="order.fulfillerName" class="fulfiller-card">
-                                <div class="f-left">
-                                    <el-avatar :size="60" :src="order.fulfillerAvatar">{{ order.fulfillerName.charAt(0)
-                                    }}</el-avatar>
-                                </div>
-                                <div class="f-right">
-                                    <div class="f-row1">
-                                        <span class="f-name">{{ order.fulfillerName }}</span>
-                                        <el-tag size="small" type="primary" effect="plain" round>Lv1 普通</el-tag>
-                                    </div>
-                                    <div class="f-row2">
-                                        <span>联系电话:{{ order.fulfillerPhone || '138****0000' }}</span>
-                                        <span class="sep">|</span>
-                                        <span>归属区域:{{ order.fulfillerStation || '朝阳一站' }}</span>
-                                    </div>
-                                    <div class="f-row3"
-                                        style="margin-top: 8px; font-size: 13px; color: #606266; background: #f9fafe; padding: 8px; border-radius: 4px; display: flex; gap: 20px;">
-                                        <span><span style="color:#909399;">指派时间:</span>{{ order.createTime }}</span>
-                                        <span><span style="color:#909399;">接单时间:</span>{{ order.detail?.receiveTime ||
-                                            order.serviceTime }}</span>
-                                    </div>
-                                </div>
-                            </div>
-                            <div v-else class="empty-state">
-                                <el-result icon="info" title="暂无履约者" sub-title="该订单尚未指派履约人员"></el-result>
-                            </div>
-                        </div>
-                    </el-tab-pane>
-
-                    <!-- Tab 3: Service Progress -->
-                    <el-tab-pane label="服务进度" name="service">
-                        <div class="tab-pane-content">
-                            <div v-if="serviceProgressSteps.length === 0" class="empty-progress"
-                                style="padding:40px; text-align:center; color:#909399;">
-                                <el-result icon="info" title="待接单" sub-title="履约者接单后将在此记录服务进度"></el-result>
-                            </div>
-
-                            <el-timeline style="padding: 10px 20px;" v-else>
-                                <el-timeline-item v-for="(step, index) in serviceProgressSteps" :key="index"
-                                    :timestamp="step.time" placement="top" :color="step.color" :icon="step.icon"
-                                    size="large">
-                                    <div class="progress-card">
-                                        <h4 class="p-title">{{ step.title }}</h4>
-                                        <p class="p-desc">{{ step.desc }}</p>
-                                        <div class="p-media" v-if="step.media && step.media.length">
-                                            <div v-for="(item, i) in step.media" :key="i" class="media-item">
-                                                <el-image v-if="item.type === 'image'" :src="item.url"
-                                                    :preview-src-list="step.media.map(m => m.url)" fit="cover"
-                                                    class="p-img" :preview-teleported="true" />
-                                            </div>
-                                        </div>
-                                    </div>
-                                </el-timeline-item>
-                            </el-timeline>
-                        </div>
-                    </el-tab-pane>
-
-                    <!-- Tab 4: Logs -->
-                    <el-tab-pane label="订单日志" name="logs">
-                        <div class="tab-pane-content">
-                            <div style="display: flex; justify-content: flex-end; margin-bottom: 15px;">
-                                <el-button type="primary" size="small" icon="Download"
-                                    @click="handleExportLogs">导出日志Excel</el-button>
-                            </div>
-                            <el-timeline>
-                                <el-timeline-item v-for="(log, index) in (orderLogs || [])" :key="index" :timestamp="''"
-                                    :type="'primary'" :icon="undefined" placement="top">
-                                    <div class="log-card">
-                                        <div class="l-tit">{{ log.title }}</div>
-                                        <div class="l-txt">{{ log.content }}</div>
-                                    </div>
-                                </el-timeline-item>
-                            </el-timeline>
-                        </div>
-                    </el-tab-pane>
-                </el-tabs>
-            </div>
-        </div>
-    </el-drawer>
-</template>
-
-<script setup>
-import { ref, computed, watch } from 'vue'
-import { ElMessage } from 'element-plus'
-import { getPet } from '@/api/archieves/pet'
-import { getCustomer } from '@/api/archieves/customer'
-import { listSubOrderLog } from '@/api/order/subOrderLog'
-
-const props = defineProps({
-    visible: Boolean,
-    order: Object
-})
-
-const emit = defineEmits(['update:visible', 'dispatch', 'cancel', 'command', 'care-summary'])
-
-const drawerVisible = computed({
-    get: () => props.visible,
-    set: (val) => emit('update:visible', val)
-})
-
-const orderDetail = ref(null)
-const order = computed(() => orderDetail.value || props.order)
-
-const loadSeq = ref(0)
-
-const orderLogs = ref([])
-const fulfillerLogs = ref([])
-
-const loadOrderLogs = async (order) => {
-    const id = order?.id
-    if (!id) {
-        orderLogs.value = []
-        fulfillerLogs.value = []
-        return
-    }
-    try {
-        const res = await listSubOrderLog({ orderId: id })
-        const list = res?.data?.data || res?.data || []
-        const arr = Array.isArray(list) ? list : []
-        orderLogs.value = arr.filter(i => Number(i?.logType) === 0)
-        fulfillerLogs.value = arr.filter(i => Number(i?.logType) === 1)
-    } catch {
-        orderLogs.value = []
-        fulfillerLogs.value = []
-    }
-}
-
-const loadPetAndCustomer = async (order) => {
-    const seq = ++loadSeq.value
-    const next = { ...(order || {}) }
-
-    const petId = next?.pet || next?.petId
-    if (petId) {
-        try {
-            const res = await getPet(petId)
-            const pet = res?.data
-            if (pet) {
-                next.petName = pet.name ?? next.petName
-                next.petAvatar = pet.avatarUrl ?? next.petAvatar
-                next.petGender = pet.gender ?? next.petGender
-                next.petAge = (pet.age !== undefined && pet.age !== null) ? `${pet.age}岁` : next.petAge
-                next.petWeight = (pet.weight !== undefined && pet.weight !== null) ? `${pet.weight}kg` : next.petWeight
-                next.petBreed = pet.breed ?? next.petBreed
-                next.petSterilized = (pet.isSterilized !== undefined && pet.isSterilized !== null)
-                    ? (Number(pet.isSterilized) === 1)
-                    : next.petSterilized
-                next.petVaccine = pet.vaccineStatus ?? next.petVaccine
-                next.petCharacter = pet.personality ?? next.petCharacter
-                next.petHealth = pet.healthStatus ?? next.petHealth
-            }
-        } catch {
-        }
-    }
-
-    const customerId = next?.customer || next?.customerId
-    if (customerId) {
-        try {
-            const res = await getCustomer(customerId)
-            const customer = res?.data
-            if (customer) {
-                next.userName = customer.name ?? next.userName
-                next.userAvatar = customer.avatarUrl ?? next.userAvatar
-                next.contactPhone = customer.phone ?? next.contactPhone
-                next.city = customer.areaName ?? next.city
-                next.address = customer.address ?? next.address
-            }
-        } catch {
-        }
-    }
-
-    if (seq !== loadSeq.value) return
-    orderDetail.value = next
-}
-
-watch(() => props.order, (val) => {
-    if (!val) {
-        orderDetail.value = null
-        orderLogs.value = []
-        fulfillerLogs.value = []
-        return
-    }
-    loadPetAndCustomer(val)
-    loadOrderLogs(val)
-}, { immediate: true, deep: true })
-
-const activeDetailTab = ref('basic')
-
-const getStatusName = (status) => {
-    const map = { 0: '待派单', 1: '待接单', 2: '服务中', 3: '待商家确认', 4: '已完成', 5: '已取消' }
-    return map[status] || '未知'
-}
-const getStatusTag = (status) => {
-    const map = { 0: 'danger', 1: 'warning', 2: 'primary', 3: 'warning', 4: 'success', 5: 'info' }
-    return map[status] || 'info'
-}
-const getTypeName = (type) => {
-    const map = { transport: '宠物接送', feeding: '上门喂遛', washing: '上门洗护' }
-    return map[type]
-}
-const getTransportModeName = (type) => {
-    const map = { round: '往返接送', pick: '单程接(到店)', drop: '单程送(回家)' }
-    return map[type] || '接送服务'
-}
-
-const getTransportLabel = (t) => {
-    if (t === 0 || t === '0') return '接'
-    if (t === 1 || t === '1') return '送'
-    if (t === 2 || t === '2') return '单程接'
-    if (t === 3 || t === '3') return '单程送'
-    return '接送'
-}
-const getServiceTimeRange = (timeStr) => {
-    if (!timeStr) return '--'
-    try {
-        if (timeStr.length < 16) return timeStr
-        let timePart = timeStr.substring(11, 16)
-        let [hh, mm] = timePart.split(':').map(Number)
-        let endH = hh + 2
-        if (endH >= 24) endH -= 24
-        let endHStr = endH.toString().padStart(2, '0')
-        return `${timeStr}-${endHStr}:${mm.toString().padStart(2, '0')}`
-    } catch (e) {
-        return timeStr
-    }
-}
-
-const currentOrderSteps = computed(() => {
-    if (!props.order) return { active: 0, steps: [] }
-    const steps = [
-        { title: '商户下单', status: 'created', time: '' },
-        { title: '运营派单', status: 'dispatched', time: '' },
-        { title: '履约接单', status: 'accepted', time: '' },
-        { title: '服务中', status: 'serving', time: '' },
-        { title: '待商家确认', status: 'confirming', time: '' },
-        { title: '已完成', status: 'completed', time: '' }
-    ]
-    const logs = orderLogs.value || []
-    const status = props.order.status
-    let active = 0
-    const findTime = (keyword) => {
-        const log = logs.find(l => l.title.includes(keyword) || l.content.includes(keyword))
-        return log ? log.time : ''
-    }
-    steps[0].time = props.order.createTime || findTime('下单') || findTime('创建')
-    if (steps[0].time) active = 1
-    if ([0].includes(status)) {
-        steps[1].time = findTime('派单') || steps[0].time
-    } else {
-        steps[1].time = findTime('派单') || ''
-    }
-    if ([1, 2, 3, 4].includes(status)) active = 2
-    steps[2].time = findTime('接单')
-    if ([1].includes(status)) {
-        steps[2].title = '待履约者接单'
-    } else if ([2, 3, 4].includes(status)) {
-        steps[2].title = '履约者已接单'
-        active = 3
-    }
-    steps[3].time = findTime('到达') || findTime('出发')
-    if ([2].includes(status)) {
-        steps[3].title = '服务进行中'
-    } else if ([3, 4].includes(status)) {
-        steps[3].title = '服务已完成'
-        active = 4
-    }
-    steps[4].time = findTime('等待商家确认') || findTime('待验收')
-    if ([3].includes(status)) {
-        steps[4].title = '待商家确认'
-    } else if ([4].includes(status)) {
-        steps[4].title = '商家已确认'
-        active = 5
-    }
-    if (status === 4) {
-        steps[5].time = findTime('完成')
-        active = 6
-    }
-    if (status === 5) {
-        return {
-            active: 1,
-            steps: [
-                { title: '商户下单', time: steps[0].time },
-                { title: '已取消', time: findTime('取消') || '订单已取消' }
-            ]
-        }
-    }
-    return { active, steps }
-})
-
-const serviceProgressSteps = computed(() => {
-    const list = fulfillerLogs.value || []
-    return list.map((i) => {
-        const photos = (i?.photos || '')
-            .split(',')
-            .map(s => s.trim())
-            .filter(Boolean)
-            .map(url => ({ type: 'image', url }))
-        return {
-            title: i?.title || '--',
-            time: '',
-            icon: undefined,
-            color: '#ff9900',
-            desc: i?.content || '',
-            media: photos
-        }
-    })
-})
-
-const handleExportLogs = () => {
-    const logs = orderLogs.value || []
-    if (logs.length === 0) {
-        ElMessage.warning('暂无日志可导出')
-        return
-    }
-    let csvContent = "时间,类型,标题,内容\n"
-    logs.forEach(log => {
-        const time = ''
-        const type = log.logType ?? ''
-        const title = (log.title || '').replace(/"/g, '""')
-        const content = (log.content || '').replace(/"/g, '""')
-        csvContent += `${time},${type},"${title}","${content}"\n`
-    })
-    const blob = new Blob(["\uFEFF" + csvContent], { type: 'text/csv;charset=utf-8;' })
-    const url = URL.createObjectURL(blob)
-    const link = document.createElement("a")
-    link.href = url
-    link.download = `OrderLogs_${props.order.orderNo}.csv`
-    link.click()
-    URL.revokeObjectURL(url)
-    ElMessage.success('导出成功')
-}
-</script>
-
-<style scoped>
-/* Detail Styles */
-.order-detail-drawer :deep(.el-drawer__body) {
-    padding: 0 !important;
-}
-
-.detail-container {
-    height: 100%;
-    display: flex;
-    flex-direction: column;
-    background: #f5f7fa;
-}
-
-.detail-header {
-    background: #fff;
-    padding: 20px 24px;
-    border-bottom: 1px solid #ebeef5;
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-}
-
-.left-head {
-    display: flex;
-    align-items: center;
-    gap: 12px;
-}
-
-.order-no {
-    font-size: 20px;
-    font-weight: bold;
-    color: #303133;
-}
-
-.type-tag {
-    font-weight: normal;
-}
-
-.detail-actions {
-    display: flex;
-    align-items: center;
-    gap: 12px;
-}
-
-.detail-scroll-area {
-    flex: 1;
-    overflow-y: auto;
-    padding: 20px 24px;
-}
-
-/* Progress */
-.progress-section {
-    background: #fff;
-    padding: 30px 20px 20px;
-    border-radius: 8px;
-    margin-bottom: 20px;
-    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
-}
-
-.custom-steps :deep(.el-step__title) {
-    font-size: 13px;
-}
-
-/* Top Info Row */
-.top-info-row {
-    display: flex;
-    gap: 20px;
-    margin-bottom: 20px;
-    align-items: stretch;
-}
-
-.info-section {
-    flex: 1;
-    background: #fff;
-    border-radius: 8px;
-    padding: 15px;
-    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
-}
-
-.sec-header {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    margin-bottom: 15px;
-    padding-bottom: 10px;
-    border-bottom: 1px solid #f2f2f2;
-}
-
-.sec-header .label {
-    font-weight: bold;
-    font-size: 15px;
-    color: #303133;
-    border-left: 3px solid #409eff;
-    padding-left: 8px;
-}
-
-/* Pet Section */
-.pet-basic-row {
-    display: flex;
-    gap: 15px;
-    margin-bottom: 15px;
-    align-items: center;
-}
-
-.pet-avatar-lg {
-    border-radius: 8px;
-    background: #ecf5ff;
-    color: #409eff;
-    font-size: 20px;
-    font-weight: bold;
-}
-
-.pet-names {
-    display: flex;
-    flex-direction: column;
-    gap: 6px;
-}
-
-.b-name {
-    font-size: 18px;
-    font-weight: bold;
-    display: flex;
-    align-items: center;
-    gap: 6px;
-}
-
-.b-tags {
-    display: flex;
-    gap: 5px;
-}
-
-.pet-desc :deep(.el-descriptions__label) {
-    width: 70px;
-}
-
-/* User Section */
-.u-row {
-    display: flex;
-    gap: 12px;
-    align-items: center;
-    margin-bottom: 12px;
-}
-
-.u-info .nm {
-    font-weight: bold;
-    font-size: 15px;
-    color: #303133;
-    display: flex;
-    align-items: center;
-    gap: 6px;
-}
-
-.u-info .ph {
-    font-size: 13px;
-    color: #909399;
-    margin-top: 2px;
-}
-
-.addr-box {
-    background: #fdf6ec;
-    padding: 8px 10px;
-    border-radius: 4px;
-    margin-bottom: 10px;
-}
-
-.addr-label {
-    font-size: 12px;
-    color: #e6a23c;
-    margin-bottom: 2px;
-    font-weight: bold;
-}
-
-.addr-txt {
-    font-size: 13px;
-    color: #606266;
-    line-height: 1.4;
-}
-
-/* Tabs */
-.detail-tabs {
-    background: #fff;
-    padding: 10px 20px;
-    border-radius: 8px;
-    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
-    min-height: 400px;
-}
-
-.tab-pane-content {
-    padding: 15px 0;
-}
-
-/* Fulfiller Card inside Tab */
-.fulfiller-card {
-    display: flex;
-    align-items: center;
-    gap: 20px;
-    padding: 20px;
-    background: #fff;
-    border: 1px solid #ebeef5;
-    border-radius: 8px;
-}
-
-.f-right {
-    flex: 1;
-    display: flex;
-    flex-direction: column;
-    gap: 8px;
-}
-
-.f-row1 {
-    display: flex;
-    align-items: center;
-    gap: 10px;
-}
-
-.f-name {
-    font-size: 18px;
-    font-weight: bold;
-    color: #303133;
-}
-
-.f-row2 {
-    font-size: 13px;
-    color: #606266;
-    display: flex;
-    gap: 10px;
-}
-
-.sep {
-    color: #e4e7ed;
-}
-
-.empty-state {
-    padding: 40px 0;
-    text-align: center;
-}
-
-/* Progress Card Styles */
-.progress-card {
-    background: #f8fcfb;
-    border-radius: 8px;
-    padding: 12px;
-    border: 1px solid #ebeef5;
-}
-
-.p-title {
-    margin: 0 0 8px;
-    font-size: 15px;
-    font-weight: bold;
-    color: #303133;
-}
-
-.p-desc {
-    margin: 0 0 12px;
-    color: #606266;
-    font-size: 13px;
-    line-height: 1.5;
-}
-
-.p-media {
-    display: flex;
-    gap: 8px;
-    flex-wrap: wrap;
-}
-
-.media-item {
-    display: inline-block;
-}
-
-.p-img {
-    width: 80px;
-    height: 80px;
-    border-radius: 4px;
-    border: 1px solid #e4e7ed;
-    cursor: pointer;
-}
-
-/* New Transport Split Styles */
-.transport-split-block {
-    margin-top: 20px;
-}
-
-.transport-grid {
-    display: flex;
-    gap: 20px;
-}
-
-.transport-card {
-    flex: 1;
-    border: 1px solid #ebeef5;
-    border-radius: 6px;
-    overflow: hidden;
-    background: #fff;
-    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.02);
-}
-
-.transport-card .t-header {
-    background: #f5f7fa;
-    padding: 10px 15px;
-    border-bottom: 1px solid #ebeef5;
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-}
-
-.transport-card .t-header .time {
-    font-size: 13px;
-    font-weight: bold;
-    color: #f56c6c;
-}
-
-.transport-card .t-body {
-    padding: 15px;
-    display: flex;
-    flex-direction: column;
-    gap: 10px;
-}
-
-.transport-card .row {
-    display: flex;
-    align-items: flex-start;
-    gap: 8px;
-    font-size: 14px;
-    color: #303133;
-    line-height: 1.4;
-}
-
-.transport-card .row.sub {
-    color: #909399;
-    font-size: 13px;
-    margin-top: 4px;
-}
-
-.transport-card .row .el-icon {
-    margin-top: 3px;
-}
-
-.transport-one {
-    border: 1px solid #ebeef5;
-    border-radius: 6px;
-    background: #fff;
-    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.02);
-    padding: 14px 16px;
-    display: flex;
-    flex-direction: column;
-    gap: 10px;
-}
-
-.transport-one .t-row {
-    display: flex;
-    align-items: baseline;
-    gap: 10px;
-}
-
-.transport-one .t-row .time {
-    font-size: 13px;
-    font-weight: bold;
-    color: #f56c6c;
-}
-
-.transport-one .t-k {
-    width: 40px;
-    color: #909399;
-    font-size: 13px;
-}
-
-.transport-one .t-v {
-    color: #303133;
-    font-size: 14px;
-    line-height: 1.4;
-}
-
-.transport-one .t-row.sub .t-v {
-    color: #909399;
-    font-size: 13px;
-}
-
-/* Logs */
-.log-card {
-    background: #f4f4f5;
-    padding: 10px 15px;
-    border-radius: 4px;
-    position: relative;
-    top: -5px;
-    width: 100%;
-}
-
-.l-tit {
-    font-weight: bold;
-    font-size: 14px;
-    margin-bottom: 4px;
-    color: #303133;
-}
-
-.l-txt {
-    font-size: 13px;
-    color: #606266;
-    line-height: 1.5;
-}
-
-.section-block {
-    margin-bottom: 20px;
-}
-
-.sec-title-bar {
-    font-weight: bold;
-    font-size: 14px;
-    color: #303133;
-    margin-bottom: 12px;
-    padding-left: 8px;
-    border-left: 3px solid #409eff;
-}
-</style>

+ 0 - 52
src/views/order/management-bak/components/RemarkDialog.vue

@@ -1,52 +0,0 @@
-<template>
-  <el-dialog :model-value="visible" @update:model-value="updateVisible" title="订单备注" width="500px">
-    <div style="margin-bottom:10px; font-size:13px; color:#909399;">
-      <span v-if="data">订单号:{{ data.orderNo }}</span>
-    </div>
-    <el-input
-      v-model="remarkForm"
-      type="textarea"
-      :rows="5"
-      placeholder="请输入订单备注信息..."
-    />
-    <template #footer>
-      <span class="dialog-footer">
-        <el-button @click="updateVisible(false)">取消</el-button>
-        <el-button type="primary" @click="handleSubmit">保存备注</el-button>
-      </span>
-    </template>
-  </el-dialog>
-</template>
-
-<script setup>
-import { ref, watch } from 'vue'
-import { ElMessage } from 'element-plus'
-
-const props = defineProps({
-  visible: Boolean,
-  data: Object
-})
-
-const emit = defineEmits(['update:visible', 'success'])
-
-const remarkForm = ref('')
-
-watch(() => props.visible, (val) => {
-  if (val && props.data) {
-    remarkForm.value = props.data.remark || ''
-  }
-})
-
-const updateVisible = (val) => {
-  emit('update:visible', val)
-}
-
-const handleSubmit = () => {
-  if (props.data) {
-    props.data.remark = remarkForm.value
-    ElMessage.success('备注已更新')
-    updateVisible(false)
-    emit('success', remarkForm.value)
-  }
-}
-</script>

+ 0 - 101
src/views/order/management-bak/components/RewardDialog.vue

@@ -1,101 +0,0 @@
-<template>
-  <el-dialog :model-value="visible" @update:model-value="updateVisible" title="奖惩操作" width="500px">
-    <div v-if="data" style="padding: 0 10px;">
-      <div style="margin-bottom: 20px; font-size: 14px; color: #606266; line-height: 1.6; background: #fdf6ec; padding: 10px; border-radius: 4px;">
-        <div>奖惩履约者:<span style="font-weight: bold; color: #303133;">{{ data.fulfillerName || '未指派' }}</span></div>
-        <div style="font-size: 13px; margin-top: 4px;">订单号:{{ data.orderNo }}</div>
-        <div style="font-size: 13px; margin-top: 4px; display:flex; align-items:center; gap:6px;">
-          服务类型:
-          <el-tag :type="getTypeTag(data.type)" size="small">{{ getTypeName(data.type) }}</el-tag>
-          <el-tag v-if="data.type === 'transport' && data.transportType === 'round'" size="small" effect="plain" type="warning">往返</el-tag>
-          <el-tag v-if="data.splitType === 'pick'" size="small" effect="dark" color="#409eff" style="border:none; color:white;">接</el-tag>
-          <el-tag v-if="data.splitType === 'drop'" size="small" effect="dark" color="#67c23a" style="border:none; color:white;">送</el-tag>
-          <el-tag v-if="data.type === 'transport' && data.transportType === 'pick' && !data.splitType" size="small" effect="plain">单程接</el-tag>
-          <el-tag v-if="data.type === 'transport' && data.transportType === 'drop' && !data.splitType" size="small" effect="plain" type="success">单程送</el-tag>
-        </div>
-      </div>
-
-      <el-form :model="rewardForm" label-width="80px">
-        <el-form-item label="操作类型">
-          <el-radio-group v-model="rewardForm.type">
-            <el-radio label="reward">奖励 (增加)</el-radio>
-            <el-radio label="punish">惩罚 (扣除)</el-radio>
-          </el-radio-group>
-        </el-form-item>
-        <el-form-item label="调整项目">
-          <el-radio-group v-model="rewardForm.item">
-            <el-radio label="points">积分</el-radio>
-            <el-radio label="amount">金额 (元)</el-radio>
-          </el-radio-group>
-        </el-form-item>
-        <el-form-item label="数额" required>
-          <el-input-number v-model="rewardForm.value" :min="1" :step="10" />
-        </el-form-item>
-        <el-form-item label="原因备注" required>
-          <el-input
-            v-model="rewardForm.reason"
-            type="textarea"
-            :rows="3"
-            placeholder="请输入奖惩原因..."
-          />
-        </el-form-item>
-      </el-form>
-    </div>
-    <template #footer>
-      <el-button @click="updateVisible(false)">取消</el-button>
-      <el-button type="primary" @click="handleSubmit">确认执行</el-button>
-    </template>
-  </el-dialog>
-</template>
-
-<script setup>
-import { reactive, watch } from 'vue'
-import { ElMessage } from 'element-plus'
-
-const props = defineProps({
-  visible: Boolean,
-  data: Object
-})
-
-const emit = defineEmits(['update:visible', 'success'])
-
-const rewardForm = reactive({
-  type: 'reward',
-  item: 'points',
-  value: 10,
-  reason: ''
-})
-
-watch(() => props.visible, (val) => {
-  if (val) {
-    rewardForm.type = 'reward'
-    rewardForm.item = 'points'
-    rewardForm.value = 10
-    rewardForm.reason = ''
-  }
-})
-
-const getTypeTag = (type) => {
-  const map = { transport: '', feeding: 'warning', washing: 'success' }
-  return map[type]
-}
-
-const getTypeName = (type) => {
-  const map = { transport: '宠物接送', feeding: '上门喂遛', washing: '上门洗护' }
-  return map[type]
-}
-
-const updateVisible = (val) => {
-  emit('update:visible', val)
-}
-
-const handleSubmit = () => {
-  if (!rewardForm.reason) {
-    ElMessage.warning('请输入奖惩原因')
-    return
-  }
-  ElMessage.success(`操作成功:${rewardForm.type === 'reward' ? '奖励' : '惩罚'}已执行`)
-  updateVisible(false)
-  emit('success')
-}
-</script>

+ 0 - 2572
src/views/order/management-bak/index.vue

@@ -1,2572 +0,0 @@
-<template>
-  <div class="page-container">
-    <el-card shadow="never" class="table-card">
-      <template #header>
-        <div class="card-header">
-          <span class="title">订单列表</span>
-          <div class="right-panel">
-            <el-radio-group v-model="filters.orderType" size="default" @change="handleSearch">
-              <el-radio-button label="">全部类型</el-radio-button>
-              <el-radio-button v-for="item in serviceTypeList" :key="item.id" :label="item.id">{{ item.name
-              }}</el-radio-button>
-            </el-radio-group>
-            <el-input v-model="filters.keyword" placeholder="订单号/商户/宠主/手机号" class="search-input" prefix-icon="Search"
-              clearable @clear="handleSearch" @keyup.enter="handleSearch" />
-            <el-button type="primary" icon="Search" @click="handleSearch">查询</el-button>
-          </div>
-        </div>
-
-        <el-tabs v-model="filters.status" class="status-tabs" @tab-click="handleSearch">
-          <el-tab-pane label="全部订单" name="" />
-          <el-tab-pane label="待派单" name="0" />
-          <el-tab-pane label="待接单" name="1" />
-          <el-tab-pane label="服务中" name="2" />
-          <el-tab-pane label="待商家确认" name="3" />
-          <el-tab-pane label="已完成" name="4" />
-          <el-tab-pane label="已取消" name="5" />
-        </el-tabs>
-      </template>
-
-      <el-table :data="tableData" style="width: 100%" v-loading="loading"
-        :header-cell-style="{ background: '#f5f7fa' }">
-        <el-table-column prop="code" label="订单号" width="170" fixed="left" />
-
-        <el-table-column label="服务类型" width="190">
-          <template #default="{ row }">
-            <div class="service-type-cell">
-              <el-tag>{{ getServiceName(row.service) }}</el-tag>
-              <el-tag v-if="getServiceModeTag(row)" class="sub-tag" type="warning" effect="plain">{{
-                getServiceModeTag(row) }}</el-tag>
-              <el-tag v-if="getServiceOrderTypeTag(row)" class="sub-tag" :type="getServiceOrderTypeTag(row).type"
-                effect="dark">{{ getServiceOrderTypeTag(row).label }}</el-tag>
-            </div>
-          </template>
-        </el-table-column>
-
-        <el-table-column label="宠物信息" min-width="150">
-          <template #default="{ row }">
-            <div class="pet-info">
-              <el-avatar :size="30" :src="row.petAvatar" :class="'avatar-' + row.type">{{ row.petName?.charAt(0)
-              }}</el-avatar>
-              <div class="pet-detail">
-                <div class="pet-name">
-                  {{ row.petName }}
-                  <span class="pet-breed">{{ row.petBreed }}</span>
-                </div>
-              </div>
-            </div>
-          </template>
-        </el-table-column>
-
-        <el-table-column label="所属用户" width="120" prop="customerName">
-          <template #default="{ row }">
-            <span style="font-weight: 500">{{ row.customerName }}</span>
-          </template>
-        </el-table-column>
-
-        <el-table-column label="城市/区域" width="140">
-          <template #default="{ row }">
-            <div>{{ getCityDistrictText(row).city || '-' }}</div>
-            <div class="sub-text">{{ getCityDistrictText(row).district || '-' }}</div>
-          </template>
-        </el-table-column>
-
-        <el-table-column label="商户/下单人" min-width="160">
-          <template #default="{ row }">
-            <div class="merchant-info">
-              <div>{{ row.storeName }}</div>
-              <div class="sub-text" v-if="row.placerUsername">{{ row.placerUsername }}</div>
-            </div>
-          </template>
-        </el-table-column>
-
-        <el-table-column prop="createTime" label="下单时间" width="165" sortable>
-          <template #default="{ row }">
-            <span class="time-text">{{ row.createTime }}</span>
-          </template>
-        </el-table-column>
-
-        <el-table-column prop="serviceTime" label="预约服务时间" width="165" sortable>
-          <template #default="{ row }">
-            <span class="time-text">{{ row.serviceTime }}</span>
-          </template>
-        </el-table-column>
-
-        <el-table-column label="订单状态" width="100">
-          <template #default="{ row }">
-            <div class="status-cell">
-              <div class="status-dot" :class="'status-' + row.status"></div>
-              <span>{{ getStatusName(row.status) }}</span>
-            </div>
-          </template>
-        </el-table-column>
-
-        <el-table-column label="履约信息" width="140">
-          <template #default="{ row }">
-            <div v-if="row.fulfillerName" class="fulfiller-info">
-              <span class="fulfiller-name">{{ row.fulfillerName }}</span>
-              <span class="fulfiller-fee" v-if="row.price !== null && row.price !== undefined">¥{{ (row.price /
-                100).toFixed(2) }}</span>
-            </div>
-            <span v-else class="text-gray">暂未指派</span>
-          </template>
-        </el-table-column>
-
-        <el-table-column label="操作" width="200" fixed="right">
-          <template #default="{ row }">
-            <div class="op-cell">
-              <el-button link type="primary" size="small" @click="handleDetail(row)">详情</el-button>
-              <el-button v-if="row.status === 0" link type="success" size="small"
-                @click="openDispatchDialog(row)">派单</el-button>
-              <el-button v-if="[1, 2].includes(row.status)" link type="warning" size="small"
-                @click="openDispatchDialog(row)">重新派单</el-button>
-              <el-button v-if="[0, 1].includes(row.status)" link type="danger" size="small"
-                @click="handleCancel(row)">取消</el-button>
-
-              <el-dropdown v-if="[2, 3, 4].includes(row.status)" trigger="click"
-                @command="(cmd) => handleCommand(cmd, row)">
-                <span class="el-dropdown-link">
-                  更多<el-icon class="el-icon--right">
-                    <ArrowDown />
-                  </el-icon>
-                </span>
-                <template #dropdown>
-                  <el-dropdown-menu>
-                    <el-dropdown-item v-if="row.status === 3" command="complete">确认完成</el-dropdown-item>
-                    <el-dropdown-item v-if="[3, 4].includes(row.status)" command="care_summary">护理小结</el-dropdown-item>
-                    <el-dropdown-item command="reward">奖惩</el-dropdown-item>
-                    <el-dropdown-item command="remark">备注</el-dropdown-item>
-                  </el-dropdown-menu>
-                </template>
-              </el-dropdown>
-            </div>
-          </template>
-        </el-table-column>
-      </el-table>
-
-      <div class="pagination-container">
-        <el-pagination v-model:current-page="pagination.current" v-model:page-size="pagination.size"
-          :page-sizes="[10, 20, 50, 100]" layout="total, sizes, prev, pager, next, jumper" :total="pagination.total"
-          @size-change="handleSizeChange" @current-change="handleCurrentChange" />
-      </div>
-    </el-card>
-
-    <!-- 订单详情侧滑栏 -->
-    <el-drawer v-model="detailVisible" title="订单详情" direction="rtl" size="60%" class="order-detail-drawer">
-      <div class="detail-container" v-if="currentOrder">
-        <!-- 1. Header Status -->
-        <!-- 1. Header Status -->
-        <div class="detail-header">
-          <div class="left-head">
-            <span class="order-no">{{ currentOrder.orderNo }}</span>
-            <el-tag :type="getStatusTag(currentOrder.status)" effect="dark" class="status-tag">{{
-              getStatusName(currentOrder.status) }}</el-tag>
-            <el-tag effect="plain" class="type-tag"
-              :type="currentOrder.type === 'transport' ? '' : (currentOrder.type === 'feeding' ? 'warning' : 'danger')">
-              {{ getTypeName(currentOrder.type) }}
-            </el-tag>
-          </div>
-          <div class="right-head">
-            <!-- Action Buttons Group -->
-            <div class="detail-actions">
-              <template v-if="currentOrder.status === 0">
-                <el-button type="danger" plain icon="CircleClose" @click="handleCancel(currentOrder)">取消订单</el-button>
-              </template>
-
-              <template v-if="currentOrder.status === 3">
-                <el-button type="primary" icon="CircleCheck"
-                  @click="handleCommand('complete', currentOrder)">确认完成</el-button>
-              </template>
-
-              <template v-if="[3, 4].includes(currentOrder.status)">
-                <el-button icon="Notebook" @click="openCareSummary(currentOrder)">护理小结</el-button>
-              </template>
-
-              <el-dropdown trigger="click" @command="(cmd) => handleCommand(cmd, currentOrder)"
-                style="margin-left: 12px;">
-                <el-button icon="More">更多操作</el-button>
-                <template #dropdown>
-                  <el-dropdown-menu>
-                    <el-dropdown-item command="reward" icon="Trophy">奖惩操作</el-dropdown-item>
-                    <el-dropdown-item command="remark" icon="EditPen">订单备注</el-dropdown-item>
-                    <el-dropdown-item command="delete" v-if="[5, 4].includes(currentOrder.status)" divided icon="Delete"
-                      style="color: #f56c6c;">删除订单</el-dropdown-item>
-                  </el-dropdown-menu>
-                </template>
-              </el-dropdown>
-            </div>
-          </div>
-        </div>
-
-        <div class="detail-scroll-area">
-          <!-- 2. Progress Section -->
-          <div class="progress-section">
-            <el-steps :active="currentOrderSteps.active" finish-status="success" align-center class="custom-steps">
-              <el-step v-for="(step, index) in currentOrderSteps.steps" :key="index" :title="step.title"
-                :description="step.time" />
-            </el-steps>
-          </div>
-
-          <!-- 3. Top Info: Pet & User -->
-          <div class="top-info-row">
-            <!-- Left: Pet Info (Enhanced) -->
-            <div class="info-section pet-section">
-              <div class="sec-header">
-                <span class="label">宠物档案</span>
-                <el-tag size="small" effect="plain">{{ currentOrder.petBreed }}</el-tag>
-              </div>
-              <div class="pet-basic-row">
-                <el-avatar :size="50" :src="currentOrder.petAvatar" shape="square" class="pet-avatar-lg">{{
-                  (currentOrder.petName || '').charAt(0) }}</el-avatar>
-                <div class="pet-names">
-                  <div class="b-name">{{ currentOrder.petName }}
-                    <el-icon v-if="currentOrder.petGender === 'male'" color="#409eff">
-                      <Male />
-                    </el-icon>
-                    <el-icon v-else color="#f56c6c">
-                      <Female />
-                    </el-icon>
-                  </div>
-                  <div class="b-tags">
-                    <el-tag size="small" type="info">{{ currentOrder.petAge || '未知年龄' }}</el-tag>
-                    <el-tag size="small" type="info">{{ currentOrder.petWeight || '未知体重' }}</el-tag>
-                  </div>
-                </div>
-              </div>
-              <el-descriptions :column="2" size="small" class="pet-desc" border>
-                <el-descriptions-item label="绝育状态">{{ currentOrder.petSterilized ? '已绝育' : '未绝育'
-                }}</el-descriptions-item>
-                <el-descriptions-item label="疫苗状态"><span style="color:#67c23a">{{ currentOrder.petVaccine || '未知'
-                }}</span></el-descriptions-item>
-                <el-descriptions-item label="性格特点">{{ currentOrder.petCharacter || '温顺' }}</el-descriptions-item>
-                <el-descriptions-item label="健康状况">{{ currentOrder.petHealth || '健康' }}</el-descriptions-item>
-              </el-descriptions>
-            </div>
-
-            <!-- Right: User Info -->
-            <div class="info-section user-section">
-              <div class="sec-header">
-                <span class="label">用户信息</span>
-              </div>
-              <div class="user-content">
-                <div class="u-row">
-                  <el-avatar :size="40" :src="currentOrder.userAvatar">{{ (currentOrder.userName || '').charAt(0)
-                  }}</el-avatar>
-                  <div class="u-info">
-                    <div class="nm">{{ currentOrder.userName }}</div>
-                    <div class="ph">{{ currentOrder.contactPhone }}</div>
-                  </div>
-                </div>
-                <div class="addr-box">
-                  <div class="addr-label">服务地址</div>
-                  <div class="addr-txt">{{ currentOrder.city }}{{ currentOrder.district }} {{ currentOrder.address ||
-                    '' }}
-                  </div>
-                </div>
-              </div>
-            </div>
-          </div>
-
-          <!-- 4. Bottom Tabs -->
-          <el-tabs v-model="activeDetailTab" class="detail-tabs type-card">
-
-            <!-- Tab 1: Basic Info -->
-            <el-tab-pane label="订单基础信息" name="basic">
-              <div class="tab-pane-content">
-                <!-- A. General Order Info -->
-                <div class="section-block">
-                  <div class="sec-title-bar">基础业务信息</div>
-                  <el-descriptions :column="3" border size="default" class="custom-desc">
-                    <el-descriptions-item label="系统单号">{{ currentOrder.orderNo }}</el-descriptions-item>
-                    <el-descriptions-item label="服务类型">
-                      {{ getTypeName(currentOrder.type) }}
-                      <el-tag size="small" v-if="currentOrder.type === 'transport'" style="margin-left:5px"
-                        effect="light">{{
-                          getTransportModeName(currentOrder.transportType) }}</el-tag>
-                    </el-descriptions-item>
-
-                    <el-descriptions-item label="归属门店">{{ currentOrder.merchantName }} (平台代下单)</el-descriptions-item>
-                    <el-descriptions-item label="宠主信息">{{ currentOrder.userName }} / {{ currentOrder.contactPhone
-                    }}</el-descriptions-item>
-                    <el-descriptions-item label="服务费用" label-class-name="money-label">
-                      <span style="color:#f56c6c; font-weight:bold;">¥ {{ currentOrder.fulfillerFee }}</span>
-                    </el-descriptions-item>
-
-                    <el-descriptions-item label="预约时间">{{ getServiceTimeRange(currentOrder.serviceTime)
-                    }}</el-descriptions-item>
-                    <el-descriptions-item label="团购套餐">{{ currentOrder.groupBuyPackage || '未使用团购套餐'
-                    }}</el-descriptions-item>
-                    <el-descriptions-item label="创建时间">{{ currentOrder.createTime }}</el-descriptions-item>
-
-                    <el-descriptions-item label="订单备注" :span="3">
-                      {{ currentOrder.remark || '暂无备注' }}
-                    </el-descriptions-item>
-                  </el-descriptions>
-                </div>
-
-                <!-- B. Transport Specifics (Single Display) -->
-                <div v-if="currentOrder.type === 'transport'" class="section-block transport-split-block">
-                  <div class="sec-title-bar">接送任务详情</div>
-                  <div class="transport-grid">
-                    <!-- Pick Up Info (Only if pick or round) -->
-                    <div class="transport-card pick-card" v-if="['round', 'pick'].includes(currentOrder.transportType)">
-                      <div class="t-header">
-                        <div class="left-badges">
-                          <el-tag :type="currentOrder.type === 'feeding' ? 'warning' : ''" effect="dark">{{
-                            getTypeName(currentOrder.type) }}</el-tag>
-                          <el-tag size="small" effect="plain" class="sub-badge">接</el-tag>
-                        </div>
-                        <span class="time">{{ currentOrder.detail.pickTime || currentOrder.serviceTime }}</span>
-                      </div>
-                      <div class="t-body">
-                        <div class="row"><el-icon>
-                            <Location />
-                          </el-icon> <span class="addr">{{ currentOrder.detail.pickAddr }}</span></div>
-                        <div class="row sub"><el-icon>
-                            <User />
-                          </el-icon> {{ currentOrder.detail.pickContact || currentOrder.userName }} <el-icon>
-                            <Phone />
-                          </el-icon> {{ currentOrder.detail.pickPhone || currentOrder.contactPhone }}</div>
-                      </div>
-                    </div>
-                    <!-- Drop Off Info (Only if drop or round) -->
-                    <div class="transport-card drop-card" v-if="['round', 'drop'].includes(currentOrder.transportType)">
-                      <div class="t-header">
-                        <div class="left-badges">
-                          <el-tag :type="currentOrder.type === 'feeding' ? 'warning' : 'success'" effect="dark">{{
-                            getTypeName(currentOrder.type) }}</el-tag>
-                          <el-tag size="small" effect="plain" class="sub-badge">送</el-tag>
-                        </div>
-                        <span class="time">{{ currentOrder.detail.dropTime || '待定' }}</span>
-                      </div>
-                      <div class="t-body">
-                        <div class="row"><el-icon>
-                            <Location />
-                          </el-icon> <span class="addr">{{ currentOrder.detail.dropAddr }}</span></div>
-                        <div class="row sub"><el-icon>
-                            <User />
-                          </el-icon> {{ currentOrder.detail.dropContact || currentOrder.userName }} <el-icon>
-                            <Phone />
-                          </el-icon> {{ currentOrder.detail.dropPhone || currentOrder.contactPhone }}</div>
-                      </div>
-                    </div>
-                  </div>
-                </div>
-
-                <!-- C. Other Service Specifics -->
-                <div v-if="['feeding', 'washing'].includes(currentOrder.type)" class="section-block">
-                  <div class="sec-title-bar">服务执行要求</div>
-                  <el-descriptions :column="2" border size="default" class="custom-desc">
-                    <el-descriptions-item label="服务地址" :span="2">{{ currentOrder.detail.area || currentOrder.address
-                    }}</el-descriptions-item>
-                    <el-descriptions-item label="服务套餐">{{ currentOrder.detail.packageName }}</el-descriptions-item>
-                    <el-descriptions-item label="特殊要求">{{ currentOrder.detail.petStatus || '无' }}</el-descriptions-item>
-                  </el-descriptions>
-                </div>
-              </div>
-            </el-tab-pane>
-
-            <!-- Tab 2: Fulfiller Info -->
-            <el-tab-pane label="指派履约者" name="fulfiller">
-              <div class="tab-pane-content">
-                <div v-if="currentOrder.fulfillerName" class="fulfiller-card">
-                  <div class="f-left">
-                    <el-avatar :size="60" :src="currentOrder.fulfillerAvatar">{{ currentOrder.fulfillerName.charAt(0)
-                    }}</el-avatar>
-                  </div>
-                  <div class="f-right">
-                    <div class="f-row1">
-                      <span class="f-name">{{ currentOrder.fulfillerName }}</span>
-                      <el-tag size="small" type="primary" effect="plain" round>Lv1 普通</el-tag>
-                    </div>
-                    <div class="f-row2">
-                      <span>联系电话:{{ currentOrder.fulfillerPhone || '138****0000' }}</span>
-                      <span class="sep">|</span>
-                      <span>归属区域:{{ currentOrder.fulfillerStation || '朝阳一站' }}</span>
-                    </div>
-                    <div class="f-row3"
-                      style="margin-top: 8px; font-size: 13px; color: #606266; background: #f9fafe; padding: 8px; border-radius: 4px; display: flex; gap: 20px;">
-                      <span><span style="color:#909399;">指派时间:</span>{{ currentOrder.createTime }}</span>
-                      <span><span style="color:#909399;">接单时间:</span>{{ currentOrder.detail?.receiveTime ||
-                        currentOrder.serviceTime }}</span>
-                    </div>
-                  </div>
-                </div>
-                <div v-else class="empty-state">
-                  <el-result icon="info" title="暂无履约者" sub-title="该订单尚未指派履约人员"></el-result>
-                </div>
-              </div>
-            </el-tab-pane>
-
-            <!-- Tab 3: Service Progress -->
-            <el-tab-pane label="服务进度" name="service">
-              <div class="tab-pane-content">
-                <!-- Empty State for Pending Accept -->
-                <div v-if="serviceProgressSteps.length === 0" class="empty-progress"
-                  style="padding:40px; text-align:center; color:#909399;">
-                  <el-result icon="info" title="待接单" sub-title="履约者接单后将在此记录服务进度"></el-result>
-                </div>
-
-                <el-timeline style="padding: 10px 20px;" v-else>
-                  <el-timeline-item v-for="(step, index) in serviceProgressSteps" :key="index" :timestamp="step.time"
-                    placement="top" :color="step.color" :icon="step.icon" size="large">
-                    <div class="progress-card">
-                      <h4 class="p-title">{{ step.title }}</h4>
-                      <p class="p-desc">{{ step.desc }}</p>
-                      <div class="p-media" v-if="step.media && step.media.length">
-                        <div v-for="(item, i) in step.media" :key="i" class="media-item">
-                          <el-image v-if="item.type === 'image'" :src="item.url"
-                            :preview-src-list="step.media.map(m => m.url)" fit="cover" class="p-img"
-                            :preview-teleported="true" />
-                        </div>
-                      </div>
-                    </div>
-                  </el-timeline-item>
-                </el-timeline>
-              </div>
-            </el-tab-pane>
-
-            <!-- Tab 4: Logs -->
-            <el-tab-pane label="订单日志" name="logs">
-              <div class="tab-pane-content">
-                <div style="display: flex; justify-content: flex-end; margin-bottom: 15px;">
-                  <el-button type="primary" size="small" icon="Download" @click="handleExportLogs">导出日志Excel</el-button>
-                </div>
-                <el-timeline>
-                  <el-timeline-item v-for="(log, index) in (currentOrder.orderLogs || [])" :key="index"
-                    :timestamp="log.time" :type="log.type || 'primary'" :icon="log.icon" placement="top">
-                    <div class="log-card">
-                      <div class="l-tit">{{ log.title }}</div>
-                      <div class="l-txt">{{ log.content }}</div>
-                    </div>
-                  </el-timeline-item>
-
-                  <!-- Fallback Legacy Mock -->
-                  <el-timeline-item
-                    v-if="(!currentOrder.orderLogs || currentOrder.orderLogs.length === 0) && currentOrder.timeline"
-                    v-for="(log, idx) in currentOrder.timeline" :key="'old-' + idx" :timestamp="log.time"
-                    :type="log.type">
-                    {{ log.content }}
-                  </el-timeline-item>
-                </el-timeline>
-              </div>
-            </el-tab-pane>
-          </el-tabs>
-
-        </div>
-      </div>
-    </el-drawer>
-
-    <!-- 派单弹窗 (Enhanced) -->
-    <el-dialog v-model="dispatchDialogVisible" title="派单调度" width="900px" top="5vh" destroy-on-close append-to-body>
-      <div class="dispatch-dialog-content">
-        <!-- Top: Order Info (OrderDispatch Style) -->
-        <div class="dispatch-order-info" v-if="currentDispatchOrder">
-          <div class="list-card order-card" style="margin:0; box-shadow:none; cursor:default; border:none;">
-            <div class="card-left">
-              <div class="type-tag" :class="currentDispatchOrder.typeCode">
-                {{ getShortType(currentDispatchOrder.typeCode) }}
-              </div>
-            </div>
-            <div class="card-main">
-              <template v-if="currentDispatchOrder.typeCode === 'transport'">
-                <div class="row-addr" v-if="['round', 'pick'].includes(currentDispatchOrder.transportType)"
-                  :title="currentDispatchOrder.pickAddr">
-                  <span class="tag pick">取</span> {{ currentDispatchOrder.pickAddr }}
-                </div>
-                <div class="row-addr" v-if="['round', 'drop'].includes(currentDispatchOrder.transportType)"
-                  :title="currentDispatchOrder.dropAddr">
-                  <span class="tag drop">送</span> {{ currentDispatchOrder.dropAddr }}
-                </div>
-              </template>
-              <template v-else>
-                <div class="row-addr" :title="currentDispatchOrder.address">
-                  <span class="tag home">址</span> {{ currentDispatchOrder.address }}
-                </div>
-              </template>
-              <div class="row-time" style="margin-top: 4px;">
-                <el-icon>
-                  <Clock />
-                </el-icon> {{ currentDispatchOrder.time }}
-                <span class="days-tag" v-if="currentDispatchOrder.daysLater">{{ currentDispatchOrder.daysLater }}</span>
-              </div>
-            </div>
-          </div>
-        </div>
-
-        <!-- Current Rider Info (If Exists) -->
-        <div class="current-rider-section" v-if="currentRider">
-          <div class="select-header" style="margin-bottom:8px;">
-            <span class="tit">当前派单履约者</span>
-          </div>
-          <div class="list-card rider-card"
-            style="margin-bottom: 20px; border: 1px solid #e4e7ed; background:#fafafa; cursor:default;">
-            <div class="card-left relative">
-              <el-avatar :src="currentRider.avatar" :size="40" />
-              <div class="dot" :class="currentRider.status"></div>
-            </div>
-            <div class="card-main">
-              <div class="row-1" style="justify-content: space-between; align-items: flex-start; display: flex;">
-                <div style="display:flex; align-items:baseline; gap:8px;">
-                  <span class="r-name">{{ currentRider.name }}</span>
-                  <span class="r-phone">{{ currentRider.maskPhone }}</span>
-                </div>
-                <div class="status-right">
-                  <span class="status-badge" :class="currentRider.status">{{ getRiderStatusText(currentRider.status)
-                  }}</span>
-                </div>
-              </div>
-
-              <div class="row-2 categories-row" style="margin-top: 6px; display:flex; gap:4px; flex-wrap:wrap;">
-                <span v-for="cat in currentRider.categories" :key="cat" class="cat-tag"
-                  :class="getCategoryClass(cat)">{{
-                    cat }}</span>
-              </div>
-
-              <div class="row-3 time-row" style="margin-top: 4px;">
-                <span class="last-time">下一单: {{ (currentRider.status === 'offline' || currentRider.status ===
-                  'disabled') ?
-                  '--' : currentRider.lastServiceTime }}</span>
-              </div>
-            </div>
-          </div>
-        </div>
-
-        <!-- Middle: Rider Selection -->
-        <div class="dispatch-rider-select">
-          <div class="select-header">
-            <span class="tit">选择履约者 (下一单时间由近及远排序)</span>
-            <el-input v-model="dispatchSearchQuery" placeholder="搜索履约者姓名/手机号" prefix-icon="Search" clearable
-              style="width: 240px" />
-          </div>
-
-          <div class="rider-grid-wrapper">
-            <el-scrollbar height="400px">
-              <div class="rider-grid">
-                <div v-for="rider in filteredDispatchRiders" :key="rider.id" class="list-card rider-card select-card"
-                  :class="{ active: selectedRiderId === rider.id }" @click="selectedRiderId = rider.id">
-                  <!-- Reusing Rider Card Layout -->
-                  <div class="card-left relative">
-                    <el-avatar :src="rider.avatar" :size="40" />
-                    <div class="dot" :class="rider.status"></div>
-                  </div>
-                  <div class="card-main">
-                    <div class="row-1" style="justify-content: space-between; align-items: flex-start; display: flex;">
-                      <div style="display:flex; align-items:baseline; gap:8px;">
-                        <span class="r-name">{{ rider.name }}</span>
-                        <span class="r-phone">{{ rider.maskPhone }}</span>
-                      </div>
-                      <div class="status-right">
-                        <span class="status-badge" :class="rider.status">{{ getRiderStatusText(rider.status) }}</span>
-                      </div>
-                    </div>
-
-                    <div class="row-2 categories-row" style="margin-top: 6px; display:flex; gap:4px; flex-wrap:wrap;">
-                      <span v-for="cat in rider.categories" :key="cat" class="cat-tag" :class="getCategoryClass(cat)">{{
-                        cat
-                      }}</span>
-                    </div>
-
-                    <div class="row-3 time-row" style="margin-top: 4px;">
-                      <span class="last-time">下一单: {{ (rider.status === 'offline' || rider.status === 'disabled') ? '--'
-                        :
-                        rider.lastServiceTime }}</span>
-                    </div>
-                  </div>
-
-                  <!-- Selected Check -->
-                  <div class="selected-mark" v-if="selectedRiderId === rider.id">
-                    <el-icon>
-                      <Check />
-                    </el-icon>
-                  </div>
-                </div>
-
-                <div v-if="filteredDispatchRiders.length === 0" class="empty-text">暂无符合条件的履约者</div>
-              </div>
-            </el-scrollbar>
-          </div>
-        </div>
-
-        <!-- Bottom: Fee & Submit -->
-        <div class="dispatch-footer">
-          <div class="fee-input">
-            <span class="label">服务费用:</span>
-            <el-input-number v-model="dispatchFee" :min="0" :precision="2" :step="10" placeholder="请输入"
-              style="width: 140px;" />
-            <span class="unit">元</span>
-          </div>
-          <div class="btns">
-            <el-button @click="dispatchDialogVisible = false">取消</el-button>
-            <el-button type="primary" @click="handleDispatchSubmit">确认派单</el-button>
-          </div>
-        </div>
-      </div>
-    </el-dialog>
-
-    <!-- 护理小结侧滑栏 -->
-    <CareSummaryDrawer v-model:visible="careSummaryVisible" :order="careSummaryOrder"
-      @success="handleCareSummarySuccess" />
-
-    <!-- 奖惩弹窗 -->
-    <RewardDialog v-model:visible="rewardDialogVisible" :data="currentOperateRow" />
-
-    <!-- 备注弹窗 -->
-    <RemarkDialog v-model:visible="remarkDialogVisible" :data="currentOperateRow" />
-
-  </div>
-</template>
-
-<script setup>
-import { ref, reactive, onMounted, computed } from 'vue'
-import { ElMessage, ElMessageBox } from 'element-plus'
-import OrderDetailDrawer from './components/OrderDetailDrawer.vue'
-import RewardDialog from './components/RewardDialog.vue'
-import RemarkDialog from './components/RemarkDialog.vue'
-import CareSummaryDrawer from './components/CareSummaryDrawer.vue'
-import { listServiceOnOrder } from '@/api/service/list'
-import { listSubOrderOnMerchant } from '@/api/order/subOrder/index'
-import { listOnStore } from '@/api/system/areaStation'
-
-const loading = ref(false)
-const detailVisible = ref(false)
-const dispatchVisible = ref(false)
-const currentOrder = ref(null)
-const serviceTypeList = ref([])
-const areaStationList = ref([])
-
-const filters = reactive({
-  orderType: '',
-  status: '',
-  keyword: ''
-})
-
-const pagination = reactive({
-  current: 1,
-  size: 10,
-  total: 100
-})
-
-const dispatchForm = reactive({
-  orderId: null,
-  fulfillerId: null,
-  fee: 0,
-  remark: ''
-})
-
-// Mocks
-const fulfillerOptions = ref([
-  { id: 101, name: '王大力', distance: '1.2km' },
-  { id: 102, name: '张小美', distance: '3.5km' },
-  { id: 103, name: '李建国', distance: '0.8km' }
-])
-
-const tableData = ref([])
-
-const mockData = [
-  // 宠物接送 - 待派单 (往返)
-  {
-    id: 1,
-    orderNo: 'ORD202402048801',
-    type: 'transport',
-    transportType: 'round', // 往返
-    petName: '旺财',
-    petBreed: '金毛',
-    petAvatar: '',
-    userName: '李先生',
-    city: '北京市',
-    district: '朝阳区',
-    createTime: '2024-02-04 09:30',
-    merchantName: '爱宠生活馆 (三里屯店)',
-    contactPhone: '13812345678',
-    serviceTime: '2024-02-05 10:00',
-    status: 0,
-    fulfillerName: '',
-    fulfillerFee: 0,
-    detail: {
-      pickAddr: '朝阳区三里屯SOHO B座',
-      pickContact: '张先生',
-      pickPhone: '138xxxx',
-      pickTime: '10:00',
-      dropAddr: '朝阳区某某宠物医院',
-      dropContact: '前台',
-      dropPhone: '010-xxxx',
-    },
-    timeline: [{ time: '2024-02-04 09:30', content: '商户下单成功', type: 'primary' }]
-  },
-  // 宠物接送 - 待接单 (单程接)
-  {
-    id: 2,
-    orderNo: 'ORD202402048802',
-    type: 'transport',
-    transportType: 'pick', // 单程接
-    petName: 'Bella',
-    petBreed: '拉布拉多',
-    petAvatar: '',
-    userName: '赵女士',
-    city: '北京市',
-    district: '海淀区',
-    createTime: '2024-02-04 10:00',
-    merchantName: '爱宠生活馆 (国贸店)',
-    contactPhone: '13911112222',
-    serviceTime: '2024-02-05 14:00',
-    status: 1,
-    fulfillerName: '王大力',
-    fulfillerFee: 35.00,
-    detail: {
-      pickAddr: '海淀区万柳书院',
-      pickContact: '李女士',
-      pickPhone: '139xxxx',
-      pickTime: '14:00',
-      dropAddr: '',
-    },
-    timeline: [
-      { time: '2024-02-04 10:00', content: '下单成功', type: 'info' },
-      { time: '2024-02-04 10:30', content: '已派单给 王大力', type: 'primary' }
-    ]
-  },
-  // 宠物接送 - 服务中 (单程送)
-  {
-    id: 3,
-    orderNo: 'ORD202402048803',
-    type: 'transport',
-    transportType: 'drop', // 单程送
-    petName: 'Cookie',
-    petBreed: '柯基',
-    petAvatar: '',
-    userName: '王先生',
-    city: '北京市',
-    district: '朝阳区',
-    createTime: '2024-02-04 12:00',
-    merchantName: '爱宠生活馆 (中关村店)',
-    contactPhone: '13612345678',
-    serviceTime: '2024-02-04 18:00',
-    status: 2,
-    fulfillerName: '张小美',
-    fulfillerFee: 40.00,
-    detail: {
-      pickAddr: '', // 单程送不需要接的详细起始点,实际业务中是已在店
-      dropAddr: '朝阳公园西门',
-      dropContact: '王先生',
-      dropPhone: '136xxxx',
-    },
-    timeline: [
-      { time: '2024-02-04 12:00', content: '下单成功', type: 'info' },
-      { time: '2024-02-04 17:50', content: '履约者出发', type: 'primary' }
-    ]
-  },
-  // 上门喂遛 - 待派单
-  {
-    id: 4,
-    orderNo: 'ORD202402048804',
-    type: 'feeding',
-    petName: '咪咪',
-    petBreed: '布偶猫',
-    petAvatar: '',
-    userName: '李女士',
-    city: '上海市',
-    district: '徐汇区',
-    createTime: '2024-02-04 12:00',
-    merchantName: '爱宠生活馆 (三里屯店)',
-    contactPhone: '13987654321',
-    serviceTime: '2024-02-06 12:00',
-    status: 0,
-    fulfillerName: '',
-    fulfillerFee: 0,
-    detail: {
-      packageName: '春节上门喂猫7天套餐',
-      currentCount: 1,
-      totalCount: 7,
-      area: '客厅、阳台',
-      itemLoc: '厨房柜子里',
-      cleanLoc: '卫生间洗手台',
-      foodAmount: '每次一罐头 + 半碗粮',
-    },
-    timeline: [{ time: '2024-02-04 12:00', content: '订单创建', type: 'info' }]
-  },
-  // 上门喂遛 - 服务中
-  {
-    id: 5,
-    orderNo: 'ORD202402048805',
-    type: 'feeding',
-    petName: '大黄',
-    petBreed: '中华田园犬',
-    petAvatar: '',
-    userName: '张先生',
-    city: '杭州市',
-    district: '西湖区',
-    createTime: '2024-02-04 12:30',
-    merchantName: '爱宠生活馆 (国贸店)',
-    contactPhone: '13555555555',
-    serviceTime: '2024-02-04 14:00',
-    status: 2,
-    fulfillerName: '李建国',
-    fulfillerFee: 50.00,
-    detail: {
-      packageName: '上门遛狗1小时',
-      currentCount: 1,
-      totalCount: 1,
-      area: '小区公园',
-      itemLoc: '门口鞋柜处',
-      cleanLoc: '楼下垃圾桶',
-      foodAmount: '-',
-    },
-    timeline: [
-      { time: '2024-02-04 12:00', content: '张小美 已接单', type: 'primary' },
-      { time: '2024-02-04 13:55', content: '履约者到达并在门口打卡', type: 'success', media: ['https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg'] }
-    ]
-  },
-  // 上门洗护 - 待接单
-  {
-    id: 6,
-    orderNo: 'ORD202402048806',
-    type: 'washing',
-    petName: '豆豆',
-    petBreed: '泰迪',
-    petAvatar: '',
-    userName: '刘小姐',
-    city: '深圳市',
-    district: '南山区',
-    createTime: '2024-02-04 15:00',
-    merchantName: '爱宠生活馆 (三里屯店)',
-    contactPhone: '13666666666',
-    serviceTime: '2024-02-04 16:00',
-    status: 1,
-    fulfillerName: '王大力',
-    fulfillerFee: 80.00,
-    detail: {
-      packageName: '精致洗护套餐',
-      petStatus: '胆小,怕吹风机',
-      area: '浴室',
-      cleanLoc: '浴室淋浴间',
-      toolLoc: '自带工具箱',
-    },
-    timeline: [
-      { time: '2024-02-04 15:00', content: '订单创建', type: 'info' },
-      { time: '2024-02-04 15:05', content: '派单给 王大力', type: 'primary' }
-    ]
-  },
-  // 上门洗护 - 已取消
-  {
-    id: 7,
-    orderNo: 'ORD202402047701',
-    type: 'washing',
-    petName: 'Snow',
-    petBreed: '萨摩耶',
-    petAvatar: '',
-    userName: 'Zhao',
-    city: '北京市',
-    district: '朝阳区',
-    createTime: '2024-02-02 10:00',
-    merchantName: '爱宠生活馆 (国贸店)',
-    contactPhone: '13777777777',
-    serviceTime: '2024-02-03 09:00',
-    status: 5,
-    fulfillerName: '',
-    fulfillerFee: 0,
-    detail: { packageName: '洗澡+美容', petStatus: '温顺' },
-    timeline: [
-      { time: '2024-02-02 10:00', content: '订单创建', type: 'info' },
-      { time: '2024-02-02 12:00', content: '用户取消订单', type: 'warning' }
-    ]
-  },
-  // 宠物接送 - 已完成 (往返)
-  {
-    id: 8,
-    orderNo: 'ORD202402038899',
-    type: 'transport',
-    transportType: 'round',
-    petName: 'Cooper',
-    petBreed: '法斗',
-    petAvatar: '',
-    userName: '孙女士',
-    city: '北京市',
-    district: '通州区',
-    createTime: '2024-02-03 09:00',
-    merchantName: '爱宠生活馆 (三里屯店)',
-    contactPhone: '13333333333',
-    serviceTime: '2024-02-03 10:00',
-    status: 4,
-    fulfillerName: '张小美',
-    fulfillerFee: 65.00,
-    detail: {
-      pickAddr: '朝阳大悦城',
-      dropAddr: '瑞鹏宠物医院',
-    },
-    timeline: [
-      { time: '2024-02-03 09:00', content: '订单创建', type: 'info' },
-      { time: '2024-02-03 11:30', content: '服务完成', type: 'success' }
-    ]
-  },
-  // 待商家确认
-  {
-    id: 99,
-    orderNo: 'ORD202402048999',
-    type: 'feeding',
-    petName: '小黑',
-    petBreed: '拉布拉多',
-    petAvatar: '',
-    userName: '周先生',
-    city: '北京市',
-    district: '海淀区',
-    createTime: '2024-02-04 14:00',
-    merchantName: '爱宠生活馆 (三里屯店)',
-    contactPhone: '13811112222',
-    serviceTime: '2024-02-04 16:00',
-    status: 3,
-    fulfillerName: '赵铁柱',
-    fulfillerFee: 45.00,
-    detail: {
-      packageName: '上门喂遛',
-      area: '小区内部',
-    },
-    timeline: [
-      { time: '2024-02-04 14:00', content: '订单创建', type: 'info' },
-      { time: '2024-02-04 14:05', content: '赵铁柱 已接单', type: 'primary' },
-      { time: '2024-02-04 16:30', content: '履约者完成服务,等待商家确认', type: 'warning' }
-    ]
-  }
-]
-
-const fetchServiceTypes = async () => {
-  try {
-    const res = await listServiceOnOrder()
-    serviceTypeList.value = res.data || []
-  } catch (error) {
-    console.error('获取服务类型失败:', error)
-  }
-}
-
-const fetchAreaStations = async () => {
-  try {
-    const res = await listOnStore()
-    areaStationList.value = res.data || []
-  } catch (error) {
-    console.error('获取区域站点失败:', error)
-  }
-}
-
-onMounted(() => {
-  fetchServiceTypes()
-  fetchAreaStations()
-  handleSearch()
-})
-
-const handleSearch = async () => {
-  loading.value = true
-  try {
-    const params = {
-      content: filters.keyword || undefined,
-      service: filters.orderType || undefined,
-      status: filters.status || undefined,
-      pageNum: pagination.current,
-      pageSize: pagination.size
-    }
-    const res = await listSubOrderOnMerchant(params)
-    if (res) {
-      tableData.value = res.rows || []
-      pagination.total = res.total || 0
-    } else {
-      tableData.value = []
-      pagination.total = 0
-    }
-  } catch (error) {
-    console.error('获取订单列表失败:', error)
-    tableData.value = []
-    pagination.total = 0
-  } finally {
-    loading.value = false
-  }
-}
-
-const handleSizeChange = (val) => {
-  pagination.size = val
-  handleSearch()
-}
-const handleCurrentChange = (val) => {
-  pagination.current = val
-  handleSearch()
-}
-
-const getTypeTag = (type) => {
-  const map = { transport: '', feeding: 'warning', washing: 'success' }
-  return map[type]
-}
-const getTypeName = (type) => {
-  const map = { transport: '宠物接送', feeding: '上门喂遛', washing: '上门洗护' }
-  return map[type]
-}
-
-const getServiceName = (serviceId) => {
-  const service = serviceTypeList.value.find(s => s.id === serviceId)
-  return service ? service.name : '未知服务'
-}
-
-const getServiceModeTag = (row) => {
-  if (row.mode === 1 || row.mode === '1') {
-    return '往返'
-  }
-  return null
-}
-
-const getServiceOrderTypeTag = (row) => {
-  const t = row.type
-  if (t === 0 || t === '0' || t === 1 || t === '1') return null
-  if (t === 2 || t === '2') return { label: '接', type: 'primary' }
-  if (t === 3 || t === '3') return { label: '送', type: 'success' }
-  return null
-}
-
-const getCityDistrictText = (row) => {
-  if (!row.site) return { city: '-', district: '-' }
-
-  const findArea = (id) => {
-    return areaStationList.value.find(item =>
-      item.id === id || item.id === String(id) || String(item.id) === String(id)
-    )
-  }
-
-  // site是站点ID,type=2
-  const station = findArea(row.site)
-  if (!station) return { city: '-', district: '-' }
-
-  // 站点的parentId是区域,type=1
-  const district = findArea(station.parentId)
-  if (!district) return { city: station.name || '-', district: '-' }
-
-  // 区域的parentId是城市,type=0
-  const city = findArea(district.parentId)
-
-  return {
-    city: city ? city.name : '-',
-    district: district.name || '-'
-  }
-}
-
-const getStatusName = (status) => {
-  const map = { 0: '待派单', 1: '待接单', 2: '服务中', 3: '待商家确认', 4: '已完成', 5: '已取消' }
-  return map[status] || '未知'
-}
-
-const getStatusTag = (status) => {
-  const map = {
-    0: 'danger',
-    1: 'warning',
-    2: 'primary',
-    3: 'warning',
-    4: 'success',
-    5: 'info'
-  }
-  return map[status] || 'info'
-}
-
-const getStepActive = (status) => {
-  // Kept for table list if needed, but detail now uses computed steps below
-  if (status === 'pending_dispatch') return 1
-  if (status === 'pending_accept') return 2
-  if (status === 'serving') return 3
-  if (status === 'pending_confirm') return 4
-  if (status === 'completed') return 6
-  if (status === 'cancelled') return 0
-  return 0
-}
-
-const getTransportModeName = (type) => {
-  const map = { round: '往返接送', pick: '单程接(到店)', drop: '单程送(回家)' }
-  return map[type] || '接送服务'
-}
-
-// Generate dynamic steps with times for detail view
-const currentOrderSteps = computed(() => {
-  if (!currentOrder.value) return { active: 0, steps: [] }
-
-  // Base timeline nodes
-  const steps = [
-    { title: '商户下单', status: 'created', time: '' },
-    { title: '运营派单', status: 'dispatched', time: '' },
-    { title: '履约接单', status: 'accepted', time: '' },
-    { title: '服务中', status: 'serving', time: '' }, // Includes arrival/start
-    { title: '待商家确认', status: 'confirming', time: '' }, // Finished service
-    { title: '已完成', status: 'completed', time: '' }
-  ]
-
-  const logs = currentOrder.value.orderLogs || []
-  const status = currentOrder.value.status
-
-  let active = 0
-
-  // Map logs to steps time
-  // This is a simple mapper, in real app would match specific log types/codes
-  const findTime = (keyword) => {
-    const log = logs.find(l => l.title.includes(keyword) || l.content.includes(keyword))
-    return log ? log.time : ''
-  }
-
-  // 1. Created
-  steps[0].time = currentOrder.value.createTime || findTime('下单') || findTime('创建')
-  if (steps[0].time) active = 1
-
-  // 2. Dispatched
-  steps[1].time = findTime('派单') || (status !== 0 ? steps[0].time : '') // Mock if passed
-  if ([1, 2, 3, 4].includes(status)) active = 2
-
-  // 3. Accepted
-  steps[2].time = findTime('接单')
-  if (status === 1) {
-    steps[2].title = '待履约者接单'
-  } else if ([2, 3, 4].includes(status)) {
-    steps[2].title = '履约者已接单'
-    active = 3
-  }
-
-  // 4. Serving (Arrival/Start)
-  steps[3].time = findTime('到达') || findTime('出发')
-  if (status === 2) {
-    steps[3].title = '服务进行中'
-  } else if ([3, 4].includes(status)) {
-    steps[3].title = '服务已完成'
-    active = 4
-  }
-
-  // 5. Confirming
-  steps[4].time = findTime('等待商家确认') || findTime('待验收')
-  if (status === 3) {
-    steps[4].title = '待商家确认'
-  } else if (status === 4) {
-    steps[4].title = '商家已确认'
-    active = 5
-  }
-
-  // 6. Completed
-  if (status === 4) {
-    steps[5].time = findTime('完成') // or calculate based on logic
-    active = 6
-  }
-
-  if (status === 5) {
-    // Handle cancelled state simply or insert a cancelled step
-    return {
-      active: 1,
-      steps: [
-        { title: '商户下单', time: steps[0].time },
-        { title: '已取消', time: findTime('取消') || '订单已取消' }
-      ]
-    }
-  }
-
-  return { active, steps }
-})
-
-const activeDetailTab = ref('basic')
-
-const handleDetail = (row) => {
-  const typeName = getServiceName(row?.service)
-  const isTransport = row?.mode === 1 || row?.mode === '1'
-  const typeCode = isTransport ? 'transport' : typeName?.includes('喂') || typeName?.includes('遛') ? 'feeding' : 'washing'
-
-  currentOrder.value = {
-    ...row,
-    orderNo: row?.code || row?.orderCode || row?.orderNo || row?.orderNumber || row?.no || '',
-    type: row?.typeCode || row?.type || typeCode,
-    serviceItem: getServiceName(row?.service) || row?.serviceName || row?.service || '',
-    userAvatar: 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png',
-    address: '某小区5号楼2单元101',
-    groupBuyPackage: '',
-    transportType: row.splitType || row.transportType,
-    detail: {
-      ...row.detail,
-      pickTime: '2024-02-05 09:30',
-      pickAddr: row.detail?.pickAddr || '北京市朝阳区某小区5号楼2单元101',
-      pickContact: '李先生',
-      pickPhone: '13812345678',
-      dropTime: '2024-02-05 18:30',
-      dropAddr: row.detail?.dropAddr || '北京市朝阳区某小区5号楼2单元101',
-      dropContact: '李先生',
-      dropPhone: '13812345678',
-      packageName: row.detail?.packageName || '精细洗护套餐A',
-      petStatus: '胆小,需安抚',
-      area: '北京市朝阳区某小区5号楼2单元101'
-    },
-    petGender: 'male',
-    petAge: '2岁',
-    petWeight: '15kg',
-    petVaccine: '已接种',
-    petSterilized: true,
-    petCharacter: '活泼好动,喜欢球类玩具',
-    petHealth: '健康良好',
-    fulfillerAvatar: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png',
-    fulfillerPhone: '13812345678',
-    fulfillerStation: '朝阳服务站',
-    orderLogs: [
-      { time: '2024-02-04 09:30', title: '订单创建', content: '商户提交订单', icon: 'Document' },
-      { time: '2024-02-04 10:00', title: '系统派单', content: '指派给 王大力', icon: 'Bicycle' },
-      { time: '2024-02-04 10:05', title: '接单成功', content: '履约者已确认接单', icon: 'CircleCheck' },
-      { time: '2024-02-04 13:55', title: '到达服务点', content: '履约者已打卡', icon: 'Location' }
-    ]
-  }
-  activeDetailTab.value = 'basic'
-  detailVisible.value = true
-}
-
-
-// --- Dispatch Dialog Logic (Copied from OrderDispatch) ---
-const ridersList = ref([
-  {
-    id: 101, name: '王大力', station: '朝阳站', phone: '13800138000', maskPhone: '138****8000',
-    status: 'online', categories: ['接送', '喂遛'], lastServiceTime: '2024-02-07 11:00',
-    avatar: 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png',
-    pendingCount: 0, todoCount: 2, lng: 116.460, lat: 39.920
-  },
-  {
-    id: 102, name: '李小龙', station: '海淀站', phone: '13912345678', maskPhone: '139****5678',
-    status: 'online', categories: ['接送', '洗护'], lastServiceTime: '2024-02-07 10:30',
-    avatar: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png',
-    pendingCount: 1, todoCount: 3, lng: 116.450, lat: 39.915
-  },
-  {
-    id: 103, name: '张小美', station: '望京站', phone: '13666666666', maskPhone: '136****6666',
-    status: 'online', categories: ['喂遛'], lastServiceTime: '2024-02-07 10:45',
-    avatar: '',
-    pendingCount: 0, todoCount: 0, lng: 116.470, lat: 39.930
-  },
-  {
-    id: 104, name: '赵铁柱', station: '通州站', phone: '13555555555', maskPhone: '135****5555',
-    status: 'offline', categories: ['接送'], lastServiceTime: '2024-02-06 18:00',
-    avatar: '',
-    pendingCount: 0, todoCount: 0, lng: 116.440, lat: 39.910
-  },
-  {
-    id: 105, name: '孙悟空', station: '花果山', phone: '13888888888', maskPhone: '138****8888',
-    status: 'online', categories: ['接送', '喂遛', '洗护'], lastServiceTime: '2024-02-07 09:30',
-    avatar: '',
-    pendingCount: 0, todoCount: 1, lng: 116.480, lat: 39.925
-  }
-])
-
-const serviceProgressSteps = computed(() => {
-  const order = currentOrder.value
-  if (!order) return []
-
-  // 1. Pending / Waiting for Rider: No progress yet
-  // Strict requirement: "待接单时应该为空"
-  if ([0, 1, 5].includes(order.status)) {
-    return []
-  }
-
-  const baseTime = order.serviceTime || '2024-02-10 10:00'
-  const datePart = baseTime.split(' ')[0]
-  const isTransport = order.type === 'transport'
-
-  let steps = []
-
-  // --- Step 1: Accepted (Start for Serving+) ---
-  steps.push({
-    title: '已接单',
-    time: `${datePart} 09:30`,
-    icon: 'Bicycle',
-    color: '#ff9900', // Active color
-    desc: `履约者 ${order.fulfillerName || '当前履约者'} 已确认接单,准备前往服务地点`,
-    media: []
-  })
-
-  // --- Step 2: Arrived (Assume arrived if serving) ---
-  steps.push({
-    title: '到达打卡',
-    time: `${datePart} 09:50`,
-    icon: 'Location',
-    color: '#ff9900',
-    desc: '已到达指定位置,打卡确认',
-    media: [
-      { type: 'image', url: 'https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg' }
-    ]
-  })
-
-  if (isTransport) {
-    // Transport Flow
-    // --- Step 3: Depart (Active in Serving) ---
-    steps.push({
-      title: '确认出发',
-      time: `${datePart} 10:10`,
-      icon: 'Van',
-      color: '#ff9900',
-      desc: '接到宠物,状态良好,开始运输。备注:宠物很乖,已放入航空箱。',
-      media: [
-        { type: 'image', url: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg' },
-        { type: 'image', url: 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg' }
-      ]
-    })
-
-    // --- Step 4: Deliver (Only if Confirming or Completed) ---
-    if ([3, 4].includes(order.status)) {
-      steps.push({
-        title: '送达打卡',
-        time: `${datePart} 10:50`,
-        icon: 'Place',
-        color: '#ff9900',
-        desc: '宠物已安全送达目的地,等待商家验收',
-        media: [
-          { type: 'image', url: 'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg' }
-        ]
-      })
-    }
-  } else {
-    // Service Flow
-    // --- Step 3: Start Service (Active in Serving) ---
-    steps.push({
-      title: '开始服务',
-      time: `${datePart} 10:00`,
-      icon: 'VideoPlay',
-      color: '#ff9900',
-      desc: '已确认宠物状态,开始进行服务视频录制',
-      media: [
-        { type: 'image', url: 'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg' }
-      ]
-    })
-
-    // --- Step 4: End Service (Only if Confirming or Completed) ---
-    if ([3, 4].includes(order.status)) {
-      steps.push({
-        title: '服务结束',
-        time: `${datePart} 10:50`,
-        icon: 'VideoPause',
-        color: '#ff9900',
-        desc: '服务项目已全部完成,清理现场完毕。备注:狗狗今天很配合,完成了梳毛和喂食。',
-        media: [
-          { type: 'image', url: 'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg' },
-          { type: 'image', url: 'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg' }
-        ]
-      })
-    }
-  }
-
-  // --- Step 5: Wait Confirm (Only if Confirming or Completed) ---
-  if ([3, 4].includes(order.status)) {
-    steps.push({
-      title: '待商家确认',
-      time: `${datePart} 10:55`,
-      icon: 'Clock',
-      color: '#ff9900',
-      desc: '履约者已提交完成信息,等待商家确认订单',
-      media: []
-    })
-  }
-
-  // --- Step 6: Completed (Only if Completed) ---
-  if (order.status === 4) {
-    steps.push({
-      title: '订单完成',
-      time: `${datePart} 11:00`,
-      icon: 'Select',
-      color: '#67C23A',
-      desc: '用户/商家已确认,服务圆满结束',
-      media: []
-    })
-  }
-
-  return steps
-})
-
-const dispatchDialogVisible = ref(false)
-const currentDispatchOrder = ref(null)
-const currentRider = ref(null)
-const dispatchSearchQuery = ref('')
-const selectedRiderId = ref(null)
-const dispatchFee = ref(0) // Default fee
-
-const openDispatchDialog = (row) => {
-  // Map table row to order card structure if needed, or use row directly if fields match
-  // OrderDispatch uses: pickAddr, dropAddr, address, typeCode, daysLater, time
-  // OrderList row has: detail.pickAddr/dropAddr, type, serviceTime (as time), etc.
-  // We need to adapt the row to 'currentDispatchOrder' structure expected by dialog template
-
-  // Construct dispatch order object
-  let orderObj = {
-    id: row.id,
-    typeCode: row.type,
-    transportType: row.splitType || row.transportType, // Add transportType
-    time: row.serviceTime,
-    status: row.status,
-    daysLater: getDaysLater(row.serviceTime), // Need helper
-    address: '', // generic address for feeding/washing
-    pickAddr: '',
-    dropAddr: '',
-    riderId: ([1, 2].includes(row.status)) ? getRiderIdByName(row.fulfillerName) : null // Mock finding rider ID
-  }
-
-  if (row.type === 'transport') {
-    orderObj.pickAddr = row.detail.pickAddr
-    orderObj.dropAddr = row.detail.dropAddr
-  } else {
-    // Feeding/Washing address isn't in main row usually, let's assume city+district or from detail if we had it
-    // row.city + row.district is available.
-    // We will just use row.city + row.district for display in card for now, or add address to mock data details.
-    // Actually, OrderList mock has detailed addresses implicit in description?
-    // Let's use City + District + "详细地址" placeholder or row.detail.address if strictly needed.
-    // For visual, let's just use City+District.
-    orderObj.address = row.city + row.district
-  }
-
-  currentDispatchOrder.value = orderObj
-
-  // Set Current Rider Logic
-  if (orderObj.riderId) {
-    currentRider.value = ridersList.value.find(r => r.id === orderObj.riderId) || null
-  } else {
-    currentRider.value = null
-  }
-
-  dispatchDialogVisible.value = true
-  dispatchSearchQuery.value = ''
-  selectedRiderId.value = null
-  dispatchFee.value = 0
-}
-
-const handleDispatchSubmit = () => {
-  if (!selectedRiderId.value) {
-    ElMessage.warning('请选择履约者')
-    return
-  }
-  if (!dispatchFee.value) {
-    ElMessage.warning('请输入服务费用')
-    return
-  }
-  dispatchDialogVisible.value = false
-  ElMessage.success('派单成功')
-
-  // Update local list
-  if (currentDispatchOrder.value) {
-    const row = tableData.value.find(r => r.id === currentDispatchOrder.value.id)
-    if (row) {
-      row.status = 1
-      const rider = ridersList.value.find(r => r.id === selectedRiderId.value)
-      row.fulfillerName = rider ? rider.name : 'Unknown'
-      row.fulfillerFee = dispatchFee.value
-    }
-  }
-}
-
-const handleExportLogs = () => {
-  const logs = currentOrder.value.orderLogs || []
-  if (logs.length === 0) {
-    ElMessage.warning('暂无日志可导出')
-    return
-  }
-
-  let csvContent = "时间,类型,标题,内容\n"
-  logs.forEach(log => {
-    const time = log.time || ''
-    const type = log.type || ''
-    const title = (log.title || '').replace(/"/g, '""')
-    const content = (log.content || '').replace(/"/g, '""')
-    csvContent += `${time},${type},"${title}","${content}"\n`
-  })
-
-  const blob = new Blob(["\uFEFF" + csvContent], { type: 'text/csv;charset=utf-8;' })
-  const url = URL.createObjectURL(blob)
-  const link = document.createElement("a")
-  link.href = url
-  link.download = `OrderLogs_${currentOrder.value.orderNo}.csv`
-  link.click()
-  URL.revokeObjectURL(url)
-
-  ElMessage.success('导出成功')
-}
-
-// Helpers
-const getShortType = (code) => {
-  const map = { 'transport': '接送', 'feeding': '喂遛', 'washing': '洗护' }
-  return map[code] || '订单'
-}
-const getRiderStatusText = (status) => {
-  const map = { 'online': '接单中', 'busy': '接单中', 'offline': '休息中', 'disabled': '禁用' }
-  return map[status]
-}
-const getCategoryClass = (cat) => {
-  const map = { '接送': 'cat-transport', '喂遛': 'cat-feeding', '洗护': 'cat-washing' }
-  return map[cat] || ''
-}
-
-const getServiceTimeRange = (timeStr) => {
-  if (!timeStr) return '--'
-  try {
-    // Assume format YYYY-MM-DD HH:mm
-    if (timeStr.length < 16) return timeStr
-
-    let timePart = timeStr.substring(11, 16)
-    let [hh, mm] = timePart.split(':').map(Number)
-    let endH = hh + 2 // Assume 2 hours duration
-    if (endH >= 24) endH -= 24
-
-    let endHStr = endH.toString().padStart(2, '0')
-    return `${timeStr}-${endHStr}:${mm.toString().padStart(2, '0')}`
-  } catch (e) {
-    return timeStr
-  }
-}
-// Mock helper to get days later text
-const getDaysLater = (dateStr) => {
-  // Simple mock logic
-  if (dateStr.includes('02-07')) return '今天'
-  if (dateStr.includes('02-08')) return '明天'
-  return ''
-}
-// Mock helper to find rider ID by name (since table has name only)
-const getRiderIdByName = (name) => {
-  const rider = ridersList.value.find(r => r.name === name)
-  return rider ? rider.id : null
-}
-const filteredDispatchRiders = computed(() => {
-  let result = ridersList.value.filter(r => r.status === 'online' || r.status === 'busy')
-  if (dispatchSearchQuery.value) {
-    const q = dispatchSearchQuery.value.toLowerCase()
-    result = result.filter(r => r.name.includes(q) || r.phone.includes(q))
-  }
-  result.sort((a, b) => {
-    return a.lastServiceTime.localeCompare(b.lastServiceTime)
-  })
-  return result
-})
-
-
-const handleCancel = (row) => {
-  ElMessageBox.confirm('确认取消该订单吗?', '提示', { type: 'warning' })
-    .then(() => {
-      ElMessage.success('订单已取消')
-      handleSearch()
-    })
-}
-
-const careSummaryVisible = ref(false)
-const careSummaryOrder = ref(null)
-
-const handleCareSummarySuccess = (summaryData) => {
-  if (careSummaryOrder.value) {
-    careSummaryOrder.value.careSummary = summaryData
-  }
-}
-
-const openCareSummary = (row) => {
-  // Inject rich mock data for the detailed profile view
-  careSummaryOrder.value = {
-    ...row,
-    petAge: '3岁',
-    petGender: 'male',
-    petTags: ['易过敏', '胆小'],
-    petWeight: '30 kg',
-    petSize: '大型',
-    petPersonality: '活泼,超级粘人,喜欢玩球',
-    homeTime: '2023-01-01',
-    houseType: '电梯',
-    entryMethod: '密码开门',
-    entryDetail: '密码: 123456 (仅限服务期间使用)',
-    healthStatus: '健康',
-    aggression: '无',
-    vaccineImg: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg',
-    medicalHistory: '无',
-    allergy: '海鲜'
-  }
-  careSummaryVisible.value = true
-}
-
-// Reward / Punish Logic
-const rewardDialogVisible = ref(false)
-const remarkDialogVisible = ref(false)
-const currentOperateRow = ref(null)
-
-const openRewardDialog = (row) => {
-  currentOperateRow.value = row
-  rewardDialogVisible.value = true
-}
-
-const openRemarkDialog = (row) => {
-  currentOperateRow.value = row
-  remarkDialogVisible.value = true
-}
-
-const handleCommand = (cmd, row) => {
-  if (cmd === 'reward') openRewardDialog(row)
-  if (cmd === 'remark') openRemarkDialog(row)
-  if (cmd === 'care_summary') openCareSummary(row)
-
-  if (cmd === 'complete') {
-    ElMessageBox.confirm('确认将该订单手动标记为完成吗?', '提示', { type: 'warning' })
-      .then(() => {
-        row.status = 4
-        ElMessage.success('订单已标记完成')
-      })
-  }
-
-  if (cmd === 'delete') {
-    ElMessageBox.confirm('确认删除该订单吗?此操作不可恢复', '警告', { type: 'error' })
-      .then(() => {
-        tableData.value = tableData.value.filter(item => item.id !== row.id)
-        ElMessage.success('订单已删除')
-      })
-  }
-}
-
-</script>
-
-<style scoped>
-.page-container {
-  padding: 20px;
-}
-
-.card-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-}
-
-.title {
-  font-weight: bold;
-  font-size: 18px;
-}
-
-.right-panel {
-  display: flex;
-  gap: 10px;
-  align-items: center;
-}
-
-.search-input {
-  width: 220px;
-}
-
-.status-tabs {
-  margin-top: 10px;
-  margin-bottom: -10px;
-}
-
-.pagination-container {
-  display: flex;
-  justify-content: flex-end;
-  margin-top: 20px;
-}
-
-/* Table Content Styles */
-.service-type-cell {
-  display: flex;
-  flex-direction: row;
-  gap: 4px;
-  align-items: center;
-}
-
-/* Changed to row */
-.sub-tag {
-  font-size: 11px;
-  height: 20px;
-  padding: 0 5px;
-}
-
-.pet-info {
-  display: flex;
-  align-items: center;
-  gap: 10px;
-}
-
-.pet-info .el-avatar {
-  background: #e0eaff;
-  color: #409eff;
-  font-weight: bold;
-  flex-shrink: 0;
-}
-
-.pet-info .avatar-feeding {
-  background: #fdf6ec;
-  color: #e6a23c;
-}
-
-.pet-info .avatar-washing {
-  background: #f0f9eb;
-  color: #67c23a;
-}
-
-.pet-detail {
-  display: flex;
-  flex-direction: column;
-  line-height: 1.4;
-}
-
-.pet-name {
-  font-weight: bold;
-  font-size: 14px;
-  color: #303133;
-}
-
-.pet-breed {
-  color: #909399;
-  font-weight: normal;
-  font-size: 12px;
-  margin-left: 4px;
-}
-
-.merchant-info {
-  display: flex;
-  flex-direction: column;
-  line-height: 1.4;
-}
-
-.sub-text {
-  font-size: 12px;
-  color: #999;
-}
-
-.text-gray {
-  color: #ccc;
-  font-style: italic;
-}
-
-.time-text {
-  font-size: 13px;
-  color: #606266;
-}
-
-.status-cell {
-  display: flex;
-  align-items: center;
-}
-
-.status-dot {
-  width: 6px;
-  height: 6px;
-  border-radius: 50%;
-  margin-right: 6px;
-  background-color: #909399;
-}
-
-.status-dot.status-0 {
-  background-color: #f56c6c;
-  box-shadow: 0 0 4px rgba(245, 108, 108, 0.4);
-}
-
-.status-dot.status-1 {
-  background-color: #e6a23c;
-}
-
-.status-dot.status-2 {
-  background-color: #409eff;
-}
-
-.status-dot.status-3 {
-  background-color: #bf24e8;
-}
-
-.status-dot.status-4 {
-  background-color: #67c23a;
-}
-
-.status-dot.status-5 {
-  background-color: #909399;
-}
-
-.fulfiller-info {
-  display: flex;
-  flex-direction: column;
-}
-
-.fulfiller-name {
-  font-weight: 500;
-  color: #333;
-}
-
-.fulfiller-fee {
-  font-size: 12px;
-  color: #e6a23c;
-}
-
-.op-cell {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-}
-
-/* Added flex for operation column */
-.el-dropdown-link {
-  cursor: pointer;
-  color: #409eff;
-  font-size: 12px;
-  display: flex;
-  align-items: center;
-  line-height: 1;
-  height: 24px;
-}
-
-/* Ensure alignment */
-
-/* Detail Styles */
-.detail-content {
-  padding: 0 10px;
-}
-
-.order-detail-drawer .el-drawer__body {
-  padding: 0 !important;
-}
-
-.detail-container {
-  height: 100%;
-  display: flex;
-  flex-direction: column;
-  background: #f5f7fa;
-}
-
-.detail-header {
-  background: #fff;
-  padding: 20px 24px;
-  border-bottom: 1px solid #ebeef5;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-}
-
-.left-head {
-  display: flex;
-  align-items: center;
-  gap: 12px;
-}
-
-.order-no {
-  font-size: 20px;
-  font-weight: bold;
-  color: #303133;
-}
-
-.type-tag {
-  font-weight: normal;
-}
-
-.crt-time {
-  font-size: 13px;
-  color: #909399;
-}
-
-.detail-scroll-area {
-  flex: 1;
-  overflow-y: auto;
-  padding: 20px 24px;
-}
-
-/* Progress */
-.progress-section {
-  background: #fff;
-  padding: 30px 20px 20px;
-  border-radius: 8px;
-  margin-bottom: 20px;
-  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
-}
-
-.custom-steps :deep(.el-step__title) {
-  font-size: 13px;
-}
-
-/* Top Info Row */
-.top-info-row {
-  display: flex;
-  gap: 20px;
-  margin-bottom: 20px;
-  align-items: stretch;
-}
-
-.info-section {
-  flex: 1;
-  background: #fff;
-  border-radius: 8px;
-  padding: 15px;
-  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
-}
-
-.sec-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  margin-bottom: 15px;
-  padding-bottom: 10px;
-  border-bottom: 1px solid #f2f2f2;
-}
-
-.sec-header .label {
-  font-weight: bold;
-  font-size: 15px;
-  color: #303133;
-  border-left: 3px solid #409eff;
-  padding-left: 8px;
-}
-
-/* Pet Section */
-.pet-basic-row {
-  display: flex;
-  gap: 15px;
-  margin-bottom: 15px;
-  align-items: center;
-}
-
-.pet-avatar-lg {
-  border-radius: 8px;
-  background: #ecf5ff;
-  color: #409eff;
-  font-size: 20px;
-  font-weight: bold;
-}
-
-.pet-names {
-  display: flex;
-  flex-direction: column;
-  gap: 6px;
-}
-
-.b-name {
-  font-size: 18px;
-  font-weight: bold;
-  display: flex;
-  align-items: center;
-  gap: 6px;
-}
-
-.b-tags {
-  display: flex;
-  gap: 5px;
-}
-
-.pet-desc :deep(.el-descriptions__label) {
-  width: 70px;
-}
-
-/* User Section */
-.u-row {
-  display: flex;
-  gap: 12px;
-  align-items: center;
-  margin-bottom: 12px;
-}
-
-.u-info .nm {
-  font-weight: bold;
-  font-size: 15px;
-  color: #303133;
-  display: flex;
-  align-items: center;
-  gap: 6px;
-}
-
-.vip-badge {
-  background: linear-gradient(90deg, #f3d19e, #e6a23c);
-  color: #fff;
-  font-size: 10px;
-  padding: 0 5px;
-  border-radius: 10px;
-  height: 16px;
-  line-height: 16px;
-  font-weight: bold;
-}
-
-.u-info .ph {
-  font-size: 13px;
-  color: #909399;
-  margin-top: 2px;
-}
-
-.addr-box {
-  background: #fdf6ec;
-  padding: 8px 10px;
-  border-radius: 4px;
-  margin-bottom: 10px;
-}
-
-.addr-label {
-  font-size: 12px;
-  color: #e6a23c;
-  margin-bottom: 2px;
-  font-weight: bold;
-}
-
-.addr-txt {
-  font-size: 13px;
-  color: #606266;
-  line-height: 1.4;
-}
-
-.stat-row {
-  font-size: 12px;
-  color: #909399;
-  display: flex;
-  gap: 10px;
-}
-
-/* Tabs */
-.detail-tabs {
-  background: #fff;
-  padding: 10px 20px;
-  border-radius: 8px;
-  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
-  min-height: 400px;
-}
-
-.tab-pane-content {
-  padding: 15px 0;
-}
-
-.order-desc :deep(.el-descriptions__label) {
-  width: 90px;
-  font-weight: bold;
-  color: #606266;
-}
-
-/* Fulfiller Card inside Tab */
-.fulfiller-card {
-  display: flex;
-  align-items: center;
-  gap: 20px;
-  padding: 20px;
-  background: #fff;
-  border: 1px solid #ebeef5;
-  border-radius: 8px;
-}
-
-.f-right {
-  flex: 1;
-  display: flex;
-  flex-direction: column;
-  gap: 8px;
-}
-
-.f-row1 {
-  display: flex;
-  align-items: center;
-  gap: 10px;
-}
-
-.f-name {
-  font-size: 18px;
-  font-weight: bold;
-  color: #303133;
-}
-
-.f-row2 {
-  font-size: 13px;
-  color: #606266;
-  display: flex;
-  gap: 10px;
-}
-
-.sep {
-  color: #e4e7ed;
-}
-
-.f-row3 {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-}
-
-.score-text {
-  font-weight: bold;
-  color: #ff9900;
-}
-
-.empty-state {
-  padding: 40px 0;
-  text-align: center;
-}
-
-/* Service Block */
-.service-block {
-  margin-bottom: 25px;
-}
-
-.block-title {
-  font-weight: bold;
-  font-size: 15px;
-  margin-bottom: 15px;
-  padding-left: 8px;
-  border-left: 4px solid #409eff;
-}
-
-/* New Dispatch Styles */
-/* Dispatch Dialog Styles from OrderDispatch */
-.list-card {
-  background: #fff;
-  border: 1px solid #ebeef5;
-  border-radius: 8px;
-  padding: 12px;
-  margin-bottom: 10px;
-  display: flex;
-  align-items: stretch;
-  gap: 12px;
-  transition: all 0.2s;
-  cursor: pointer;
-}
-
-.list-card:hover {
-  border-color: #c6e2ff;
-  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
-}
-
-.card-left {
-  flex-shrink: 0;
-  display: flex;
-  align-items: center;
-}
-
-.order-card .type-tag {
-  width: 40px;
-  height: 40px;
-  border-radius: 8px;
-  color: #fff;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  font-size: 12px;
-  font-weight: bold;
-}
-
-.type-tag.transport {
-  background: #e6a23c;
-}
-
-.type-tag.feeding {
-  background: #67c23a;
-}
-
-.type-tag.washing {
-  background: #409eff;
-}
-
-.card-main {
-  flex: 1;
-  overflow: hidden;
-  display: flex;
-  flex-direction: column;
-  justify-content: center;
-  gap: 4px;
-}
-
-.row-addr {
-  font-size: 13px;
-  color: #303133;
-  display: flex;
-  align-items: center;
-  gap: 4px;
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  line-height: 1.5;
-}
-
-.row-addr .tag {
-  font-size: 11px;
-  color: #fff;
-  padding: 1px 4px;
-  border-radius: 4px;
-  flex-shrink: 0;
-  transform: scale(0.9);
-}
-
-.tag.pick {
-  background: #409eff;
-}
-
-.tag.drop {
-  background: #e6a23c;
-}
-
-.tag.home {
-  background: #67c23a;
-}
-
-.row-time {
-  font-size: 12px;
-  color: #909399;
-  display: flex;
-  align-items: center;
-  gap: 4px;
-}
-
-.days-tag {
-  color: #f56c6c;
-  background: #fef0f0;
-  padding: 0 4px;
-  border-radius: 4px;
-  font-size: 11px;
-  border: 1px solid #fde2e2;
-  transform: scale(0.95);
-}
-
-.dispatch-order-info {
-  background: #f5f7fa;
-  padding: 10px;
-  border-radius: 4px;
-  margin-bottom: 20px;
-  border: 1px solid #e4e7ed;
-  display: block;
-}
-
-.dispatch-rider-select .select-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  margin-bottom: 10px;
-}
-
-.dispatch-rider-select .tit {
-  font-weight: bold;
-  font-size: 14px;
-}
-
-.rider-grid {
-  display: grid;
-  grid-template-columns: repeat(2, 1fr);
-  gap: 12px;
-  padding-right: 10px;
-}
-
-.rider-card.select-card {
-  cursor: pointer;
-  border: 1px solid #dcdfe6;
-  position: relative;
-  transition: all 0.2s;
-  margin-bottom: 0;
-}
-
-.rider-card.select-card:hover {
-  border-color: #409eff;
-}
-
-.rider-card.select-card.active {
-  border-color: #409eff;
-  background-color: #ecf5ff;
-}
-
-.selected-mark {
-  position: absolute;
-  top: 0;
-  right: 0;
-  background: #409eff;
-  color: #fff;
-  border-bottom-left-radius: 6px;
-  width: 20px;
-  height: 20px;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  font-size: 12px;
-}
-
-.rider-card .card-left .dot {
-  position: absolute;
-  bottom: 0;
-  right: 0;
-  width: 10px;
-  height: 10px;
-  border-radius: 50%;
-  border: 2px solid #fff;
-}
-
-.dot.online {
-  background: #67c23a;
-}
-
-.dot.busy {
-  background: #409eff;
-}
-
-.dot.offline {
-  background: #909399;
-}
-
-.r-name {
-  font-weight: bold;
-  font-size: 14px;
-  color: #303133;
-  margin-right: 8px;
-}
-
-.r-phone {
-  font-size: 12px;
-  color: #909399;
-}
-
-.status-badge {
-  font-size: 11px;
-  padding: 2px 6px;
-  border-radius: 4px;
-  display: inline-block;
-  font-weight: bold;
-}
-
-.status-badge.online {
-  background: #f0f9eb;
-  color: #67c23a;
-}
-
-.status-badge.busy {
-  background: #ecf5ff;
-  color: #409eff;
-}
-
-.status-badge.offline {
-  background: #f4f4f5;
-  color: #909399;
-}
-
-.cat-tag {
-  background: #f4f4f5;
-  color: #909399;
-  font-size: 10px;
-  padding: 1px 4px;
-  border-radius: 2px;
-  margin-right: 4px;
-}
-
-.cat-tag.cat-transport {
-  background: #e6f7ff;
-  color: #1890ff;
-  border: 1px solid #91d5ff;
-}
-
-.cat-tag.cat-feeding {
-  background: #f6ffed;
-  color: #52c41a;
-  border: 1px solid #b7eb8f;
-}
-
-.cat-tag.cat-washing {
-  background: #fff0f6;
-  color: #eb2f96;
-  border: 1px solid #ffadd2;
-}
-
-.last-time {
-  font-size: 11px;
-  color: #999;
-}
-
-.empty-text {
-  text-align: center;
-  color: #909399;
-  padding: 20px;
-  width: 100%;
-  grid-column: span 2;
-}
-
-.dispatch-footer {
-  margin-top: 20px;
-  padding-top: 20px;
-  border-top: 1px solid #ebeef5;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-}
-
-.dispatch-footer .fee-input {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  font-size: 14px;
-}
-
-
-/* Removed Enhanced Care Summary Styles */
-
-/* Progress Card Styles */
-.progress-card {
-  background: #f8fcfb;
-  border-radius: 8px;
-  padding: 12px;
-  border: 1px solid #ebeef5;
-}
-
-.p-title {
-  margin: 0 0 8px;
-  font-size: 15px;
-  font-weight: bold;
-  color: #303133;
-}
-
-.p-desc {
-  margin: 0 0 12px;
-  color: #606266;
-  font-size: 13px;
-  line-height: 1.5;
-}
-
-.p-media {
-  display: flex;
-  gap: 8px;
-  flex-wrap: wrap;
-}
-
-.media-item {
-  display: inline-block;
-}
-
-.p-img {
-  width: 80px;
-  height: 80px;
-  border-radius: 4px;
-  border: 1px solid #e4e7ed;
-  cursor: pointer;
-}
-
-/* Route Graph */
-.route-graph {
-  display: flex;
-  gap: 10px;
-  align-items: center;
-  flex-wrap: wrap;
-  background: #f9f9f9;
-  padding: 20px;
-  border-radius: 6px;
-}
-
-.route-node {
-  display: flex;
-  gap: 10px;
-  align-items: flex-start;
-  background: #fff;
-  padding: 12px;
-  border-radius: 6px;
-  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
-  flex: 1;
-  min-width: 200px;
-}
-
-.node-icon {
-  width: 30px;
-  height: 30px;
-  border-radius: 50%;
-  color: #fff;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  font-size: 14px;
-  font-weight: bold;
-  flex-shrink: 0;
-}
-
-.node-icon.pick {
-  background: #409eff;
-}
-
-.node-icon.drop {
-  background: #67c23a;
-}
-
-/* New Transport Split Styles */
-.transport-split-block {
-  margin-top: 20px;
-}
-
-.transport-grid {
-  display: flex;
-  gap: 20px;
-}
-
-.transport-card {
-  flex: 1;
-  border: 1px solid #ebeef5;
-  border-radius: 6px;
-  overflow: hidden;
-  background: #fff;
-  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.02);
-}
-
-.transport-card .t-header {
-  background: #f5f7fa;
-  padding: 10px 15px;
-  border-bottom: 1px solid #ebeef5;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-}
-
-.transport-card .t-header .time {
-  font-size: 13px;
-  font-weight: bold;
-  color: #f56c6c;
-}
-
-.transport-card .t-body {
-  padding: 15px;
-  display: flex;
-  flex-direction: column;
-  gap: 10px;
-}
-
-.transport-card .row {
-  display: flex;
-  align-items: flex-start;
-  gap: 8px;
-  font-size: 14px;
-  color: #303133;
-  line-height: 1.4;
-}
-
-.transport-card .row.sub {
-  color: #909399;
-  font-size: 13px;
-  margin-top: 4px;
-}
-
-.transport-card .row .el-icon {
-  margin-top: 3px;
-}
-
-.node-icon.shop {
-  background: #e6a23c;
-  font-size: 16px;
-}
-
-.node-content {
-  display: flex;
-  flex-direction: column;
-  line-height: 1.4;
-  flex: 1;
-}
-
-.addr-t {
-  font-weight: bold;
-  font-size: 14px;
-  color: #303133;
-  margin-bottom: 4px;
-}
-
-.contact-t {
-  font-size: 12px;
-  color: #909399;
-}
-
-.time-t {
-  font-size: 12px;
-  color: #f56c6c;
-  margin-top: 4px;
-  font-weight: 500;
-}
-
-.route-arrow-lg {
-  color: #c0c4cc;
-  font-size: 20px;
-}
-
-/* Logs */
-.log-card {
-  background: #f4f4f5;
-  padding: 10px 15px;
-  border-radius: 4px;
-  position: relative;
-  top: -5px;
-  width: 100%;
-}
-
-.l-tit {
-  font-weight: bold;
-  font-size: 14px;
-  margin-bottom: 4px;
-  color: #303133;
-}
-
-.l-txt {
-  font-size: 13px;
-  color: #606266;
-  line-height: 1.5;
-}
-</style>

+ 0 - 232
src/views/order/purchase-bak/components/AddPetDialog.vue

@@ -1,232 +0,0 @@
-<template>
-  <el-dialog :model-value="visible" @update:model-value="$emit('update:visible', $event)" title="宠物档案详情" width="800px" top="10vh" class="pet-profile-dialog">
-    <el-tabs v-model="activePetTab" class="pet-tabs">
-      <el-tab-pane label="基本信息" name="basic">
-        <div class="pet-form-content">
-          <!-- Avatar Upload -->
-          <div class="avatar-col">
-            <el-upload
-              class="avatar-uploader"
-              action="#"
-              :show-file-list="false"
-              :auto-upload="false"
-              :on-change="handleAvatarChange"
-            >
-              <img v-if="petForm.avatar" :src="petForm.avatar" class="avatar" />
-              <el-icon v-else class="avatar-uploader-icon" :size="28" color="#8c939d"><Plus /></el-icon>
-            </el-upload>
-            <div style="font-size:12px; color:#999; margin-top:8px; text-align:center">点击上传头像</div>
-          </div>
-
-          <!-- Form Fields -->
-          <el-form :model="petForm" label-width="80px" class="inner-form">
-            <el-row :gutter="20">
-              <el-col :span="12">
-                <el-form-item label="宠物姓名" required>
-                  <el-input v-model="petForm.name" placeholder="请输入" />
-                </el-form-item>
-              </el-col>
-              <el-col :span="12">
-                <el-form-item label="所属主人" required>
-                  <el-select :model-value="userId" disabled placeholder="选择主人" style="width:100%">
-                    <el-option v-for="u in userOptions" :key="u.id" :label="u.name" :value="u.id" />
-                  </el-select>
-                </el-form-item>
-              </el-col>
-            </el-row>
-
-            <el-row :gutter="20">
-              <el-col :span="12">
-                <el-form-item label="性别">
-                  <el-radio-group v-model="petForm.gender">
-                    <el-radio label="MM">公</el-radio>
-                    <el-radio label="GG">母</el-radio>
-                  </el-radio-group>
-                </el-form-item>
-              </el-col>
-              <el-col :span="12">
-                <el-form-item label="品种">
-                  <el-select v-model="petForm.breed" placeholder="请选择品种" style="width:100%">
-                    <el-option label="金毛" value="金毛" />
-                    <el-option label="布偶" value="布偶" />
-                    <el-option label="边牧" value="边牧" />
-                  </el-select>
-                </el-form-item>
-              </el-col>
-            </el-row>
-
-            <el-row :gutter="20">
-              <el-col :span="12">
-                <el-form-item label="体型">
-                  <el-select v-model="petForm.bodyType" placeholder="选择体型" style="width:100%">
-                    <el-option label="小型" value="small" />
-                    <el-option label="中型" value="medium" />
-                    <el-option label="大型" value="large" />
-                  </el-select>
-                </el-form-item>
-              </el-col>
-              <el-col :span="12">
-                <el-form-item label="体重(kg)">
-                  <el-row :gutter="10">
-                    <el-col :span="12"><el-input-number v-model="petForm.weight" :min="0" :step="0.1" :controls="false" style="width:100%" /></el-col>
-                    <el-col :span="12"></el-col>
-                  </el-row>
-                </el-form-item>
-              </el-col>
-            </el-row>
-
-            <el-row :gutter="20">
-              <el-col :span="12">
-                <el-form-item label="年龄(岁)">
-                  <el-input-number v-model="petForm.age" :min="0" style="width:100%" />
-                </el-form-item>
-              </el-col>
-            </el-row>
-
-            <el-form-item label="性格关键词">
-              <el-input v-model="petForm.keywords" placeholder="如:活泼、粘人" />
-            </el-form-item>
-
-            <el-form-item label="萌宠性格">
-              <el-input v-model="petForm.desc" type="textarea" placeholder="详细描述" :rows="2" />
-            </el-form-item>
-
-            <el-form-item label="宠物标签">
-              <el-select v-model="petForm.tags" multiple placeholder="选择标签" style="width:100%">
-                <el-option label="绝育" value="1" />
-                <el-option label="疫苗齐全" value="2" />
-              </el-select>
-            </el-form-item>
-
-          </el-form>
-        </div>
-      </el-tab-pane>
-      <el-tab-pane label="家庭信息" name="family">
-        <el-form :model="petForm" label-width="120px">
-          <el-form-item label="新来家庭时间">
-            <el-date-picker v-model="petForm.arrivalTime" type="date" placeholder="选择日期" style="width: 100%" />
-          </el-form-item>
-          <el-form-item label="家庭房屋类型">
-            <el-radio-group v-model="petForm.houseType">
-              <el-radio label="stairs">楼梯</el-radio>
-              <el-radio label="elevator">电梯</el-radio>
-            </el-radio-group>
-          </el-form-item>
-          <el-form-item label="入门方式">
-            <el-radio-group v-model="petForm.entryMethod">
-              <el-radio label="password">密码开门</el-radio>
-              <el-radio label="key">钥匙开门</el-radio>
-            </el-radio-group>
-          </el-form-item>
-          <el-form-item label="密码" v-if="petForm.entryMethod === 'password'">
-            <el-input v-model="petForm.entryPassword" placeholder="请输入门锁密码" />
-          </el-form-item>
-          <el-form-item label="钥匙位置" v-if="petForm.entryMethod === 'key'">
-            <el-input v-model="petForm.keyLocation" placeholder="请输入钥匙存放位置" />
-          </el-form-item>
-        </el-form>
-      </el-tab-pane>
-      <el-tab-pane label="健康状况" name="health">
-        <el-form :model="petForm" label-width="120px">
-          <el-form-item label="健康状态">
-            <el-radio-group v-model="petForm.healthStatus">
-              <el-radio label="健康">健康</el-radio>
-              <el-radio label="亚健康">亚健康</el-radio>
-              <el-radio label="疾病">疾病</el-radio>
-            </el-radio-group>
-          </el-form-item>
-          <el-form-item label="是否有攻击倾向">
-            <el-switch v-model="petForm.aggression" active-text="是" inactive-text="否" />
-          </el-form-item>
-          <el-form-item label="疫苗情况">
-            <el-input v-model="petForm.vaccine" type="textarea" placeholder="记录疫苗接种情况" />
-          </el-form-item>
-          <el-form-item label="既往病史">
-            <el-input v-model="petForm.medicalHistory" type="textarea" placeholder="如有病史请记录" />
-          </el-form-item>
-          <el-form-item label="过敏史">
-            <el-input v-model="petForm.allergies" type="textarea" placeholder="如有过敏源请记录" />
-          </el-form-item>
-        </el-form>
-      </el-tab-pane>
-    </el-tabs>
-    <template #footer>
-      <el-button @click="$emit('update:visible', false)">取消</el-button>
-      <el-button type="primary" @click="submit">保存</el-button>
-    </template>
-  </el-dialog>
-</template>
-
-<script setup>
-import { ref, reactive, watch } from 'vue'
-import { ElMessage } from 'element-plus'
-
-const props = defineProps({
-  visible: { type: Boolean, default: false },
-  userId: { type: [String, Number], default: '' },
-  userOptions: { type: Array, default: () => [] }
-})
-
-const emit = defineEmits(['update:visible', 'success'])
-
-const activePetTab = ref('basic')
-
-const petForm = reactive({
-  name: '', breed: '', gender: 'MM', avatar: '',
-  bodyType: 'small', weight: 0, age: 0, keywords: '', desc: '', tags: [],
-
-  // Family
-  arrivalTime: '', houseType: 'stairs', entryMethod: 'key', entryPassword: '', keyLocation: '',
-  // Health
-  healthStatus: '健康', aggression: false, vaccine: '', medicalHistory: '', allergies: ''
-})
-
-watch(() => props.visible, (newVal) => {
-  if (newVal) {
-    activePetTab.value = 'basic'
-    Object.assign(petForm, {
-      name: '', breed: '', gender: 'MM', avatar: '',
-      bodyType: 'small', weight: 0, age: 0, keywords: '', desc: '', tags: [],
-      arrivalTime: '', houseType: 'stairs', entryMethod: 'key', entryPassword: '', keyLocation: '',
-      healthStatus: '健康', aggression: false, vaccine: '', medicalHistory: '', allergies: ''
-    })
-  }
-})
-
-const handleAvatarChange = (uploadFile) => {
-  // Mock upload: create local URL
-  petForm.avatar = URL.createObjectURL(uploadFile.raw)
-}
-
-const submit = () => {
-  if (!petForm.name || !petForm.breed) {
-    ElMessage.warning('请补全宠物必填信息')
-    return
-  }
-  const newPet = {
-    id: Date.now(),
-    name: petForm.name,
-    breed: petForm.breed,
-    avatar: petForm.avatar
-  }
-  emit('success', newPet)
-  emit('update:visible', false)
-}
-</script>
-
-<style scoped>
-.pet-form-content { display: flex; gap: 20px; }
-.avatar-col { width: 120px; display: flex; flex-direction: column; align-items: center; padding-top: 10px; }
-.avatar-uploader { display: inline-block; }
-.avatar-uploader:deep(.el-upload) {
-  border: 1px dashed #d9d9d9; border-radius: 6px; cursor: pointer; position: relative; overflow: hidden;
-  transition: var(--el-transition-duration-fast);
-}
-.avatar-uploader:deep(.el-upload:hover) { border-color: var(--el-color-primary); }
-.avatar-uploader-icon {
-  font-size: 28px; color: #8c939d; width: 100px; height: 100px; text-align: center; border: 1px dashed #d9d9d9;
-  border-radius: 50%; display: flex; align-items: center; justify-content: center;
-}
-.avatar { width: 100px; height: 100px; display: block; border-radius: 50%; object-fit: cover; }
-.inner-form { flex: 1; }
-</style>

+ 0 - 164
src/views/order/purchase-bak/components/AddUserDialog.vue

@@ -1,164 +0,0 @@
-<template>
-  <el-dialog :model-value="visible" @update:model-value="$emit('update:visible', $event)" title="新增用户" width="700px" destroy-on-close append-to-body class="add-user-dialog">
-    <el-form :model="userForm" label-width="90px" class="user-form">
-      <div style="display: flex; justify-content: center; align-items: center; gap: 20px; margin-bottom: 30px;">
-        <el-upload action="#" :show-file-list="false" :auto-upload="false" :on-change="handleUserAvatarChange">
-          <el-avatar :size="80" :src="userForm.avatar || 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png'" style="cursor: pointer; border: 2px solid #e4e7ed;" />
-        </el-upload>
-        <el-button type="primary" link @click="">点击修改头像</el-button>
-      </div>
-
-      <div class="form-section-header">基本资料</div>
-      <el-row :gutter="30">
-        <el-col :span="12">
-          <el-form-item label="录入来源">
-            <el-select v-model="userForm.source" style="width: 100%" filterable allow-create default-first-option>
-              <el-option label="平台录入" value="平台录入" />
-              <el-option label="萌它宠物连锁录入" value="萌它宠物连锁录入" />
-            </el-select>
-          </el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item label="所属区域">
-            <el-select v-model="userForm.area" style="width: 100%" filterable allow-create default-first-option placeholder="请选择或输入">
-              <el-option label="朝阳区" value="朝阳区" />
-              <el-option label="海淀区" value="海淀区" />
-            </el-select>
-          </el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item label="姓名" required><el-input v-model="userForm.name" placeholder="请输入姓名" /></el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item label="电话" required><el-input v-model="userForm.phone" placeholder="请输入电话" /></el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item label="性别">
-            <el-radio-group v-model="userForm.gender">
-              <el-radio label="男">男</el-radio>
-              <el-radio label="女">女</el-radio>
-            </el-radio-group>
-          </el-form-item>
-        </el-col>
-      </el-row>
-
-      <div class="form-section-header">居住信息</div>
-      <el-row :gutter="30">
-        <el-col :span="24">
-          <el-form-item label="所在地区">
-            <el-cascader v-model="userForm.region" :options="pcaOptions" placeholder="请选择省/市/区" style="width: 100%" />
-          </el-form-item>
-        </el-col>
-        <el-col :span="24">
-          <el-form-item label="详细住址"><el-input v-model="userForm.detailAddress" placeholder="请输入街道/门牌号" /></el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item label="房屋类型">
-            <el-radio-group v-model="userForm.houseType">
-              <el-radio label="stairs">楼梯</el-radio>
-              <el-radio label="elevator">电梯</el-radio>
-            </el-radio-group>
-          </el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item label="入门方式">
-            <el-radio-group v-model="userForm.entryMethod">
-              <el-radio label="password">密码开门</el-radio>
-              <el-radio label="key">钥匙开门</el-radio>
-            </el-radio-group>
-          </el-form-item>
-        </el-col>
-        <el-col :span="12" v-if="userForm.entryMethod === 'password'">
-          <el-form-item label="开门密码">
-            <el-input v-model="userForm.entryPassword" placeholder="请输入密码" />
-          </el-form-item>
-        </el-col>
-        <el-col :span="12" v-if="userForm.entryMethod === 'key'">
-          <el-form-item label="钥匙位置">
-            <el-input v-model="userForm.keyLocation" placeholder="如:地毯下" />
-          </el-form-item>
-        </el-col>
-      </el-row>
-
-      <div class="form-section-header">其他</div>
-      <el-row :gutter="30">
-        <el-col :span="24">
-          <el-form-item label="用户标签">
-            <el-select v-model="userSelectedTagIds" multiple placeholder="选择标签" style="width: 100%">
-              <el-option v-for="tag in allUserTags" :key="tag.id" :label="tag.name" :value="tag.id">
-                <el-tag :type="tag.type" effect="light" size="small">{{ tag.name }}</el-tag>
-              </el-option>
-            </el-select>
-          </el-form-item>
-        </el-col>
-        <el-col :span="24">
-          <el-form-item label="备注说明"><el-input type="textarea" v-model="userForm.remark" rows="3" /></el-form-item>
-        </el-col>
-      </el-row>
-    </el-form>
-    <template #footer>
-      <div style="text-align: center; margin-top: 20px;">
-        <el-button @click="$emit('update:visible', false)" size="large" style="width: 120px;">取消</el-button>
-        <el-button type="primary" @click="submit" size="large" style="width: 120px;">保存</el-button>
-      </div>
-    </template>
-  </el-dialog>
-</template>
-
-<script setup>
-import { reactive, ref, watch } from 'vue'
-import { ElMessage } from 'element-plus'
-
-const props = defineProps({
-  visible: { type: Boolean, default: false },
-  pcaOptions: { type: Array, default: () => [] }
-})
-
-const emit = defineEmits(['update:visible', 'success'])
-
-const userSelectedTagIds = ref([])
-const allUserTags = [
-  { id: 1, name: '优质客户', type: 'success' },
-  { id: 2, name: '潜在流失', type: 'warning' },
-  { id: 3, name: '黑名单', type: 'danger' }
-]
-
-const userForm = reactive({
-  id: null, avatar: '', name: '', phone: '', gender: '男', address: '', detailAddress: '', region: [], remark: '',
-  houseType: 'elevator', entryMethod: 'password', entryPassword: '', keyLocation: '',
-  source: '平台录入', area: ''
-})
-
-watch(() => props.visible, (newVal) => {
-  if (newVal) {
-    userSelectedTagIds.value = []
-    Object.assign(userForm, {
-      id: null, avatar: '', name: '', phone: '', gender: '男', address: '', detailAddress: '', region: [], remark: '',
-      houseType: 'elevator', entryMethod: 'password', entryPassword: '', keyLocation: '',
-      source: '平台录入', area: ''
-    })
-  }
-})
-
-const handleUserAvatarChange = (uploadFile) => {
-  userForm.avatar = URL.createObjectURL(uploadFile.raw)
-}
-
-const submit = () => {
-  if (!userForm.name || !userForm.phone) {
-    ElMessage.warning('请补全用户必填信息')
-    return
-  }
-  const newUser = {
-    id: Date.now(),
-    name: userForm.name,
-    phone: userForm.phone
-  }
-  emit('success', newUser)
-  emit('update:visible', false)
-}
-</script>
-
-<style scoped>
-.form-section-header { font-weight: bold; margin-bottom: 20px; font-size: 15px; color: #303133; }
-</style>

+ 0 - 86
src/views/order/purchase-bak/components/FeedingForm.vue

@@ -1,86 +0,0 @@
-<template>
-  <div class="business-form">
-    <div style="margin-bottom: 20px;">
-      <div class="section-label">上门服务地址</div>
-      <el-row :gutter="10">
-        <el-col :span="8">
-          <el-cascader v-model="feedingData.region" :options="pcaOptions" placeholder="省/市/区" style="width: 100%" />
-        </el-col>
-        <el-col :span="16">
-          <el-input v-model="feedingData.addressDetail" placeholder="详细地址 (街道/门牌号)" prefix-icon="Location" />
-        </el-col>
-      </el-row>
-    </div>
-
-    <div style="margin-bottom: 20px;">
-      <div class="section-label" style="display:flex; align-items:center; margin-bottom:10px;">
-        预约服务时间
-        <el-tag type="info" size="small" style="margin-left:10px;">共 {{ feedingData.appointments.length }} 次</el-tag>
-      </div>
-      <div v-for="(item, index) in feedingData.appointments" :key="index" style="display:flex; align-items:center; margin-bottom:10px;">
-        <span style="width:30px; color:#999; font-size:12px; font-weight:bold;">{{ index + 1 }}.</span>
-        <el-date-picker
-          v-model="item.startTime"
-          type="datetime"
-          placeholder="开始时间"
-          style="width: 200px; margin-right: 5px;"
-          format="YYYY-MM-DD HH:mm"
-        />
-        <span style="margin:0 5px; color:#999;">~</span>
-        <el-date-picker
-          v-model="item.endTime"
-          type="datetime"
-          placeholder="结束时间 (可选)"
-          style="width: 200px; margin-right: 15px;"
-          format="YYYY-MM-DD HH:mm"
-        />
-
-        <div style="display:flex; gap:8px; margin-left:5px;">
-          <el-button v-if="index === feedingData.appointments.length - 1" type="primary" circle size="small" icon="Plus" @click="addAppointment" />
-          <el-button v-if="feedingData.appointments.length > 1" type="danger" circle size="small" icon="Minus" @click="removeAppointment(index)" plain />
-        </div>
-      </div>
-    </div>
-
-    <div class="remark-section">
-      <div class="section-label">家庭服务及宠物档案备注</div>
-      <el-row :gutter="15">
-        <el-col :span="12"><el-input v-model="feedingData.area" placeholder="宠物活动区域" /></el-col>
-        <el-col :span="12"><el-input v-model="feedingData.itemLoc" placeholder="物品存放位置" /></el-col>
-        <el-col :span="12" style="margin-top:10px"><el-input v-model="feedingData.cleanLoc" placeholder="清洗位置" /></el-col>
-        <el-col :span="12" style="margin-top:10px"><el-input v-model="feedingData.foodAmount" placeholder="喂食量标准" /></el-col>
-        <el-col :span="24" style="margin-top:10px"><el-input v-model="feedingData.other" type="textarea" :rows="2" placeholder="其他注意事项" /></el-col>
-      </el-row>
-    </div>
-  </div>
-</template>
-
-<script setup>
-import { defineProps, defineEmits } from 'vue'
-
-const props = defineProps({
-  feedingData: { type: Object, required: true },
-  pcaOptions: { type: Array, default: () => [] }
-})
-
-const emit = defineEmits(['change'])
-
-const addAppointment = () => {
-  props.feedingData.appointments.push({ startTime: '', endTime: '' })
-  props.feedingData.count = props.feedingData.appointments.length
-  emit('change', 'feeding')
-}
-
-const removeAppointment = (index) => {
-  if (props.feedingData.appointments.length <= 1) return
-  props.feedingData.appointments.splice(index, 1)
-  props.feedingData.count = props.feedingData.appointments.length
-  emit('change', 'feeding')
-}
-</script>
-
-<style scoped>
-.business-form { padding-top: 5px; }
-.remark-section { background: #fdfdfd; border: 1px dashed #dcdfe6; padding: 15px; border-radius: 6px; margin-top: 20px; }
-.section-label { font-size: 13px; font-weight: bold; color: #606266; margin-bottom: 12px; }
-</style>

+ 0 - 95
src/views/order/purchase-bak/components/TransportForm.vue

@@ -1,95 +0,0 @@
-<template>
-  <div class="business-form">
-    <el-form-item label="接送模式">
-      <el-radio-group v-model="transportData.subType" size="large" @change="$emit('change', 'transport')">
-        <el-radio-button label="round">往返接送</el-radio-button>
-        <el-radio-button label="pick">单程接 (到店)</el-radio-button>
-        <el-radio-button label="drop">单程送 (回家)</el-radio-button>
-      </el-radio-group>
-    </el-form-item>
-
-    <div class="route-box">
-      <!-- 接宠段 -->
-      <div class="route-segment" v-if="['round', 'pick'].includes(transportData.subType)">
-        <div class="seg-badge start">接</div>
-        <div class="seg-content">
-          <el-row :gutter="10">
-            <el-col :span="8">
-              <el-cascader v-model="transportData.pickRegion" :options="pcaOptions" placeholder="省/市/区" style="width: 100%" />
-            </el-col>
-            <el-col :span="16">
-              <el-input v-model="transportData.pickDetail" placeholder="详细地址 (街道/门牌号)" prefix-icon="Location" />
-            </el-col>
-          </el-row>
-          <el-row :gutter="10">
-            <el-col :span="12"><el-input v-model="transportData.pickContact" placeholder="联系人" /></el-col>
-            <el-col :span="12"><el-input v-model="transportData.pickPhone" placeholder="电话" /></el-col>
-          </el-row>
-          <el-row :gutter="10">
-            <el-col :span="24">
-              <el-date-picker v-model="transportData.pickTime" type="datetime" placeholder="选择接宠时间" style="width: 100%" />
-            </el-col>
-          </el-row>
-        </div>
-      </div>
-
-      <!-- 门店中转标识 -->
-      <div class="route-connector">
-        <div class="line"></div>
-        <div class="store-node"><el-icon><Shop /></el-icon> 服务门店</div>
-        <div class="line"></div>
-      </div>
-
-      <!-- 送回段 -->
-      <div class="route-segment" v-if="['round', 'drop'].includes(transportData.subType)">
-        <div class="seg-badge end">送</div>
-        <div class="seg-content">
-          <el-row :gutter="10">
-            <el-col :span="8">
-              <el-cascader v-model="transportData.dropRegion" :options="pcaOptions" placeholder="省/市/区" style="width: 100%" />
-            </el-col>
-            <el-col :span="16">
-              <el-input v-model="transportData.dropDetail" placeholder="详细地址" prefix-icon="Location" />
-            </el-col>
-          </el-row>
-          <el-row :gutter="10">
-            <el-col :span="12"><el-input v-model="transportData.dropContact" placeholder="联系人" /></el-col>
-            <el-col :span="12"><el-input v-model="transportData.dropPhone" placeholder="电话" /></el-col>
-          </el-row>
-          <el-row :gutter="10">
-            <el-col :span="24">
-              <el-date-picker v-model="transportData.dropTime" type="datetime" placeholder="预计送回时间 (可选)" style="width: 100%" />
-            </el-col>
-          </el-row>
-        </div>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script setup>
-import { defineProps, defineEmits } from 'vue'
-
-const props = defineProps({
-  transportData: { type: Object, required: true },
-  pcaOptions: { type: Array, default: () => [] }
-})
-
-const emit = defineEmits(['change'])
-</script>
-
-<style scoped>
-.business-form { padding-top: 5px; }
-.route-box { background: #f9f9f9; padding: 20px; border-radius: 8px; border: 1px solid #EBEEF5; }
-.route-segment { display: flex; gap: 15px; }
-.seg-badge {
-  width: 32px; height: 32px; background: #409eff; color: white; border-radius: 8px;
-  text-align: center; line-height: 32px; font-weight: bold; flex-shrink: 0;
-}
-.seg-badge.end { background: #67c23a; }
-.seg-content { flex: 1; display: flex; flex-direction: column; gap: 10px; }
-
-.route-connector { display: flex; align-items: center; justify-content: center; margin: 15px 0; gap: 10px; color: #909399; font-size: 12px; }
-.route-connector .line { height: 1px; width: 80px; background: #dcdfe6; }
-.route-connector .store-node { background: white; padding: 4px 12px; border-radius: 20px; border: 1px solid #dcdfe6; display: flex; align-items: center; gap: 5px; }
-</style>

+ 0 - 90
src/views/order/purchase-bak/components/WashingForm.vue

@@ -1,90 +0,0 @@
-<template>
-  <div class="business-form">
-    <div style="margin-bottom: 20px;">
-      <div class="section-label">上门服务地址</div>
-      <el-row :gutter="10">
-        <el-col :span="8">
-          <el-cascader v-model="washingData.region" :options="pcaOptions" placeholder="省/市/区" style="width: 100%" />
-        </el-col>
-        <el-col :span="16">
-          <el-input v-model="washingData.addressDetail" placeholder="详细地址 (街道/门牌号)" prefix-icon="Location" />
-        </el-col>
-      </el-row>
-    </div>
-
-    <div style="margin-bottom: 20px;">
-      <div class="section-label" style="display:flex; align-items:center; margin-bottom:10px;">
-        预约服务时间
-        <el-tag type="info" size="small" style="margin-left:10px;">共 {{ washingData.appointments.length }} 次</el-tag>
-      </div>
-      <div v-for="(item, index) in washingData.appointments" :key="index" style="display:flex; align-items:center; margin-bottom:10px;">
-        <span style="width:30px; color:#999; font-size:12px; font-weight:bold;">{{ index + 1 }}.</span>
-        <el-date-picker
-          v-model="item.startTime"
-          type="datetime"
-          placeholder="开始时间"
-          style="width: 200px; margin-right: 5px;"
-          format="YYYY-MM-DD HH:mm"
-        />
-        <span style="margin:0 5px; color:#999;">~</span>
-        <el-date-picker
-          v-model="item.endTime"
-          type="datetime"
-          placeholder="结束时间 (可选)"
-          style="width: 200px; margin-right: 15px;"
-          format="YYYY-MM-DD HH:mm"
-        />
-
-        <div style="display:flex; gap:8px; margin-left:5px;">
-          <el-button v-if="index === washingData.appointments.length - 1" type="primary" circle size="small" icon="Plus" @click="addAppointment" />
-          <el-button v-if="washingData.appointments.length > 1" type="danger" circle size="small" icon="Minus" @click="removeAppointment(index)" plain />
-        </div>
-      </div>
-    </div>
-
-    <div class="remark-section">
-      <div class="section-label">服务备注及宠物状态</div>
-      <el-row :gutter="15">
-        <el-col :span="8">
-          <el-select v-model="washingData.petStatus" placeholder="宠物应激状态" style="width:100%">
-            <el-option label="性格温顺" value="calm" />
-            <el-option label="胆小怕人" value="shy" />
-            <el-option label="容易应激" value="stress" />
-            <el-option label="有攻击性" value="aggressive" />
-          </el-select>
-        </el-col>
-        <el-col :span="8"><el-input v-model="washingData.cleanLoc" placeholder="清洗位置" /></el-col>
-        <el-col :span="8"><el-input v-model="washingData.toolLoc" placeholder="工具/水源位置" /></el-col>
-        <el-col :span="24" style="margin-top:10px"><el-input v-model="washingData.other" type="textarea" :rows="2" placeholder="其他注意事项" /></el-col>
-      </el-row>
-    </div>
-  </div>
-</template>
-
-<script setup>
-import { defineProps, defineEmits } from 'vue'
-
-const props = defineProps({
-  washingData: { type: Object, required: true },
-  pcaOptions: { type: Array, default: () => [] }
-})
-
-const emit = defineEmits(['change'])
-
-const addAppointment = () => {
-  props.washingData.appointments.push({ startTime: '', endTime: '' })
-  emit('change', 'washing')
-}
-
-const removeAppointment = (index) => {
-  if (props.washingData.appointments.length <= 1) return
-  props.washingData.appointments.splice(index, 1)
-  emit('change', 'washing')
-}
-</script>
-
-<style scoped>
-.business-form { padding-top: 5px; }
-.remark-section { background: #fdfdfd; border: 1px dashed #dcdfe6; padding: 15px; border-radius: 6px; margin-top: 20px; }
-.section-label { font-size: 13px; font-weight: bold; color: #606266; margin-bottom: 12px; }
-</style>

+ 0 - 562
src/views/order/purchase-bak/index.vue

@@ -1,562 +0,0 @@
-<template>
-  <div class="page-container">
-    <div class="create-layout">
-
-      <!-- 左侧:下单填写区 -->
-      <div class="form-container">
-        <!-- 1. 服务类型选择 -->
-        <div class="type-selection">
-          <div
-            v-for="item in serviceList"
-            :key="item.type"
-            class="type-card"
-            :class="[item.type, { active: form.type === item.type }]"
-            @click="handleTypeChange(item.type)"
-          >
-            <div class="icon-box"><el-icon><component :is="item.icon" /></el-icon></div>
-            <div class="text">
-              <div class="type-name">{{ item.name }}</div>
-              <div class="type-desc">{{ item.desc }}</div>
-            </div>
-          </div>
-        </div>
-
-        <!-- 2. 基础信息:门店与宠主 -->
-        <el-card shadow="never" class="section-card">
-          <template #header>
-            <div class="card-title">
-              <span class="step-num">02</span> 基础信息
-            </div>
-          </template>
-          <div class="card-body">
-            <el-form label-position="top" class="base-form">
-              <el-row :gutter="20">
-                <el-col :span="12">
-                  <el-form-item>
-                    <template #label>
-                      <div style="display:flex; align-items:center; height: 24px;">
-                        <span>服务门店 (平台代下单)</span>
-                      </div>
-                    </template>
-                    <el-select v-model="form.merchantId" placeholder="请选择商户门店" size="large" style="width: 100%" filterable>
-                      <el-option v-for="m in merchants" :key="m.id" :label="m.name" :value="m.id" />
-                    </el-select>
-                  </el-form-item>
-                </el-col>
-                <el-col :span="12">
-                  <el-form-item>
-                    <template #label>
-                      <div style="display:flex; justify-content:space-between; align-items:center; width:100%; height: 24px;">
-                        <span>宠主用户</span>
-                        <el-button type="primary" plain size="small" @click="openAddUser" icon="Plus" style="margin-left: 15px;">添加用户</el-button>
-                      </div>
-                    </template>
-                    <el-select
-                      v-model="form.userId"
-                      placeholder="搜索手机号/姓名"
-                      size="large"
-                      style="width: 100%"
-                      filterable
-                      remote
-                      :remote-method="searchUser"
-                      :loading="userLoading"
-                      @change="handleUserChange"
-                    >
-                      <el-option v-for="u in userOptions" :key="u.id" :label="u.name + ' - ' + u.phone" :value="u.id" />
-                    </el-select>
-                  </el-form-item>
-                </el-col>
-              </el-row>
-
-              <el-form-item label="选择宠物" v-if="form.userId">
-                <div class="pet-select-row">
-                  <div
-                    v-for="p in currentPets"
-                    :key="p.id"
-                    class="pet-card"
-                    :class="{ active: form.petId === p.id }"
-                    @click="form.petId = p.id"
-                  >
-                    <el-avatar :size="48" :src="p.avatar" shape="square" style="border-radius: 6px;">{{ p.name.charAt(0) }}</el-avatar>
-                    <div class="pet-info">
-                      <div class="name">{{ p.name }}</div>
-                      <div class="sub">{{ p.breed }}</div>
-                    </div>
-                    <div class="check-mark" v-if="form.petId === p.id"><el-icon><Check /></el-icon></div>
-                  </div>
-
-                  <!-- Add Button Card (Last Item in Grid) -->
-                  <div class="pet-card add-card" @click="openAddPet">
-                    <el-icon :size="24"><Plus /></el-icon>
-                    <span style="font-size: 15px; font-weight: bold;">新增宠物</span>
-                  </div>
-                </div>
-              </el-form-item>
-            </el-form>
-          </div>
-        </el-card>
-
-        <!-- 3. 业务详情表单 -->
-        <el-card shadow="never" class="section-card form-card" v-if="form.type">
-          <template #header>
-            <div class="card-title">
-              <span class="step-num">03</span>
-              {{ getStepTitle(form.type) }}
-            </div>
-          </template>
-
-          <div class="card-body">
-            <!-- 服务套餐信息 -->
-            <el-form-item label="团购套餐">
-              <el-input v-model="form.groupBuyPackage" placeholder="请输入团购套餐名称 (选填)" clearable />
-            </el-form-item>
-
-            <div class="divider"></div>
-
-            <!-- A. 宠物接送表单 -->
-            <TransportForm v-show="form.type === 'transport'" :transport-data="form.transport" :pca-options="pcaOptions" @change="calcPrice" />
-
-            <!-- B. 上门喂遛表单 -->
-            <FeedingForm v-show="form.type === 'feeding'" :feeding-data="form.feeding" :pca-options="pcaOptions" @change="calcPrice" />
-
-            <!-- C. 上门洗护表单 -->
-            <WashingForm v-show="form.type === 'washing'" :washing-data="form.washing" :pca-options="pcaOptions" @change="calcPrice" />
-
-          </div>
-        </el-card>
-      </div>
-
-      <!-- 右侧:收银台概览 -->
-      <div class="summary-sidebar">
-        <div class="summary-panel">
-          <div class="summary-header">订单概览</div>
-
-          <div class="summary-content">
-            <div class="row" v-if="selectedMerchantName">
-              <span class="label">服务门店</span>
-              <span class="value">{{ selectedMerchantName }}</span>
-            </div>
-            <div class="row" v-if="selectedUserName">
-              <span class="label">客户</span>
-              <span class="value">{{ selectedUserName }}</span>
-            </div>
-            <div class="row" v-if="selectedPetName">
-              <span class="label">服务对象</span>
-              <span class="value action-text">{{ selectedPetName }} ({{ selectedPetBreed }})</span>
-            </div>
-            <div class="divider"></div>
-
-            <div class="service-preview" v-if="form.type">
-              <div class="preview-title">{{ getTypeName(form.type) }}</div>
-
-              <!-- 套餐显示 -->
-              <div class="preview-detail" v-if="selectedPkgName">
-                <div style="font-weight:bold; color:#409eff">{{ selectedPkgName }}</div>
-              </div>
-              <div class="preview-detail" v-else>
-                <div style="color:#e6a23c">非服务套餐 (单次)</div>
-              </div>
-
-              <!-- 接送预览 -->
-              <div v-if="form.type === 'transport'" class="preview-detail">
-                <div>{{ form.transport.subType === 'round' ? '往返接送' : (form.transport.subType === 'pick' ? '单程接' : '单程送') }}</div>
-                <div class="minor">接: {{ form.transport.pickTime ? formatTime(form.transport.pickTime) : '未选时间' }}</div>
-                <div class="minor" v-if="form.transport.subType !== 'pick'">送: {{ form.transport.dropTime ? formatTime(form.transport.dropTime) : '未选' }}</div>
-              </div>
-            </div>
-
-          </div>
-
-          <div class="summary-footer">
-            <el-button type="primary" size="large" class="submit-btn" :disabled="!canSubmit" @click="handleSubmit">
-              立即下单
-            </el-button>
-          </div>
-        </div>
-      </div>
-
-    </div>
-
-    <!-- Dialogs -->
-    <!-- Add User Dialog -->
-    <AddUserDialog v-model:visible="userDialogVisible" :pca-options="pcaOptions" @success="handleUserSuccess" />
-    <AddPetDialog v-model:visible="petDialogVisible" :user-id="form.userId" :user-options="userOptions" @success="handlePetSuccess" />
-
-  </div>
-</template>
-
-<script setup>
-import { ref, reactive, computed, onMounted, watch } from 'vue'
-import { ElMessage } from 'element-plus'
-import TransportForm from './components/TransportForm.vue'
-import FeedingForm from './components/FeedingForm.vue'
-import WashingForm from './components/WashingForm.vue'
-import AddUserDialog from './components/AddUserDialog.vue'
-import AddPetDialog from './components/AddPetDialog.vue'
-
-// --- Mock Data ---
-const merchants = ref([
-  { id: 1, name: '萌它宠物三里屯店' },
-  { id: 2, name: '宠爱国际动物医院' }
-])
-const userOptions = ref([
-  { id: 101, name: '张三', phone: '13812345678' },
-  { id: 102, name: '李四', phone: '13987654321' }
-])
-const mockPets = {
-  101: [
-    { id: 1, name: '旺财', breed: '金毛', avatar: '', region: ['北京市', '市辖区', '朝阳区'], address: '三里屯SOHO A座 1001' },
-    { id: 2, name: '咪咪', breed: '布偶', avatar: '', region: ['北京市', '市辖区', '朝阳区'], address: '三里屯SOHO A座 1001' }
-  ],
-  102: [
-    { id: 3, name: '奥利奥', breed: '边牧', avatar: '', region: ['上海市', '市辖区', '浦东新区'], address: '陆家嘴一号院 5-502' }
-  ]
-}
-
-const serviceList = [
-  { type: 'transport', name: '宠物接送', icon: 'Van', desc: '专车接送 · 全程监护', basePrice: 35 },
-  { type: 'feeding', name: '上门喂遛', icon: 'Food', desc: '喂食添水 · 陪玩遛狗', basePrice: 68 },
-  { type: 'washing', name: '上门洗护', icon: 'Soap', desc: '专业设备 · 深度清洁', basePrice: 88 }
-]
-
-const allPackages = [
-  { id: 10, type: 'transport', name: '包月接送套餐', price: 0 },
-  { id: 11, type: 'feeding', name: '基础喂猫套餐', price: 0 },
-  { id: 12, type: 'feeding', name: '深度陪玩套餐', price: 0 },
-  { id: 13, type: 'washing', name: '精致洗护+美容', price: 0 },
-  { id: 14, type: 'washing', name: '除菌药浴套餐', price: 0 },
-]
-
-// --- State ---
-const userLoading = ref(false)
-const currentPets = ref([])
-
-const form = reactive({
-  merchantId: '',
-  userId: '',
-  petId: '',
-  type: 'transport',
-  groupBuyPackage: '',
-
-  // Sub Forms Data
-  transport: {
-    pkgId: '',
-    price: 0,
-    pickPrice: 35,
-    dropPrice: 35,
-    subType: 'round',
-    pickRegion: [], pickDetail: '', pickContact: '', pickPhone: '', pickTime: '',
-    dropRegion: [], dropDetail: '', dropContact: '', dropPhone: '', dropTime: ''
-  },
-  feeding: {
-    pkgId: '', price: 68,
-    appointments: [{ startTime: '', endTime: '' }],
-    region: [], addressDetail: '',
-    count: 1, dates: [], area: '', itemLoc: '', cleanLoc: '', foodAmount: '', other: ''
-  },
-  washing: {
-    pkgId: '', price: 88,
-    appointments: [{ startTime: '', endTime: '' }],
-    region: [], addressDetail: '',
-    time: '', petStatus: '', cleanLoc: '', toolLoc: '', other: ''
-  }
-})
-
-// Address Autofill Watcher
-watch(() => form.petId, (newId) => {
-  if (!newId) return
-  const pet = currentPets.value.find(p => p.id === newId)
-  if (!pet) return
-
-  const user = userOptions.value.find(u => u.id === form.userId)
-
-  // Fill Transport
-  form.transport.pickRegion = pet.region || []
-  form.transport.pickDetail = pet.address || ''
-  form.transport.pickContact = user?.name || ''
-  form.transport.pickPhone = user?.phone || ''
-
-  form.transport.dropRegion = pet.region || []
-  form.transport.dropDetail = pet.address || ''
-  form.transport.dropContact = user?.name || ''
-  form.transport.dropPhone = user?.phone || ''
-
-  // Fill Feeding
-  form.feeding.region = pet.region || []
-  form.feeding.addressDetail = pet.address || ''
-
-  // Fill Washing
-  form.washing.region = pet.region || []
-  form.washing.addressDetail = pet.address || ''
-})
-
-// Current Active Data Helper
-const activeData = computed(() => {
-  return form[form.type]
-})
-
-// --- Logic ---
-
-const handleTypeChange = (type) => {
-  form.type = type
-  calcPrice(type)
-}
-
-const currentPackages = computed(() => {
-  return allPackages.filter(p => p.type === form.type)
-})
-
-const handlePkgSelect = (id) => {
-  activeData.value.pkgId = id
-  // Price calculation should remain same (base price), just payable changes
-  calcPrice(form.type)
-}
-
-const calcPrice = (type) => {
-  const data = form[type]
-  const base = serviceList.find(s => s.type === type)?.basePrice || 0
-
-  // Always use Base Logic for "Order Value", regardless of package
-  if (type === 'transport') {
-    if(data.subType === 'round') {
-      data.pickPrice = base
-      data.dropPrice = base
-    } else if (data.subType === 'pick') {
-      data.pickPrice = base
-      data.dropPrice = 0
-    } else if (data.subType === 'drop') {
-      data.pickPrice = 0
-      data.dropPrice = base
-    }
-  } else if (type === 'feeding') {
-    data.price = base * data.count
-  } else if (type === 'washing') {
-    data.price = base
-  }
-}
-
-// Add User Logic
-const userDialogVisible = ref(false)
-const openAddUser = () => { userDialogVisible.value = true }
-const handleUserSuccess = (newUser) => {
-  userOptions.value.push(newUser)
-  form.userId = newUser.id
-  currentPets.value = []
-  form.petId = ''
-  ElMessage.success('用户添加成功并已选中')
-}
-
-const pcaOptions = [
-  {
-    value: '北京市', label: '北京市',
-    children: [
-      { value: '市辖区', label: '市辖区', children: [ { value: '朝阳区', label: '朝阳区' }, { value: '海淀区', label: '海淀区' } ] }
-    ]
-  },
-  {
-    value: '上海市', label: '上海市',
-    children: [
-      { value: '市辖区', label: '市辖区', children: [ { value: '浦东新区', label: '浦东新区' }, { value: '徐汇区', label: '徐汇区' } ] }
-    ]
-  }
-]
-
-// Add Pet Logic
-const petDialogVisible = ref(false)
-const openAddPet = () => { petDialogVisible.value = true }
-const handlePetSuccess = (newPet) => {
-  if(!currentPets.value) currentPets.value = []
-  currentPets.value.push(newPet)
-  form.petId = newPet.id
-  ElMessage.success('宠物添加成功')
-}
-
-
-// --- Computed Helpers ---
-const selectedMerchantName = computed(() => merchants.value.find(m => m.id === form.merchantId)?.name)
-const selectedUserName = computed(() => userOptions.value.find(u => u.id === form.userId)?.name)
-const selectedPet = computed(() => currentPets.value.find(p => p.id === form.petId))
-const selectedPetName = computed(() => selectedPet.value?.name)
-const selectedPetBreed = computed(() => selectedPet.value?.breed)
-
-const selectedPkgName = computed(() => {
-  const pkgId = activeData.value.pkgId
-  return allPackages.find(p => p.id === pkgId)?.name || ''
-})
-
-
-
-const canSubmit = computed(() => {
-  if(!form.merchantId || !form.userId || !form.petId) return false
-  return true
-})
-
-// --- Methods ---
-const searchUser = (query) => { /* Mock */ }
-const handleUserChange = (val) => {
-  currentPets.value = mockPets[val] || []
-  form.petId = ''
-}
-const getStepTitle = (type) => {
-  const map = { transport: '填写接送路线与时间', feeding: '选择套餐与服务的细则', washing: '选择套餐与服务的细则' }
-  return map[type]
-}
-const getTypeName = (type) => {
-  const map = { transport: '宠物接送', feeding: '上门喂遛', washing: '上门洗护' }
-  return map[type]
-}
-const formatTime = (time) => {
-  if(!time) return ''
-  const d = new Date(time)
-  return `${d.getMonth()+1}-${d.getDate()} ${d.getHours()}:${d.getMinutes() < 10 ? '0'+d.getMinutes() : d.getMinutes()}`
-}
-
-const handleSubmit = () => {
-  ElMessage.success('下单成功!订单号:ORD20248888')
-}
-
-// Initialize
-onMounted(() => {
-  calcPrice('transport')
-})
-</script>
-
-<style scoped>
-.page-container { padding: 20px; background-color: #f0f2f5; min-height: 100vh; }
-.create-layout { display: flex; gap: 20px; align-items: flex-start; max-width: 1400px; margin: 0 auto; }
-
-/* Left Content */
-.form-container { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 20px; }
-
-.section-card { border-radius: 8px; border: none; }
-.card-title { font-size: 16px; font-weight: bold; color: #303133; display: flex; align-items: center; gap: 10px; }
-.step-num {
-  background: #e6f7ff; color: #1890ff; width: 28px; height: 28px; border-radius: 50%;
-  text-align: center; line-height: 28px; font-family: Impact, sans-serif;
-}
-.base-form .el-form-item { margin-bottom: 18px; }
-
-/* Pet Selection */
-/* Pet Selection */
-.pet-select-row {
-  display: grid;
-  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
-  gap: 15px;
-  width: 100%;
-}
-.pet-card {
-  border: 1px solid #8D9095;
-  border-radius: 8px;
-  padding: 12px 15px;
-  cursor: pointer;
-  display: flex;
-  align-items: center;
-  gap: 12px;
-  position: relative;
-  transition: all 0.2s ease-in-out;
-  background: #fff;
-  min-height: 70px;
-}
-.pet-card:hover {
-  border-color: #303133;
-  transform: translateY(-2px);
-  box-shadow: 0 4px 12px rgba(0,0,0,0.08);
-}
-.pet-card.active {
-  border-color: #409eff;
-  background-color: #fff;
-  box-shadow: 0 0 0 1px #409eff inset;
-}
-.check-mark {
-  position: absolute;
-  right: 0;
-  top: 0;
-  background: #409eff;
-  color: white;
-  width: 28px;
-  height: 18px;
-  border-radius: 0 8px 0 12px;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  font-size: 12px;
-}
-.pet-info .name { font-weight: bold; font-size: 15px; color: #303133; margin-bottom: 2px; }
-.pet-info .sub { font-size: 12px; color: #606266; line-height: 1.2; }
-
-.pet-card.add-card {
-  border: 1px solid #8D9095;
-  justify-content: center;
-  align-items: center;
-  color: #303133;
-  flex-direction: row;
-  gap: 8px;
-  background: #fff;
-  box-shadow: none;
-  height: auto;
-  min-height: 70px;
-}
-.pet-card.add-card:hover {
-  border-color: #303133;
-  color: #303133;
-  background: #f9f9f9;
-  transform: translateY(-2px);
-}
-
-/* Type Selection */
-.type-selection { display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; }
-.type-card {
-  background: white; border-radius: 8px; padding: 20px; cursor: pointer; position: relative;
-  display: flex; align-items: center; gap: 15px; transition: all 0.2s;
-  border: 2px solid transparent; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
-}
-.type-card:hover { transform: translateY(-2px); box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.1); }
-.type-card.active { border-color: #409eff; background-color: #f0f9ff; }
-.type-card .icon-box {
-  width: 48px; height: 48px; border-radius: 12px; background: #f2f3f5;
-  display: flex; align-items: center; justify-content: center; font-size: 24px; color: #606266;
-}
-.type-card.active .icon-box { background: #409eff; color: white; }
-/* Colors */
-.type-card.transport.active .icon-box { background: #409eff; }
-.type-card.transport.active { border-color: #409eff; background-color: #f0f9ff; }
-.type-card.feeding.active .icon-box { background: #e6a23c; }
-.type-card.feeding.active { border-color: #e6a23c; background-color: #fdf6ec; }
-.type-card.washing.active .icon-box { background: #67c23a; }
-.type-card.washing.active { border-color: #67c23a; background-color: #f0f9eb; }
-
-.type-name { font-weight: bold; font-size: 16px; color: #303133; margin-bottom: 4px; }
-.type-desc { font-size: 12px; color: #909399; margin-bottom: 4px; }
-.type-price { font-size: 14px; color: #f56c6c; font-weight: bold; }
-
-/* Package Selection Grid */
-.form-section-title { font-weight: bold; margin-bottom: 12px; font-size: 14px; }
-.package-selection-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 20px; }
-.pkg-select-card {
-  border: 1px solid #dcdfe6; border-radius: 8px; padding: 10px 15px; cursor: pointer; position: relative;
-  background: #fff; transition: all 0.2s; min-height: 56px; display: flex; flex-direction: column; justify-content: center;
-}
-.pkg-select-card:hover { border-color: #409eff; }
-.pkg-select-card.active { border-color: #409eff; background-color: #ecf5ff; }
-.pkg-select-card .pkg-name { font-weight: bold; font-size: 14px; color: #303133; }
-.pkg-select-card .pkg-desc { font-size: 12px; color: #909399; margin-top: 2px; }
-
-.divider { height: 1px; background: #EBEEF5; margin: 15px 0; }
-
-/* Sidebar */
-.summary-sidebar { width: 320px; flex-shrink: 0; }
-.summary-panel { background: white; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.05); position: sticky; top: 20px; }
-.summary-header { background: #304156; color: white; padding: 15px 20px; font-weight: bold; font-size: 16px; border-radius: 8px 8px 0 0; }
-.summary-content { padding: 20px; }
-.row { display: flex; justify-content: space-between; margin-bottom: 12px; font-size: 14px; }
-.row .label { color: #909399; }
-.row .value { color: #303133; font-weight: 500; }
-.preview-title { font-weight: bold; margin-bottom: 8px; color: #333; }
-.preview-detail { background: #f8f9fa; padding: 10px; border-radius: 4px; font-size: 13px; margin-bottom: 8px; }
-.preview-detail .minor { color: #999; font-size: 12px; margin-top: 2px; }
-.placeholder { color: #C0C4CC; text-align: center; padding: 20px 0; font-size: 13px; font-style: italic; }
-
-
-.summary-footer { background: #f9f9fc; padding: 15px 20px; border-top: 1px solid #ebeef5; text-align: center; border-radius: 0 0 8px 8px; }
-.submit-btn { width: 100%; font-weight: bold; border-radius: 22px; }
-</style>