ソースを参照

feat(delivery): 新增售后订单管理功能

新增售后订单列表页面,支持查看和处理退款退货订单。
- 添加 `delivery_after-sales-order` 路由及对应视图组件
- 引入相关接口和服务类型定义,包括 `OrderRefund`、`OrderRefundSku` 等
- 实现售后订单状态枚举与映射展示
- 在普通订单列表中增加发货按钮并联动发货弹窗逻辑优化
- 更新国际化语言包,添加相关菜单和路由标题翻译

fix(normal-order): 修复订单数量列样式及提示标签显示问题

调整订单表格中的数量列宽度,并优化售后状态标签的颜色区分。
zhangtao 6 日 前
コミット
1deedb7cd3

+ 2 - 1
src/locales/langs/en-us.ts

@@ -302,7 +302,8 @@ const local: App.I18n.Schema = {
     'config_order-splitting': '',
     delivery: '',
     'delivery_normal-order': '',
-    'operation_delivery-admin': ''
+    'operation_delivery-admin': '',
+    'delivery_after-sales-order': ''
   },
   page: {
     login: {

+ 2 - 1
src/locales/langs/zh-cn.ts

@@ -299,7 +299,8 @@ const local: App.I18n.Schema = {
     'config_order-splitting': '',
     delivery: '',
     'delivery_normal-order': '',
-    'operation_delivery-admin': ''
+    'operation_delivery-admin': '',
+    'delivery_after-sales-order': ''
   },
   page: {
     login: {

+ 1 - 0
src/router/elegant/imports.ts

@@ -23,6 +23,7 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
   about: () => import("@/views/about/index.vue"),
   "config_fright-config": () => import("@/views/config/fright-config/index.vue"),
   "config_order-splitting": () => import("@/views/config/order-splitting/index.vue"),
+  "delivery_after-sales-order": () => import("@/views/delivery/after-sales-order/index.vue"),
   "delivery_normal-order": () => import("@/views/delivery/normal-order/index.vue"),
   "goods_desk-category": () => import("@/views/goods/desk-category/index.vue"),
   "goods_store-goods": () => import("@/views/goods/store-goods/index.vue"),

+ 9 - 0
src/router/elegant/routes.ts

@@ -88,6 +88,15 @@ export const generatedRoutes: GeneratedRoute[] = [
       i18nKey: 'route.delivery'
     },
     children: [
+      {
+        name: 'delivery_after-sales-order',
+        path: '/delivery/after-sales-order',
+        component: 'view.delivery_after-sales-order',
+        meta: {
+          title: 'delivery_after-sales-order',
+          i18nKey: 'route.delivery_after-sales-order'
+        }
+      },
       {
         name: 'delivery_normal-order',
         path: '/delivery/normal-order',

+ 1 - 0
src/router/elegant/transform.ts

@@ -186,6 +186,7 @@ const routeMap: RouteMap = {
   "config_fright-config": "/config/fright-config",
   "config_order-splitting": "/config/order-splitting",
   "delivery": "/delivery",
+  "delivery_after-sales-order": "/delivery/after-sales-order",
   "delivery_normal-order": "/delivery/normal-order",
   "goods": "/goods",
   "goods_desk-category": "/goods/desk-category",

+ 61 - 0
src/service/api/delivery/after-sales-order/index.ts

@@ -0,0 +1,61 @@
+import { request } from '@/service/request';
+
+/**
+ * 售后快递订单
+ * @param data
+ * @returns
+ */
+export function fetchGetAfterSalesOrderList(data: any) {
+  return request<Api.Common.PaginatingQueryRecord<Api.delivery.OrderRefund>>({
+    url: '/platform/orderRefund/orderRefundPage',
+    method: 'get',
+    params: data
+  });
+}
+
+/**
+ *  获取售后快递订单状态数量
+ * @returns
+ */
+export function fetchGetAfterSalesStatusNum(data: any) {
+  return request<Api.delivery.OrderRefundCountParam>({
+    url: '/platform/orderRefund/orderRefundCount',
+    method: 'get',
+    params: data
+  });
+}
+
+/**
+ * 获取快递订单详情
+ * @param orderNumber
+ * @returns
+ */
+export function fetchGetNomalOrderInfo(orderNumber: string) {
+  return request<Api.delivery.deliveryOrder>({
+    url: `/platform/order/orderInfo/${orderNumber}`,
+    method: 'get'
+  });
+}
+
+/**
+ *
+ * 快递公司列表
+ *  */
+export function fetchGetDevList(data: any) {
+  return request<Api.delivery.devList>({
+    url: '/platform/delivery/list',
+    method: 'get',
+    params: data
+  });
+}
+
+/**
+ * 发货
+ */
+export function fetchDeliveryOrder(data: any) {
+  return request({
+    url: '/platform/order/delivery',
+    method: 'PUT',
+    data
+  });
+}

+ 213 - 0
src/typings/api.d.ts

@@ -1315,5 +1315,218 @@ declare namespace Api {
       completed: number;
       cancel: number;
     }
+    interface OrderRefund {
+      /**
+       * 申请时间
+       */
+      applyTime?: string;
+      /**
+       * 申请类型:1,仅退款,2退款退货,5差价退款
+       */
+      applyType?: number;
+      /**
+       * 申请说明
+       */
+      buyerDesc?: string;
+      /**
+       * 联系方式
+       */
+      buyerMobile?: string;
+      /**
+       * 申请原因
+       */
+      buyerReason?: string;
+      /**
+       * 撤销时间
+       */
+      cancelTime?: string;
+      /**
+       * 同意退款时间
+       */
+      decisionTime?: string;
+      /**
+       * 退款单总分销金额
+       */
+      distributionTotalAmount?: number;
+      freightAmount?: number;
+      /**
+       * 退货数量(0:为全部订单项)
+       */
+      goodsNum?: number;
+      /**
+       * 受理时间
+       */
+      handelTime?: string;
+      handler?: boolean;
+      /**
+       * 是否接收到商品(1:已收到,0:未收到)
+       */
+      isReceiver?: boolean;
+      /**
+       * 是否填写了退货物流信息(1:已填写,0:未填写)
+       */
+      isReturnLogistics?: boolean;
+      offsetPoints?: number;
+      /**
+       * 订单ID
+       */
+      orderId?: number;
+      /**
+       * 订单项ID
+       */
+      orderItemId?: number;
+      /**
+       * 订单编号
+       */
+      orderNumber: string;
+      /**
+       * 退款商品详情
+       */
+      orderRefundSkuList?: OrderRefundSku[];
+      /**
+       * 文件凭证json
+       */
+      photoFiles?: string;
+      /**
+       * 平台退款金额(退款时将这部分钱退回给平台,所以商家要扣除从平台这里获取的金额)
+       */
+      platformRefundAmount?: number;
+      /**
+       * 收货时间
+       */
+      receiveTime?: string;
+      /**
+       * 退款金额
+       */
+      refundAmount?: number;
+      /**
+       * 过期的积分
+       */
+      refundExpiredScore?: number;
+      /**
+       * 记录ID
+       */
+      refundId?: number;
+      /**
+       * 退还积分
+       */
+      refundScore?: number;
+      /**
+       * 退款编号
+       */
+      refundSn: string;
+      /**
+       * 退款时间
+       */
+      refundTime?: string;
+      /**
+       * 退款单类型(1:整单退款,2:单个物品退款)
+       */
+      refundType?: number;
+      /**
+       * 拒绝原因
+       */
+      rejectMessage?: string;
+      /**
+       * 拒绝时间
+       */
+      rejectTime?: string;
+      /**
+       * 退款单状态 10:待审核 20:处理中 30:驳回退款 40:撤销退款 60:待退货(一审同意) 65:待确认收货(二审待审核) 70:退款完成
+       */
+      returnMoneySts?: number;
+      /**
+       * 卖家备注
+       */
+      sellerMsg?: string;
+      /**
+       * 发货时间
+       */
+      shipTime?: string;
+      /**
+       * 店铺ID
+       */
+      shopId?: number;
+      /**
+       * 更新时间
+       */
+      updateTime?: string;
+      /**
+       * 买家ID
+       */
+      userId?: string;
+
+      [property: string]: any;
+    }
+
+    /**
+     * OrderRefundSku
+     */
+    interface OrderRefundSku {
+      /**
+       * 记录ID
+       */
+      id?: number;
+      /**
+       * 订单项id
+       */
+      orderItemId?: number;
+      /**
+       * 退款单ID
+       */
+      orderRefundId?: number;
+      /**
+       * 退款商品数量
+       */
+      productCount?: number;
+      /**
+       * 退款商品ID
+       */
+      skuId?: number;
+      /**
+       * 商品单价
+       */
+      skuPrice?: number;
+      /**
+       * 规格
+       */
+      spec: string;
+      [property: string]: any;
+    }
+    interface OrderRefundCountParam {
+      /**
+       * 全部数量
+       */
+      allCount?: number;
+      /**
+       * 买家发货(65)
+       */
+      buyerDeliveryCount?: number;
+      /**
+       * 退款完成(70)
+       */
+      refundCompleteCount?: number;
+      /**
+       * 卖家接受(60)
+       */
+      sellerAcceptCount?: number;
+      /**
+       * 卖家申请(10)
+       */
+      sellerApplyCount?: number;
+      /**
+       * 卖家拒绝(30)
+       */
+      sellerRejectCount?: number;
+      /**
+       * 配送中数量(40)
+       */
+      shippingCount?: number;
+      /**
+       * 撤回申请(40)
+       */
+      withdrawApplyCount?: number;
+      [property: string]: any;
+    }
   }
 }

+ 2 - 0
src/typings/elegant-router.d.ts

@@ -40,6 +40,7 @@ declare module "@elegant-router/types" {
     "config_fright-config": "/config/fright-config";
     "config_order-splitting": "/config/order-splitting";
     "delivery": "/delivery";
+    "delivery_after-sales-order": "/delivery/after-sales-order";
     "delivery_normal-order": "/delivery/normal-order";
     "goods": "/goods";
     "goods_desk-category": "/goods/desk-category";
@@ -191,6 +192,7 @@ declare module "@elegant-router/types" {
     | "about"
     | "config_fright-config"
     | "config_order-splitting"
+    | "delivery_after-sales-order"
     | "delivery_normal-order"
     | "goods_desk-category"
     | "goods_store-goods"

+ 38 - 0
src/views/delivery/after-sales-order/after-sales-order.ts

@@ -0,0 +1,38 @@
+export enum refundEnum {
+  /**
+   * 买家申请
+   */
+  BUYER_APPLY = 10,
+
+  /**
+   * 卖家同意
+   */
+  SELLER_AGREE = 60,
+
+  /**
+   * 卖家拒绝
+   */
+  SELLER_REFUSE = 30,
+
+  /**
+   * 退款成功
+   */
+  REFUND_SUCCESS = 70,
+  /**
+   * 买家发货
+   */
+  BUYER_DELIVERY = 65,
+  /**
+   * 撤回申请
+   */
+  REVOKE_APPLY = 40
+}
+
+export const refundStatus = {
+  [refundEnum.BUYER_APPLY]: '买家申请',
+  [refundEnum.SELLER_AGREE]: '卖家同意',
+  [refundEnum.SELLER_REFUSE]: '卖家拒绝',
+  [refundEnum.REFUND_SUCCESS]: '退款成功',
+  [refundEnum.BUYER_DELIVERY]: '买家发货',
+  [refundEnum.REVOKE_APPLY]: '撤回申请'
+};

+ 320 - 0
src/views/delivery/after-sales-order/index.vue

@@ -0,0 +1,320 @@
+<script setup lang="tsx">
+import { reactive, ref, unref, useTemplateRef, watch } from 'vue';
+import { NImage, NTag } from 'naive-ui';
+import { fetchGetAfterSalesOrderList, fetchGetAfterSalesStatusNum } from '@/service/api/delivery/after-sales-order';
+import { useAppStore } from '@/store/modules/app';
+import { defaultTransform, useNaivePaginatedTable } from '@/hooks/common/table';
+import { copyTextToClipboard } from '@/utils/zt';
+import { $t } from '@/locales';
+import { useForm } from '@/components/zt/Form/hooks/useForm';
+import NormalMoadl from '../normal-order/component/normal-modal.vue';
+import { SearchForm, orderStatus } from '../normal-order/normal-order';
+import { refundEnum, refundStatus } from './after-sales-order';
+const appStore = useAppStore();
+const checkedRowKeys = ref([]);
+const activeTab = ref(0);
+const statusList = ref<{ label: string; value: number; num?: number; key: string }[]>([]);
+const orderMoadl = useTemplateRef('orderMoadl');
+
+const [registerSearchForm, { getFieldsValue }] = useForm({
+  schemas: SearchForm,
+  showAdvancedButton: false,
+  labelWidth: 120,
+  layout: 'horizontal',
+  gridProps: {
+    cols: '1 xl:4 s:1 l:3',
+    itemResponsive: true
+  },
+  collapsedRows: 1
+});
+const searchForm = ref();
+const searchParams = reactive({
+  current: 1,
+  size: 10
+});
+const { columns, data, loading, getData, mobilePagination } = useNaivePaginatedTable({
+  api: () => fetchGetAfterSalesOrderList({ ...searchParams, returnMoneySts: activeTab.value, ...unref(searchForm) }),
+  transform: response => defaultTransform(response),
+  paginationProps: {
+    pageSizes: [10, 20, 50, 100, 150, 200]
+  },
+  onPaginationParamsChange: params => {
+    searchParams.current = Number(params.page);
+    searchParams.size = Number(params.pageSize);
+  },
+  columns: () => [
+    {
+      key: 'orderItems',
+      title: '商品',
+      align: 'left',
+      width: 200,
+      colSpan: (_rowData, _rowIndex) => 2,
+      render: row => {
+        return (
+          <div>
+            <div class={'mb3 flex items-center'}>
+              <n-tag>
+                <div class={'flex items-center'}>
+                  退款编号:{row.refundSn}
+                  <div onClick={() => handleCopy(row.refundSn)}>
+                    <svgIcon icon={'bxs:copy'} class={'mx-3 cursor-pointer text-[#f97316]'}></svgIcon>
+                  </div>
+                  订单编号:{row.orderNumber}
+                  <div onClick={() => handleCopy(row.orderNumber)}>
+                    <svgIcon icon={'bxs:copy'} class={'mx-3 cursor-pointer text-[#f97316]'}></svgIcon>
+                  </div>
+                  申请时间:
+                  {row.applyTime} 门店名称 {row.shopName}
+                </div>
+              </n-tag>
+            </div>
+            {row.orderRefundSkuList?.map(item => {
+              return (
+                <div class={'mb-3 h-80px flex items-center'}>
+                  <NImage src={item.pic} class="h-[80px] min-w-80px w-[80px]" lazy />
+                  <div class={'ml12px flex-1'}>
+                    <div class={'w-full flex items-center justify-between'}>
+                      <div class={'w250px'}>
+                        <n-ellipsis class={'w250px'}>
+                          <span class={'w-full text-left text-15px font-semibold'}>{item.skuName}</span>
+                        </n-ellipsis>
+                      </div>
+                      <div class={'w100px text-left'}>
+                        <div class={'text-16px font-semibold'}>¥{item.skuPrice} </div>
+                      </div>
+                    </div>
+                    <div class={'w-full flex items-center justify-between'}>
+                      <div class={'w250px text-gray'}>规格:{item.spec || '--'} </div>
+                      <div class={'w100px text-left text-gray'}>x{item.productCount} </div>
+                    </div>
+                  </div>
+                </div>
+              );
+            })}
+          </div>
+        );
+      }
+    },
+    {
+      key: 'deptName',
+      title: '单价(元)/数量',
+      align: 'center',
+      width: 100
+    },
+    {
+      key: 'actualTotal',
+      title: '实付金额(元)',
+      align: 'center',
+      width: 120,
+      render: row => {
+        return (
+          <div class={'mt7'}>
+            <div class={'text-16px text-#ff0000 font-semibold'}>{row.actualTotal} 元</div>
+            <div>共 {row.goodsTotalCount} 件</div>
+          </div>
+        );
+      }
+    },
+    {
+      key: 'refundAmount',
+      title: '退款金额',
+      align: 'center',
+      width: 120,
+      render: row => {
+        return (
+          <div class={'mt7'}>
+            <div class={'text-16px text-#ff0000 font-semibold'}>{row.actualTotal} 元</div>
+            <div>共 {row.goodsTotalCount} 件</div>
+          </div>
+        );
+      }
+    },
+    {
+      title: '商品状况',
+      key: 'goods',
+      width: 220,
+      align: 'center',
+      render: row => {
+        const TypeText = ['仅退款', '退款退货', '差价退款'];
+        return (
+          <div class={'mt7'}>
+            <div class={'text-16px font-semibold'}>{TypeText[Number(row.applyType) - 1] || '未知状况'} </div>
+            <div class={'text-#ff0000'}> {row.buyerReason} </div>
+          </div>
+        );
+      }
+    },
+    {
+      key: 'status',
+      title: '订单状态',
+      align: 'center',
+      width: 220,
+      render: row => {
+        const statusKey = row.hbOrderStatus as keyof typeof orderStatus;
+        const statusText = orderStatus[statusKey] || '未知状态';
+        return <NTag class={'mt7'}>{statusText}</NTag>;
+      }
+    },
+    {
+      key: 'createTime',
+      title: '售后状态',
+      align: 'center',
+      width: 160,
+      render: row => {
+        const statusKey = row.returnMoneySts as keyof typeof refundStatus;
+        const statusText = refundStatus[statusKey] || '暂无售后';
+        return <NTag class={'mt7'}>{statusText}</NTag>;
+      }
+    },
+    {
+      key: 'operate',
+      title: $t('common.operate'),
+      align: 'center',
+      width: 130,
+      fixed: 'right',
+      render: row => {
+        return (
+          <div class={'mt7'}>
+            <n-button size="small" type="primary" quaternary onClick={() => handleOpenMoadl(row)}>
+              查看订单
+            </n-button>
+          </div>
+        );
+      }
+    }
+  ]
+});
+function handleOpenMoadl(row: Api.delivery.OrderRefund) {
+  if (!row.orderNumber) {
+    window.$message?.error('订单异常');
+    return;
+  }
+  orderMoadl.value?.open(String(row.orderNumber));
+}
+async function getNums() {
+  const { data: keyData } = await fetchGetAfterSalesStatusNum({ ...getFieldsValue() });
+  if (!keyData) return;
+  const orderStatusList = [
+    {
+      label: '全部',
+      value: 0,
+      key: 'allCount'
+    },
+    {
+      label: '买家申请',
+      value: refundEnum.BUYER_APPLY,
+      key: 'sellerApplyCount'
+    },
+    {
+      label: '卖家拒绝',
+      value: refundEnum.SELLER_REFUSE,
+      key: 'sellerAcceptCount'
+    },
+    {
+      label: '买家发货',
+      value: refundEnum.BUYER_DELIVERY,
+      key: 'sellerAcceptCount'
+    },
+    {
+      label: '卖家接受',
+      value: refundEnum.SELLER_AGREE,
+      key: 'buyerDeliveryCount'
+    },
+    {
+      label: '退款成功',
+      value: refundEnum.REFUND_SUCCESS,
+      key: 'refundCompleteCount'
+    },
+    {
+      label: '撤回申请',
+      value: refundEnum.REVOKE_APPLY,
+      key: 'withdrawApplyCount'
+    }
+  ];
+  const updatedOrderStatusList = orderStatusList.map(item => {
+    if (Object.hasOwn(keyData, item.key)) {
+      return {
+        ...item,
+        num: keyData[item.key]
+      };
+    }
+    return item;
+  });
+  console.log(updatedOrderStatusList, 'updatedOrderStatusList');
+  statusList.value = updatedOrderStatusList;
+}
+getNums();
+watch(
+  () => [activeTab.value],
+  () => {
+    searchParams.current = 1;
+    getData();
+  }
+);
+function handleSearch() {
+  const form = getFieldsValue();
+  if (form.createTime) {
+    form.startTime = form.createTime[0];
+    form.endTime = form.createTime[1];
+    delete form.createTime;
+  }
+  searchForm.value = form;
+  getData();
+  getNums();
+}
+function handleReset() {
+  searchForm.value = getFieldsValue();
+  getData();
+}
+async function handleCopy(No: string) {
+  await copyTextToClipboard(No);
+}
+</script>
+
+<template>
+  <div class="flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
+    <NCard :bordered="false" size="small">
+      <NCollapse display-directive="show">
+        <NCollapseItem title="搜索">
+          <BasicForm @register-form="registerSearchForm" @submit="handleSearch" @reset="handleReset" />
+        </NCollapseItem>
+      </NCollapse>
+    </NCard>
+    <NCard title="售后列表" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
+      <NTabs v-model:value="activeTab" type="line" animated class="mb-16px h-full">
+        <NTabPane
+          v-for="item in statusList"
+          :key="item.value"
+          display-directive="show"
+          :name="item.value"
+          :tab="`${item.label}(${item.num})`"
+        >
+          <NDataTable
+            v-model:checked-row-keys="checkedRowKeys"
+            :columns="columns"
+            :data="data"
+            size="small"
+            :flex-height="!appStore.isMobile"
+            :scroll-x="1800"
+            :loading="loading"
+            :row-key="row => row.refundId"
+            remote
+            class="sm:h-full"
+            :pagination="mobilePagination"
+          />
+        </NTabPane>
+      </NTabs>
+
+      <NormalMoadl ref="orderMoadl" @finish="(getData, getNums)"></NormalMoadl>
+    </NCard>
+  </div>
+</template>
+
+<style scoped lang="scss">
+:deep(.n-tabs-pane-wrapper) {
+  height: 100%;
+}
+:deep(.n-tab-pane) {
+  height: 100%;
+}
+</style>

+ 0 - 0
src/views/delivery/after-sales-order/order-modal.vue


+ 19 - 14
src/views/delivery/normal-order/component/delivery-modal.vue

@@ -1,10 +1,10 @@
 <script setup lang="tsx">
 import { nextTick, ref } from 'vue';
-import { fetchDeliveryOrder } from '@/service/api/delivery/normal-orde';
+import { fetchDeliveryOrder, fetchGetNomalOrderInfo } from '@/service/api/delivery/normal-orde';
 import { useModal } from '@/components/zt/Modal/hooks/useModal';
 import { useForm } from '@/components/zt/Form/hooks/useForm';
 import { deliveryInfo } from '../normal-order';
-const [registerModal, { openModal, setModalProps, setSubLoading, closeModal }] = useModal({
+const [registerModal, { openModal, setModalProps, setSubLoading, closeModal, setModalLoading }] = useModal({
   title: '订单发货',
   width: 1200,
   height: 800,
@@ -77,21 +77,26 @@ const ShipmentColumns: NaiveUI.TableColumn<Api.delivery.OrderItemElement>[] = [
     }
   }
 ];
-function handleOpenMoadl(data: Api.delivery.deliveryOrder) {
-  orderInfo.value = data;
-  const Info = {
-    ...data.userAddrOrder
-  };
-  openModal();
 
-  nextTick(() => {
-    setFieldsValue(Info);
-  });
-}
 defineExpose({
-  handleOpenMoadl,
-  setModalProps
+  setModalProps,
+  handleOpenOrder
 });
+async function handleOpenOrder(orderNumber: string) {
+  openModal();
+  setModalLoading(true);
+  const { data, error } = await fetchGetNomalOrderInfo(orderNumber);
+  setModalLoading(false);
+  if (!error) {
+    orderInfo.value = data;
+    const Info = {
+      ...data.userAddrOrder
+    };
+    nextTick(() => {
+      setFieldsValue(Info);
+    });
+  }
+}
 async function handleSubmit() {
   setSubLoading(false);
   await validate();

+ 10 - 1
src/views/delivery/normal-order/component/normal-modal.vue

@@ -43,7 +43,16 @@ function handleFinish() {
   emit('finish');
 }
 function handleShipment() {
-  ShipmentRef.value?.handleOpenMoadl(orderInfo.value as Api.delivery.deliveryOrder);
+  if (orderInfo.value?.refundStatus == 1) {
+    window.$message?.error('当前订单正在申请退款中');
+    return;
+  }
+  if (orderInfo.value?.refundStatus == 2) {
+    window.$message?.error('当前订单已经退款成功');
+    return;
+  }
+
+  ShipmentRef.value?.handleOpenOrder(String(orderInfo.value?.orderNumber));
 }
 
 const currentSteps = computed(() => {

+ 15 - 0
src/views/delivery/normal-order/index.vue

@@ -9,6 +9,7 @@ import { copyTextToClipboard } from '@/utils/zt';
 import { $t } from '@/locales';
 import { useForm } from '@/components/zt/Form/hooks/useForm';
 import { SearchForm, orderStatus, refundStatus } from './normal-order';
+import DeliveryModal from './component/delivery-modal.vue';
 import NormalMoadl from './component/normal-modal.vue';
 const appStore = useAppStore();
 const checkedRowKeys = ref([]);
@@ -16,6 +17,7 @@ const activeTab = ref('all');
 const statusList = ref<{ label: string; value: string; num?: number }[]>([]);
 const tabsInstRef = ref<TabsInst | null>(null);
 const orderMoadl = useTemplateRef('orderMoadl');
+const ShipmentModal = useTemplateRef('Shipment');
 onMounted(() => {
   nextTick(() => {
     tabsInstRef.value?.syncBarPosition();
@@ -171,12 +173,24 @@ const { columns, data, loading, getData, mobilePagination } = useNaivePaginatedT
             <n-button size="small" type="primary" quaternary onClick={() => handleOpenMoadl(row)}>
               查看订单
             </n-button>
+            {row.hbOrderStatus == 1 && (
+              <n-button size="small" type="primary" quaternary onClick={() => handleDeivery(row)}>
+                发货
+              </n-button>
+            )}
           </div>
         );
       }
     }
   ]
 });
+async function handleDeivery(row: Api.delivery.deliveryOrder) {
+  if (!row.orderNumber) {
+    window.$message?.error('订单异常');
+    return;
+  }
+  ShipmentModal.value?.handleOpenOrder(row.orderNumber);
+}
 function handleOpenMoadl(row: Api.delivery.deliveryOrder) {
   if (!row.orderNumber) {
     window.$message?.error('订单异常');
@@ -291,6 +305,7 @@ async function handleCopy(row: Api.delivery.deliveryOrder) {
         </NTabPane>
       </NTabs>
       <NormalMoadl ref="orderMoadl" @finish="(getData, getNums)"></NormalMoadl>
+      <DeliveryModal ref="Shipment" @finish="(getData, getNums)"></DeliveryModal>
     </NCard>
   </div>
 </template>

+ 3 - 3
src/views/delivery/normal-order/normal-order.ts

@@ -174,14 +174,14 @@ export const orderColumns: NaiveUI.TableColumn<Api.delivery.OrderItemElement>[]
   {
     title: '数量',
     key: 'prodCount',
-    width: 100,
+    width: 150,
     render: row => {
       const nodes = [h('div', { class: 'mr-2' }, row.prodCount)];
       if (row.refundIngCount) {
-        nodes.push(h(NTag, { class: 'ml2' }, `售后处理:${row.refundIngCount}`));
+        nodes.push(h(NTag, { class: 'ml2', type: 'error' }, () => `售后处理:${row.refundIngCount}`));
       }
       if (row.refundSuccessCount) {
-        nodes.push(h(NTag, { class: 'ml2', type: 'success' }, `退款成功:${row.refundSuccessCount}`));
+        nodes.push(h(NTag, { class: 'ml2', type: 'success' }, () => `退款成功:${row.refundSuccessCount}`));
       }
       return h(NFlex, { align: 'center' }, () => nodes);
     }