Explorar el Código

feat: 完善部分订单模块逻辑

叶静 hace 1 mes
padre
commit
9efb7d2cdc

+ 129 - 0
src/app/shop/admin/category/select.vue

@@ -0,0 +1,129 @@
+<template>
+  <el-container class="category-select-view">
+    <el-header class="sa-header">
+      <div class="sa-title sa-flex sa-row-between">
+        <div class="label sa-flex">选择分类</div>
+        <div>
+          <el-button @click="handleCancel">取消</el-button>
+          <el-button type="primary" @click="handleConfirm">确定</el-button>
+        </div>
+      </div>
+    </el-header>
+    <el-main class="sa-p-0">
+      <div class="category-list">
+        <el-tree
+          ref="treeRef"
+          :data="categoryList"
+          :props="treeProps"
+          node-key="id"
+          :default-checked-keys="selectedIds"
+          show-checkbox
+          :check-strictly="checkStrictly"
+          @check="handleCheck"
+        />
+      </div>
+    </el-main>
+  </el-container>
+</template>
+
+<script>
+export default {
+  name: 'CategorySelect',
+};
+</script>
+
+<script setup>
+import { ref, reactive, onMounted } from 'vue';
+import { api } from './category.service';
+
+const emit = defineEmits(['modalCallBack']);
+const props = defineProps({
+  modal: {
+    type: Object,
+    default: () => ({}),
+  },
+  multiple: {
+    type: Boolean,
+    default: true,
+  },
+  checkStrictly: {
+    type: Boolean,
+    default: false,
+  },
+});
+
+const treeRef = ref();
+const categoryList = ref([]);
+const selectedIds = ref([]);
+
+const treeProps = {
+  children: 'children',
+  label: 'name',
+  value: 'id',
+};
+
+// 获取分类数据
+async function getData() {
+  try {
+    const { data, error } = await api.category.list();
+    if (error === 0) {
+      categoryList.value = data || [];
+    }
+  } catch (error) {
+    console.error('获取分类数据失败:', error);
+  }
+}
+
+// 处理选择
+function handleCheck(data, checked) {
+  if (props.multiple) {
+    selectedIds.value = checked.checkedKeys;
+  } else {
+    selectedIds.value = [data.id];
+    // 单选模式下,取消其他选择
+    treeRef.value.setCheckedKeys([data.id]);
+  }
+}
+
+// 确认选择
+function handleConfirm() {
+  const checkedNodes = treeRef.value.getCheckedNodes();
+  const selectedCategories = checkedNodes.map(node => ({
+    id: node.id,
+    name: node.name,
+  }));
+
+  emit('modalCallBack', {
+    type: 'confirm',
+    data: props.multiple ? selectedCategories : selectedCategories[0] || null,
+  });
+}
+
+// 取消选择
+function handleCancel() {
+  emit('modalCallBack', {
+    type: 'cancel',
+  });
+}
+
+onMounted(() => {
+  getData();
+  
+  // 设置默认选中
+  if (props.modal.selectedIds) {
+    selectedIds.value = Array.isArray(props.modal.selectedIds) 
+      ? props.modal.selectedIds 
+      : [props.modal.selectedIds];
+  }
+});
+</script>
+
+<style lang="scss" scoped>
+.category-select-view {
+  .category-list {
+    padding: 20px;
+    height: 400px;
+    overflow-y: auto;
+  }
+}
+</style>

+ 48 - 0
src/app/shop/admin/data/data.service.js

@@ -0,0 +1,48 @@
+import Content from '@/sheep/layouts/content.vue';
+import { request } from '@/sheep/request';
+import { CRUD } from '@/sheep/request/crud';
+
+const route = {
+  path: 'data',
+  name: 'shop.admin.data',
+  component: Content,
+  meta: {
+    title: '数据',
+  },
+  children: [
+    {
+      path: 'report',
+      name: 'shop.admin.data.report',
+      component: () => import('@/app/shop/admin/data/report/index.vue'),
+      meta: {
+        title: '数据报表',
+      },
+    },
+  ],
+};
+
+const api = {
+  report: {
+    ...CRUD('shop/admin/data/report', ['list']),
+    getStats: () =>
+      request({
+        url: '/shop/admin/data/report/stats',
+        method: 'GET',
+      }),
+  },
+  express: {
+    list: () =>
+      request({
+        url: '/shop/admin/data/express/list',
+        method: 'GET',
+      }),
+    track: (code, no) =>
+      request({
+        url: '/shop/admin/data/express/track',
+        method: 'GET',
+        params: { code, no },
+      }),
+  },
+};
+
+export { route, api };

+ 114 - 0
src/app/shop/admin/data/express/express.js

@@ -0,0 +1,114 @@
+/**
+ * 快递公司相关功能
+ */
+import { ref, reactive } from 'vue';
+
+// 快递公司列表
+const expressList = [
+  { code: 'SF', name: '顺丰速运' },
+  { code: 'YTO', name: '圆通速递' },
+  { code: 'ZTO', name: '中通快递' },
+  { code: 'STO', name: '申通快递' },
+  { code: 'YD', name: '韵达速递' },
+  { code: 'HHTT', name: '天天快递' },
+  { code: 'JD', name: '京东物流' },
+  { code: 'EMS', name: '中国邮政' },
+  { code: 'HTKY', name: '百世快递' },
+  { code: 'UC', name: '优速快递' },
+];
+
+// 快递公司Hook
+export default function useExpress() {
+  const express = reactive({
+    code: '',
+    name: '',
+    no: '',
+  });
+
+  const expressOptions = ref(expressList);
+
+  // 快递公司数据
+  const deliverCompany = reactive({
+    data: expressList,
+    loading: false,
+    pageData: {
+      page: 1,
+      list_rows: 10,
+      total: expressList.length,
+    },
+  });
+
+  // 根据快递代码获取快递公司名称
+  const getExpressName = (code) => {
+    const item = expressList.find((item) => item.code === code);
+    return item ? item.name : '';
+  };
+
+  // 设置快递信息
+  const setExpress = (code, no = '') => {
+    express.code = code;
+    express.name = getExpressName(code);
+    express.no = no;
+  };
+
+  // 重置快递信息
+  const resetExpress = () => {
+    express.code = '';
+    express.name = '';
+    express.no = '';
+  };
+
+  // 验证快递信息
+  const validateExpress = () => {
+    if (!express.code) {
+      return { valid: false, message: '请选择快递公司' };
+    }
+    if (!express.no) {
+      return { valid: false, message: '请输入快递单号' };
+    }
+    return { valid: true, message: '' };
+  };
+
+  // 获取快递公司列表
+  const getDeliverCompany = (page = 1) => {
+    deliverCompany.pageData.page = page;
+    // 这里可以添加实际的API调用
+    deliverCompany.data = expressList;
+  };
+
+  // 快递公司选择变化
+  const onChangeExpressCode = (code) => {
+    express.code = code;
+    express.name = getExpressName(code);
+  };
+
+  // 远程搜索方法
+  const remoteMethod = (query) => {
+    if (query) {
+      deliverCompany.loading = true;
+      setTimeout(() => {
+        deliverCompany.data = expressList.filter(
+          (item) =>
+            item.name.toLowerCase().includes(query.toLowerCase()) ||
+            item.code.toLowerCase().includes(query.toLowerCase()),
+        );
+        deliverCompany.loading = false;
+      }, 200);
+    } else {
+      deliverCompany.data = expressList;
+    }
+  };
+
+  return {
+    express,
+    expressOptions,
+    deliverCompany,
+    getExpressName,
+    setExpress,
+    resetExpress,
+    validateExpress,
+    getDeliverCompany,
+    onChangeExpressCode,
+    remoteMethod,
+  };
+}

+ 1 - 9
src/app/shop/admin/order/order/components/index-status.vue

@@ -27,7 +27,6 @@
   import OrderDispatch from '../dispatch.vue';
   import AftersaleDetail from '../../aftersale/detail.vue';
   import OrderRefund from '../refund.vue';
-  import CommentIndex from '@/app/shop/admin/goods/comment/index.vue';
 
   const emit = defineEmits(['updateList']);
   const props = defineProps({
@@ -232,14 +231,7 @@
   }
 
   function onOpenComment() {
-    useModal(CommentIndex, {
-      title: '查看评价',
-      type: 'modal',
-      data: {
-        order_id: props.order.id,
-        order_item_id: props.item.id,
-      },
-    });
+    console.log('查看评价功能暂未实现');
   }
 </script>
 

+ 2 - 9
src/app/shop/admin/order/order/components/status.vue

@@ -19,7 +19,7 @@
   import OrderDispatch from '../dispatch.vue';
   import AftersaleDetail from '../../aftersale/detail.vue';
   import OrderRefund from '../refund.vue';
-  import CommentIndex from '@/app/shop/admin/goods/comment/index.vue';
+
   import { checkAuth } from '@/sheep/directives/auth';
 
   const emit = defineEmits(['updateList']);
@@ -266,14 +266,7 @@
   }
 
   function onOpenComment() {
-    useModal(CommentIndex, {
-      title: '查看评价',
-      type: 'modal',
-      data: {
-        order_id: props.order.id,
-        order_item_id: props.item.id,
-      },
-    });
+    console.log('查看评价功能暂未实现');
   }
 </script>
 

+ 143 - 81
src/app/shop/admin/order/order/dispatch.vue

@@ -2,14 +2,19 @@
   <el-container class="send">
     <el-main>
       <el-tabs class="sa-m-b-20" v-model="state.dispatch_type">
-                    <el-tab-pane v-if="state.nosendItem.length" label="快递发货" name="express"></el-tab-pane>
-                    <el-tab-pane v-if="state.customItem.length" label="手动发货" name="custom"></el-tab-pane>
-                </el-tabs>
+        <el-tab-pane v-if="state.nosendItem.length" label="快递发货" name="express"></el-tab-pane>
+        <el-tab-pane v-if="state.customItem.length" label="手动发货" name="custom"></el-tab-pane>
+      </el-tabs>
       <el-alert class="sa-alert sa-m-b-16">
         <template #title>温馨提示:如果该商品处在售后状态,请先处理完售后再进行发货。</template>
       </el-alert>
-      <div v-if="state.dispatch_type=='express'">
-        <el-table class="sa-table" :data="state.nosendItem" @selection-change="handleSelectionChange">
+      <div v-if="state.dispatch_type == 'express'">
+        <el-table
+          ref="expressTableRef"
+          class="sa-table"
+          :data="state.nosendItem"
+          @selection-change="handleSelectionChange"
+        >
           <template #empty>
             <sa-empty />
           </template>
@@ -114,74 +119,85 @@
         </div>
       </div>
       <div v-if="state.dispatch_type == 'custom'">
-          <el-table class="sa-table" :data="state.customItem" @selection-change="handleSelectionChange">
-              <el-table-column type="selection" width="48"></el-table-column>
-              <el-table-column label="商品信息" min-width="360">
-                  <template #default="scope">
-                      <div class="sa-flex">
-                          <sa-image :url="scope.row.goods_image" size="40"></sa-image>
-                          <div class="sa-m-l-8">{{ scope.row.goods_title }}</div>
-                      </div>
-                  </template>
-              </el-table-column>
-              <el-table-column prop="goods_num" label="数量" min-width="80"></el-table-column>
-              <el-table-column prop="dispatch_status_text" label="状态" min-width="140">
-                  <template #default="scope">
-                      {{ scope.row.dispatch_status_text }}/{{ scope.row.aftersale_status_text }}
-                  </template>
-              </el-table-column>
-              <el-table-column label="快递单号" min-width="80">
-                  <template #default>-</template>
-              </el-table-column>
-          </el-table>
-          <el-form class="sa-m-t-20">
-              <el-form-item label="发货类型:">
-                  <el-radio-group v-model="state.custom_type" @change="onChangeAutosendType">
-                      <el-radio label="text">固定内容</el-radio>
-                      <el-radio label="params">自定义内容</el-radio>
-                  </el-radio-group>
-              </el-form-item>
-              <el-form-item v-if="state.custom_type == 'text'" label="发货内容:">
-                  <el-input v-model="state.custom_content" placeholder="请输入自动发货内容"></el-input>
-              </el-form-item>
-              <el-form-item v-if="state.custom_type == 'params'" label="发货内容:">
-                  <div class="sa-template-wrap">
-                      <div class="title sa-flex">
-                          <div class="key">参数名称</div>
-                          <div class="key">内容</div>
-                          <div class="oper">操作</div>
-                      </div>
-                      <draggable v-model="state.custom_content" :animation="300"
-                          handle=".sortable-drag" item-key="element">
-                          <template #item="{ element, index }">
-                              <div class="item">
-                                  <el-form-item class="key">
-                                      <el-input placeholder="请输入" v-model="element.title">
-                                      </el-input>
-                                  </el-form-item>
-                                  <el-form-item class="key">
-                                      <el-input placeholder="请输入" v-model="element.content">
-                                      </el-input>
-                                  </el-form-item>
-                                  <el-form-item class="oper">
-                                      <el-popconfirm width="fit-content" confirm-button-text="确认"
-                                          cancel-button-text="取消" title="确认删除这条记录?"
-                                          @confirm="onDeleteContent(index)">
-                                          <template #reference>
-                                              <el-button type="danger" link @click.stop>删除
-                                              </el-button>
-                                          </template>
-                                      </el-popconfirm>
-                                      <i class="iconfont iconmove sortable-drag"></i>
-                                  </el-form-item>
-                              </div>
-                          </template>
-                      </draggable>
-                      <el-button class="add-params" type="primary" plain icon="Plus" @click="onAddContent">添加
-                      </el-button>
+        <el-table
+          ref="customTableRef"
+          class="sa-table"
+          :data="state.customItem"
+          @selection-change="handleSelectionChange"
+        >
+          <el-table-column type="selection" width="48"></el-table-column>
+          <el-table-column label="商品信息" min-width="360">
+            <template #default="scope">
+              <div class="sa-flex">
+                <sa-image :url="scope.row.goods_image" size="40"></sa-image>
+                <div class="sa-m-l-8">{{ scope.row.goods_title }}</div>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column prop="goods_num" label="数量" min-width="80"></el-table-column>
+          <el-table-column prop="dispatch_status_text" label="状态" min-width="140">
+            <template #default="scope">
+              {{ scope.row.dispatch_status_text }}/{{ scope.row.aftersale_status_text }}
+            </template>
+          </el-table-column>
+          <el-table-column label="快递单号" min-width="80">
+            <template #default>-</template>
+          </el-table-column>
+        </el-table>
+        <el-form class="sa-m-t-20">
+          <el-form-item label="发货类型:">
+            <el-radio-group v-model="state.custom_type" @change="onChangeAutosendType">
+              <el-radio label="text">固定内容</el-radio>
+              <el-radio label="params">自定义内容</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item v-if="state.custom_type == 'text'" label="发货内容:">
+            <el-input v-model="state.custom_content" placeholder="请输入自动发货内容"></el-input>
+          </el-form-item>
+          <el-form-item v-if="state.custom_type == 'params'" label="发货内容:">
+            <div class="sa-template-wrap">
+              <div class="title sa-flex">
+                <div class="key">参数名称</div>
+                <div class="key">内容</div>
+                <div class="oper">操作</div>
+              </div>
+              <draggable
+                v-model="state.custom_content"
+                :animation="300"
+                handle=".sortable-drag"
+                item-key="element"
+              >
+                <template #item="{ element, index }">
+                  <div class="item">
+                    <el-form-item class="key">
+                      <el-input placeholder="请输入" v-model="element.title"> </el-input>
+                    </el-form-item>
+                    <el-form-item class="key">
+                      <el-input placeholder="请输入" v-model="element.content"> </el-input>
+                    </el-form-item>
+                    <el-form-item class="oper">
+                      <el-popconfirm
+                        width="fit-content"
+                        confirm-button-text="确认"
+                        cancel-button-text="取消"
+                        title="确认删除这条记录?"
+                        @confirm="onDeleteContent(index)"
+                      >
+                        <template #reference>
+                          <el-button type="danger" link @click.stop>删除 </el-button>
+                        </template>
+                      </el-popconfirm>
+                      <i class="iconfont iconmove sortable-drag"></i>
+                    </el-form-item>
                   </div>
-              </el-form-item>
-          </el-form>
+                </template>
+              </draggable>
+              <el-button class="add-params" type="primary" plain icon="Plus" @click="onAddContent"
+                >添加
+              </el-button>
+            </div>
+          </el-form-item>
+        </el-form>
       </div>
     </el-main>
     <el-footer class="sa-footer--submit">
@@ -196,7 +212,7 @@
   </el-container>
 </template>
 <script setup>
-  import { computed, getCurrentInstance, onMounted, reactive } from 'vue';
+  import { computed, getCurrentInstance, onMounted, reactive, ref, nextTick, watch } from 'vue';
   import { api } from '../order.service';
   import useExpress from '@/app/shop/admin/data/express/express.js';
   import draggable from 'vuedraggable';
@@ -206,10 +222,18 @@
 
   const { proxy } = getCurrentInstance();
 
-    const state = reactive({
+  // 表格引用
+  const expressTableRef = ref();
+  const customTableRef = ref();
+
+  const state = reactive({
     nosendItem: computed(() => {
+      if (!props.modal.params.data.items) return [];
       return props.modal.params.data.items.filter(
-        i => i.dispatch_status == 0 && i.refund_status == 0 && i.dispatch_type == 'express'
+        (i) =>
+          (i.dispatch_status == 0 || i.dispatch_status === undefined) &&
+          (i.refund_status == 0 || i.refund_status === undefined) &&
+          (i.dispatch_type == 'express' || i.dispatch_type === undefined),
       );
     }),
     method: 'input',
@@ -222,8 +246,12 @@
 
     dispatch_type: 'express',
     customItem: computed(() => {
+      if (!props.modal.params.data.items) return [];
       return props.modal.params.data.items.filter(
-        i => i.dispatch_status == 0 && i.refund_status == 0 && i.dispatch_type == 'custom',
+        (i) =>
+          (i.dispatch_status == 0 || i.dispatch_status === undefined) &&
+          (i.refund_status == 0 || i.refund_status === undefined) &&
+          i.dispatch_type == 'custom',
       );
     }),
     custom_type: 'text',
@@ -289,11 +317,11 @@
   }
 
   function onChangeAutosendType(type) {
-    state.custom_content = type == 'text' ? '' : []
+    state.custom_content = type == 'text' ? '' : [];
   }
   function onAddContent() {
     if (!state.custom_content) {
-      state.custom_content = []
+      state.custom_content = [];
     }
     state.custom_content.push({
       title: '',
@@ -304,13 +332,47 @@
     state.custom_content.splice(index, 1);
   }
 
+  // 监听发货类型变化,自动选中所有商品
+  watch(
+    () => state.dispatch_type,
+    (newType) => {
+      nextTick(() => {
+        if (newType === 'express' && expressTableRef.value && state.nosendItem.length) {
+          state.nosendItem.forEach((row) => {
+            expressTableRef.value.toggleRowSelection(row, true);
+          });
+        } else if (newType === 'custom' && customTableRef.value && state.customItem.length) {
+          state.customItem.forEach((row) => {
+            customTableRef.value.toggleRowSelection(row, true);
+          });
+        }
+      });
+    },
+  );
+
   onMounted(() => {
     if (state.nosendItem.length) {
-      state.dispatch_type = 'express'
+      state.dispatch_type = 'express';
+      // 默认选中所有快递发货商品
+      nextTick(() => {
+        if (expressTableRef.value) {
+          state.nosendItem.forEach((row) => {
+            expressTableRef.value.toggleRowSelection(row, true);
+          });
+        }
+      });
     } else if (state.customItem.length) {
-      state.dispatch_type = 'custom'
+      state.dispatch_type = 'custom';
+      // 默认选中所有手动发货商品
+      nextTick(() => {
+        if (customTableRef.value) {
+          state.customItem.forEach((row) => {
+            customTableRef.value.toggleRowSelection(row, true);
+          });
+        }
+      });
     }
-  })
+  });
 </script>
 <style lang="scss" scoped>
   .send {

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 294 - 651
src/app/shop/admin/order/order/index.vue


+ 123 - 0
src/app/shop/admin/order/order/manualOrder.vue

@@ -0,0 +1,123 @@
+<template>
+  <el-container>
+    <el-main>
+      <el-form :model="form" label-width="110px" :rules="rules" ref="formRef">
+        <el-form-item label="订单ID" prop="id">
+          <el-input v-model="form.id" disabled></el-input>
+        </el-form-item>
+        <el-form-item label="外部订单号" prop="out_order_id">
+          <el-input v-model="form.out_order_id" placeholder="请输入外部订单号"></el-input>
+        </el-form-item>
+        <el-form-item label="外部子订单号" prop="out_order_item_id">
+          <el-input v-model="form.out_order_item_id" placeholder="请输入外部子订单号"></el-input>
+        </el-form-item>
+        <el-form-item label="下单渠道" prop="order_source">
+          <el-input v-model="form.order_source" placeholder="请输入下单渠道"></el-input>
+        </el-form-item>
+      </el-form>
+    </el-main>
+    <el-footer class="sa-footer--submit">
+      <el-button @click="onCancel">取消</el-button>
+      <el-button
+        v-auth="'shop.admin.order.order.dispatch'"
+        type="primary"
+        @click="submit"
+        :loading="loading"
+        >确定</el-button
+      >
+    </el-footer>
+  </el-container>
+</template>
+
+<script setup>
+  import { reactive, ref, onMounted } from 'vue';
+  import { api } from '../order.service';
+  import { ElMessage } from 'element-plus';
+
+  const props = defineProps({
+    modal: {
+      type: Object,
+      default: () => {},
+    },
+  });
+
+  const emit = defineEmits(['modalCallBack']);
+
+  const formRef = ref(null);
+  const loading = ref(false);
+
+  const form = reactive({
+    id: '',
+    out_order_id: '',
+    out_order_item_id: '',
+    order_source: '',
+  });
+
+  const rules = {
+    out_order_id: [{ required: true, message: '请输入外部订单号', trigger: 'blur' }],
+    out_order_item_id: [{ required: true, message: '请输入外部子订单号', trigger: 'blur' }],
+    order_source: [{ required: true, message: '请输入下单渠道', trigger: 'blur' }],
+  };
+
+  onMounted(() => {
+    console.log(props.modal);
+    // 从传入的参数中获取订单ID
+    if (props.modal?.params?.id) {
+      form.id = props.modal.params.id;
+    } else if (props.modal?.data?.id) {
+      // 兼容另一种传参方式
+      form.id = props.modal.data.id;
+    }
+
+    // 如果有旧的表单数据,则回显
+    if (props.modal?.data?.out_order_id) {
+      form.out_order_id = props.modal.data.out_order_id;
+    }
+
+    if (props.modal?.data?.out_order_item_id) {
+      form.out_order_item_id = props.modal.data.out_order_item_id;
+    }
+
+    if (props.modal?.data?.order_source) {
+      form.order_source = props.modal.data.order_source;
+    }
+  });
+
+  // 取消操作
+  function onCancel() {
+    emit('modalCallBack', { event: 'close' });
+  }
+
+  // 提交表单
+  async function submit() {
+    if (!formRef.value) return;
+
+    await formRef.value.validate(async (valid) => {
+      if (valid) {
+        loading.value = true;
+        try {
+          const { error } = await api.order.manualOrderSubmit(form.id, {
+            out_order_id: form.out_order_id,
+            out_order_item_id: form.out_order_item_id,
+            order_source: form.order_source,
+          });
+
+          if (error === 0) {
+            ElMessage({
+              message: '手动下单成功',
+              type: 'success',
+            });
+            emit('modalCallBack', { event: 'confirm' });
+          }
+        } finally {
+          loading.value = false;
+        }
+      }
+    });
+  }
+
+  // 暴露方法给父组件调用
+  defineExpose({
+    submit,
+  });
+</script>

+ 1207 - 0
src/app/shop/admin/order/order/o-index.vue

@@ -0,0 +1,1207 @@
+<template>
+  <el-container class="order-page panel-block">
+    <el-header class="sa-header">
+      <el-tabs class="sa-tabs" v-model="filterParams.data.status" @tab-change="onChangeStatus">
+        <el-tab-pane
+          v-for="(sl, key) in statusList"
+          :key="sl"
+          :label="`${sl.label}${sl.num ? '(' + sl.num + ')' : ''}`"
+          :name="key"
+        ></el-tab-pane>
+      </el-tabs>
+      <div class="sa-title sa-flex sa-row-between">
+        <div class="label sa-flex">
+          <span class="left">订单列表</span>
+          <search-condition
+            :conditionLabel="filterParams.conditionLabel"
+            @deleteFilter="deleteFilter"
+          ></search-condition>
+        </div>
+        <div>
+          <el-button
+            v-auth="'shop.admin.order.order.list'"
+            class="sa-button-refresh"
+            icon="RefreshRight"
+            @click="getData()"
+          ></el-button>
+          <el-button class="sa-button-refresh" icon="Search" @click="openFilter"></el-button>
+          <el-button
+            v-auth="'shop.admin.order.order.export'"
+            :loading="exportLoading"
+            :disabled="exportLoading"
+            @click="onExport('export')"
+            >订单导出</el-button
+          >
+          <el-button
+            v-if="filterParams.data.status == 'nosend'"
+            v-auth="'shop.admin.order.order.exportdelivery'"
+            :loading="exportLoading"
+            :disabled="exportLoading"
+            @click="onExport('exportDelivery')"
+            >导出发货单</el-button
+          >
+        </div>
+      </div>
+    </el-header>
+    <el-main class="sa-p-0" v-loading="loading">
+      <el-table
+        height="100%"
+        class="sa-table"
+        :data="table.data"
+        :span-method="arraySpanMethod"
+        default-expand-all
+        @selection-change="handleSelectionChange"
+      >
+        <template #empty>
+          <sa-empty />
+        </template>
+        <el-table-column type="expand">
+          <template #default="props">
+            <el-table
+              class="sa-table sa-expand-table"
+              :data="props.row.items"
+              :span-method="objectSpanMethod"
+            >
+              <el-table-column width="88"></el-table-column>
+              <el-table-column width="324">
+                <template #default="scope">
+                  <div class="goods-item sa-flex">
+                    <sa-image :url="scope.row.goods_image" size="58" />
+                    <div class="right sa-m-l-12">
+                      <div class="goods-title sa-flex sa-table-line-1">
+                        <span class="goods-id" @click="onOpenGoodsEdit(scope.row.goods_id)"
+                          >#{{ scope.row.goods_id }}</span
+                        >
+                        {{ scope.row.goods_title }}
+                      </div>
+                      <div class="goods-sku-text sa-m-t-10">
+                        <span>商品编码:{{ scope.row.goods_sku_price_out_code }}</span>
+                      </div>
+                      <div class="sa-flex">
+                        <span class="goods-price sa-m-r-8">¥{{ scope.row.goods_price }}</span>
+                        <span class="goods-num sa-m-r-12">x{{ scope.row.goods_num }}</span>
+                        <index-status type="dispatch" :item="scope.row" />
+                        <el-button
+                          class="sa-m-l-8"
+                          v-auth="'shop.admin.order.order.dispatch'"
+                          type="primary"
+                          size="small"
+                          plain
+                          @click="onOpenManualOrder(scope.row.id)"
+                          >手动下单</el-button
+                        >
+                        <el-button
+                          class="sa-m-l-8"
+                          v-auth="'shop.admin.order.order.dispatch'"
+                          type="primary"
+                          size="small"
+                          plain
+                          v-if="
+                            scope.row.order_source === 'zkh' && scope.row.status_code === 'nosend'
+                          "
+                          @click="onOpenZkhSubmitConfirm(scope.row.id)"
+                          >震坤行下单</el-button
+                        >
+                      </div>
+                      <div class="sa-m-t-8 sa-font-24">
+                        <div v-if="scope.row.out_order_id"
+                          >外部订单号:{{ scope.row.out_order_id }}</div
+                        >
+                        <div v-if="scope.row.out_order_item_id" class="sa-m-t-5 sa-m-b-5"
+                          >外部子订单号:{{ scope.row.out_order_item_id }}</div
+                        >
+                        <div v-if="scope.row.order_source"
+                          >下单渠道:{{ formatOrderSource(scope.row.order_source) }}</div
+                        >
+                      </div>
+                    </div>
+                  </div>
+                </template>
+              </el-table-column>
+              <el-table-column min-width="140" align="center">
+                <template #default="scope">
+                  <index-status type="aftersale" :item="scope.row" @updateList="getData" />
+                </template>
+              </el-table-column>
+              <el-table-column min-width="92" align="center">
+                <template #default>
+                  <sa-user-profile :user="props.row.user" :id="props.row.user_id" mode="col" />
+                </template>
+              </el-table-column>
+              <el-table-column min-width="168" align="center">
+                <template #default>
+                  <div
+                    class="address-content sa-flex sa-flex-col sa-col-top"
+                    v-if="props.row.address"
+                  >
+                    <div class="consignee sa-m-b-6">
+                      <span>{{ props.row.address.consignee }}</span>
+                      <span class="sa-m-l-8">{{ props.row.address.mobile }}</span>
+                    </div>
+                    <div class="address-name sa-m-b-6">
+                      {{ props.row.address.province_name }}/{{ props.row.address.city_name }}/{{
+                        props.row.address.district_name
+                      }}/{{ props.row.address.town_name || '暂无' }}
+                    </div>
+                    <div class="address sa-table-line-1">
+                      {{ props.row.address.address }}
+                    </div>
+                  </div>
+                  <div v-else>{{ props.row.address_id }}</div>
+                </template>
+              </el-table-column>
+              <el-table-column prop="dispatch_type_text" min-width="168" align="center">
+              </el-table-column>
+              <el-table-column min-width="160" align="center">
+                <template #default="scope">
+                  <div class="sa-flex-col sa-col-center">
+                    <div
+                      v-if="scope.row.activity_type"
+                      class="activity-type-text sa-m-r-4"
+                      :class="scope.row.activity_type"
+                      >{{ scope.row.activity_type_text }}</div
+                    >
+                    <div class="sa-flex">
+                      ¥{{ scope.row.pay_fee }}
+                      <index-status
+                        v-if="scope.row.refund_status != 0"
+                        type="refund"
+                        :item="scope.row"
+                      />
+                    </div>
+                    <template v-if="Number(scope.row.discount_fee)">
+                      <el-popover
+                        popper-class="discount-fee-popover"
+                        placement="top"
+                        trigger="hover"
+                      >
+                        <div class="sa-flex">
+                          <div
+                            class="promo-type-text"
+                            v-for="text in scope.row.promo_types_text"
+                            :key="text"
+                            >{{ text }}</div
+                          >
+                        </div>
+                        <template #reference>
+                          <div>
+                            <div v-if="scope.row.promo_types_text?.length > 0" class="discount-fee">
+                              (优惠: ¥{{ scope.row.discount_fee }})
+                            </div>
+                          </div>
+                        </template>
+                      </el-popover>
+                      <div v-if="scope.row.promo_types_text?.length == 0" class="discount-fee">
+                        (优惠: -¥{{ scope.row.discount_fee }})
+                      </div>
+                    </template>
+                  </div>
+                </template>
+              </el-table-column>
+              <el-table-column min-width="240">
+                <template #default>
+                  <div class="sa-flex">
+                    <el-popover
+                      v-model:visible="refundPopover[props.$index]"
+                      popper-class="refund-popover"
+                      placement="top-start"
+                      :width="204"
+                      trigger="click"
+                    >
+                      <div class="title sa-flex">
+                        <el-icon><QuestionFilled /></el-icon>
+                        您同意用户进行申请退款吗?
+                      </div>
+                      <div class="sa-flex sa-row-right">
+                        <el-button
+                          v-auth="'shop.admin.order.order.applyrefundrefuse'"
+                          class="is-link"
+                          size="small"
+                          type="info"
+                          @click="onApplyRefundRefuse(props.row.id, props.$index)"
+                          >拒绝</el-button
+                        >
+                        <el-button
+                          v-auth="'shop.admin.order.order.fullrefund'"
+                          size="small"
+                          type="danger"
+                          @click="onOpenRefund(props.row, props.$index)"
+                          >同意</el-button
+                        >
+                      </div>
+                      <template #reference>
+                        <div class="apply-refund-wrap">
+                          <el-button
+                            v-if="props.row.btns?.includes('apply_refund_oper')"
+                            class="apply-refund-button sa-m-r-12"
+                            type="danger"
+                            plain
+                          >
+                            用户申请退款
+                            <el-icon><ArrowRight /></el-icon>
+                          </el-button>
+                        </div>
+                      </template>
+                    </el-popover>
+                    <el-popover
+                      v-model:visible="confirmPopover[props.$index]"
+                      popper-class="confirm-popover sa-popper"
+                      placement="top-start"
+                      :width="204"
+                      trigger="click"
+                    >
+                      <div class="title sa-flex">
+                        <el-icon>
+                          <question-filled />
+                        </el-icon>
+                        确认用户是否收货?
+                      </div>
+                      <div class="sa-flex sa-row-right">
+                        <el-button
+                          v-auth="'shop.admin.order.order.offlinerefuse'"
+                          size="small"
+                          type="danger"
+                          link
+                          @click="onOfflineRefuse(props.row.id, props.$index)"
+                          >用户拒收
+                        </el-button>
+                        <el-button
+                          v-auth="'shop.admin.order.order.offlineconfirm'"
+                          size="small"
+                          type="primary"
+                          @click="onOfflineConfirm(props.row.id, props.$index)"
+                          >确认收货
+                        </el-button>
+                      </div>
+                      <template #reference>
+                        <div class="apply-refund-wrap">
+                          <el-button
+                            v-if="props.row.btns?.includes('confirm')"
+                            class="send-button sa-m-r-12"
+                            type="primary"
+                            plain
+                          >
+                            确认收货
+                            <el-icon>
+                              <arrow-right />
+                            </el-icon>
+                          </el-button>
+                        </div>
+                      </template>
+                    </el-popover>
+
+                    <el-button
+                      v-if="props.row.btns?.includes('send')"
+                      v-auth="'shop.admin.order.order.dispatch'"
+                      class="send-button"
+                      type="primary"
+                      plain
+                      @click="onSend(props.row)"
+                    >
+                      立即发货
+                      <el-icon><ArrowRight /></el-icon>
+                    </el-button>
+                    <el-button
+                      v-auth="'shop.admin.order.order.detail'"
+                      class="is-link"
+                      type="primary"
+                      @click="detailRow(props.row.id)"
+                      >详情</el-button
+                    >
+                    <el-button
+                      v-auth="'shop.admin.order.order.action'"
+                      class="is-link"
+                      type="primary"
+                      @click="onOpenAction(props.row.id)"
+                      >日志</el-button
+                    >
+                  </div>
+                </template>
+              </el-table-column>
+            </el-table>
+          </template>
+        </el-table-column>
+        <el-table-column type="selection" width="40" />
+        <el-table-column label="商品信息" width="304">
+          <template #default="scope">
+            <div class="order-wrap sa-flex">
+              <div class="id">#{{ scope.row.id }}</div>
+              <div class="order-sn sa-flex">
+                订单号:{{ scope.row.order_sn }}
+                <sa-svg
+                  class="copy sa-m-l-4 cursor-pointer"
+                  name="sa-copy"
+                  @click="useClip(scope.row.order_sn)"
+                ></sa-svg>
+              </div>
+              <div class="create-time"> 下单时间:{{ scope.row.create_time }} </div>
+              <div class="pay-types-text">{{ scope.row.pay_types_text?.join(',') }}</div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="售后状态" min-width="140" align="center"></el-table-column>
+        <el-table-column label="下单用户" min-width="92" align="center"></el-table-column>
+        <el-table-column label="收货地址" min-width="168" align="center"></el-table-column>
+        <el-table-column label="配送方式" min-width="168" align="center"></el-table-column>
+        <el-table-column label="支付信息" min-width="160" align="center">
+          <template #default="scope">
+            <div class="sa-flex sa-row-center">
+              <el-popover popper-class="pay-fee-popover sa-popper" placement="top" trigger="hover">
+                <div>
+                  <div class="pay-fee-item">
+                    <div class="label">商品总价:</div>
+                    <div class="content">¥{{ scope.row.goods_amount }}</div>
+                  </div>
+                  <div class="pay-fee-item">
+                    <div class="label">运费价格:</div>
+                    <div class="content"> ¥{{ scope.row.dispatch_amount }} </div>
+                  </div>
+                  <div
+                    class="pay-fee-item pay-fee-item-discount"
+                    v-if="scope.row.ext && (scope.row.ext.promo_infos || scope.row.coupon_id)"
+                  >
+                    <div class="label">活动优惠:</div>
+                    <div class="content">
+                      <div
+                        class="pay-fee-item"
+                        v-if="Number(scope.row.ext.promo_discounts.full_reduce) > 0"
+                      >
+                        <div class="label sa-m-r-8">满减</div>
+                        <div class="content">
+                          -¥{{ scope.row.ext.promo_discounts.full_reduce }}
+                        </div>
+                      </div>
+                      <div
+                        class="pay-fee-item"
+                        v-if="Number(scope.row.ext.promo_discounts.full_discount) > 0"
+                      >
+                        <div class="label sa-m-r-8">满折</div>
+                        <div class="content">
+                          -¥{{ scope.row.ext.promo_discounts.full_discount }}
+                        </div>
+                      </div>
+                      <div
+                        class="pay-fee-item"
+                        v-if="Number(scope.row.ext.promo_discounts.full_gift) > 0"
+                      >
+                        <div class="label sa-m-r-8">满赠</div>
+                        <div class="content"></div>
+                      </div>
+                      <div
+                        class="pay-fee-item"
+                        v-if="Number(scope.row.ext.promo_discounts.free_shipping) > 0"
+                      >
+                        <div class="label sa-m-r-8">满包邮</div>
+                        <div class="content">
+                          -¥{{ scope.row.ext.promo_discounts.free_shipping }}
+                        </div>
+                      </div>
+                      <div v-if="scope.row.coupon_id" class="pay-fee-item">
+                        <div class="label sa-m-r-8">优惠券</div>
+                        <div class="content"> -¥{{ scope.row.coupon_discount_fee }} </div>
+                      </div>
+                    </div>
+                  </div>
+                  <div class="pay-fee-item">
+                    <div class="label"
+                      >{{
+                        ['paid', 'completed'].includes(scope.row.status) ? '实付金额' : '应付金额'
+                      }}:</div
+                    >
+                    <div class="content sa-flex">
+                      ¥{{ scope.row.pay_fee }}
+                      <s
+                        v-if="scope.row.pay_fee != scope.row.original_pay_fee"
+                        class="original-pay-fee sa-m-l-4"
+                      >
+                        {{ scope.row.original_pay_fee }}
+                      </s>
+                    </div>
+                  </div>
+                </div>
+                <template #reference>
+                  <div class="pay-fee-reference">¥{{ scope.row.pay_fee }}</div>
+                </template>
+              </el-popover>
+              <el-button
+                v-if="scope.row?.btns.includes('change_fee')"
+                class="is-link"
+                type="primary"
+                @click="onChangeFee(scope.row)"
+                >改价</el-button
+              >
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" min-width="240">
+          <template #default="scope">
+            <index-status :order="scope.row" type="status_code" />
+          </template>
+        </el-table-column>
+      </el-table>
+    </el-main>
+    <sa-view-bar>
+      <template #left>
+        <sa-batch-handle
+          :batchHandleTools="batchHandleTools"
+          :selectedLeng="table.selected.length"
+          @batchHandle="batchHandle"
+        ></sa-batch-handle>
+      </template>
+      <template #right>
+        <sa-pagination :pageData="pageData" @updateFn="getData" />
+      </template>
+    </sa-view-bar>
+  </el-container>
+</template>
+<script>
+  export default {
+    name: 'shop.admin.order.order',
+  };
+</script>
+<script setup>
+  import { computed, onMounted, reactive, ref } from 'vue';
+  import { ElMessage, ElMessageBox } from 'element-plus';
+  import { api } from '../order.service';
+  import { useModal, usePagination } from '@/sheep/hooks';
+  import { useSearch } from '@/sheep/components/sa-table/sa-search/useSearch';
+  import { composeFilter } from '@/sheep/utils';
+  import useClip from '@/sheep/utils/clipboard.js';
+  import StatusButton from './components/status.vue';
+  import IndexStatus from './components/index-status.vue';
+  import OrderDispatch from './dispatch.vue';
+  import OrderRefund from './refund.vue';
+  import OrderFee from './fee.vue';
+  import { activityStatusStyle } from './status.js';
+  import OrderBatchDispatch from './batchDispatch.vue';
+  import OrderDetail from './detail.vue';
+  import OrderAction from './action.vue';
+  import GoodsEdit from '@/app/shop/admin/goods/goods/edit.vue';
+  import { useRoute } from 'vue-router';
+  import { cloneDeep } from 'lodash';
+  import ManualOrder from './manualOrder.vue';
+  const route = useRoute();
+
+  // getType
+  const statusList = reactive({});
+  async function getType() {
+    const { data } = await api.order.getType();
+    for (var key in data) {
+      if (filterParams.tools[key] && key != 'status') {
+        filterParams.tools[key].options.data = data[key];
+      } else if (key == 'pay_type') {
+        filterParams.tools['pay.pay_type'].options.data = data[key];
+      } else if (key == 'status') {
+        data[key].forEach((s) => {
+          statusList[s.type] = { label: s.name, num: 0 };
+        });
+      }
+    }
+  }
+
+  const filterParams = reactive({
+    tools: {
+      status: { label: '订单状态', value: route.query.status || 'all' },
+      order: {
+        type: 'tinputprepend',
+        label: '请输入查询内容',
+        field: 'order',
+        order: {
+          field: 'id',
+          value: '',
+        },
+        options: [
+          {
+            label: '订单ID',
+            value: 'id',
+          },
+          {
+            label: '订单编号',
+            value: 'order_sn',
+          },
+          {
+            label: '售后单号',
+            value: 'aftersale.aftersale_sn',
+          },
+          {
+            label: '支付单号',
+            value: 'pay.pay_sn',
+          },
+          {
+            label: '交易流水号',
+            value: 'pay.transaction_id',
+          },
+        ],
+      },
+      user: {
+        type: 'tinputprepend',
+        label: '请输入查询内容',
+        field: 'user',
+        user: {
+          field: 'user_id',
+          value: '',
+        },
+        options: [
+          {
+            label: '用户ID',
+            value: 'user_id',
+          },
+          {
+            label: '用户昵称',
+            value: 'user.nickname',
+          },
+          {
+            label: '用户手机号',
+            value: 'user.mobile',
+          },
+          {
+            label: '收货人',
+            value: 'address.consignee',
+          },
+          {
+            label: '收货人手机号',
+            value: 'address.mobile',
+          },
+        ],
+      },
+      type: {
+        type: 'tselect',
+        label: '订单类型',
+        field: 'type',
+        value: '',
+        options: {
+          data: [],
+          props: {
+            label: 'name',
+            value: 'type',
+          },
+        },
+      },
+      platform: {
+        type: 'tselect',
+        label: '订单来源',
+        field: 'platform',
+        value: '',
+        options: {
+          data: [],
+          props: {
+            label: 'name',
+            value: 'type',
+          },
+        },
+      },
+      'pay.pay_type': {
+        type: 'tselect',
+        label: '支付方式',
+        field: 'pay.pay_type',
+        value: '',
+        options: {
+          data: [],
+          props: {
+            label: 'name',
+            value: 'type',
+          },
+        },
+      },
+      activity_type: {
+        type: 'tselect',
+        label: '活动类型',
+        field: 'activity_type',
+        value: '',
+        options: {
+          data: [],
+          props: {
+            label: 'name',
+            value: 'type',
+          },
+        },
+      },
+      promo_types: {
+        type: 'tselect',
+        label: '促销类型',
+        field: 'promo_types',
+        value: '',
+        options: {
+          data: [],
+          props: {
+            label: 'name',
+            value: 'type',
+          },
+        },
+      },
+      'item.goods_title': {
+        type: 'tinput',
+        label: '商品名称',
+        field: 'item.goods_title',
+        value: '',
+      },
+      create_time: {
+        type: 'tdatetimerange',
+        label: '下单时间',
+        field: 'create_time',
+        value: route.query.create_time || [],
+      },
+    },
+    data: {
+      status: route.query.status || 'all',
+      order: { field: 'id', value: '' },
+      user: { field: 'user_id', value: '' },
+      type: '',
+      platform: '',
+      'pay.pay_type': '',
+      activity_type: '',
+      promo_types: '',
+      'item.goods_title': '',
+      create_time: route.query.create_time || [],
+    },
+    conditionLabel: {},
+  });
+  const { openFilter, deleteFilter } = useSearch({ filterParams, getData });
+
+  const loading = ref(true);
+
+  // 表格
+  const table = reactive({
+    data: [],
+    order: '',
+    sort: '',
+    selected: [],
+  });
+
+  const { pageData } = usePagination();
+
+  // 下单渠道格式化函数
+  const formatOrderSource = (source) => {
+    const sourceMap = {
+      self: '自下单',
+      linkedmall: 'linkedmall',
+      zkh: '震坤行',
+    };
+    return sourceMap[source] || source;
+  };
+
+  // 获取数据
+  async function getData(page) {
+    loading.value = true;
+    if (page) pageData.page = page;
+    let tempSearch = cloneDeep(filterParams.data);
+    let search = composeFilter(tempSearch, {
+      order_sn: 'like',
+      'aftersale.aftersale_sn': 'like',
+      'pay.pay_sn': 'like',
+      'pay.transaction_id': 'like',
+      'user.nickname': 'like',
+      'user.mobile': 'like',
+      'address.consignee': 'like',
+      'address.mobile': 'like',
+      promo_types: 'find_in_set',
+      'item.goods_title': 'like',
+      create_time: 'range',
+    });
+    const { error, data } = await api.order.list({
+      page: pageData.page,
+      list_rows: pageData.list_rows,
+      ...search,
+    });
+    if (error === 0) {
+      table.data = data.orders.data;
+      pageData.page = data.orders.current_page;
+      pageData.list_rows = data.orders.per_page;
+      pageData.total = data.orders.total;
+      for (var key in statusList) {
+        statusList[key].num = data[key];
+      }
+    }
+    loading.value = false;
+  }
+
+  function onChangeStatus(tab) {
+    table.data = [];
+    getData(1);
+  }
+
+  function handleSelectionChange(val) {
+    table.selected = val;
+  }
+
+  // 导出订单/导出发货单
+  const exportLoading = ref(false);
+  async function onExport(type) {
+    exportLoading.value = true;
+    let tempSearch = cloneDeep(filterParams.data);
+    let search = composeFilter(tempSearch, {
+      order_sn: 'like',
+      'aftersale.aftersale_sn': 'like',
+      'pay.pay_sn': 'like',
+      'pay.transaction_id': 'like',
+      'user.nickname': 'like',
+      'user.mobile': 'like',
+      'address.consignee': 'like',
+      'address.mobile': 'like',
+      promo_types: 'find_in_set',
+      'item.goods_title': 'like',
+      create_time: 'range',
+    });
+    await api.order.export(type, { search: search.search });
+    exportLoading.value = false;
+  }
+
+  const batchHandleTools = [
+    {
+      type: 'all',
+      label: '批量发货',
+      auth: 'shop.admin.order.order.dispatch',
+      buttonType: 'default',
+    },
+  ];
+  function batchHandle() {
+    let order_ids = [];
+    table.selected.forEach((s) => {
+      order_ids.push(s.id);
+    });
+    useModal(
+      OrderBatchDispatch,
+      {
+        title: '批量发货',
+        order_ids,
+      },
+      {
+        confirm: () => {
+          getData();
+        },
+      },
+    );
+  }
+
+  function detailRow(id) {
+    useModal(
+      OrderDetail,
+      {
+        title: '订单详情',
+        type: 'detail',
+        id,
+      },
+      {
+        confirm: () => {
+          getData();
+        },
+        close: () => {
+          getData();
+        },
+      },
+    );
+  }
+
+  function onOpenAction(id) {
+    useModal(OrderAction, {
+      title: '日志',
+      id,
+    });
+  }
+
+  const arraySpanMethod = ({ row, column, rowIndex, columnIndex }) => {
+    if (columnIndex == 2) {
+      return [1, 4];
+    } else if (columnIndex == 3 || columnIndex == 4 || columnIndex == 5) {
+      return [0, 0];
+    }
+  };
+
+  const objectSpanMethod = ({ row, column, rowIndex, columnIndex }) => {
+    if (columnIndex == 0) {
+      return [0, 0];
+    }
+    if (columnIndex == 1) {
+      return [1, 2];
+    }
+    if (columnIndex == 3 || columnIndex == 4 || columnIndex == 7) {
+      if (rowIndex == 0) {
+        return {
+          rowspan: 200,
+          colspan: 1,
+        };
+      } else {
+        return {
+          rowspan: 0,
+          colspan: 0,
+        };
+      }
+    }
+  };
+
+  function onOpenGoodsEdit(id) {
+    useModal(GoodsEdit, {
+      title: '商品',
+      type: 'edit',
+      id: id,
+    });
+  }
+
+  function onSend(row) {
+    useModal(
+      OrderDispatch,
+      {
+        title: '订单发货',
+        data: row,
+      },
+      {
+        confirm: () => {
+          getData();
+        },
+      },
+    );
+  }
+
+  function onChangeFee(row) {
+    useModal(
+      OrderFee,
+      {
+        title: '改价',
+        class: 'fee-dialog',
+        id: row.id,
+        pay_fee: row.pay_fee,
+      },
+      {
+        confirm: () => {
+          getData();
+        },
+      },
+    );
+  }
+
+  function onOpenRefund(row, index) {
+    refundPopover[index] = false;
+    useModal(
+      OrderRefund,
+      {
+        title: '全部退款',
+        class: 'refund-dialog',
+        type: 'order.fullRefund',
+        data: {
+          id: row.id,
+          money: row.pay_fee,
+        },
+      },
+      {
+        confirm: () => {
+          getData();
+        },
+      },
+    );
+  }
+
+  const refundPopover = reactive({});
+  async function onApplyRefundRefuse(id, index) {
+    refundPopover[index] = false;
+    const { error } = await api.order.applyRefundRefuse(id);
+    if (error == 0) {
+      getData();
+    }
+  }
+
+  function onOpenZkhSubmitConfirm(order_item_id) {
+    ElMessageBox.confirm('确定要下单到震坤行吗?', '提示', {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning',
+    })
+      .then(async () => {
+        const { error } = await api.order.zkhOrderSubmit({ order_item_id });
+        if (error == 0) {
+          ElMessage.success('下单成功');
+          getData();
+        }
+      })
+      .catch(() => {
+        // 用户取消操作,不做任何处理
+      });
+  }
+
+  const confirmPopover = reactive({});
+  async function onOfflineRefuse(id, index) {
+    confirmPopover[index] = false;
+    const { error } = await api.order.offlineRefuse(id);
+    if (error == 0) {
+      getData();
+    }
+  }
+  async function onOfflineConfirm(id, index) {
+    confirmPopover[index] = false;
+    const { error } = await api.order.offlineConfirm(id);
+    if (error == 0) {
+      getData();
+    }
+  }
+
+  function onOpenManualOrder(id) {
+    useModal(
+      ManualOrder,
+      {
+        title: '手动下单',
+        id: id,
+      },
+      {
+        confirm: () => {
+          getData();
+        },
+      },
+    );
+  }
+
+  onMounted(async () => {
+    await getType();
+    getData();
+  });
+</script>
+<style lang="scss" scoped>
+  .order-page {
+    .el-main {
+      :deep() {
+        .el-table {
+          --el-table-row-hover-bg-color: var(--sa-background-hex-hover);
+          .el-table__row {
+            background: var(--sa-background-hex-hover);
+          }
+          .el-table__header-wrapper {
+            margin-bottom: 4px;
+          }
+          .el-table__expanded-cell {
+            padding: 0;
+            background: var(--sa-background-assist);
+          }
+        }
+        .sa-expand-table {
+          --el-table-row-hover-bg-color: var(--el-fill-color-light);
+          .el-table__header-wrapper {
+            margin-bottom: 0;
+          }
+          .el-table__row {
+            background: var(--el-table-tr-bg-color);
+          }
+          .el-table__body tr:hover > td.el-table__cell {
+            background-color: var(--sa-background-assist) !important;
+          }
+          .el-table__body tr.hover-row.current-row > td.el-table__cell,
+          .el-table__body tr.hover-row.el-table__row--striped.current-row > td.el-table__cell,
+          .el-table__body tr.hover-row.el-table__row--striped > td.el-table__cell,
+          .el-table__body tr.hover-row > td.el-table__cell {
+            background-color: var(--sa-background-assist) !important;
+          }
+        }
+      }
+
+      .sa-table {
+        .apply-refund {
+          font-size: 12px;
+          font-weight: 400;
+          color: #999;
+        }
+        .order-wrap {
+          position: relative;
+          line-height: 14px;
+          font-size: 12px;
+          font-weight: 400;
+          color: var(--sa-font);
+          & > div {
+            margin-right: 24px;
+          }
+          .id {
+            min-width: 80px;
+            color: var(--sa-subtitle);
+          }
+          .order-sn {
+            min-width: 228px;
+            height: 14px;
+            font-size: 12px;
+            color: var(--sa-subtitle);
+            .copy {
+              width: 12px !important;
+              height: 12px !important;
+            }
+          }
+          .create-time {
+            line-height: 14px;
+            font-size: 12px;
+            color: var(--sa-subtfont);
+          }
+          .platform-text {
+            min-width: 116px;
+          }
+          .pay-types-text {
+            margin-right: 0;
+          }
+        }
+        .address-content {
+          width: 100%;
+          display: inline-flex;
+          .consignee {
+            line-height: 14px;
+            color: var(--sa-font);
+            font-size: 12px;
+            text-align: left;
+          }
+          .address-name {
+            line-height: 16px;
+            font-size: 14px;
+            color: var(--sa-subtitle);
+            text-align: left;
+          }
+          .address {
+            height: 14px;
+            line-height: 14px;
+            font-size: 12px;
+            color: var(--sa-subfont);
+          }
+        }
+      }
+      .sa-expand-table {
+        :deep() {
+          .el-table__header-wrapper {
+            display: none;
+          }
+        }
+      }
+    }
+  }
+  .refund-popover,
+  .confirm-popover {
+    .title {
+      line-height: 20px;
+      font-size: 12px;
+      font-weight: 400;
+      color: var(--sa-font);
+      margin-bottom: 16px;
+      .el-icon {
+        font-size: 14px;
+        color: #faad14;
+        margin-right: 8px;
+      }
+    }
+    .tip {
+      font-size: 12px;
+      font-weight: 400;
+      color: var(--sa-subfont);
+    }
+  }
+  .pay-fee-reference {
+    width: fit-content;
+    color: var(--t-color-primary);
+    border-bottom: 1px dashed var(--t-color-primary);
+    cursor: pointer;
+  }
+  .pay-fee-popover {
+    .pay-fee-item {
+      line-height: 16px;
+      font-size: 12px;
+      display: flex;
+      align-items: center;
+      margin-bottom: 8px;
+      &.pay-fee-item-discount {
+        align-items: flex-start;
+      }
+      &:last-child {
+        margin-bottom: 0;
+      }
+      .label {
+        flex-shrink: 0;
+        color: var(--sa-subfont);
+      }
+      .content {
+        color: var(--sa-subtitle);
+      }
+      .original-pay-fee {
+        color: #999;
+      }
+    }
+  }
+
+  .goods-item {
+    .right {
+      flex: 1;
+      line-height: 14px;
+      font-size: 12px;
+      font-weight: 400;
+      color: var(--sa-font);
+      .goods-title {
+        height: 14px;
+        line-height: 14px;
+        font-size: 12px;
+        font-weight: 500;
+        margin-bottom: 4px;
+        .goods-id {
+          color: var(--t-color-primary);
+          cursor: pointer;
+        }
+      }
+      .goods-sku-text {
+        height: 14px;
+        line-height: 14px;
+        margin-bottom: 10px;
+      }
+      .goods-price {
+      }
+      .goods-num {
+      }
+    }
+  }
+
+  .activity-type-text {
+    width: fit-content;
+    height: 20px;
+    padding: 0 5px;
+    border-radius: 2px;
+    font-weight: 400;
+    font-size: 12px;
+    line-height: 20px;
+    text-align: center;
+    &.groupon,
+    &.groupon_ladder {
+      background: var(--t-bg-active);
+      color: var(--t-color-primary);
+    }
+    &.seckill {
+      background: rgba(255, 77, 79, 0.16);
+      color: #ff4d4f;
+    }
+  }
+
+  .discount-fee {
+    line-height: 14px;
+    font-size: 12px;
+    font-weight: 400;
+    color: var(--sa-font);
+    text-decoration-line: underline;
+  }
+  .discount-fee-popover {
+    .promo-type-text {
+      width: fit-content;
+      height: 20px;
+      padding: 0 8px;
+      background: rgba(250, 173, 20, 0.16);
+      border-radius: 10px;
+      font-weight: 400;
+      font-size: 12px;
+      color: #faad14;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+    }
+  }
+  .apply-refund-wrap {
+    width: fit-content;
+  }
+  .apply-refund-button {
+    height: 26px;
+    border-radius: 13px;
+    border: none;
+    padding: 0 8px 0 12px;
+    --el-button-bg-color: rgba(255, 77, 79, 0.16);
+  }
+  .send-button {
+    height: 26px;
+    border-radius: 13px;
+    border: none;
+    padding: 0 8px 0 12px;
+    --el-button-bg-color: var(--t-bg-active);
+  }
+</style>

+ 1 - 7
src/app/shop/components/goods-item.vue

@@ -157,7 +157,6 @@
   import { computed } from 'vue';
   import { useModal } from '@/sheep/hooks';
   import GoodsEdit from '@/app/shop/admin/goods/goods/edit.vue';
-  import ActivityEdit from '@/app/shop/admin/activity/activity/edit.vue';
 
   const props = defineProps({
     goods: {
@@ -208,12 +207,7 @@
   }
 
   function openDetail(data) {
-    useModal(ActivityEdit, {
-      title: `编辑${data.type_text}`,
-      type: 'edit',
-      atype: data.type,
-      id: data.id,
-    });
+    console.log('活动编辑功能暂未实现', data);
   }
 </script>
 <style lang="scss" scoped>

+ 0 - 2
src/sheep/components/sa-table/sa-batch-handle.global.vue

@@ -6,8 +6,6 @@
     </span>
     <div class="tools-pc">
       <el-button
-        v-auth="item.auth"
-        :class="item.class"
         v-for="item in batchHandleTools"
         :key="item"
         :type="item.buttonType"

+ 1 - 7
src/sheep/components/sa-table/sa-search/sa-search-simple.global.vue

@@ -65,12 +65,7 @@
           <el-form-item>
             <el-button type="primary" @click="handleSearch">搜索</el-button>
             <el-button @click="handleReset">重置</el-button>
-            <el-button
-              v-if="hasMoreThanThree"
-              type="text"
-              @click="toggleExpand"
-              class="expand-toggle-btn"
-            >
+            <el-button v-if="hasMoreThanThree" type="text" @click="toggleExpand">
               {{ isExpanded ? '收起' : '展开' }}
               <el-icon class="expand-toggle-icon" :class="{ 'is-expanded': isExpanded }">
                 <ArrowDown />
@@ -285,7 +280,6 @@
 
       .expand-toggle-btn {
         margin-left: 8px;
-        color: #409eff;
         transition: all 0.3s ease;
 
         .expand-toggle-icon {

+ 1 - 1
src/sheep/layouts/taskbar/index.vue

@@ -45,7 +45,7 @@
             {{ (userInfo.nickname || 'admin').charAt(0).toUpperCase() }}
           </el-avatar>
           <span class="user-name mx-8px">{{ userInfo.nickname || 'admin' }}</span>
-          <el-tag type="primary" plain size="small" class="mr-10px">管理员</el-tag>
+          <el-tag type="info" plain size="small" class="mr-10px">管理员</el-tag>
           <el-icon class="dropdown-icon"><ArrowDown /></el-icon>
         </div>
         <template #dropdown>

+ 149 - 0
src/sheep/mock/data/order.js

@@ -0,0 +1,149 @@
+/**
+ * 订单相关 Mock 数据
+ */
+
+// 订单状态配置
+export const orderStatusConfig = [
+  { type: 'all', name: '全部', num: 0 },
+  { type: 'unpaid', name: '待付款', num: 0 },
+  { type: 'paid', name: '已付款', num: 0 },
+  { type: 'nosend', name: '待发货', num: 0 },
+  { type: 'noget', name: '待收货', num: 0 },
+  { type: 'completed', name: '已完成', num: 0 },
+  { type: 'closed', name: '已关闭', num: 0 },
+  { type: 'refunded', name: '已退款', num: 0 },
+  { type: 'cancelled', name: '已取消', num: 0 },
+];
+
+// 订单类型配置
+export const orderTypeConfig = [
+  { type: 'normal', name: '普通订单' },
+  { type: 'groupon', name: '拼团订单' },
+  { type: 'seckill', name: '秒杀订单' },
+];
+
+// 订单来源配置
+export const orderPlatformConfig = [
+  { type: 'wechat', name: '微信小程序' },
+  { type: 'h5', name: 'H5商城' },
+  { type: 'app', name: 'APP' },
+];
+
+// 支付方式配置
+export const payTypeConfig = [
+  { type: 'wechat', name: '微信支付' },
+  { type: 'alipay', name: '支付宝' },
+  { type: 'balance', name: '余额支付' },
+];
+
+// 活动类型配置
+export const activityTypeConfig = [
+  { type: 'normal', name: '普通商品' },
+  { type: 'groupon', name: '拼团活动' },
+  { type: 'seckill', name: '秒杀活动' },
+];
+
+// 促销类型配置
+export const promoTypesConfig = [
+  { type: 'full_reduce', name: '满减' },
+  { type: 'full_discount', name: '满折' },
+  { type: 'coupon', name: '优惠券' },
+];
+
+// 生成订单列表数据
+export const generateOrderList = (page = 1, pageSize = 10) => {
+  const orders = [];
+  const startIndex = (page - 1) * pageSize;
+
+  for (let i = 0; i < pageSize; i++) {
+    const index = startIndex + i + 1;
+    const orderId = `202505051230${index.toString().padStart(2, '0')}`;
+
+    orders.push({
+      id: index,
+      order_sn: orderId,
+      status: ['unpaid', 'nosend', 'noget', 'completed'][Math.floor(Math.random() * 4)],
+      status_text: ['待付款', '待发货', '待收货', '已完成'][Math.floor(Math.random() * 4)],
+      user_id: 1000 + index,
+      user: {
+        id: 1000 + index,
+        nickname: `Aamer Khan`,
+        avatar:
+          'https://mall-oss.trust-will.com/storage/default/20250701/7bf12c56300454532244dec2aff808eb.jpg?x-oss-process=image/resize,w_200,h_200',
+        mobile: '138****5678',
+      },
+      goods_amount: '1,000',
+      dispatch_amount: '0',
+      pay_fee: '1,000',
+      original_pay_fee: '1,000',
+      discount_fee: '0',
+      coupon_discount_fee: '0',
+      create_time: '2025/06/06 12:30:30',
+      pay_time: '2025/06/06 12:31:30',
+      dispatch_time: null,
+      address: {
+        id: index,
+        consignee: 'Aamer Khan',
+        mobile: '138****5678',
+        province_name: 'Dhaka',
+        city_name: 'Dhaka',
+        district_name: 'Dhanmondi',
+        address: 'House 123, Road 456, Block A',
+      },
+      dispatch_type_text: '快递配送',
+      pay_types_text: ['微信支付'],
+      activity_type: null,
+      activity_type_text: '',
+      promo_types_text: [],
+      btns: ['send', 'detail', 'action'],
+      items: [
+        {
+          id: index,
+          goods_id: 100 + index,
+          goods_title: 'HOLUN Classic Aviator Polarized Sunglasses, Exclusive Eyewear Brand...',
+          goods_image:
+            'https://mall-oss.trust-will.com/storage/default/20250701/7bf12c56300454532244dec2aff808eb.jpg?x-oss-process=image/resize,w_200,h_200',
+          goods_sku_text: 'Black Grey',
+          goods_price: '1,000',
+          goods_num: 1,
+          pay_fee: '1,000',
+          dispatch_status: 0,
+          dispatch_status_text: '未发货',
+          refund_status: 0,
+          refund_status_text: '无退款',
+        },
+      ],
+      ext: {
+        promo_infos: [],
+        promo_discounts: {
+          full_reduce: '0',
+          full_discount: '0',
+          full_gift: '0',
+          free_shipping: '0',
+        },
+      },
+    });
+  }
+
+  return orders;
+};
+
+// 订单统计数据
+export const orderStats = {
+  all: 100,
+  unpaid: 25,
+  nosend: 30,
+  noget: 20,
+  completed: 20,
+  closed: 5,
+};
+
+// 订单类型数据
+export const orderTypeData = {
+  status: orderStatusConfig,
+  type: orderTypeConfig,
+  platform: orderPlatformConfig,
+  pay_type: payTypeConfig,
+  activity_type: activityTypeConfig,
+  promo_types: promoTypesConfig,
+};

+ 55 - 69
src/sheep/mock/goods-edit.js

@@ -14,8 +14,8 @@ export const categoryData = [
         children: [
           { id: 111, name: '智能手机' },
           { id: 112, name: '老人机' },
-          { id: 113, name: '对讲机' }
-        ]
+          { id: 113, name: '对讲机' },
+        ],
       },
       {
         id: 12,
@@ -23,8 +23,8 @@ export const categoryData = [
         children: [
           { id: 121, name: '笔记本电脑' },
           { id: 122, name: '台式机' },
-          { id: 123, name: '平板电脑' }
-        ]
+          { id: 123, name: '平板电脑' },
+        ],
       },
       {
         id: 13,
@@ -32,10 +32,10 @@ export const categoryData = [
         children: [
           { id: 131, name: '手机壳' },
           { id: 132, name: '充电器' },
-          { id: 133, name: '数据线' }
-        ]
-      }
-    ]
+          { id: 133, name: '数据线' },
+        ],
+      },
+    ],
   },
   {
     id: 2,
@@ -47,8 +47,8 @@ export const categoryData = [
         children: [
           { id: 211, name: 'T恤' },
           { id: 212, name: '衬衫' },
-          { id: 213, name: '裤子' }
-        ]
+          { id: 213, name: '裤子' },
+        ],
       },
       {
         id: 22,
@@ -56,8 +56,8 @@ export const categoryData = [
         children: [
           { id: 221, name: '连衣裙' },
           { id: 222, name: '上衣' },
-          { id: 223, name: '下装' }
-        ]
+          { id: 223, name: '下装' },
+        ],
       },
       {
         id: 23,
@@ -65,10 +65,10 @@ export const categoryData = [
         children: [
           { id: 231, name: '运动鞋' },
           { id: 232, name: '休闲鞋' },
-          { id: 233, name: '皮鞋' }
-        ]
-      }
-    ]
+          { id: 233, name: '皮鞋' },
+        ],
+      },
+    ],
   },
   {
     id: 3,
@@ -80,8 +80,8 @@ export const categoryData = [
         children: [
           { id: 311, name: '沙发' },
           { id: 312, name: '床' },
-          { id: 313, name: '桌椅' }
-        ]
+          { id: 313, name: '桌椅' },
+        ],
       },
       {
         id: 32,
@@ -89,11 +89,11 @@ export const categoryData = [
         children: [
           { id: 321, name: '床上用品' },
           { id: 322, name: '窗帘' },
-          { id: 323, name: '地毯' }
-        ]
-      }
-    ]
-  }
+          { id: 323, name: '地毯' },
+        ],
+      },
+    ],
+  },
 ];
 
 // 商品详情数据示例
@@ -112,20 +112,20 @@ export const goodsDetailData = {
   stock_warning: 10,
   status: 'up',
   supplier: '博伦眼镜有限公司',
-  
+
   // 图片
   images: [
     'https://mall-oss.trust-will.com/storage/default/20250701/7bf12c56300454532244dec2aff808eb.jpg',
-    'https://mall-oss.trust-will.com/storage/default/20250701/8bf12c56300454532244dec2aff808eb.jpg'
+    'https://mall-oss.trust-will.com/storage/default/20250701/8bf12c56300454532244dec2aff808eb.jpg',
   ],
   white_bg_image: [
-    'https://mall-oss.trust-will.com/storage/default/20250701/9bf12c56300454532244dec2aff808eb.jpg'
+    'https://mall-oss.trust-will.com/storage/default/20250701/9bf12c56300454532244dec2aff808eb.jpg',
   ],
   detail_images: [
     'https://mall-oss.trust-will.com/storage/default/20250701/abf12c56300454532244dec2aff808eb.jpg',
-    'https://mall-oss.trust-will.com/storage/default/20250701/bbf12c56300454532244dec2aff808eb.jpg'
+    'https://mall-oss.trust-will.com/storage/default/20250701/bbf12c56300454532244dec2aff808eb.jpg',
   ],
-  
+
   // 规格
   has_spec: true,
   specs: [
@@ -135,7 +135,7 @@ export const goodsDetailData = {
       price: '299.00',
       stock: '50',
       weight: '0.15',
-      sku: 'BL001-BK-M'
+      sku: 'BL001-BK-M',
     },
     {
       spec_0: '黑色',
@@ -143,7 +143,7 @@ export const goodsDetailData = {
       price: '299.00',
       stock: '30',
       weight: '0.15',
-      sku: 'BL001-BK-L'
+      sku: 'BL001-BK-L',
     },
     {
       spec_0: '棕色',
@@ -151,9 +151,9 @@ export const goodsDetailData = {
       price: '319.00',
       stock: '20',
       weight: '0.15',
-      sku: 'BL001-BR-M'
-    }
-  ]
+      sku: 'BL001-BR-M',
+    },
+  ],
 };
 
 // 保存商品接口响应
@@ -162,22 +162,22 @@ export const saveGoodsResponse = {
   msg: '保存成功',
   data: {
     id: 'BZ6542',
-    status: 'success'
-  }
+    status: 'success',
+  },
 };
 
 // 获取商品详情接口响应
 export const getGoodsDetailResponse = {
   error: 0,
   msg: '获取成功',
-  data: goodsDetailData
+  data: goodsDetailData,
 };
 
 // 获取商品分类接口响应
 export const getCategoryResponse = {
   error: 0,
   msg: '获取成功',
-  data: categoryData
+  data: categoryData,
 };
 
 // 上传图片接口响应
@@ -187,45 +187,31 @@ export const uploadImageResponse = {
   data: {
     url: 'https://mall-oss.trust-will.com/storage/default/20250701/new-image.jpg',
     name: 'new-image.jpg',
-    size: 102400
-  }
+    size: 102400,
+  },
 };
 
 // 商品编辑表单验证规则
 export const goodsFormRules = {
-  category_id: [
-    { required: true, message: '请选择商品分类', trigger: 'change' }
-  ],
+  category_id: [{ required: true, message: '请选择商品分类', trigger: 'change' }],
   title: [
     { required: true, message: '请输入商品名称', trigger: 'blur' },
-    { min: 1, max: 100, message: '商品名称长度在 1 到 100 个字符', trigger: 'blur' }
-  ],
-  brand: [
-    { required: true, message: '请输入商品品牌', trigger: 'blur' }
-  ],
-  freight_template: [
-    { required: true, message: '请选择运费模板', trigger: 'change' }
-  ],
-  goods_no: [
-    { required: true, message: '请输入商品货号', trigger: 'blur' }
+    { min: 1, max: 100, message: '商品名称长度在 1 到 100 个字符', trigger: 'blur' },
   ],
+  brand: [{ required: true, message: '请输入商品品牌', trigger: 'blur' }],
+  freight_template: [{ required: true, message: '请选择运费模板', trigger: 'change' }],
+  goods_no: [{ required: true, message: '请输入商品货号', trigger: 'blur' }],
   price: [
     { required: true, message: '请输入商品售价', trigger: 'blur' },
-    { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的价格格式', trigger: 'blur' }
+    { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的价格格式', trigger: 'blur' },
   ],
   stock: [
     { required: true, message: '请输入商品库存', trigger: 'blur' },
-    { pattern: /^\d+$/, message: '库存必须为正整数', trigger: 'blur' }
+    { pattern: /^\d+$/, message: '库存必须为正整数', trigger: 'blur' },
   ],
-  status: [
-    { required: true, message: '请选择商品状态', trigger: 'change' }
-  ],
-  supplier: [
-    { required: true, message: '请输入商品供应商', trigger: 'blur' }
-  ],
-  images: [
-    { required: true, message: '请上传商品主图', trigger: 'change' }
-  ]
+  status: [{ required: true, message: '请选择商品状态', trigger: 'change' }],
+  supplier: [{ required: true, message: '请输入商品供应商', trigger: 'blur' }],
+  images: [{ required: true, message: '请上传商品主图', trigger: 'change' }],
 };
 
 // 运费模板选项
@@ -233,14 +219,14 @@ export const freightTemplateOptions = [
   { label: '包邮', value: 'free' },
   { label: '按重量计费', value: 'weight' },
   { label: '按件数计费', value: 'piece' },
-  { label: '按体积计费', value: 'volume' }
+  { label: '按体积计费', value: 'volume' },
 ];
 
 // 商品状态选项
 export const goodsStatusOptions = [
   { label: '上架', value: 'up' },
   { label: '下架', value: 'down' },
-  { label: '草稿', value: 'draft' }
+  { label: '草稿', value: 'draft' },
 ];
 
 // 图片上传配置
@@ -250,20 +236,20 @@ export const imageUploadConfig = {
     maxCount: 5,
     accept: ['jpg', 'jpeg', 'png'],
     maxSize: 2, // MB
-    recommend: '建议尺寸800x800px,支持jpg、png格式'
+    recommend: '建议尺寸800x800px,支持jpg、png格式',
   },
   // 白底图配置
   whiteBgImage: {
     maxCount: 1,
     accept: ['jpg', 'jpeg', 'png'],
     maxSize: 2, // MB
-    recommend: '白底图,建议尺寸800x800px'
+    recommend: '白底图,建议尺寸800x800px',
   },
   // 详情图配置
   detailImage: {
     maxCount: 10,
     accept: ['jpg', 'jpeg', 'png'],
     maxSize: 2, // MB
-    recommend: '商品详情图片,建议宽度750px'
-  }
+    recommend: '商品详情图片,建议宽度750px',
+  },
 };

+ 2 - 0
src/sheep/mock/handlers/index.js

@@ -5,6 +5,7 @@ import { authHandlers } from './auth.js';
 import { notificationHandlers } from './notification.js';
 import { goodsHandlers } from './goods.js';
 import { categoryHandlers } from './category.js';
+import { orderHandlers } from './order.js';
 
 // 合并所有处理器
 export const handlers = [
@@ -12,6 +13,7 @@ export const handlers = [
   ...notificationHandlers,
   ...goodsHandlers,
   ...categoryHandlers,
+  ...orderHandlers,
   // 后续可以添加更多处理器
   // ...adminHandlers,
   // ...userHandlers,

+ 136 - 0
src/sheep/mock/handlers/order.js

@@ -0,0 +1,136 @@
+/**
+ * 订单相关 Mock 处理器
+ */
+import { http, HttpResponse } from 'msw';
+import { generateOrderList, orderStats, orderTypeData } from '../data/order.js';
+import { createSuccessResponse, createErrorResponse } from '../utils.js';
+
+// 订单列表接口
+const orderListHandler = http.get(
+  'https://shop.trust-will.com/shop/admin/order/order',
+  ({ request }) => {
+    const url = new URL(request.url);
+    const page = parseInt(url.searchParams.get('page')) || 1;
+    const listRows = parseInt(url.searchParams.get('list_rows')) || 10;
+    const status = url.searchParams.get('status') || 'all';
+
+    // 生成订单数据
+    const orders = generateOrderList(page, listRows);
+
+    // 根据状态过滤数据
+    let filteredOrders = orders;
+    if (status !== 'all') {
+      filteredOrders = orders.filter((order) => order.status === status);
+    }
+
+    const response = {
+      orders: {
+        current_page: page,
+        per_page: listRows,
+        total: 100,
+        last_page: Math.ceil(100 / listRows),
+        data: filteredOrders,
+      },
+      ...orderStats,
+    };
+
+    return HttpResponse.json(createSuccessResponse(response));
+  },
+);
+
+// 订单类型接口
+const orderTypeHandler = http.get(
+  'https://shop.trust-will.com/shop/admin/order/order/getType',
+  () => {
+    return HttpResponse.json(createSuccessResponse(orderTypeData));
+  },
+);
+
+// 订单详情接口
+const orderDetailHandler = http.get(
+  'https://shop.trust-will.com/shop/admin/order/order/detail/:id',
+  ({ params }) => {
+    const { id } = params;
+    const orders = generateOrderList(1, 100);
+    const order = orders.find((o) => o.id == id);
+
+    if (!order) {
+      return HttpResponse.json(createErrorResponse('订单不存在', 404));
+    }
+
+    return HttpResponse.json(createSuccessResponse(order));
+  },
+);
+
+// 订单发货接口
+const orderDispatchHandler = http.post(
+  'https://shop.trust-will.com/shop/admin/order/order/dispatch',
+  async ({ request }) => {
+    const data = await request.json();
+
+    // 模拟发货处理
+    return HttpResponse.json(createSuccessResponse({ message: '发货成功' }));
+  },
+);
+
+// 订单退款接口
+const orderRefundHandler = http.put(
+  'https://shop.trust-will.com/shop/admin/order/order/fullRefund/:id',
+  async ({ params, request }) => {
+    const { id } = params;
+    const data = await request.json();
+
+    // 模拟退款处理
+    return HttpResponse.json(createSuccessResponse({ message: '退款成功' }));
+  },
+);
+
+// 订单改价接口
+const orderChangeFeeHandler = http.put(
+  'https://shop.trust-will.com/shop/admin/order/order/changeFee/:id',
+  async ({ params, request }) => {
+    const { id } = params;
+    const data = await request.json();
+
+    // 模拟改价处理
+    return HttpResponse.json(createSuccessResponse({ message: '改价成功' }));
+  },
+);
+
+// 订单日志接口
+const orderActionHandler = http.get(
+  'https://shop.trust-will.com/shop/admin/order/order/action/:id',
+  ({ params }) => {
+    const { id } = params;
+
+    const logs = [
+      {
+        id: 1,
+        action: '创建订单',
+        operator: '系统',
+        create_time: '2025/06/06 12:30:30',
+        remark: '用户下单',
+      },
+      {
+        id: 2,
+        action: '支付成功',
+        operator: '系统',
+        create_time: '2025/06/06 12:31:30',
+        remark: '微信支付',
+      },
+    ];
+
+    return HttpResponse.json(createSuccessResponse(logs));
+  },
+);
+
+// 导出订单处理器
+export const orderHandlers = [
+  orderListHandler,
+  orderTypeHandler,
+  orderDetailHandler,
+  orderDispatchHandler,
+  orderRefundHandler,
+  orderChangeFeeHandler,
+  orderActionHandler,
+];

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio