Преглед изворни кода

```
feat(editor): 添加disabled属性并优化渲染逻辑

- 添加nextTick导入以确保DOM更新完成
- 新增disabled属性用于控制编辑器启用状态
- 异步化renderWangEditor函数并添加禁用状态检查
- 在组件创建后检查并应用禁用状态
```

wenjie пре 1 месец
родитељ
комит
52b3adf08e
29 измењених фајлова са 1977 додато и 95 уклоњено
  1. 2 2
      .env.test
  2. 7 2
      src/components/zt/editor/index.vue
  3. 4 1
      src/locales/langs/en-us.ts
  4. 4 1
      src/locales/langs/zh-cn.ts
  5. 3 0
      src/router/elegant/imports.ts
  6. 27 0
      src/router/elegant/routes.ts
  7. 3 0
      src/router/elegant/transform.ts
  8. 52 0
      src/service/api/djk-manage/normal-order/index.ts
  9. 12 0
      src/service/api/goods-center/virtual-goods/index.ts
  10. 27 0
      src/service/api/order-manage/after-sales-order/index.ts
  11. 25 0
      src/service/api/xsb-manage/store-info/index.ts
  12. 2 0
      src/typings/components.d.ts
  13. 6 0
      src/typings/elegant-router.d.ts
  14. 6 3
      src/views/djk-manage/activity/index.vue
  15. 5 2
      src/views/djk-manage/edit-activity/index.vue
  16. 156 0
      src/views/djk-manage/normal-order/component/delivery-modal.vue
  17. 224 0
      src/views/djk-manage/normal-order/component/normal-modal.vue
  18. 270 0
      src/views/djk-manage/normal-order/index.vue
  19. 377 0
      src/views/djk-manage/normal-order/normal-order.ts
  20. 45 31
      src/views/goods-center/edit-health-goods/index.vue
  21. 3 2
      src/views/goods-center/health-goods/index.vue
  22. 147 5
      src/views/goods-center/store-goods/index.vue
  23. 71 2
      src/views/goods-center/virtual-goods/index.vue
  24. 189 0
      src/views/order-manage/after-sales-order-detail/index.vue
  25. 165 0
      src/views/order-manage/after-sales-order/index.vue
  26. 32 21
      src/views/order-manage/normal-order/index.vue
  27. 106 3
      src/views/order-manage/normal-order/normal-order.ts
  28. 4 4
      src/views/order-manage/order-detail/index.vue
  29. 3 16
      src/views/xsb-manage/store-info/index.vue

+ 2 - 2
.env.test

@@ -7,9 +7,9 @@
 # VITE_SERVICE_BASE_URL=http://74949mkfh190.vicp.fun #付
 # VITE_SERVICE_BASE_URL=https://smqjh.api.zswlgz.com
 # VITE_SERVICE_BASE_URL=https://735a1bda.r24.cpolar.top #黄
-# VITE_SERVICE_BASE_URL=https://1fa1ad42.r9.vip.cpolar.cn
+# VITE_SERVICE_BASE_URL=http://89561bkaq794.vicp.fun:53846
 
-VITE_SERVICE_BASE_URL=http://47.109.84.152:8081 #打包测试本地服务器
+VITE_SERVICE_BASE_URL=https://smqjh.api.zswlgz.com #打包测试本地服务器
 # VITE_SERVICE_BASE_URL=/plt #测试打包服务器
 
 # other backend service base url, test environment

+ 7 - 2
src/components/zt/editor/index.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { onMounted, ref } from 'vue';
+import { nextTick, onMounted, ref } from 'vue';
 import WangEditor from 'wangeditor';
 import { fetchUpload } from '@/service/api/common';
 
@@ -9,6 +9,7 @@ const domRef = ref<HTMLElement>();
 const context = defineModel<string>();
 const props = defineProps<{
   height?: number;
+  disabled?: boolean;
 }>();
 const uploadConfig = {
   // 服务器端点
@@ -20,11 +21,15 @@ const uploadConfig = {
   // 超时时间
   timeout: 30 * 1000
 };
-function renderWangEditor() {
+async function renderWangEditor() {
   editor.value = new WangEditor(domRef.value);
   setEditorConfig();
   configureImageUpload();
   editor.value.create();
+  await nextTick();
+  if (props.disabled) {
+    editor.value.disable();
+  }
   if (context.value) {
     editor.value.txt.html(context.value);
   }

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

@@ -282,7 +282,10 @@ const local: App.I18n.Schema = {
     'djk-manage': '',
     'djk-manage_activity': '',
     'government_claim-records': '',
-    'djk-manage_edit-activity': ''
+    'djk-manage_edit-activity': '',
+    'djk-manage_normal-order': '',
+    'order-manage_after-sales-order': '',
+    'order-manage_after-sales-order-detail': ''
   },
   page: {
     login: {

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

@@ -279,7 +279,10 @@ const local: App.I18n.Schema = {
     'djk-manage': '',
     'djk-manage_activity': '',
     'government_claim-records': '',
-    'djk-manage_edit-activity': ''
+    'djk-manage_edit-activity': '',
+    'djk-manage_normal-order': '',
+    'order-manage_after-sales-order': '',
+    'order-manage_after-sales-order-detail': ''
   },
   page: {
     login: {

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

@@ -24,6 +24,7 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
   "device_terminal-manage": () => import("@/views/device/terminal-manage/index.vue"),
   "djk-manage_activity": () => import("@/views/djk-manage/activity/index.vue"),
   "djk-manage_edit-activity": () => import("@/views/djk-manage/edit-activity/index.vue"),
+  "djk-manage_normal-order": () => import("@/views/djk-manage/normal-order/index.vue"),
   "film-manage_config": () => import("@/views/film-manage/config/index.vue"),
   "film-manage_film-list": () => import("@/views/film-manage/film-list/index.vue"),
   "film-manage_setprice": () => import("@/views/film-manage/setprice/index.vue"),
@@ -46,6 +47,8 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
   manage_schedule: () => import("@/views/manage/schedule/index.vue"),
   manage_user: () => import("@/views/manage/user/index.vue"),
   "operation_accounting-strategy": () => import("@/views/operation/accounting-strategy/index.vue"),
+  "order-manage_after-sales-order-detail": () => import("@/views/order-manage/after-sales-order-detail/index.vue"),
+  "order-manage_after-sales-order": () => import("@/views/order-manage/after-sales-order/index.vue"),
   "order-manage_normal-order": () => import("@/views/order-manage/normal-order/index.vue"),
   "order-manage_order-detail": () => import("@/views/order-manage/order-detail/index.vue"),
   "user-center": () => import("@/views/user-center/index.vue"),

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

@@ -94,6 +94,15 @@ export const generatedRoutes: GeneratedRoute[] = [
           title: 'djk-manage_edit-activity',
           i18nKey: 'route.djk-manage_edit-activity'
         }
+      },
+      {
+        name: 'djk-manage_normal-order',
+        path: '/djk-manage/normal-order',
+        component: 'view.djk-manage_normal-order',
+        meta: {
+          title: 'djk-manage_normal-order',
+          i18nKey: 'route.djk-manage_normal-order'
+        }
       }
     ]
   },
@@ -397,6 +406,24 @@ export const generatedRoutes: GeneratedRoute[] = [
       i18nKey: 'route.order-manage'
     },
     children: [
+      {
+        name: 'order-manage_after-sales-order',
+        path: '/order-manage/after-sales-order',
+        component: 'view.order-manage_after-sales-order',
+        meta: {
+          title: 'order-manage_after-sales-order',
+          i18nKey: 'route.order-manage_after-sales-order'
+        }
+      },
+      {
+        name: 'order-manage_after-sales-order-detail',
+        path: '/order-manage/after-sales-order-detail',
+        component: 'view.order-manage_after-sales-order-detail',
+        meta: {
+          title: 'order-manage_after-sales-order-detail',
+          i18nKey: 'route.order-manage_after-sales-order-detail'
+        }
+      },
       {
         name: 'order-manage_normal-order',
         path: '/order-manage/normal-order',

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

@@ -187,6 +187,7 @@ const routeMap: RouteMap = {
   "djk-manage": "/djk-manage",
   "djk-manage_activity": "/djk-manage/activity",
   "djk-manage_edit-activity": "/djk-manage/edit-activity",
+  "djk-manage_normal-order": "/djk-manage/normal-order",
   "film-manage": "/film-manage",
   "film-manage_config": "/film-manage/config",
   "film-manage_film-list": "/film-manage/film-list",
@@ -217,6 +218,8 @@ const routeMap: RouteMap = {
   "operation": "/operation",
   "operation_accounting-strategy": "/operation/accounting-strategy",
   "order-manage": "/order-manage",
+  "order-manage_after-sales-order": "/order-manage/after-sales-order",
+  "order-manage_after-sales-order-detail": "/order-manage/after-sales-order-detail",
   "order-manage_normal-order": "/order-manage/normal-order",
   "order-manage_order-detail": "/order-manage/order-detail",
   "user-center": "/user-center",

+ 52 - 0
src/service/api/djk-manage/normal-order/index.ts

@@ -0,0 +1,52 @@
+import { request } from '@/service/request';
+
+/**
+ * 正常订单
+ * @param data
+ * @returns
+ */
+export function fetchGetOrderList(data: any) {
+  return request<Api.Common.PaginatingQueryRecord<Api.delivery.deliveryOrder>>({
+    url: '/smqjh-oms/api/v1/djkOrder/backendDJKOrderList',
+    method: 'get',
+    params: data
+  });
+}
+
+/**
+ *  获取订单状态数量
+ * @returns
+ */
+export function fetchGetStatusNum(data: any) {
+  return request<Api.delivery.DeliveryStatusNum>({
+    url: '/smqjh-oms/api/v1/djkOrder/backendDJKOrderStatusCount',
+    method: 'get',
+    params: data
+  });
+}
+
+/**
+ * 获取快递订单详情
+ * @param orderNumber
+ * @returns
+ */
+export function fetchGetNomalOrderInfo(orderNumber: string) {
+  return request<Api.delivery.deliveryOrder>({
+    // url: `/smqjh-oms/api/v1/order/backendOrderInfo`,
+    url: `/smqjh-oms/api/v1/djkOrder/backendDJKOrderInfo`,
+    method: 'get',
+    // params: { orderNo }
+    params: { orderNumber }
+  });
+}
+
+/**
+ * 核销
+ */
+export function fetchAudit(data: any) {
+  return request({
+    url: '/smqjh-oms/api/v1/djkOrder/backendVerification',
+    method: 'get',
+    params: data
+  });
+}

+ 12 - 0
src/service/api/goods-center/virtual-goods/index.ts

@@ -73,3 +73,15 @@ export function fetchChangeStatus(data: any) {
     params: data
   });
 }
+
+/**
+ * 修改商品封面
+ * @returns
+ */
+export function fetchUpdateProductImg(data: any) {
+  return request({
+    url: '/smqjh-pms/v1/videoProduct/updateProductImg',
+    method: 'post',
+    params: data
+  });
+}

+ 27 - 0
src/service/api/order-manage/after-sales-order/index.ts

@@ -0,0 +1,27 @@
+import { request } from '@/service/request';
+
+/**
+ * 售后订单
+ * @param data
+ * @returns
+ */
+export function fetchGetAfterSalesOrderList(data: any) {
+  return request<Api.Common.PaginatingQueryRecord<Api.delivery.deliveryOrder>>({
+    url: '/smqjh-oms/api/v1/orderRefund/findBackgroundPage',
+    method: 'get',
+    params: data
+  });
+}
+
+/**
+ * 获取售后订单详情
+ * @param orderNumber
+ * @returns
+ */
+export function fetchGetAfterSalesOrderDetail(refundNumber: string) {
+  return request<Api.delivery.deliveryOrder>({
+    url: `/smqjh-oms/api/v1/orderRefund/backendOrderRefundInfo`,
+    method: 'get',
+    params: { refundNumber }
+  });
+}

+ 25 - 0
src/service/api/xsb-manage/store-info/index.ts

@@ -75,3 +75,28 @@ export function fetchGetShopCity(data: any) {
     params: data
   });
 }
+/**
+ * 通过地址获取经纬度信息
+ * @param data
+ * @returns
+ */
+export function fetchParseAddress(data: any) {
+  return request({
+    url: '/smqjh-pms/api/v1/shopDetail/parseAddress',
+    method: 'GET',
+    params: data
+  });
+}
+
+/**
+ * 查询商品导入记录
+ * @param data
+ * @returns
+ */
+export function fetchImportLogList(data: any) {
+  return request({
+    url: '/smqjh-pms/api/v1/channelProdRecord/group',
+    method: 'GET',
+    params: data
+  });
+}

+ 2 - 0
src/typings/components.d.ts

@@ -106,6 +106,8 @@ declare module 'vue' {
     NText: typeof import('naive-ui')['NText']
     NTh: typeof import('naive-ui')['NTh']
     NThead: typeof import('naive-ui')['NThead']
+    NTimeline: typeof import('naive-ui')['NTimeline']
+    NTimelineItem: typeof import('naive-ui')['NTimelineItem']
     NTooltip: typeof import('naive-ui')['NTooltip']
     NTr: typeof import('naive-ui')['NTr']
     NTree: typeof import('naive-ui')['NTree']

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

@@ -41,6 +41,7 @@ declare module "@elegant-router/types" {
     "djk-manage": "/djk-manage";
     "djk-manage_activity": "/djk-manage/activity";
     "djk-manage_edit-activity": "/djk-manage/edit-activity";
+    "djk-manage_normal-order": "/djk-manage/normal-order";
     "film-manage": "/film-manage";
     "film-manage_config": "/film-manage/config";
     "film-manage_film-list": "/film-manage/film-list";
@@ -71,6 +72,8 @@ declare module "@elegant-router/types" {
     "operation": "/operation";
     "operation_accounting-strategy": "/operation/accounting-strategy";
     "order-manage": "/order-manage";
+    "order-manage_after-sales-order": "/order-manage/after-sales-order";
+    "order-manage_after-sales-order-detail": "/order-manage/after-sales-order-detail";
     "order-manage_normal-order": "/order-manage/normal-order";
     "order-manage_order-detail": "/order-manage/order-detail";
     "user-center": "/user-center";
@@ -171,6 +174,7 @@ declare module "@elegant-router/types" {
     | "device_terminal-manage"
     | "djk-manage_activity"
     | "djk-manage_edit-activity"
+    | "djk-manage_normal-order"
     | "film-manage_config"
     | "film-manage_film-list"
     | "film-manage_setprice"
@@ -193,6 +197,8 @@ declare module "@elegant-router/types" {
     | "manage_schedule"
     | "manage_user"
     | "operation_accounting-strategy"
+    | "order-manage_after-sales-order-detail"
+    | "order-manage_after-sales-order"
     | "order-manage_normal-order"
     | "order-manage_order-detail"
     | "user-center"

+ 6 - 3
src/views/djk-manage/activity/index.vue

@@ -1,13 +1,14 @@
 <script setup lang="tsx">
+import { useRouter } from 'vue-router';
 import { NButton, NImage, NSwitch } from 'naive-ui';
 // import dayjs from 'dayjs';
-import { router } from '@/router';
 import {
   // fetchGetAllChannelList,
   fetchActivityList,
   fetchDelActivity
 } from '@/service/api/djk-manage/activity';
 import { useTable } from '@/components/zt/Table/hooks/useTable';
+const router = useRouter();
 
 // const TypeName = ['企业用户', 'B端用户', 'C端用户'];
 // const statusList = ['上架', '下架'];
@@ -215,8 +216,10 @@ function handleDelete(row: any) {
       <template #op="{ row }">
         <NSpace>
           <NButton size="small" @click="handleDetail(row)">商品详情</NButton>
-          <NButton size="small" @click="handleEdit(row)">编辑</NButton>
-          <NButton size="small" @click="handleDelete(row)">删除</NButton>
+          <template v-if="row.activityStatus == 1">
+            <NButton size="small" @click="handleEdit(row)">编辑</NButton>
+            <NButton size="small" @click="handleDelete(row)">删除</NButton>
+          </template>
         </NSpace>
       </template>
     </ZTable>

+ 5 - 2
src/views/djk-manage/edit-activity/index.vue

@@ -188,7 +188,7 @@ const [registerModalTable, { refresh, getTableCheckedRowKeys, getTableData }] =
     keyField: 'id',
     title: '商品列表',
     showAddButton: false,
-    minHeight: 400,
+    minHeight: 200,
     defaultParamsNotReset: 'channelIdList'
   }
 });
@@ -377,7 +377,10 @@ onMounted(() => {
       <NFormItem label="库存" path="inventory">
         <NInputNumber v-model:value="model.inventory" />
       </NFormItem>
-      <div class="flex justify-end">
+      <NFormItem label="状态">
+        <NSwitch v-model:value="model.shelfStatus" :unchecked-value="0" :checked-value="1" />
+      </NFormItem>
+      <div v-if="!disabled" class="flex justify-end">
         <NButton round type="primary" :loading="loading" @click="handleValidateButtonClick">保存</NButton>
       </div>
     </NForm>

+ 156 - 0
src/views/djk-manage/normal-order/component/delivery-modal.vue

@@ -0,0 +1,156 @@
+<script setup lang="tsx">
+import { nextTick, ref, unref } from 'vue';
+import { fetchDeliveryOrder, fetchGetNomalOrderInfo } from '@/service/api/order-manage/normal-order';
+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, setModalLoading }] = useModal({
+  title: '订单发货',
+  width: 1200,
+  height: 800,
+  isShowHeaderText: false
+});
+const [registerForm, { validate, getFieldsValue, setFieldsValue }] = useForm({
+  schemas: deliveryInfo,
+  labelWidth: 120,
+  layout: 'horizontal',
+  gridProps: {
+    cols: '1',
+    itemResponsive: true
+  },
+  collapsedRows: 1,
+  showActionButtonGroup: false
+});
+const emit = defineEmits<{
+  (e: 'finish'): void;
+}>();
+
+const orderInfo = ref<Api.delivery.deliveryOrder>();
+const isRefundIng = ref(false);
+const ShipmentColumns: NaiveUI.TableColumn<Api.delivery.OrderItemElement>[] = [
+  {
+    title: '商品',
+    key: 'goodsName',
+    width: 300,
+    render: row => {
+      return (
+        <div class={'flex items-center'}>
+          <n-image src={row.pic} width={80} height={80} class={'min-w-80px'}></n-image>
+          <div class={'ml2'}>
+            <div class={'text-15px font-semibold'}> {row.skuName} </div>
+            <div class={'text-gray'}>规格: {row.spec || '---'}</div>
+          </div>
+        </div>
+      );
+    }
+  },
+  {
+    title: '可发货数量',
+    key: 'num',
+    width: 250,
+    render: row => {
+      const count = Number(row.prodCount) - Number(row.refundSuccessCount);
+      if (Number(row.refundIngCount)) {
+        isRefundIng.value = true;
+      }
+      return (
+        <div class={'flex items-center justify-center'}>
+          {count} {handleCreateTag(row)}
+        </div>
+      );
+    }
+  },
+  {
+    title: '状态',
+    key: 'status',
+    align: 'center',
+    render: _row => {
+      return orderInfo.value?.hbOrderStatus == 1 ? <n-tag>等待发货</n-tag> : <n-tag type="success">已发货</n-tag>;
+    }
+  },
+  {
+    title: '发货数量',
+    key: 'count',
+    align: 'center',
+    render: row => {
+      const count = Number(row.prodCount) - Number(row.refundSuccessCount);
+      return count;
+    }
+  }
+];
+
+defineExpose({
+  setModalProps,
+  handleOpenOrder
+});
+function handleCreateTag(row: Api.delivery.OrderItemElement) {
+  if (row.refundSuccessCount) {
+    return (
+      <n-tag type="success" class={'ml2'}>
+        已扣除退款成功:{row.refundSuccessCount}
+      </n-tag>
+    );
+  }
+  if (row.refundIngCount) {
+    return (
+      <n-tag type="error" class={'ml2'}>
+        售后处理:{row.refundIngCount}
+      </n-tag>
+    );
+  }
+  return '';
+}
+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,
+      ...data
+    };
+    nextTick(() => {
+      setFieldsValue(Info);
+    });
+  }
+}
+async function handleSubmit() {
+  if (unref(isRefundIng)) {
+    window.$message?.error('存在售后处理中的商品,请处理后再发货');
+    return;
+  }
+  await validate();
+  setSubLoading(true);
+  const form: Recordable = {
+    ...getFieldsValue(),
+    orderNumber: orderInfo.value?.orderNumber
+  };
+  delete form.receiver;
+  delete form.mobile;
+  delete form.address;
+  const { error } = await fetchDeliveryOrder(form);
+  if (!error) {
+    emit('finish');
+    closeModal();
+  } else {
+    setSubLoading(false);
+  }
+}
+</script>
+
+<template>
+  <BasicModal @register="registerModal" @ok="handleSubmit" @after-leave="isRefundIng = false">
+    <div v-if="orderInfo">
+      <NCard :bordered="false" title="商品信息">
+        <NDataTable :scroll-x="1000" :columns="ShipmentColumns" :data="orderInfo.orderItems" :bordered="false" />
+      </NCard>
+      <NCard :bordered="false" title="订单信息">
+        <BasicForm @register-form="registerForm"></BasicForm>
+      </NCard>
+    </div>
+  </BasicModal>
+</template>
+
+<style scoped></style>

+ 224 - 0
src/views/djk-manage/normal-order/component/normal-modal.vue

@@ -0,0 +1,224 @@
+<script setup lang="ts">
+import { computed, ref, useTemplateRef } from 'vue';
+import dayjs from 'dayjs';
+import { fetchGetNomalOrderInfo } from '@/service/api/order-manage/normal-order';
+import { useAppStore } from '@/store/modules/app';
+import { copyTextToClipboard } from '@/utils/zt';
+import { useModal } from '@/components/zt/Modal/hooks/useModal';
+import { ShippingButton, dvyStatus, orderColumns, orderStatusEnum } from '../normal-order';
+import DeliveryModal from './delivery-modal.vue';
+const [registerModal, { openModal, setModalLoading }] = useModal({
+  title: '订单详情',
+  isShowHeaderText: false,
+  showFooter: false,
+  width: 1200,
+  height: 800
+});
+const orderInfo = ref<Api.delivery.deliveryOrder>();
+const appStore = useAppStore();
+const TimeDown = ref<number>(0);
+const ShipmentRef = useTemplateRef('Shipment');
+const emit = defineEmits<{
+  (e: 'finish'): void;
+}>();
+async function open(orderNumber: string) {
+  openModal();
+  setModalLoading(true);
+  const { data, error } = await fetchGetNomalOrderInfo(orderNumber);
+  if (!error) {
+    orderInfo.value = data;
+    if (orderInfo.value.hbLogisticStatus == orderStatusEnum.WAIT_PAY) {
+      const createTime = dayjs(orderInfo.value.createTime);
+      const currentTime = dayjs();
+      const elapsed = currentTime.diff(createTime);
+      const fifteenMinutesInMillis = 15 * 60 * 1000;
+      TimeDown.value = fifteenMinutesInMillis - elapsed;
+    }
+  }
+  setModalLoading(false);
+}
+defineExpose({ open });
+function handleFinish() {
+  open(String(orderInfo.value?.orderNumber));
+  emit('finish');
+}
+const isRefund = computed(() => {
+  const goodsData = orderInfo.value?.orderItems?.find(it => it.refundIngCount == 1);
+  return Boolean(goodsData);
+});
+function handleShipment() {
+  if (isRefund.value) {
+    window.$message?.error('当前订单正在申请退款中');
+    return;
+  }
+  ShipmentRef.value?.handleOpenOrder(String(orderInfo.value?.orderNumber));
+}
+
+const currentSteps = computed(() => {
+  switch (orderInfo.value?.hbOrderStatus) {
+    case orderStatusEnum.WAIT_PAY:
+      return 1;
+    case orderStatusEnum.ORDER_ACCEPT:
+      return 2;
+    case orderStatusEnum.ORDER_WAIT_DELIVERY:
+      return 2;
+    case orderStatusEnum.WAIT_DELIVERY:
+      return 2;
+    case orderStatusEnum.ORDER_DELIVERY:
+      return 3;
+    case orderStatusEnum.ORDER_ARRIVE:
+      return 3;
+    case orderStatusEnum.ORDER_COMPLETE:
+      return 4;
+    default:
+      return 1;
+  }
+});
+function handleCopy(value: string | number | undefined) {
+  copyTextToClipboard(String(value));
+  // copyTextToClipboard(String(orderInfo.value?.orderNumber));
+}
+</script>
+
+<template>
+  <div>
+    <BasicModal @register="registerModal" @after-leave="orderInfo = undefined">
+      <div v-if="orderInfo">
+        <NFlex justify="space-between" align="center">
+          <NFlex>
+            <NTag v-if="orderInfo.parentOrderNumber">
+              <div class="flex items-center">
+                父订单编号: {{ orderInfo?.parentOrderNumber }}
+                <div @click="handleCopy(orderInfo?.parentOrderNumber)">
+                  <SvgIcon icon="bxs:copy" class="mx-3 cursor-pointer text-[#f97316]"></SvgIcon>
+                </div>
+              </div>
+            </NTag>
+            <NTag>
+              <div class="flex items-center">
+                {{ orderInfo.orderLevel === 0 ? '订单编号' : '子订单编号' }}: {{ orderInfo?.orderNumber }}
+                <div @click="handleCopy(orderInfo?.orderNumber)">
+                  <SvgIcon icon="bxs:copy" class="mx-3 cursor-pointer text-[#f97316]"></SvgIcon>
+                </div>
+              </div>
+            </NTag>
+            <NTag>下单时间: {{ orderInfo?.createTime }}</NTag>
+          </NFlex>
+          <NFlex vertical>
+            <template v-if="orderInfo.hbOrderStatus == orderStatusEnum.WAIT_PAY">
+              <div class="text-16px font-semibold">商品已拍下,等待买家付款</div>
+              <div class="text-gray">
+                如买家未在
+                <NTag :type="TimeDown > 300094 ? 'success' : 'error'">
+                  <NCountdown :duration="TimeDown" @finish="handleFinish" />
+                </NTag>
+                内付款,订单将 自动关闭。
+              </div>
+            </template>
+            <template v-if="!orderInfo.dvyFlowId">
+              <template v-if="ShippingButton.includes(orderInfo.hbOrderStatus)">
+                <div class="text-16px font-semibold">等待商家发货</div>
+                <NButton size="small" type="primary" @click="handleShipment">发货</NButton>
+              </template>
+            </template>
+            <template v-if="orderInfo.hbOrderStatus == orderStatusEnum.ORDER_ARRIVE">
+              <div class="text-16px font-semibold">等待买家收货</div>
+              <div>商家已发货,等待确认收货</div>
+            </template>
+            <template v-if="orderInfo.hbOrderStatus == orderStatusEnum.ORDER_CANCEL">
+              <div class="text-16px font-semibold">已取消</div>
+              <div>取消原因:{{ orderInfo.cancelReason || '未知取消原因' }}</div>
+            </template>
+            <template v-if="orderInfo.hbOrderStatus == orderStatusEnum.ORDER_COMPLETE">
+              <div class="text-16px font-semibold">交易成功</div>
+              <div>买家已收货</div>
+            </template>
+          </NFlex>
+        </NFlex>
+        <NDivider />
+        <template v-if="orderInfo.hbOrderStatus != orderStatusEnum.ORDER_CANCEL">
+          <div class="p3">
+            <NSteps :current="currentSteps" :vertical="appStore.isMobile">
+              <NStep title="用户下单" :description="orderInfo.createTime" />
+              <NStep title="买家已付款" :description="orderInfo.payTime" />
+              <NStep title="卖家已发货" :description="orderInfo.dvyTime" />
+              <NStep title="买家已收货" :description="orderInfo.finallyTime" />
+            </NSteps>
+          </div>
+          <NDivider />
+        </template>
+        <NDescriptions bordered :column="appStore.isMobile ? 1 : 4">
+          <NDescriptionsItem label="收货人信息">
+            <div>收货人姓名:{{ orderInfo?.userAddrOrder?.receiver || '---' }}</div>
+            <div>收货人手机号:{{ orderInfo?.userAddrOrder?.mobile || '---' }}</div>
+            <div>收货地址:{{ orderInfo?.userAddrOrder?.address || '---' }}</div>
+          </NDescriptionsItem>
+          <NDescriptionsItem label="配送信息">
+            <div>配送方式: {{ dvyStatus[orderInfo.dvyType as keyof typeof dvyStatus] || '暂无' }}</div>
+          </NDescriptionsItem>
+          <NDescriptionsItem label="父订单付款信息">
+            <div>实付金额:{{ orderInfo.actualTotal }}元</div>
+            <div>
+              付款方式:{{
+                orderInfo.hbOrderStatus == orderStatusEnum.WAIT_PAY ||
+                orderInfo.hbOrderStatus == orderStatusEnum.ORDER_CANCEL
+                  ? '暂无'
+                  : '微信'
+              }}
+            </div>
+            <div>付款时间:{{ orderInfo.payTime || '暂无' }}</div>
+          </NDescriptionsItem>
+          <NDescriptionsItem label="买家信息">
+            <div>买家昵称:{{ orderInfo?.nickName || '---' }}</div>
+            <div>买家电话:{{ orderInfo?.userMobile || '---' }}</div>
+            <div>买家留言:{{ orderInfo?.remarks || '暂无' }}</div>
+          </NDescriptionsItem>
+        </NDescriptions>
+        <NDivider />
+        <NCard title="子订单信息" :bordered="false">
+          <NDataTable :columns="orderColumns" :data="orderInfo.orderItems" :bordered="false" />
+        </NCard>
+        <NCard title="子费用信息" :bordered="false">
+          <NTable :single-line="false">
+            <NThead>
+              <NTr>
+                <NTh>费用类型</NTh>
+                <NTh>金额/元</NTh>
+              </NTr>
+            </NThead>
+            <NTbody>
+              <NTr>
+                <NTd>商品总额</NTd>
+                <NTd>{{ orderInfo.total }}</NTd>
+              </NTr>
+              <NTr>
+                <NTd>配送费(快递)</NTd>
+                <NTd>{{ orderInfo.freightAmount }}</NTd>
+              </NTr>
+              <NTr>
+                <NTd>积分</NTd>
+                <NTd>-{{ (Number(orderInfo.offsetPoints) / 100).toFixed(2) || 0 }}</NTd>
+              </NTr>
+              <NTr>
+                <NTd v-if="orderInfo.hbOrderStatus == orderStatusEnum.WAIT_PAY">需付款</NTd>
+                <NTd
+                  v-if="
+                    orderInfo.hbOrderStatus != orderStatusEnum.WAIT_PAY &&
+                    orderInfo.hbOrderStatus != orderStatusEnum.ORDER_CANCEL
+                  "
+                >
+                  实际付款
+                </NTd>
+                <NTd v-if="orderInfo.hbOrderStatus == orderStatusEnum.ORDER_CANCEL">应付款</NTd>
+                <NTd>{{ orderInfo.actualTotal }}</NTd>
+              </NTr>
+            </NTbody>
+          </NTable>
+        </NCard>
+      </div>
+    </BasicModal>
+    <DeliveryModal ref="Shipment" @finish="emit('finish')"></DeliveryModal>
+  </div>
+</template>
+
+<style scoped></style>

+ 270 - 0
src/views/djk-manage/normal-order/index.vue

@@ -0,0 +1,270 @@
+<script setup lang="tsx">
+import { nextTick, ref, watch } from 'vue';
+import { useRouter } from 'vue-router';
+import { NTag } from 'naive-ui';
+import { fetchAudit, fetchGetOrderList, fetchGetStatusNum } from '@/service/api/djk-manage/normal-order';
+// import { fetchGetLoginUserList } from '@/service/api/common';
+// import { useAuth } from '@/hooks/business/auth';
+// import { copyTextToClipboard } from '@/utils/zt';
+import { useTable } from '@/components/zt/Table/hooks/useTable';
+// import { type } from '../../../../packages/axios/src/index';
+import { DJKOrderStatus, SearchForm } from './normal-order';
+const router = useRouter();
+const activeTab = ref('all');
+const statusList = ref<{ label: string; value: string; num?: number }[]>([]);
+// const ShipmentModal = useTemplateRef('Shipment');
+const channelIdList = ref([]);
+const loading = ref(false);
+const columns: NaiveUI.TableColumn<Api.delivery.deliveryOrder>[] = [
+  {
+    key: 'shopName',
+    title: '门店名称',
+    align: 'center',
+    width: 220
+  },
+  {
+    key: 'orderNumber',
+    title: '订单编号',
+    align: 'center'
+  },
+  {
+    key: 'consigneeMobile',
+    title: '客户手机号',
+    align: 'center'
+  },
+  {
+    key: 'activityName',
+    title: '活动名称',
+    align: 'center'
+  },
+  {
+    key: 'goodsName',
+    title: '商品名称',
+    align: 'center'
+  },
+  {
+    key: 'actualTotal',
+    title: '金额',
+    align: 'center',
+    render: row => {
+      return <div>¥{row.actualTotal}</div>;
+    }
+  },
+  {
+    key: 'hbOrderStatus',
+    title: '订单状态',
+    align: 'center',
+    width: 120,
+    render: row => {
+      const statusKey = row.hbOrderStatus as keyof typeof DJKOrderStatus;
+      const statusText = DJKOrderStatus[statusKey as keyof typeof DJKOrderStatus] || '未知状态';
+      return <NTag>{statusText}</NTag>;
+    }
+  }
+];
+
+const [registerTable, { refresh, getSeachForm }] = useTable({
+  searchFormConfig: {
+    schemas: [...SearchForm]
+  },
+  tableConfig: {
+    keyField: 'id',
+    title: '',
+    showAddButton: false,
+    showTableHeaderAction: true,
+    opWdith: 180,
+    fieldMapToTime: [['createTime', ['startTime', 'endTime']]]
+  }
+});
+
+// const dialog = useDialog();
+
+// async function handleDeivery(row: Api.delivery.deliveryOrder) {
+//   if (!row.orderNumber) {
+//     window.$message?.error('订单异常');
+//     return;
+//   }
+//   ShipmentModal.value?.handleOpenOrder(row.orderNumber);
+// }
+
+function handleOrderDetail(row: Api.delivery.deliveryOrder) {
+  if (!row.orderNumber) {
+    window.$message?.error('订单异常');
+  }
+  router.push({
+    path: '/order-manage/order-detail',
+    query: {
+      orderNumber: row.orderNumber
+    }
+  });
+  // orderMoadl.value?.open(String(row.orderNumber));
+}
+
+async function handleAudit(row: any) {
+  window.$dialog?.info({
+    title: '提示',
+    content: `此操作将核销该订单,且无法撤销,确定要核销吗?`,
+    positiveText: '确定',
+    negativeText: '取消',
+    onPositiveClick: async () => {
+      if (loading.value) return;
+      loading.value = true;
+      const { error } = await fetchAudit({ orderNumber: row.orderNumber });
+      loading.value = false;
+      if (!error) {
+        refresh();
+      }
+    }
+  });
+}
+async function getNums() {
+  const form = getSeachForm();
+  const params = {
+    ...form,
+    channelIdList: channelIdList.value,
+    startTime: form?.createTime && form.createTime[0],
+    endTime: form?.createTime && form.createTime[1],
+    createTime: null
+  };
+  const { data: keyData } = await fetchGetStatusNum(params);
+  if (!keyData) return;
+  const orderStatusList = [
+    {
+      label: '全部',
+      value: 'all'
+    },
+    {
+      label: '待支付',
+      value: 'paddingPay'
+    },
+    {
+      label: '待使用',
+      value: 'pendingUse'
+    },
+    {
+      label: '已核销',
+      value: 'verification'
+    },
+    {
+      label: '已退款',
+      value: 'refunded'
+    },
+    {
+      label: '已过期',
+      value: 'expire'
+    },
+    {
+      label: '已取消',
+      value: 'cancel'
+    }
+  ];
+  const updatedOrderStatusList = orderStatusList.map(item => {
+    const key = item.value as keyof typeof keyData;
+    if (Object.hasOwn(keyData, key)) {
+      return {
+        ...item,
+        num: keyData[key]
+      };
+    }
+    return item;
+  });
+  // console.log(updatedOrderStatusList, 'updatedOrderStatusList');
+  statusList.value = updatedOrderStatusList;
+}
+
+getNums();
+
+// async function handleCopy(row: Api.delivery.deliveryOrder, key: string) {
+//   if (!row[key]) {
+//     window.$message?.error('订单编号不存在');
+//     return;
+//   }
+//   await copyTextToClipboard(row[key]);
+// }
+
+// async function handleExport() {
+//   setTableLoading(true);
+//   try {
+//     // await commonExport(
+//     //   '/platform/order/export',
+//     //   { ...getFieldsValue(), orderStatus: activeTab.value },
+//     //   '正常订单列表.xlsx'
+//     // );
+//     await fetchExportOrderList({ ...getSeachForm(), orderStatus: activeTab.value });
+//     dialog.success({
+//       title: '提示',
+//       content: () => {
+//         return (
+//           <div>
+//             <p>导出操作进行中......</p>
+//             <p>是否进入导出记录</p>
+//           </div>
+//         );
+//       },
+//       positiveText: '确定',
+//       negativeText: '取消',
+//       onPositiveClick: () => {
+//         openModal();
+//       },
+//       onNegativeClick: () => {}
+//     });
+//   } finally {
+//     setTableLoading(false);
+//   }
+// }
+
+// async function handleExportLog() {
+//   setTableLoading(true);
+//   try {
+//     openModal();
+//   } finally {
+//     setTableLoading(false);
+//   }
+// }
+watch(
+  () => [activeTab.value],
+  () => {
+    nextTick(() => {
+      refresh();
+    });
+  }
+);
+</script>
+
+<template>
+  <LayoutTable>
+    <ZTable
+      :columns="columns"
+      :api="fetchGetOrderList"
+      :default-params="{ orderStatus: activeTab }"
+      @register="registerTable"
+    >
+      <template #op="{ row }">
+        <NButton size="small" type="primary" ghost @click="handleOrderDetail(row)">订单详情</NButton>
+        <NButton v-if="row.hbOrderStatus == 20" size="small" type="primary" ghost @click="handleAudit(row)">
+          核销
+        </NButton>
+      </template>
+      <template #header>
+        <div class="flex items-center">
+          <NScrollbar x-scrollable>
+            <div class="flex items-center">
+              <div class="max-w-800px">
+                <NTabs v-model:value="activeTab" type="line" animated display-directive="show">
+                  <NTab
+                    v-for="item in statusList"
+                    :key="item.value"
+                    :name="item.value"
+                    :tab="`${item.label}(${item.num})`"
+                  ></NTab>
+                </NTabs>
+              </div>
+            </div>
+          </NScrollbar>
+        </div>
+      </template>
+    </ZTable>
+  </LayoutTable>
+</template>
+
+<style scoped></style>

+ 377 - 0
src/views/djk-manage/normal-order/normal-order.ts

@@ -0,0 +1,377 @@
+import { h } from 'vue';
+import { NFlex, NImage, NTag } from 'naive-ui';
+// import { fetchGetAllStoreList } from '@/service/api/goods/desk-category';
+import { fetchGetStoreList } from '@/service/api/xsb-manage/store-info';
+// import { fetchGetDictDataList } from '@/service/api/system-manage';
+// import { useAuth } from '@/hooks/business/auth';
+import type { FormSchema } from '@/components/zt/Form/types/form';
+
+export const SearchForm: FormSchema[] = [
+  {
+    label: '门店名称',
+    component: 'ApiSelect',
+    field: 'shopId',
+    componentProps: {
+      api: fetchGetStoreList,
+      resultFeild: 'data.list',
+      labelFeild: 'shopName',
+      valueFeild: 'shopId'
+    }
+  },
+  {
+    label: '订单编号',
+    component: 'NInput',
+    field: 'orderNumber'
+  },
+  {
+    label: '订单类型',
+    component: 'NSelect',
+    field: 'djkOrderType',
+    componentProps: {
+      options: [
+        {
+          label: '正常订单',
+          value: 0
+        },
+        {
+          label: '福利订单',
+          value: 1
+        }
+      ]
+    }
+  },
+
+  {
+    label: '客户姓名',
+    component: 'NInput',
+    field: 'consigneeName'
+  },
+  {
+    label: '客户电话',
+    component: 'NInput',
+    field: 'consigneeMobile'
+  },
+  {
+    label: '用户电话',
+    component: 'NInput',
+    field: 'memberMobile'
+  },
+  {
+    label: '下单时间',
+    component: 'NDatePicker',
+    field: 'createTime',
+    componentProps: {
+      type: 'datetimerange',
+      defaultTime: ['00:00:00', '23:59:59']
+    }
+  }
+  // {
+  //   field: 'userAttrType',
+  //   label: '人员属性',
+  //   component: 'dictSelect',
+  //   componentProps: {
+  //     dictCode: 'user_attr_type',
+  //     immediate: true
+  //   },
+  //   show: useAuth().hasAuth('user:attr:type')
+  // }
+];
+
+export enum orderStatusEnum {
+  /**
+   *
+   *  待支付
+   */
+  WAIT_PAY = 0,
+  /**
+   * 待发货
+   */
+  WAIT_DELIVERY = 1,
+  /**
+   * 订单已接单(待拣货)
+   */
+  ORDER_ACCEPT = 20,
+  /**
+   * 订单待配送(拣货完成/自提类订单为待自提)
+   */
+  ORDER_WAIT_DELIVERY = 30,
+  /**
+   * 订单配送中
+   */
+  ORDER_DELIVERY = 40,
+  /**
+   * 订单取消待审核
+   */
+  ORDER_CANCEL_WAIT_AUDIT = 50,
+  /**
+   * 订单已取消
+   */
+  ORDER_CANCEL = 60,
+  /**
+   * 订单已退款
+   */
+  ORDER_REFUNDED = 61,
+  /**
+   * 订单已过期
+   */
+  ORDER_EXPIRED = 62,
+  /**
+   * 订单已送达
+   */
+  ORDER_ARRIVE = 70,
+  /**
+   * 订单已完成
+   */
+  ORDER_COMPLETE = 80
+}
+/**
+ * 发货按钮显示状态
+ */
+export const ShippingButton = [
+  orderStatusEnum.WAIT_DELIVERY,
+  orderStatusEnum.ORDER_ACCEPT,
+  orderStatusEnum.ORDER_DELIVERY,
+  orderStatusEnum.ORDER_WAIT_DELIVERY
+];
+/**
+ *  // 0-待支付 1-待发货,20-订单已接单(待拣货),30-订单待配送(拣货完成/自提类订单为待自提),40-订单配送中
+        // ,50-订单取消待审核,60-订单已取消,70-订单已送达,80-订单已完成
+ */
+export const orderStatus = {
+  [orderStatusEnum.WAIT_PAY]: '待支付',
+  [orderStatusEnum.WAIT_DELIVERY]: '待发货',
+  [orderStatusEnum.ORDER_ACCEPT]: '订单已接单(待拣货)',
+  [orderStatusEnum.ORDER_WAIT_DELIVERY]: '订单待配送(拣货完成/自提类订单为待自提)',
+  [orderStatusEnum.ORDER_DELIVERY]: '订单配送中',
+  [orderStatusEnum.ORDER_CANCEL_WAIT_AUDIT]: '订单取消待审核',
+  [orderStatusEnum.ORDER_CANCEL]: '订单已取消',
+  [orderStatusEnum.ORDER_ARRIVE]: '订单已送达',
+  [orderStatusEnum.ORDER_COMPLETE]: '订单已完成'
+};
+
+export const DJKOrderStatus = {
+  [orderStatusEnum.WAIT_PAY]: '待支付',
+  [orderStatusEnum.ORDER_ACCEPT]: '待使用',
+  [orderStatusEnum.ORDER_CANCEL]: '已取消',
+  [orderStatusEnum.ORDER_REFUNDED]: '已退款',
+  [orderStatusEnum.ORDER_EXPIRED]: '已过期',
+  [orderStatusEnum.ORDER_COMPLETE]: '已核销'
+};
+
+export enum yppStatusEnum {
+  /**
+   *
+   *  待支付
+   */
+  WAIT_PAY = 0,
+  /**
+   * 已支付
+   */
+  WAIT_DELIVERY = 1,
+  /**
+   * 出票成功
+   */
+  SUCCESS = 4,
+  /**
+   * 出票失败(退款)
+   */
+  REFUND_FAIL = 7,
+  /**
+   * 超时未支付(取消)
+   */
+  TIMEOUT_CANCEL = 8
+}
+export const yppStatus = {
+  [yppStatusEnum.WAIT_PAY]: '待支付',
+  [yppStatusEnum.WAIT_DELIVERY]: '已支付',
+  [yppStatusEnum.SUCCESS]: '出票成功',
+  [yppStatusEnum.REFUND_FAIL]: '出票失败(退款)',
+  [yppStatusEnum.TIMEOUT_CANCEL]: '超时未支付(取消)'
+};
+/**
+ // 1:申请退款 2:退款成功 3:部分退款成功 4:退款失败
+ *
+ */
+
+export const refundStatus = {
+  1: '申请退款',
+  2: '退款成功',
+  3: '部分退款成功',
+  4: '退款失败'
+};
+/**
+ *
+ * 配送方式
+ */
+
+export const dvyStatus = {
+  1: '快递',
+  2: '自提',
+  3: '即时配送'
+};
+
+export const orderColumns: NaiveUI.TableColumn<Api.delivery.OrderItemElement>[] = [
+  {
+    title: '商品',
+    key: 'goods',
+    width: 300,
+    render: row => {
+      const goodsNodes = [
+        h(NImage, { src: row.pic, width: 80, height: 80 }),
+        h('div', { class: 'ml-2 ' }, [
+          h('div', { class: 'text-15px font-semibold' }, row.skuName),
+          h('div', { class: 'text-gray' }, `规格:${row.spec || '--'}`)
+        ])
+      ];
+      return h('div', { class: 'flex items-center' }, goodsNodes);
+    }
+  },
+  {
+    title: '单价(元)',
+    key: 'price',
+    width: 100
+  },
+  {
+    title: '数量',
+    key: 'prodCount',
+    width: 250,
+    render: row => {
+      const nodes = [h('div', { class: 'mr-2' }, row.prodCount)];
+      if (row.refundSuccessCount) {
+        nodes.push(h(NTag, { class: 'ml2', type: 'success' }, () => `退款成功:${row.refundSuccessCount}`));
+      }
+      if (row.refundIngCount && !row.refundSuccessCount) {
+        nodes.push(h(NTag, { class: 'ml2', type: 'error' }, () => `售后处理:${row.refundIngCount}`));
+      }
+      return h(NFlex, { align: 'center' }, () => nodes);
+    }
+  },
+  {
+    title: '小计/元',
+    key: 'productTotalAmount',
+    width: 100
+  }
+];
+
+export const orderDJKColumns: NaiveUI.TableColumn<Api.delivery.OrderItemElement>[] = [
+  {
+    title: '商品',
+    key: 'goods',
+    width: 300,
+    render: row => {
+      const goodsNodes = [
+        h(NImage, { src: row.goodsImg, width: 80, height: 80 }),
+        h('div', { class: 'ml-2 ' }, [
+          h('div', { class: 'text-15px font-semibold' }, row.skuName),
+          h('div', { class: 'text-gray' }, `规格:${row.spec || '--'}`)
+        ])
+      ];
+      return h('div', { class: 'flex items-center' }, goodsNodes);
+    }
+  },
+  {
+    title: '单价(元)',
+    key: 'price',
+    width: 100
+  },
+  {
+    title: '数量',
+    key: 'goodsNum',
+    width: 250,
+    render: row => {
+      const nodes = [h('div', { class: 'mr-2' }, row.goodsNum)];
+      if (row.refundSuccessCount) {
+        nodes.push(h(NTag, { class: 'ml2', type: 'success' }, () => `退款成功:${row.refundSuccessCount}`));
+      }
+      if (row.refundIngCount && !row.refundSuccessCount) {
+        nodes.push(h(NTag, { class: 'ml2', type: 'error' }, () => `售后处理:${row.refundIngCount}`));
+      }
+      return h(NFlex, { align: 'center' }, () => nodes);
+    }
+  },
+  {
+    title: '小计/元',
+    key: 'productTotalAmount',
+    width: 100,
+    render: (row: any) => {
+      return h('div', {}, (row.goodsNum * 1000 * (row.price * 1000)) / 1000);
+    }
+  }
+];
+
+export const orderDJKLogColumns: NaiveUI.TableColumn<Api.delivery.OrderItemElement>[] = [
+  {
+    title: '时间',
+    key: 'createTime'
+  },
+  {
+    title: '操作',
+    key: 'operation'
+  },
+  {
+    title: '操作员',
+    key: 'operator'
+  },
+  {
+    title: '备注',
+    key: 'remark'
+  }
+];
+
+export const deliveryInfo: FormSchema[] = [
+  {
+    label: '配送方式',
+    component: 'NGradientText',
+    field: 'dvyMethod',
+    render() {
+      return h('div', {}, '快递');
+    }
+  },
+  {
+    label: '收货人姓名',
+    component: 'NGradientText',
+    field: 'receiver',
+    render({ model, field }) {
+      return h('div', {}, model[field]);
+    }
+  },
+  {
+    label: '收货人手机号',
+    component: 'NInput',
+    field: 'mobile',
+    render({ model, field }) {
+      return h('div', {}, model[field]);
+    }
+  },
+  {
+    label: '收货地址',
+    component: 'NInput',
+    field: 'address',
+
+    render({ model, field }) {
+      return h('div', {}, model[field]);
+    }
+  }
+];
+
+/**
+ * 0:用户手动停止充电;1:客户归属地运营商平台停止充电;2:BMS停止充电;3:充电机设备故障;4:连接器断开;其它:自定义
+ */
+
+export const chargeMethod = [
+  '用户手动停止充电',
+  '客户归属地运营商平台停止充电',
+  'BMS停止充电',
+  '充电机设备故障',
+  '连接器断开',
+  '其它'
+];
+
+export const businessType = {
+  XSB: '星闪豹',
+  CD: '充电',
+  DYY: '电影演出',
+  DJK: '大健康',
+  XNSP: '虚拟商品',
+  JY: '加油'
+};

+ 45 - 31
src/views/goods-center/edit-health-goods/index.vue

@@ -1,13 +1,13 @@
 <script setup lang="ts">
-import { onMounted, ref } from 'vue';
-import { useRoute } from 'vue-router';
+import { computed, ref } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
 import type { FormInst, FormRules } from 'naive-ui';
 import { NForm, NInput, NSwitch, useMessage } from 'naive-ui';
-import E from 'wangeditor';
-import { router } from '@/router';
+// import { router } from '@/router';
 import { fetchAddGoods, fetchEditGoods, fetchGoodsDetail } from '@/service/api/goods-center/health-goods';
+import { fetchGetStoreList } from '@/service/api/xsb-manage/store-info';
 import ZUpload from '../../../components/zt/upload/z-upload.vue';
-const editor = ref();
+const router = useRouter();
 
 const route = useRoute();
 const formRef = ref<FormInst | null>(null);
@@ -37,7 +37,8 @@ const model = ref({
 });
 
 const rules: FormRules = {
-  shopName: {
+  shopId: {
+    type: 'number',
     required: true,
     trigger: ['blur', 'input'],
     message: '请输入'
@@ -48,6 +49,7 @@ const rules: FormRules = {
     message: '请输入'
   },
   goodsImg: {
+    type: 'string',
     required: true,
     trigger: ['blur', 'change'],
     message: '请输入'
@@ -82,11 +84,11 @@ const rules: FormRules = {
     trigger: ['blur', 'input'],
     message: '请输入'
   },
-  content: {
-    required: true,
-    trigger: ['blur', 'input'],
-    message: '请输入'
-  },
+  // content: {
+  //   required: true,
+  //   trigger: ['blur', 'input'],
+  //   message: '请输入'
+  // },
   useStartTime: {
     type: 'string',
     required: true,
@@ -95,12 +97,22 @@ const rules: FormRules = {
   }
 };
 
+const isShow = computed(() => {
+  if (!route.query.id) {
+    return true;
+  } else if (route.query.id && model.value.content) {
+    return true;
+  }
+  return false;
+});
+
 function handleValidateButtonClick(e: MouseEvent) {
+  console.log(model.value);
+
   e.preventDefault();
   formRef.value?.validate(async errors => {
     if (!errors) {
       loading.value = true;
-      model.value.content = editor.value.txt.html();
       model.value.useStartTime = useTime.value[0];
       model.value.useEndTime = useTime.value[1];
       let res;
@@ -110,9 +122,11 @@ function handleValidateButtonClick(e: MouseEvent) {
         res = await fetchAddGoods(model.value);
       }
       loading.value = false;
-      console.log(res);
+      console.log(11111111, res);
+
+      if (!res.error) {
+        console.log(22222222);
 
-      if (res.data === null) {
         router.push({
           path: '/goods-center/health-goods'
         });
@@ -129,24 +143,17 @@ async function getDetail() {
   const res = await fetchGoodsDetail(route.query.id);
   if (res.data) {
     model.value = res.data;
-    editor.value.txt.html(res.data.content); // 重新设置编辑器内容
     useTime.value = [res.data.useStartTime, res.data.useEndTime];
-    console.log(useTime.value);
+    console.log(11111111, model.value);
   }
 }
 
-onMounted(() => {
-  editor.value = new E('#div1');
-  editor.value.create();
-  if (route.query.id) {
-    if (route.query.mode === 'detail') {
-      disabled.value = true;
-      editor.value.disable();
-    }
-    getDetail();
+if (route.query.id) {
+  if (route.query.mode === 'detail') {
+    disabled.value = true;
   }
-  console.log(route.query);
-});
+  getDetail();
+}
 </script>
 
 <template>
@@ -163,13 +170,19 @@ onMounted(() => {
       :disabled="disabled"
     >
       <NFormItem label="门店名称" path="shopName">
-        <NInput v-model:value="model.shopName" placeholder="" />
+        <ApiSelect
+          v-model:value="model.shopId"
+          :api="fetchGetStoreList"
+          result-feild="data.list"
+          label-feild="shopName"
+          value-feild="shopId"
+        ></ApiSelect>
       </NFormItem>
       <NFormItem label="商品名称" path="goodsName">
         <NInput v-model:value="model.goodsName" placeholder="" />
       </NFormItem>
       <NFormItem label="封面" path="goodsImg">
-        <ZUpload :value="model.goodsImg" :max="1"></ZUpload>
+        <ZUpload v-model:value="model.goodsImg" :max="1"></ZUpload>
       </NFormItem>
       <NFormItem label="商品价格" path="price">
         <NInputNumber v-model:value="model.price" />
@@ -199,13 +212,14 @@ onMounted(() => {
         <NInput v-model:value="model.buyNotice" :maxlength="150" show-count placeholder="" type="textarea" />
       </NFormItem>
       <NFormItem label="图文说明" path="content">
-        <div id="div1"></div>
+        <!-- <div id="div1"></div> -->
+        <Editor v-if="isShow" v-model:model-value="model.content" :height="450" :disabled="disabled"></Editor>
       </NFormItem>
       <NFormItem label="上架状态" path="shelfStatus">
         <NSwitch v-model:value="model.shelfStatus" :unchecked-value="0" :checked-value="1" />
       </NFormItem>
 
-      <div class="flex justify-end">
+      <div v-if="!disabled" class="flex justify-end">
         <NButton round type="primary" :loading="loading" @click="handleValidateButtonClick">保存</NButton>
       </div>
     </NForm>

+ 3 - 2
src/views/goods-center/health-goods/index.vue

@@ -1,7 +1,7 @@
 <script setup lang="tsx">
+import { useRouter } from 'vue-router';
 import { NButton, NImage, NSwitch } from 'naive-ui';
 // import dayjs from 'dayjs';
-import { router } from '@/router';
 import { fetchGetStoreList } from '@/service/api/xsb-manage/store-info';
 import {
   // fetchGetAllChannelList,
@@ -9,6 +9,7 @@ import {
   fetchProductList
 } from '@/service/api/goods-center/health-goods';
 import { useTable } from '@/components/zt/Table/hooks/useTable';
+const router = useRouter();
 
 // const TypeName = ['企业用户', 'B端用户', 'C端用户'];
 // const statusList = ['上架', '下架'];
@@ -83,7 +84,7 @@ const columns: NaiveUI.TableColumn<Api.goods.ShopSku>[] = [
     align: 'center',
     width: 120,
     render: (row: any) => {
-      return <NSwitch uncheckedValue={0} checkedValue={1} value={row.status} disabled></NSwitch>;
+      return <NSwitch uncheckedValue={0} checkedValue={1} value={row.shelfStatus} disabled></NSwitch>;
     }
   }
 ];

+ 147 - 5
src/views/goods-center/store-goods/index.vue

@@ -1,8 +1,8 @@
 <script setup lang="tsx">
-import { computed, ref, useTemplateRef } from 'vue';
+import { computed, nextTick, ref, useTemplateRef } from 'vue';
 import { NButton, NInputNumber, NSelect } from 'naive-ui';
 import dayjs from 'dayjs';
-import { fetchGetStoreList } from '@/service/api/xsb-manage/store-info';
+import { fetchGetStoreList, fetchImportLogList } from '@/service/api/xsb-manage/store-info';
 // import {
 // fetchGetAllChannelList
 // fetchImportGoods,
@@ -24,11 +24,82 @@ import { useModal } from '@/components/zt/Modal/hooks/useModal';
 // import { businessType } from '../../order-manage/normal-order/normal-order';
 type Price = { channelId: number | undefined; channelProdPrice: number; id: number; channelName?: string };
 const importTemplateRef = useTemplateRef('importTemplateRef');
+const loading = ref(false);
 
 const options = ref<Api.goods.Channel[]>([]);
 // const TypeName = ['企业用户', 'B端用户', 'C端用户'];
 const statusList = ['商家下架', '上架', '违规下架', '平台审核'];
 const businessType = ref<Record<string, string>>({});
+const failColumns: NaiveUI.TableColumn<Api.government.PointsFailureRecordVO>[] = [
+  {
+    key: 'index',
+    title: '序号',
+    align: 'center',
+    width: 80,
+    render(_, rowIndex) {
+      return rowIndex + 1;
+    }
+  },
+  {
+    key: 'name',
+    title: '任务名称',
+    align: 'center'
+  },
+  {
+    key: 'createTime',
+    title: '时间',
+    align: 'center',
+    width: 300,
+    render(row) {
+      return (
+        <div>
+          <div>创建时间:{row.createTime}</div>
+          <div>完成时间:{row.createTime}</div>
+        </div>
+      );
+    }
+  },
+  {
+    key: 'totalUserCount',
+    title: '操作人',
+    align: 'center',
+    width: 120,
+    render(row) {
+      return (
+        <div>
+          <div>{row.createByRole}</div>
+          <div>({row.createByName})</div>
+        </div>
+      );
+    }
+  },
+  {
+    key: 'successStatus',
+    title: '状态',
+    align: 'center',
+    width: 240,
+    render(row) {
+      return (
+        <div class={'flex items-center'}>
+          共{Number(row.recordCount)}条,成功:{row.successCount},
+          <span class={'flex items-center text-red-500'}>
+            失败:
+            {row.failCount}
+            {row.failCount != 0 && (
+              <div onClick={() => hanleExportFailure(row.code)}>
+                <SvgIcon
+                  icon={'tdesign:download'}
+                  class={'ml-1 cursor-pointer text-20px'}
+                  style={'color:red'}
+                ></SvgIcon>
+              </div>
+            )}
+          </span>
+        </div>
+      );
+    }
+  }
+];
 const columns: NaiveUI.TableColumn<Api.goods.ShopSku>[] = [
   {
     type: 'selection',
@@ -55,6 +126,16 @@ const columns: NaiveUI.TableColumn<Api.goods.ShopSku>[] = [
       );
     }
   },
+  {
+    key: 'skuCode',
+    title: '商品编码',
+    align: 'center',
+    width: 120,
+    ellipsis: {
+      tooltip: true
+    }
+  },
+
   {
     key: 'pic',
     title: '商品图片',
@@ -147,6 +228,7 @@ const columns: NaiveUI.TableColumn<Api.goods.ShopSku>[] = [
     }
   }
 ];
+
 const PriceColumns: NaiveUI.TableColumn<Price>[] = [
   {
     title: '销售渠道',
@@ -320,6 +402,16 @@ const [registerTable, { getTableCheckedRowKeys, refresh, getTableData, getSeachF
           placeholder: ['最低价', '最高价'],
           allowInput: (value: string) => !value || /^\d+$/.test(value)
         }
+      },
+      {
+        label: '海博商品ID',
+        component: 'NInput',
+        field: 'hbSkuld'
+      },
+      {
+        label: '商品编码',
+        component: 'NInput',
+        field: 'skuCode'
       }
     ],
     inline: false,
@@ -338,6 +430,15 @@ const [registerTable, { getTableCheckedRowKeys, refresh, getTableData, getSeachF
     ]
   }
 });
+const [registerLogTable, { refresh: refreshLog, setTableLoading: setLogTableLoading }] = useTable({
+  tableConfig: {
+    keyField: 'skuId',
+    title: '',
+    minHeight: 200,
+    showAddButton: false,
+    showSearch: false
+  }
+});
 
 const [
   registerModalPrice,
@@ -348,6 +449,13 @@ const [
   height: 300
 });
 
+const [registerModalFail, { openModal: openModalFail }] = useModal({
+  title: '导入记录',
+  height: 400,
+  width: 1200,
+  showFooter: false
+});
+
 const isDisabledExport = computed(() => {
   return !getTableCheckedRowKeys().length;
 });
@@ -355,22 +463,45 @@ const tableData = computed(() => {
   return getTableData();
 });
 
+async function openImportLogModal() {
+  openModalFail();
+  await nextTick();
+  refreshLog();
+}
+
+async function hanleExportFailure(code: string) {
+  if (loading.value) {
+    window.$message?.error('正在导出,请勿重复点击');
+    return;
+  }
+  loading.value = true;
+  setLogTableLoading(true);
+  try {
+    await commonExport('/smqjh-pms/api/v1/channelProdRecord/exportError', { code }, '失败的记录.xlsx');
+  } finally {
+    loading.value = false;
+    setLogTableLoading(false);
+  }
+}
+
 async function getrDic() {
   const res = (await fetchGetDictDataList({ typeCode: 'sys_business_type' })) as any;
   if (!res.error) {
     res.data.list.forEach((item: any) => {
       businessType.value[item.value] = item.name;
     });
-    console.log('1111111111111111', businessType.value);
   }
 }
 
 getrDic();
 async function handleSubmitImport(file: File) {
-  const { error } = await fetchImportGoods({ file });
-  if (!error) {
+  const res = await fetchImportGoods({ file });
+  console.log(res);
+
+  if (!res.error) {
     importTemplateRef.value?.closeModal();
   }
+  window.$message?.success(res.data);
   importTemplateRef.value?.setSubLoading(false);
 }
 function openImportModal() {
@@ -481,6 +612,7 @@ async function handleExport() {
       </template>
       <template #prefix="{ loading }">
         <NSpace>
+          <NButton size="small" @click="openImportLogModal">导入记录</NButton>
           <NButton size="small" @click="openImportModal">导入商品销售渠道及价格</NButton>
           <NButton size="small" :disabled="tableData.length == 0" :loading="loading" @click="handleExport">
             导出全部
@@ -500,6 +632,16 @@ async function handleExport() {
     <BasicModal @register="registerModalPrice" @ok="handleSubmitPrice">
       <NDataTable :columns="PriceColumns" :data="PriceData" :row-key="row => row.channelId" />
     </BasicModal>
+
+    <BasicModal @register="registerModalFail">
+      <ZTable
+        :columns="failColumns"
+        :immediate="false"
+        :show-table-action="false"
+        :api="fetchImportLogList"
+        @register="registerLogTable"
+      ></ZTable>
+    </BasicModal>
   </LayoutTable>
 </template>
 

+ 71 - 2
src/views/goods-center/virtual-goods/index.vue

@@ -1,6 +1,6 @@
 <script setup lang="tsx">
 import { computed, ref, useTemplateRef } from 'vue';
-import { NButton, NInputNumber, NSelect } from 'naive-ui';
+import { NButton, NImage, NInputNumber, NSelect } from 'naive-ui';
 // import dayjs from 'dayjs';
 // import { fetchGetStoreList } from '@/service/api/xsb-manage/store-info';
 // import {
@@ -15,13 +15,15 @@ import {
   fetchGetChannelList,
   fetchImportGoods,
   fetchProductList,
-  fetchSetUpChannels
+  fetchSetUpChannels,
+  fetchUpdateProductImg
 } from '@/service/api/goods-center/virtual-goods';
 import { areAllItemsAllFieldsFilled } from '@/utils/zt';
 import { commonExport } from '@/utils/common';
 import { useTable } from '@/components/zt/Table/hooks/useTable';
 import SvgIcon from '@/components/custom/svg-icon.vue';
 import { useModal } from '@/components/zt/Modal/hooks/useModal';
+import { useModalFrom } from '@/components/zt/ModalForm/hooks/useModalForm';
 type Price = { channelId: number | undefined; channelProdPrice: number; id?: number; channelName?: string };
 const importTemplateRef = useTemplateRef('importTemplateRef');
 
@@ -41,6 +43,15 @@ const columns: NaiveUI.TableColumn<Api.goods.ShopSku>[] = [
     align: 'left',
     width: 200
   },
+  {
+    key: 'productImg',
+    title: '商品图片',
+    align: 'center',
+    width: 120,
+    render: (row: any) => {
+      return <NImage src={row.productImg} width={60} height={60}></NImage>;
+    }
+  },
   {
     key: 'productName',
     title: '商品名称',
@@ -343,6 +354,47 @@ const [
   height: 300
 });
 
+const [
+  registerModalForm,
+  {
+    openModal: openModalForm,
+    setFieldsValue: setModalFormValue,
+    getFieldsValue: getModalFormValue,
+    closeModal: closeModalForm,
+    setSubLoading
+  }
+] = useModalFrom({
+  modalConfig: {
+    title: '封面',
+    isShowHeaderText: true
+  },
+  formConfig: {
+    schemas: [
+      {
+        field: 'productId',
+        label: '分类ID',
+        component: 'NInput',
+        required: true
+      },
+      {
+        field: 'productImg',
+        component: 'zUpload',
+        label: '广告位图片',
+        componentProps: {
+          max: 1
+        },
+        required: true
+      }
+    ],
+    labelWidth: 120,
+    layout: 'horizontal',
+    gridProps: {
+      cols: '1',
+      itemResponsive: true
+    }
+  }
+});
+
 // const isDisabledExport = computed(() => {
 //   return !getTableCheckedRowKeys().length;
 // });
@@ -383,6 +435,11 @@ function handleModalPrice(row: Api.goods.ShopSku) {
 
   openPriceModal();
 }
+
+function handleModalImg(row: Api.goods.ShopSku) {
+  openModalForm(row);
+  setModalFormValue({ productImg: row.productImg, productId: row.productId });
+}
 function handleAddPrice() {
   // if (PriceData.value.length == 3) {
   //   window.$message?.error('最多只能添加3条数据');
@@ -476,6 +533,15 @@ function handleStatus(row: any) {
     }
   });
 }
+
+async function handleSubmit() {
+  const form = await getModalFormValue();
+  // console.log(form, '表单', selectChekedKeys.value);
+  await fetchUpdateProductImg(form);
+  setSubLoading(false);
+  closeModalForm();
+  refresh();
+}
 </script>
 
 <template>
@@ -483,6 +549,7 @@ function handleStatus(row: any) {
     <ZTable :columns="columns" :api="fetchProductList" @register="registerTable">
       <template #op="{ row }">
         <NSpace align="center">
+          <NButton size="small" ghost type="primary" @click="handleModalImg(row)">编辑图片</NButton>
           <NButton size="small" ghost type="primary" @click="handleModalPrice(row)">设置渠道及价格</NButton>
           <NButton size="small" ghost type="primary" @click="handleStatus(row)">
             {{ row.productStatus == 1 ? '上架' : '下架' }}
@@ -510,6 +577,8 @@ function handleStatus(row: any) {
     <BasicModal @register="registerModalPrice" @ok="handleSubmitPrice">
       <NDataTable :columns="PriceColumns" :data="PriceData" :row-key="row => row.channelId" />
     </BasicModal>
+
+    <BasicModelForm @register-modal-form="registerModalForm" @submit-form="handleSubmit"></BasicModelForm>
   </LayoutTable>
 </template>
 

+ 189 - 0
src/views/order-manage/after-sales-order-detail/index.vue

@@ -0,0 +1,189 @@
+<script setup lang="ts">
+import { ref } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+// import { NFlex } from 'naive-ui';
+import { NImage, NSpace } from 'naive-ui';
+import dayjs from 'dayjs';
+import duration from 'dayjs/plugin/duration';
+import { fetchGetAfterSalesOrderDetail } from '@/service/api/order-manage/after-sales-order';
+// import { useAppStore } from '@/store/modules/app';
+// import { copyTextToClipboard } from '@/utils/zt';
+import {
+  auditStatus,
+  businessType,
+  orderStatus,
+  orderStatusEnum,
+  refundOrderColumns,
+  refundOrderStatus,
+  returnMoneyStatus
+} from '../normal-order/normal-order';
+const router = useRouter();
+const orderInfo = ref<Api.delivery.deliveryOrder>();
+// const appStore = useAppStore();
+const TimeDown = ref<number>(0);
+dayjs.extend(duration);
+const route = useRoute();
+async function open(orderNumber: string) {
+  const { data, error } = await fetchGetAfterSalesOrderDetail(orderNumber);
+  if (!error) {
+    orderInfo.value = data;
+    if (orderInfo.value.hbLogisticStatus == orderStatusEnum.WAIT_PAY) {
+      const createTime = dayjs(orderInfo.value.createTime);
+      const currentTime = dayjs();
+      const elapsed = currentTime.diff(createTime);
+      const fifteenMinutesInMillis = 15 * 60 * 1000;
+      TimeDown.value = fifteenMinutesInMillis - elapsed;
+    }
+  }
+}
+
+open(String(route.query.refundNumber));
+defineExpose({ open });
+
+// const isRefund = computed(() => {
+//   const goodsData = orderInfo.value?.orderItems?.find(it => it.refundIngCount == 1);
+//   return Boolean(goodsData);
+// });
+
+// const currentSteps = computed(() => {
+//   switch (orderInfo.value?.hbOrderStatus) {
+//     case orderStatusEnum.WAIT_PAY:
+//       return 1;
+//     case orderStatusEnum.ORDER_ACCEPT:
+//       return 2;
+//     case orderStatusEnum.ORDER_WAIT_DELIVE RY:
+//       return 2;
+//     case orderStatusEnum.WAIT_DELIVERY:
+//       return 2;
+//     case orderStatusEnum.ORDER_DELIVERY:
+//       return 3;
+//     case orderStatusEnum.ORDER_ARRIVE:
+//       return 3;
+//     case orderStatusEnum.ORDER_COMPLETE:
+//       return 4;
+//     default:
+//       return 1;
+//   }
+// });
+// function handleCopy(value: string | number | undefined) {
+//   copyTextToClipboard(String(value));
+//   // copyTextToClipboard(String(orderInfo.value?.orderNumber));
+// }
+function handleDetail(orderNumber: string) {
+  router.push({
+    name: '/order-manage/order-detail',
+    query: {
+      orderNumber
+    }
+  });
+}
+</script>
+
+<template>
+  <div>
+    <div v-if="orderInfo" class="flex">
+      <div class="mr-20px w-300px">
+        <div class="mb-10px text-16px font-semibold">
+          统一状态:退款/售后
+          <!--
+ <template v-if="orderInfo.businessType != 'DYY'">
+            {{ orderStatus[orderInfo.hbOrderStatus as keyof typeof orderStatus] }}
+          </template>
+          <template v-else>
+            {{ yppStatus[orderInfo.yppDetail?.orderState as keyof typeof yppStatus] }}
+          </template>
+-->
+        </div>
+        <NCard size="small" title="订单概览" :bordered="false">
+          <div>售后单号:{{ orderInfo.refundNumber }}</div>
+          <div>
+            业务类型:
+            {{ businessType[orderInfo.businessType as keyof typeof businessType] || orderInfo.businessType }}
+          </div>
+          <div>
+            售后状态:{{
+              refundOrderStatus[orderInfo.refundOrderStatus as keyof typeof refundOrderStatus] || '售后已完成'
+            }}
+          </div>
+          <div>申请时间:{{ orderInfo?.createTime || '暂无' }}</div>
+          <div>售后渠道:用户自助申请</div>
+        </NCard>
+        <NCard size="small" class="mt-20px" title="客户信息" :bordered="false">
+          <div>客户姓名:{{ orderInfo?.consigneeName || '---' }}</div>
+          <div>客户手机号:{{ orderInfo?.consigneeMobile || '---' }}</div>
+          <div>客户地址:{{ orderInfo?.consigneeAddress || '---' }}</div>
+          <div>用户昵称:{{ orderInfo.userName || '---' }}</div>
+          <div>用户电话:{{ orderInfo.consigneeMobile }}</div>
+          <div>企业身份:{{ orderInfo.channelName || '---' }}</div>
+          <div>会员等级:{{ orderInfo.level || '---' }}</div>
+          <div>分销等级:{{ orderInfo.level || '---' }}</div>
+        </NCard>
+      </div>
+      <div class="flex-1">
+        <div class="flex">
+          <div class="mb-10px text-16px font-semibold">
+            业务状态:{{ returnMoneyStatus[orderInfo.returnMoneySts as keyof typeof returnMoneyStatus] }}
+          </div>
+        </div>
+        <NCard size="small" title="原订单信息" :bordered="false">
+          <div>
+            原订单号:{{ orderInfo.orderNumber }}
+            <NButton v-if="orderInfo.orderNumber" text @click="handleDetail(orderInfo.orderNumber)">
+              查看完整订单
+            </NButton>
+          </div>
+          <div>订单状态:{{ orderStatus[orderInfo.hbOrderStatus as keyof typeof orderStatus] }}</div>
+          <div>原订单号:{{ orderInfo.orderNumber }}</div>
+          <div>订单总额:{{ orderInfo.total }}</div>
+          <div>配送费(快递):{{ orderInfo.freightAmount }}</div>
+          <div>积分抵扣:{{ orderInfo.offsetPoints }}</div>
+          <div>实际付款:{{ orderInfo.actualTotal }}</div>
+          <div>支付时间:{{ orderInfo.payTime }}</div>
+        </NCard>
+        <NCard size="small" class="mt-20px" title="退款信息" :bordered="false">
+          <div class="py-20px font-semibold">01 退款情况</div>
+
+          <div>售后方式:{{ orderInfo.refundType == 1 ? '整单退款' : '部分退款' }}</div>
+          <div>退款原因:{{ orderInfo.buyerReason }} {{ orderInfo.buyerDesc }}</div>
+          <div>退款件数:{{ orderInfo.goodsNum }}</div>
+          <div class="py-20px font-semibold">02 退款商品&费用</div>
+          <NDataTable :columns="refundOrderColumns" :data="orderInfo.orderRefundSkuVoList" :bordered="false" />
+
+          <div class="mt-20px flex items-center justify-end">
+            <div class="text-20px font-semibold">退款总金额:{{ orderInfo.refundMoney }} 元</div>
+            <div class="ml-20px text-14px text-gray">退还金额:{{ orderInfo.userRefundMoney }}</div>
+            <div class="text-14px text-gray">退还积分:{{ orderInfo.refundScore }}</div>
+            <div class="text-14px text-gray">已过期:({{ orderInfo.refundExpiredScore }} )</div>
+          </div>
+
+          <div class="py-20px font-semibold">03 退款记录</div>
+
+          <NTimeline>
+            <NTimelineItem
+              v-for="(item, index) in orderInfo.omsOrderRefundRecordList"
+              :key="index"
+              :type="item.auditStatus == 30 ? 'success' : 'info'"
+              :title="auditStatus[item.auditStatus as keyof typeof auditStatus]"
+              :content="item.instructions"
+              :time="item.updateTime"
+            />
+          </NTimeline>
+          <div>
+            <NSpace v-if="orderInfo.photoFileList" class="mt-20px">
+              <NImage
+                v-for="(item, index) in orderInfo.photoFileList"
+                :key="index"
+                :src="item"
+                object-fit="scale-down"
+                class="mr-10px h-[80px] w-[80px] rounded-6px"
+                lazy
+              />
+            </NSpace>
+          </div>
+        </NCard>
+      </div>
+    </div>
+  </div>
+</template>
+
+<style scoped></style>

+ 165 - 0
src/views/order-manage/after-sales-order/index.vue

@@ -0,0 +1,165 @@
+<script setup lang="tsx">
+import { useRouter } from 'vue-router';
+import { NTag } from 'naive-ui';
+import {
+  // fetchAudit,
+  fetchGetAfterSalesOrderList
+} from '@/service/api/order-manage/after-sales-order';
+// import { fetchGetLoginUserList } from '@/service/api/common';
+// import { useAuth } from '@/hooks/business/auth';
+// import { copyTextToClipboard } from '@/utils/zt';
+import { useTable } from '@/components/zt/Table/hooks/useTable';
+// import { type } from '../../../../packages/axios/src/index';
+import { DJKOrderStatus, SearchForm, businessType, orderStatus, refundOrderStatus } from '../normal-order/normal-order';
+const router = useRouter();
+// const ShipmentModal = useTemplateRef('Shipment');
+const columns: NaiveUI.TableColumn<Api.delivery.deliveryOrder>[] = [
+  {
+    key: 'refundNumber',
+    title: '售后单号',
+    align: 'center',
+    width: 220
+  },
+  {
+    key: 'consigneeAddress',
+    title: '业务类型',
+    align: 'center',
+    width: 120,
+    render: row => {
+      return <NTag>{businessType[row.businessType as keyof typeof businessType] || row.businessType}</NTag>;
+    }
+  },
+  {
+    key: 'orderNumber',
+    title: '原订单编号',
+    align: 'center',
+    width: 220
+  },
+  {
+    key: 'info',
+    title: '客户信息',
+    align: 'center',
+    width: 220,
+    render: row => {
+      return (
+        <div>
+          <div>
+            {row.consigneeName}
+            {row.consigneeMobile}
+          </div>
+          <div>{row.consigneeAddress}</div>
+        </div>
+      );
+    }
+  },
+  {
+    key: 'refundOrderStatus',
+    title: '售后状态',
+    align: 'center',
+    width: 120,
+    render: row => {
+      const statusKey = row.refundOrderStatus as keyof typeof refundOrderStatus;
+      const statusText = refundOrderStatus[statusKey] || '售后已完成';
+      return <NTag>{statusText}</NTag>;
+    }
+  },
+  {
+    key: 'status',
+    title: '订单状态',
+    align: 'center',
+    width: 120,
+    render: row => {
+      const statusKey = row.hbOrderStatus as keyof typeof orderStatus;
+      let statusText;
+      if (row.businessType == 'XNSP') {
+        if (row.hbOrderStatus == 60 || row.hbOrderStatus == 50 || row.hbOrderStatus == 0) {
+          statusText = '订单取消';
+        } else {
+          statusText = '订单完成';
+        }
+      } else if (row.businessType == 'DJK') {
+        statusText = DJKOrderStatus[statusKey as keyof typeof DJKOrderStatus] || '未知状态';
+      } else {
+        statusText = orderStatus[statusKey] || '未知状态';
+      }
+      return <NTag>{statusText}</NTag>;
+    }
+  },
+  {
+    key: 'createTime',
+    title: '申请时间',
+    align: 'center',
+    width: 180,
+    render: row => {
+      return <div>{row.createTime?.replace('T', '  ')}</div>;
+    }
+  },
+  {
+    key: 'refundMoney',
+    title: '退款金额',
+    align: 'center',
+    width: 180,
+    render: row => {
+      return <div>¥{row.refundMoney}</div>;
+    }
+  }
+];
+
+const [registerTable] = useTable({
+  searchFormConfig: {
+    schemas: [
+      ...SearchForm,
+      {
+        label: '售后编号',
+        component: 'NInput',
+        field: 'refundNumber'
+      }
+    ]
+  },
+  tableConfig: {
+    keyField: 'id',
+    title: '',
+    opWdith: 160,
+    showAddButton: false,
+    showTableHeaderAction: true,
+    scrollX: 1800,
+    fieldMapToTime: [['createTime', ['startTime', 'endTime']]]
+  }
+});
+
+function handleOrderDetail(row: Api.delivery.deliveryOrder) {
+  if (!row.orderNumber) {
+    window.$message?.error('订单异常');
+  }
+  router.push({
+    path: '/order-manage/normal-order',
+    query: {
+      orderNumber: row.orderNumber
+    }
+  });
+}
+function handleAfterSalesOrderDetail(row: Api.delivery.deliveryOrder) {
+  if (!row.refundNumber) {
+    window.$message?.error('订单异常');
+  }
+  router.push({
+    path: '/order-manage/after-sales-order-detail',
+    query: {
+      refundNumber: row.refundNumber
+    }
+  });
+}
+</script>
+
+<template>
+  <LayoutTable>
+    <ZTable :columns="columns" :api="fetchGetAfterSalesOrderList" @register="registerTable">
+      <template #op="{ row }">
+        <NButton size="small" type="primary" ghost @click="handleAfterSalesOrderDetail(row)">售后详情</NButton>
+        <NButton size="small" type="primary" ghost @click="handleOrderDetail(row)">订单详情</NButton>
+      </template>
+    </ZTable>
+  </LayoutTable>
+</template>
+
+<style scoped></style>

+ 32 - 21
src/views/order-manage/normal-order/index.vue

@@ -1,10 +1,10 @@
 <script setup lang="tsx">
-import { nextTick, ref, watch } from 'vue';
-import { useRouter } from 'vue-router';
+import { nextTick, onMounted, ref, watch } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
 import { NTag, useDialog } from 'naive-ui';
 import type { InternalRowData } from 'naive-ui/es/data-table/src/interface';
 import {
-  fetchAudit,
+  // fetchAudit,
   fetchBreakDownload,
   fetchExportList,
   fetchExportOrderList,
@@ -18,12 +18,14 @@ import { commonExport } from '@/utils/common';
 import { useModal } from '@/components/zt/Modal/hooks/useModal';
 import { useTable } from '@/components/zt/Table/hooks/useTable';
 // import { type } from '../../../../packages/axios/src/index';
-import { SearchForm, businessType, orderStatus } from './normal-order';
+import { DJKOrderStatus, SearchForm, businessType, orderStatus } from './normal-order';
 const router = useRouter();
+const route = useRoute();
 const activeTab = ref('all');
 const statusList = ref<{ label: string; value: string; num?: number }[]>([]);
 // const ShipmentModal = useTemplateRef('Shipment');
 const channelIdList = ref([]);
+const orderNumber = route.query.orderNumber;
 const columns: NaiveUI.TableColumn<Api.delivery.deliveryOrder>[] = [
   {
     key: 'orderNumber',
@@ -71,6 +73,8 @@ const columns: NaiveUI.TableColumn<Api.delivery.deliveryOrder>[] = [
         } else {
           statusText = '订单完成';
         }
+      } else if (row.businessType == 'DJK') {
+        statusText = DJKOrderStatus[statusKey as keyof typeof DJKOrderStatus] || '未知状态';
       } else {
         statusText = orderStatus[statusKey] || '未知状态';
       }
@@ -88,7 +92,7 @@ const columns: NaiveUI.TableColumn<Api.delivery.deliveryOrder>[] = [
   }
 ];
 
-const [registerTable, { refresh, setTableLoading, getSeachForm, getTableData }] = useTable({
+const [registerTable, { refresh, setTableLoading, getSeachForm, getTableData, setFieldsValue }] = useTable({
   searchFormConfig: {
     schemas: [...SearchForm]
   },
@@ -221,20 +225,20 @@ function handleOrderDetail(row: Api.delivery.deliveryOrder) {
   // orderMoadl.value?.open(String(row.orderNumber));
 }
 
-async function handleAudit(row: any) {
-  window.$dialog?.info({
-    title: '提示',
-    content: `此操作将核销该订单,且无法撤销,确定要核销吗?`,
-    positiveText: '确定',
-    negativeText: '取消',
-    onPositiveClick: async () => {
-      const { error } = await fetchAudit({ orderNumber: row.orderNumber });
-      if (!error) {
-        refresh();
-      }
-    }
-  });
-}
+// async function handleAudit(row: any) {
+//   window.$dialog?.info({
+//     title: '提示',
+//     content: `此操作将核销该订单,且无法撤销,确定要核销吗?`,
+//     positiveText: '确定',
+//     negativeText: '取消',
+//     onPositiveClick: async () => {
+//       const { error } = await fetchAudit({ orderNumber: row.orderNumber });
+//       if (!error) {
+//         refresh();
+//       }
+//     }
+//   });
+// }
 async function getNums() {
   const form = getSeachForm();
   const params = {
@@ -339,6 +343,10 @@ watch(
     });
   }
 );
+onMounted(async () => {
+  await setFieldsValue({ orderNumber });
+  refresh();
+});
 </script>
 
 <template>
@@ -346,12 +354,14 @@ watch(
     <ZTable
       :columns="columns"
       :api="fetchGetDeliveryOrderList"
+      :immediate="false"
       :default-params="{ orderStatus: activeTab }"
       @register="registerTable"
     >
       <template #op="{ row }">
         <NButton size="small" type="primary" ghost @click="handleOrderDetail(row)">订单详情</NButton>
-        <NButton
+        <!--
+ <NButton
           v-if="row.businessType === 'DJK' && row.isWriteOff == 1 && row.hbOrderStatus != 80"
           size="small"
           type="primary"
@@ -360,6 +370,7 @@ watch(
         >
           核销
         </NButton>
+-->
       </template>
       <template #header>
         <div class="flex items-center">
@@ -416,7 +427,7 @@ watch(
           :show-table-action="false"
           :columns="exportColumns"
           :api="fetchExportList"
-          :default-params="{ exportType: 1 }"
+          :default-params="{ exportType: 1, orderNumber }"
           @register="registerTable"
         ></ZTable>
       </LayoutTable>

+ 106 - 3
src/views/order-manage/normal-order/normal-order.ts

@@ -150,6 +150,14 @@ export enum orderStatusEnum {
    * 订单已取消
    */
   ORDER_CANCEL = 60,
+  /**
+   * 订单已退款
+   */
+  ORDER_REFUNDED = 61,
+  /**
+   * 订单已过期
+   */
+  ORDER_EXPIRED = 62,
   /**
    * 订单已送达
    */
@@ -183,6 +191,47 @@ export const orderStatus = {
   [orderStatusEnum.ORDER_ARRIVE]: '订单已送达',
   [orderStatusEnum.ORDER_COMPLETE]: '订单已完成'
 };
+
+export const refundOrderStatus = {
+  0: '进行中',
+  1: '已完成',
+  2: '积分退款成功,微信退款失败',
+  3: '退款订单已取消',
+  4: '退款订单驳回'
+};
+
+export const returnMoneyStatus = {
+  10: '待审核',
+  20: '处理中',
+  30: '驳回退款',
+  40: '撤销退款',
+  60: '待退货(一审同意)',
+  65: '待确认收货(二审待审核)',
+  70: '退款完成'
+};
+
+export const auditStatus = {
+  1: '申请原因',
+  2: '商家待审核,',
+  3: '申请已通过',
+  4: '用户撤回申请',
+  5: '待用户待发货',
+  7: '待商家收货',
+  10: '审核通过',
+  20: '驳回',
+  25: '已收货',
+  30: '退款成功'
+};
+
+export const DJKOrderStatus = {
+  [orderStatusEnum.WAIT_PAY]: '待支付',
+  [orderStatusEnum.ORDER_ACCEPT]: '待使用',
+  [orderStatusEnum.ORDER_CANCEL]: '已取消',
+  [orderStatusEnum.ORDER_REFUNDED]: '已退款',
+  [orderStatusEnum.ORDER_EXPIRED]: '已过期',
+  [orderStatusEnum.ORDER_COMPLETE]: '已核销'
+};
+
 export enum yppStatusEnum {
   /**
    *
@@ -213,6 +262,7 @@ export const yppStatus = {
   [yppStatusEnum.REFUND_FAIL]: '出票失败(退款)',
   [yppStatusEnum.TIMEOUT_CANCEL]: '超时未支付(取消)'
 };
+
 /**
  // 1:申请退款 2:退款成功 3:部分退款成功 4:退款失败
  *
@@ -287,8 +337,8 @@ export const orderDJKColumns: NaiveUI.TableColumn<Api.delivery.OrderItemElement>
       const goodsNodes = [
         h(NImage, { src: row.goodsImg, width: 80, height: 80 }),
         h('div', { class: 'ml-2 ' }, [
-          h('div', { class: 'text-15px font-semibold' }, row.skuName),
-          h('div', { class: 'text-gray' }, `规格:${row.spec || '--'}`)
+          h('div', { class: 'text-15px font-semibold' }, row.goodsName),
+          h('div', { class: 'text-gray' }, `规格:${row.goodsCode || '--'}`)
         ])
       ];
       return h('div', { class: 'flex items-center' }, goodsNodes);
@@ -319,7 +369,7 @@ export const orderDJKColumns: NaiveUI.TableColumn<Api.delivery.OrderItemElement>
     key: 'productTotalAmount',
     width: 100,
     render: (row: any) => {
-      return h('div', {}, (row.goodsNum * 1000 * (row.price * 1000)) / 1000);
+      return h('div', {}, (row.goodsNum * 1000 * (row.price * 1000)) / 1000000);
     }
   }
 ];
@@ -379,6 +429,53 @@ export const deliveryInfo: FormSchema[] = [
   }
 ];
 
+export const refundOrderColumns: NaiveUI.TableColumn<Api.delivery.OrderItemElement>[] = [
+  {
+    title: '退款商品',
+    key: 'goods',
+    width: 300,
+    render: row => {
+      const goodsNodes = [
+        h(NImage, { src: row.pic, width: 80, height: 80 }),
+        h('div', { class: 'ml-2 ' }, [
+          h('div', { class: 'text-15px font-semibold' }, row.skuName || '--'),
+          h('div', { class: 'text-gray' }, `规格:${row.spec || '--'}`)
+        ])
+      ];
+      return h('div', { class: 'flex items-center' }, goodsNodes);
+    }
+  },
+  {
+    title: '购买单价(元)',
+    key: 'skuPrice',
+    width: 100
+  },
+  {
+    title: '购买数量',
+    key: 'productCount',
+    width: 100,
+    render: row => {
+      const nodes = [h('div', { class: 'mr-2' }, row.productCount)];
+      return h(NFlex, { align: 'center' }, () => nodes);
+    }
+  },
+  {
+    title: '小计/元',
+    key: 'skuTotalPrice',
+    width: 100
+  },
+  {
+    title: '退款数量',
+    key: 'refundProductCount',
+    width: 100
+  },
+  {
+    title: '退款金额/元',
+    key: 'refundSkuTotalPrice',
+    width: 100
+  }
+];
+
 /**
  * 0:用户手动停止充电;1:客户归属地运营商平台停止充电;2:BMS停止充电;3:充电机设备故障;4:连接器断开;其它:自定义
  */
@@ -400,3 +497,9 @@ export const businessType = {
   XNSP: '虚拟商品',
   JY: '加油'
 };
+
+export const payType = {
+  0: '积分支付',
+  1: '微信支付',
+  2: '支付宝'
+};

+ 4 - 4
src/views/order-manage/order-detail/index.vue

@@ -15,6 +15,7 @@ import {
   orderDJKLogColumns,
   orderStatus,
   orderStatusEnum,
+  payType,
   yppStatus,
   yppStatusEnum
 } from '../normal-order/normal-order';
@@ -357,10 +358,9 @@ function secondsToTime(seconds: number) {
             </NTable>
           </template>
           <template v-else-if="orderInfo.businessType == 'DJK'">
-            <div class="pb-20px font-semibold">基础信息</div>
-            <div>下单时间:{{ orderInfo.shopName || '暂无' }}</div>
-            <div>支付方式:{{ orderInfo.shopAddress || '暂无' }}</div>
-            <div>有效期:{{ orderInfo.tel || '暂无' }}</div>
+            <div>下单时间:{{ orderInfo.createTime || '---' }}</div>
+            <div>支付方式:{{ payType[orderInfo.payType as keyof typeof payType] || '---' }}</div>
+            <div>有效期:{{ orderInfo.djkOrderAttachInfo.expiredTime || '---' }}</div>
             <div class="py-20px font-semibold">订单信息</div>
             <NDataTable :columns="orderDJKColumns" :data="[orderInfo.djkOrderAttachInfo]" :bordered="false" />
             <div class="py-20px font-semibold">商品&费用</div>

+ 3 - 16
src/views/xsb-manage/store-info/index.vue

@@ -1,7 +1,6 @@
 <script setup lang="tsx">
 import { ref } from 'vue';
 import { NButton, NCollapse, NCollapseItem, NInput, NSelect, NTag, NTimePicker } from 'naive-ui';
-import axios from 'axios';
 import { commonStatus } from '@/constants/business';
 import {
   fetchAddShop,
@@ -9,7 +8,8 @@ import {
   fetchEditShop,
   fetchGetAreaList,
   fetchGetShopCity,
-  fetchGetStoreList
+  fetchGetStoreList,
+  fetchParseAddress
 } from '@/service/api/xsb-manage/store-info';
 import { useModalFrom } from '@/components/zt/ModalForm/hooks/useModalForm';
 import { useTable } from '@/components/zt/Table/hooks/useTable';
@@ -20,9 +20,6 @@ interface AreaOption {
   value: string;
 }
 
-// 第三方地图API配置(替换为你使用的地图API地址和密钥)
-const MAP_API_KEY = 'UNBBZ-OKDCB-FSTU4-N5EGG-CMJ67-CKB6H'; // 自行申请
-const MAP_API_URL = 'https://apis.map.qq.com/ws/geocoder/v1/';
 const columns: NaiveUI.TableColumn<Api.Store.ShopDetail>[] = [
   {
     key: 'hbStationNo',
@@ -324,17 +321,7 @@ async function handleReverves() {
   }
   if (loading.value) return;
   loading.value = true;
-
-  const res = await axios.get(MAP_API_URL, {
-    params: {
-      address: form.area + form.shopAddress, // 请求参数
-      key: MAP_API_KEY // API密钥
-    },
-    timeout: 10000, // 单独设置超时(第三方接口建议加长,避免网络问题)
-    headers: {
-      'Content-Type': 'application/x-www-form-urlencoded'
-    }
-  });
+  const res = await fetchParseAddress({ address: form.area + form.shopAddress });
   loading.value = false;
   console.log(res);