DeliveryOrderList.vue 6.07 KB
<template>
  <div>
    <a-card title="配送订单" :bordered="false" class="list-table-card">
      <div class="list-toolbar">
        <div class="list-toolbar-left">
          <a-select v-if="isAdmin" v-model:value="filterCityId" placeholder="租户" allowClear class="list-filter" @change="handleAdminCityChange">
            <a-select-option v-for="item in cityList" :key="item.id" :value="item.id">{{ item.name }}</a-select-option>
          </a-select>
          <a-input v-if="isAdmin" v-model:value="filterAppKey" placeholder="接入方 AppKey" class="list-search appkey-search" @pressEnter="loadList" />
          <a-select v-model:value="filterStatus" placeholder="状态" allowClear class="list-filter" @change="loadList">
            <a-select-option :value="2">待接单</a-select-option>
            <a-select-option :value="3">已接单</a-select-option>
            <a-select-option :value="4">配送中</a-select-option>
            <a-select-option :value="6">已完成</a-select-option>
            <a-select-option :value="10">已取消</a-select-option>
          </a-select>
          <a-input-search v-model:value="keyword" placeholder="外部订单号" @search="loadList" class="list-search" />
        </div>
      </div>
      <a-table :dataSource="list" :columns="columns" :loading="loading" rowKey="id" :pagination="false">
        <template #bodyCell="{ column, record }">
          <template v-if="column.key === 'cityName'">
            {{ getCityName(record.cityId) }}
          </template>
          <template v-if="column.key === 'status'">
            <a-tag :color="statusColor[record.status]">{{ statusMap[record.status] }}</a-tag>
          </template>
          <template v-if="column.key === 'action'">
            <a-space>
              <a @click="openDetail(record)">详情</a>
              <a-popconfirm v-if="record.status === 2 && canOperate" title="确认取消该配送订单?" @confirm="cancelOrder(record)">
                <a style="color:red">取消</a>
              </a-popconfirm>
              <span v-else-if="isAdmin && record.status === 2 && !canOperate">选择租户后可取消</span>
            </a-space>
          </template>
        </template>
      </a-table>
    </a-card>

    <a-modal v-model:open="queryVisible" title="配送订单详情" :footer="null" :confirmLoading="detailLoading">
      <div v-if="queryResult" class="soft-page-stack">
        <div class="soft-note-card">
          <strong>配送订单详情</strong>
          <p>这里展示后台可查看的配送单核心状态和计费结果,便于运营快速核对。</p>
        </div>
        <a-descriptions :column="1" bordered size="small">
          <a-descriptions-item label="配送订单ID">{{ queryResult.deliveryOrderId }}</a-descriptions-item>
          <a-descriptions-item label="配送订单号">{{ queryResult.orderNo }}</a-descriptions-item>
          <a-descriptions-item label="外部订单号">{{ queryResult.outOrderNo }}</a-descriptions-item>
          <a-descriptions-item label="状态">{{ statusMap[queryResult.status] }}</a-descriptions-item>
          <a-descriptions-item label="配送费">¥{{ queryResult.totalFee }}</a-descriptions-item>
          <a-descriptions-item label="距离">{{ queryResult.distance }} km</a-descriptions-item>
          <a-descriptions-item label="预计时间">{{ queryResult.estimatedMinutes }} 分钟</a-descriptions-item>
        </a-descriptions>
      </div>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import { computed, ref, onMounted } from 'vue'
import { message } from 'ant-design-vue'
import { riderApi } from '@/api'
import { useRoleCityList } from '@/composables/useRoleCityList'

const loading = ref(false)
const detailLoading = ref(false)
const list = ref<any[]>([])
const filterCityId = ref<number | undefined>()
const filterAppKey = ref('')
const filterStatus = ref<number | undefined>()
const keyword = ref('')
const queryVisible = ref(false)
const queryResult = ref<any>(null)
const { isAdmin, cityList, loadCities, getCityName } = useRoleCityList()
const canOperate = computed(() => !isAdmin.value || !!filterCityId.value)

const statusMap: Record<number, string> = {
  2: '待接单', 3: '已接单', 4: '配送中', 6: '已完成', 7: '退款申请',
  8: '退款成功', 9: '退款拒绝', 10: '已取消'
}
const statusColor: Record<number, string> = {
  2: 'blue', 3: 'cyan', 4: 'processing', 6: 'green',
  7: 'orange', 8: 'green', 9: 'red', 10: 'red'
}

const columns = computed(() => {
  const base = [
    { title: 'ID', dataIndex: 'id', width: 80 },
    { title: '外部订单号', dataIndex: 'outOrderNo' },
    { title: '接入方', dataIndex: 'appKey', ellipsis: true },
    { title: '收件人', dataIndex: 'recipName' },
    { title: '配送费', dataIndex: 'moneyDelivery' },
    { title: '状态', key: 'status' },
    { title: '操作', key: 'action' },
  ]
  if (!isAdmin.value) {
    return base
  }
  return [
    { title: '租户', key: 'cityName' },
    ...base,
  ]
})

async function loadList() {
  loading.value = true
  try {
    const res: any = await riderApi.deliveryOrderList({
      cityId: filterCityId.value,
      appKey: filterAppKey.value || undefined,
      status: filterStatus.value,
      outOrderNo: keyword.value || undefined,
      page: 1
    })
    list.value = Array.isArray(res?.data) ? res.data : []
  } finally { loading.value = false }
}

function handleAdminCityChange() {
  if (!filterCityId.value) {
    queryVisible.value = false
    queryResult.value = null
  }
  loadList()
}

async function openDetail(record: any) {
  detailLoading.value = true
  queryResult.value = null
  queryVisible.value = true
  try {
    const res: any = await riderApi.deliveryOrderDetail(record.id)
    queryResult.value = res.data
  } finally { detailLoading.value = false }
}

async function cancelOrder(record: any) {
  await riderApi.deliveryOrderCancel(record.id)
  message.success('取消成功')
  if (queryVisible.value && queryResult.value?.deliveryOrderId === record.id) {
    queryVisible.value = false
    queryResult.value = null
  }
  loadList()
}

onMounted(async () => {
  await loadCities()
  await loadList()
})
</script>