Prechádzať zdrojové kódy

feat: 新增配置跨域,prettier 文件

叶静 3 dní pred
rodič
commit
e0266d9e1b

+ 4 - 0
.env.development

@@ -18,6 +18,10 @@ SHEEP_CACHE_PREFIX = _SHEEP_
 # Mock 服务配置
 SHEEP_USE_MOCK = false
 
+# 代理配置
+SHEEP_USE_PROXY = true
+SHEEP_PROXY_TARGET = http://192.168.0.107:8401
+
 ##### API路由配置
 # API路由功能总开关
 SHEEP_API_ROUTING_ENABLED = true

+ 297 - 265
src/app/shop/admin/config/componenets/commission.vue

@@ -4,8 +4,13 @@
       <el-alert class="sa-m-b-16">
         <template #title>
           设置分销时,请先了解
-          <a class="shopro-form-group-title-href" href="https://www.spp.gov.cn/flfg/gfwj/201311/t20131122_64638.shtml"
-            target="_blank" rel="noopener noreferrer">《关于办理组织领导传销活动刑事案件适用法律若干问题的意见》</a>
+          <a
+            class="shopro-form-group-title-href"
+            href="https://www.spp.gov.cn/flfg/gfwj/201311/t20131122_64638.shtml"
+            target="_blank"
+            rel="noopener noreferrer"
+            >《关于办理组织领导传销活动刑事案件适用法律若干问题的意见》</a
+          >
         </template>
       </el-alert>
       <div class="sa-title sa-title--line sa-m-b-16">分销设置</div>
@@ -33,8 +38,12 @@
         <div>
           <el-radio-group v-model="form.model.invite_lock">
             <el-radio label="share">首次通过分享进入</el-radio>
-            <el-radio label="pay" :disabled="form.model.become_agent.type === 'user'">首次付款</el-radio>
-            <el-radio label="agent" :disabled="form.model.become_agent.type === 'user'">成为子分销商</el-radio>
+            <el-radio label="pay" :disabled="form.model.become_agent.type === 'user'"
+              >首次付款</el-radio
+            >
+            <el-radio label="agent" :disabled="form.model.become_agent.type === 'user'"
+              >成为子分销商</el-radio
+            >
           </el-radio-group>
         </div>
       </el-form-item>
@@ -63,8 +72,8 @@
       <template v-if="form.model.become_agent">
         <el-form-item label="成为分销商条件">
           <div>
-            <el-radio-group v-model="form.model.become_agent.type" @change="onChangeBecomeAgentType"><el-radio
-                label="user">新会员注册</el-radio>
+            <el-radio-group v-model="form.model.become_agent.type" @change="onChangeBecomeAgentType"
+              ><el-radio label="user">新会员注册</el-radio>
               <el-radio label="apply">自助申请</el-radio>
               <el-radio label="goods">购买任意商品</el-radio>
               <el-radio label="consume">消费累计</el-radio>
@@ -102,7 +111,9 @@
                   </div>
                 </div>
                 <div class="oper">
-                  <el-button class="is-link" type="danger" @click="deleteGoods(gidx)">移除</el-button>
+                  <el-button class="is-link" type="danger" @click="deleteGoods(gidx)"
+                    >移除</el-button
+                  >
                 </div>
               </div>
             </div>
@@ -118,13 +129,18 @@
         <template v-if="form.model.agent_form">
           <el-form-item label="完善资料">
             <el-radio-group v-model="form.model.agent_form.status">
-              <el-radio label="0" :disabled="form.model.become_agent.type == 'apply'">不需要</el-radio>
+              <el-radio label="0" :disabled="form.model.become_agent.type == 'apply'"
+                >不需要</el-radio
+              >
               <el-radio label="1">需要</el-radio>
             </el-radio-group>
           </el-form-item>
           <template v-if="form.model.agent_form.status == '1'">
             <el-form-item label="表单背景图" prop="agent_form.background_image">
-              <sa-uploader v-model="form.model.agent_form.background_image" fileType="image"></sa-uploader>
+              <sa-uploader
+                v-model="form.model.agent_form.background_image"
+                fileType="image"
+              ></sa-uploader>
             </el-form-item>
             <el-form-item label="表单内容">
               <div class="sa-template-content sa-template-form">
@@ -133,24 +149,36 @@
                   <div class="item">表单名称</div>
                   <div class="oper">操作</div>
                 </div>
-                <sa-draggable v-model="form.model.agent_form.content" :animation="300" handle=".sortable-drag"
-                  item-key="element">
+                <sa-draggable
+                  v-model="form.model.agent_form.content"
+                  :animation="300"
+                  handle=".sortable-drag"
+                  item-key="element"
+                >
                   <template #item="{ element, index }">
                     <div class="list sa-flex">
-                      <el-form-item class="item" :prop="`agent_form.content.${index}.type`"
-                        :rules="form.rules.agent_form.content.type">
+                      <el-form-item
+                        class="item"
+                        :prop="`agent_form.content.${index}.type`"
+                        :rules="form.rules.agent_form.content.type"
+                      >
                         <el-select v-model="element.type" placeholder="表单类型">
                           <template v-for="br in become_register_options" :key="br">
                             <el-option :label="br.label" :value="br.value" />
                           </template>
                         </el-select>
                       </el-form-item>
-                      <el-form-item class="item" :prop="`agent_form.content.${index}.name`"
-                        :rules="form.rules.agent_form.content.name">
+                      <el-form-item
+                        class="item"
+                        :prop="`agent_form.content.${index}.name`"
+                        :rules="form.rules.agent_form.content.name"
+                      >
                         <el-input v-model="element.name" placeholder="表单名称"></el-input>
                       </el-form-item>
                       <div class="oper">
-                        <el-button class="is-link" type="danger" @click="deleteContent(index)">移除</el-button>
+                        <el-button class="is-link" type="danger" @click="deleteContent(index)"
+                          >移除</el-button
+                        >
                         <sa-svg class="sa-m-l-8 sortable-drag" name="sa-round"></sa-svg>
                       </div>
                     </div>
@@ -215,9 +243,14 @@
     <el-button @click="getConfig">重置</el-button>
     <el-button type="primary" @click="onSave">保存</el-button>
   </el-footer>
-  <el-dialog class="configis-upgrade-dialog" :close-on-click-modal="false" width="900px" v-model="state.configis_upgrade">
+  <el-dialog
+    class="configis-upgrade-dialog"
+    :close-on-click-modal="false"
+    width="900px"
+    v-model="state.configis_upgrade"
+  >
     <div class="configis-upgrade-image">
-      <img src="/static/images/shop/config/upgrade-config.png">
+      <img src="/static/images/shop/config/upgrade-config.png" />
       <div class="configis-upgrade-close" @click="onOper('close')">
         <el-icon><circle-close-filled /></el-icon>
       </div>
@@ -228,8 +261,9 @@
           </el-icon>
           刷新
         </div>
-        <div class="configis-upgrade-button-upgrade sa-flex" @click="onOper('upgrade')">去升级
-          <img class="icon-right" src="/static/images/shop/config/icon-right.png">
+        <div class="configis-upgrade-button-upgrade sa-flex" @click="onOper('upgrade')"
+          >去升级
+          <img class="icon-right" src="/static/images/shop/config/icon-right.png" />
         </div>
       </div>
     </div>
@@ -237,297 +271,295 @@
 </template>
 
 <script setup>
-import { onMounted, reactive, ref, unref } from 'vue';
-import SaDraggable from 'vuedraggable';
-import { api } from '../config.service';
-import adminApi from '@/app/admin/api';
-import { api as goodsApi } from '@/app/shop/admin/goods/goods.service';
-import { useModal } from '@/sheep/hooks';
-import RichtextSelect from '@/app/shop/admin/data/richtext/select.vue';
-import GoodsSelect from '@/app/shop/admin/goods/goods/select.vue';
+  import { onMounted, reactive, ref, unref } from 'vue';
+  import SaDraggable from 'vuedraggable';
+  import { api } from '../config.service';
+  import adminApi from '@/app/admin/api';
+  import { api as goodsApi } from '@/app/shop/admin/goods/goods.service';
+  import { useModal } from '@/sheep/hooks';
+  import RichtextSelect from '@/app/shop/admin/data/richtext/select.vue';
+  import GoodsSelect from '@/app/shop/admin/goods/goods/select.vue';
 
-const formRef = ref();
-const form = reactive({
-  model: {
-    level: 0,
-    self_buy: 0,
-    invite_lock: 'share',
-    agent_check: 0,
-    upgrade_jump: 0,
-    upgrade_check: 0,
-    become_agent: {
-      type: 'apply',
-      value: '',
+  const formRef = ref();
+  const form = reactive({
+    model: {
+      level: 0,
+      self_buy: 0,
+      invite_lock: 'share',
+      agent_check: 0,
+      upgrade_jump: 0,
+      upgrade_check: 0,
+      become_agent: {
+        type: 'apply',
+        value: '',
+      },
+      // background_image: '',
+      agent_form: {
+        status: '0',
+        background_image: '',
+        content: [
+          {
+            type: '',
+            name: '',
+          },
+        ],
+      },
+      apply_protocol: {
+        status: '0',
+        id: '',
+        title: '',
+      },
+      reward_type: 'goods_price',
+      reward_event: 'paid',
+      refund_commission_reward: 0,
+      refund_commission_order: 0,
     },
-    // background_image: '',
-    agent_form: {
-      status: '0',
-      background_image: '',
-      content: [
-        {
-          type: '',
-          name: '',
+    rules: {
+      // background_image: [{ required: true, message: '请选择分销中心背景图', trigger: 'blur' }],
+      agent_form: {
+        background_image: [{ required: true, message: '请选择表单背景图', trigger: 'blur' }],
+        content: {
+          type: [{ required: true, message: '表单类型', trigger: 'change' }],
+          name: [{ required: true, message: '表单名称', trigger: 'blur' }],
         },
-      ],
-    },
-    apply_protocol: {
-      status: '0',
-      id: '',
-      title: '',
-    },
-    reward_type: 'goods_price',
-    reward_event: 'paid',
-    refund_commission_reward: 0,
-    refund_commission_order: 0,
-  },
-  rules: {
-    // background_image: [{ required: true, message: '请选择分销中心背景图', trigger: 'blur' }],
-    agent_form: {
-      background_image: [{ required: true, message: '请选择表单背景图', trigger: 'blur' }],
-      content: {
-        type: [{ required: true, message: '表单类型', trigger: 'change' }],
-        name: [{ required: true, message: '表单名称', trigger: 'blur' }],
       },
     },
-  },
-});
-const state = reactive({
-  configis_upgrade: false,
-})
+  });
+  const state = reactive({
+    configis_upgrade: false,
+  });
 
-function onChangeBecomeAgentType(type) {
-  if (type === 'apply') {
-    form.model.agent_form.status = '1';
+  function onChangeBecomeAgentType(type) {
+    if (type === 'apply') {
+      form.model.agent_form.status = '1';
+    }
+    if (type === 'user') {
+      form.model.invite_lock = 'share';
+    }
+    form.model.become_agent.value = '';
   }
-  if (type === 'user') {
-    form.model.invite_lock = 'share';
+
+  function selectRichtext() {
+    useModal(
+      RichtextSelect,
+      {
+        title: '选择活动说明',
+      },
+      {
+        confirm: (res) => {
+          form.model.apply_protocol.id = res.data.id;
+          form.model.apply_protocol.title = res.data.title;
+        },
+      },
+    );
   }
-  form.model.become_agent.value = '';
-}
 
-function selectRichtext() {
-  useModal(
-    RichtextSelect,
-    {
-      title: '选择活动说明',
-    },
-    {
-      confirm: (res) => {
-        form.model.apply_protocol.id = res.data.id;
-        form.model.apply_protocol.title = res.data.title;
+  const tempGoods = reactive({
+    list: [],
+  });
+
+  async function getGoodsList(ids) {
+    const { data } = await goodsApi.goods.select(
+      {
+        search: JSON.stringify({ id: [ids, 'in'] }),
       },
-    },
-  );
-}
+      'select',
+    );
+    tempGoods.list = data;
+  }
 
-const tempGoods = reactive({
-  list: [],
-});
+  function selectGoods() {
+    let ids = [];
+    tempGoods.list.forEach((i) => {
+      ids.push(i.id);
+    });
+    useModal(
+      GoodsSelect,
+      {
+        title: '选择商品',
+        multiple: true,
+        ids,
+      },
+      {
+        confirm: (res) => {
+          tempGoods.list = res.data;
 
-async function getGoodsList(ids) {
-  const { data } = await goodsApi.goods.select(
+          let ids = [];
+          tempGoods.list.forEach((gl) => {
+            ids.push(gl.id);
+          });
+          form.model.become_agent.value = ids.join(',');
+        },
+      },
+    );
+  }
+  function deleteGoods(index) {
+    tempGoods.list.splice(index, 1);
+    let ids = [];
+    tempGoods.list.forEach((gl) => {
+      ids.push(gl.id);
+    });
+    form.model.become_agent.value = ids.join(',');
+  }
+
+  const become_register_options = [
     {
-      search: JSON.stringify({ id: [ids, 'in'] }),
+      value: 'text',
+      label: '文本内容',
     },
-    'select',
-  );
-  tempGoods.list = data;
-}
-
-function selectGoods() {
-  let ids = [];
-  tempGoods.list.forEach((i) => {
-    ids.push(i.id);
-  });
-  useModal(
-    GoodsSelect,
     {
-      title: '选择商品',
-      multiple: true,
-      ids,
+      value: 'number',
+      label: '纯数字',
     },
     {
-      confirm: (res) => {
-        tempGoods.list = res.data;
-
-        let ids = [];
-        tempGoods.list.forEach((gl) => {
-          ids.push(gl.id);
-        });
-        form.model.become_agent.value = ids.join(',');
-      },
+      value: 'image',
+      label: '上传图片',
     },
-  );
-}
-function deleteGoods(index) {
-  tempGoods.list.splice(index, 1);
-  let ids = [];
-  tempGoods.list.forEach((gl) => {
-    ids.push(gl.id);
-  });
-  form.model.become_agent.value = ids.join(',');
-}
-
-const become_register_options = [
-  {
-    value: 'text',
-    label: '文本内容',
-  },
-  {
-    value: 'number',
-    label: '纯数字',
-  },
-  {
-    value: 'image',
-    label: '上传图片',
-  },
-];
-function addContent() {
-  form.model.agent_form.content.push({
-    type: '',
-    name: '',
-  });
-}
-function deleteContent(index) {
-  form.model.agent_form.content.splice(index, 1);
-}
-
-async function getConfig() {
-  const { data } = await api.commission();
-  form.model = data;
-  if (form.model.become_agent.type == 'goods') {
-    getGoodsList(form.model.become_agent.value);
+  ];
+  function addContent() {
+    form.model.agent_form.content.push({
+      type: '',
+      name: '',
+    });
   }
-  const initData = await adminApi.init();
-  if (!initData.data.is_pro) {
-    state.configis_upgrade = true
+  function deleteContent(index) {
+    form.model.agent_form.content.splice(index, 1);
   }
-}
 
-function onOper(type) {
-  switch (type) {
-    case 'close':
-      state.configis_upgrade = false
-      break;
-    case 'refresh':
-      window.location.reload();
-      break;
-    case 'upgrade':
-      window.open("https://shopro.top/buy")
-      break;
+  async function getConfig() {
+    const { data } = await api.commission();
+    form.model = data;
+    if (form.model.become_agent.type == 'goods') {
+      getGoodsList(form.model.become_agent.value);
+    }
+    const initData = await adminApi.init();
+    if (!initData.data.is_pro) {
+      state.configis_upgrade = true;
+    }
   }
-}
 
-function resetFrom() {
-  getConfig();
-}
+  function onOper(type) {
+    switch (type) {
+      case 'close':
+        state.configis_upgrade = false;
+        break;
+      case 'refresh':
+        window.location.reload();
+        break;
+      case 'upgrade':
+        window.open('https://shopro.top/buy');
+        break;
+    }
+  }
 
-function onSave() {
-  unref(formRef) &&
-    unref(formRef).validate(async (valid) => {
-      if (valid) {
-        await api.commission(form.model);
-      }
-    });
-}
+  function resetFrom() {
+    getConfig();
+  }
+
+  function onSave() {
+    unref(formRef) &&
+      unref(formRef).validate(async (valid) => {
+        if (valid) {
+          await api.commission(form.model);
+        }
+      });
+  }
 
-onMounted(() => {
-  getConfig();
-});
+  onMounted(() => {
+    getConfig();
+  });
 </script>
 
 <style lang="scss">
-.configis-upgrade-dialog {
-  .el-dialog__body {
-    padding: 0 !important;
-  }
+  .configis-upgrade-dialog {
+    .el-dialog__body {
+      padding: 0 !important;
+    }
 
-  .el-dialog__header {
-    height: 0 !important;
-    padding: 0 !important;
+    .el-dialog__header {
+      height: 0 !important;
+      padding: 0 !important;
+    }
   }
-}
 </style>
 <style lang="scss" scoped>
-.config-commission {
-  .sa-title {
-    font-weight: 500;
-    color: var(--sa-title);
-  }
+  .config-commission {
+    .sa-title {
+      font-weight: 500;
+      color: var(--sa-title);
+    }
 
-  .el-alert {
-    --el-alert-bg-color: var(--sa-background-hex-hover);
-    color: var(--sa-subtitle);
+    .el-alert {
+      --el-alert-bg-color: var(--sa-background-hex-hover);
+      color: var(--sa-subtitle);
 
-    :deep() {
-      .el-alert__content {
-        padding: 0;
-      }
+      :deep() {
+        .el-alert__content {
+          padding: 0;
+        }
 
-      .el-alert__close-btn {
-        color: var(--el-color-primary);
+        .el-alert__close-btn {
+          color: var(--el-color-primary);
+        }
       }
     }
   }
-}
-
-.configis-upgrade-image {
-  width: 900px;
-  height: 580px;
-  background: #FFFFFF;
-  border-radius: 4px;
-  position: relative;
-}
-
-img {
-  width: 100%;
-  height: 100%;
-}
 
+  .configis-upgrade-image {
+    width: 900px;
+    height: 580px;
+    background: #ffffff;
+    border-radius: 4px;
+    position: relative;
+  }
 
+  img {
+    width: 100%;
+    height: 100%;
+  }
 
-.configis-upgrade-button {
-  position: absolute;
-  bottom: 162px;
-  right: 360px;
-}
+  .configis-upgrade-button {
+    position: absolute;
+    bottom: 162px;
+    right: 360px;
+  }
 
-.configis-upgrade-button-upgrade {
-  width: 110px;
-  height: 34px;
-  background: #8322FF;
-  border-radius: 2px;
-  justify-content: center;
-  font-weight: bold;
-  font-size: 12px;
-  color: #FFFFFF;
-  margin-left: 42px;
-  cursor: pointer;
+  .configis-upgrade-button-upgrade {
+    width: 110px;
+    height: 34px;
+    background: #8322ff;
+    border-radius: 2px;
+    justify-content: center;
+    font-weight: bold;
+    font-size: 12px;
+    color: #ffffff;
+    margin-left: 42px;
+    cursor: pointer;
 
-  .icon-right {
-    margin-left: 12px;
-    width: 18px;
-    height: 18px;
+    .icon-right {
+      margin-left: 12px;
+      width: 18px;
+      height: 18px;
+    }
   }
-}
 
-.configis-upgrade-button-refresh {
-  color: #86818E;
-  font-size: 12px;
-  cursor: pointer;
+  .configis-upgrade-button-refresh {
+    color: #86818e;
+    font-size: 12px;
+    cursor: pointer;
 
-  .refresh-right {
-    margin-right: 6px;
-    font-size: 14px;
+    .refresh-right {
+      margin-right: 6px;
+      font-size: 14px;
+    }
   }
-}
 
-.configis-upgrade-close {
-  position: absolute;
-  top: 53px;
-  right: 58px;
-  font-size: 20px;
-  color: #7F7A87;
-  cursor: pointer;
-}
+  .configis-upgrade-close {
+    position: absolute;
+    top: 53px;
+    right: 58px;
+    font-size: 20px;
+    color: #7f7a87;
+    cursor: pointer;
+  }
 </style>

+ 90 - 92
src/app/shop/admin/data/express/index.vue

@@ -6,7 +6,7 @@
           <span>快递公司管理</span>
         </div>
       </template>
-      
+
       <div class="search-form">
         <el-form :inline="true" :model="searchForm">
           <el-form-item label="快递公司">
@@ -34,9 +34,7 @@
         </el-table-column>
         <el-table-column label="操作" width="150">
           <template #default="scope">
-            <el-button type="primary" size="small" @click="handleEdit(scope.row)">
-              编辑
-            </el-button>
+            <el-button type="primary" size="small" @click="handleEdit(scope.row)"> 编辑 </el-button>
             <el-button type="danger" size="small" @click="handleDelete(scope.row)">
               删除
             </el-button>
@@ -60,97 +58,97 @@
 </template>
 
 <script setup>
-import { ref, reactive, onMounted } from 'vue';
-import { ElMessage, ElMessageBox } from 'element-plus';
-import useExpress from './express.js';
-
-const { expressOptions, deliverCompany } = useExpress();
-
-const searchForm = reactive({
-  name: '',
-});
-
-const pagination = reactive({
-  page: 1,
-  pageSize: 10,
-  total: 0,
-});
-
-const tableData = ref([]);
-
-// 初始化数据
-const initData = () => {
-  tableData.value = expressOptions.value;
-  pagination.total = expressOptions.value.length;
-};
-
-// 搜索
-const handleSearch = () => {
-  if (searchForm.name) {
-    tableData.value = expressOptions.value.filter(item => 
-      item.name.includes(searchForm.name) || item.code.includes(searchForm.name)
-    );
-  } else {
+  import { ref, reactive, onMounted } from 'vue';
+  import { ElMessage, ElMessageBox } from 'element-plus';
+  import useExpress from './express.js';
+
+  const { expressOptions, deliverCompany } = useExpress();
+
+  const searchForm = reactive({
+    name: '',
+  });
+
+  const pagination = reactive({
+    page: 1,
+    pageSize: 10,
+    total: 0,
+  });
+
+  const tableData = ref([]);
+
+  // 初始化数据
+  const initData = () => {
     tableData.value = expressOptions.value;
-  }
-  pagination.total = tableData.value.length;
-};
-
-// 重置
-const handleReset = () => {
-  searchForm.name = '';
-  initData();
-};
-
-// 编辑
-const handleEdit = (row) => {
-  ElMessage.info('编辑功能待开发');
-};
-
-// 删除
-const handleDelete = (row) => {
-  ElMessageBox.confirm('确定要删除这个快递公司吗?', '提示', {
-    confirmButtonText: '确定',
-    cancelButtonText: '取消',
-    type: 'warning',
-  }).then(() => {
-    ElMessage.success('删除成功');
+    pagination.total = expressOptions.value.length;
+  };
+
+  // 搜索
+  const handleSearch = () => {
+    if (searchForm.name) {
+      tableData.value = expressOptions.value.filter(
+        (item) => item.name.includes(searchForm.name) || item.code.includes(searchForm.name),
+      );
+    } else {
+      tableData.value = expressOptions.value;
+    }
+    pagination.total = tableData.value.length;
+  };
+
+  // 重置
+  const handleReset = () => {
+    searchForm.name = '';
+    initData();
+  };
+
+  // 编辑
+  const handleEdit = (row) => {
+    ElMessage.info('编辑功能待开发');
+  };
+
+  // 删除
+  const handleDelete = (row) => {
+    ElMessageBox.confirm('确定要删除这个快递公司吗?', '提示', {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning',
+    }).then(() => {
+      ElMessage.success('删除成功');
+    });
+  };
+
+  // 分页大小改变
+  const handleSizeChange = (val) => {
+    pagination.pageSize = val;
+    handleCurrentChange(1);
+  };
+
+  // 当前页改变
+  const handleCurrentChange = (val) => {
+    pagination.page = val;
+  };
+
+  onMounted(() => {
+    initData();
   });
-};
-
-// 分页大小改变
-const handleSizeChange = (val) => {
-  pagination.pageSize = val;
-  handleCurrentChange(1);
-};
-
-// 当前页改变
-const handleCurrentChange = (val) => {
-  pagination.page = val;
-};
-
-onMounted(() => {
-  initData();
-});
 </script>
 
 <style scoped>
-.express-page {
-  padding: 20px;
-}
-
-.card-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-}
-
-.search-form {
-  margin-bottom: 20px;
-}
-
-.pagination {
-  margin-top: 20px;
-  text-align: right;
-}
+  .express-page {
+    padding: 20px;
+  }
+
+  .card-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+
+  .search-form {
+    margin-bottom: 20px;
+  }
+
+  .pagination {
+    margin-top: 20px;
+    text-align: right;
+  }
 </style>

+ 201 - 216
src/app/shop/admin/goods/goods/components/goods-spec-editor.vue

@@ -10,21 +10,11 @@
           style="width: 200px; margin-right: 10px"
           @input="updateSpecCombinations"
         />
-        <el-button
-          v-if="specNames.length > 1"
-          type="danger"
-          text
-          @click="removeSpecName(index)"
-        >
+        <el-button v-if="specNames.length > 1" type="danger" text @click="removeSpecName(index)">
           删除
         </el-button>
       </div>
-      <el-button
-        v-if="specNames.length < 3"
-        type="primary"
-        text
-        @click="addSpecName"
-      >
+      <el-button v-if="specNames.length < 3" type="primary" text @click="addSpecName">
         + 添加规格
       </el-button>
     </div>
@@ -53,12 +43,7 @@
             @keyup.enter="confirmSpecValue(specIndex)"
             @blur="confirmSpecValue(specIndex)"
           />
-          <el-button
-            v-else
-            size="small"
-            text
-            @click="showSpecValueInput(specIndex)"
-          >
+          <el-button v-else size="small" text @click="showSpecValueInput(specIndex)">
             + 添加规格值
           </el-button>
         </div>
@@ -113,11 +98,7 @@
         </el-table-column>
         <el-table-column label="SKU编码" width="150">
           <template #default="scope">
-            <el-input
-              v-model="scope.row.sku"
-              placeholder="请输入SKU"
-              size="small"
-            />
+            <el-input v-model="scope.row.sku" placeholder="请输入SKU" size="small" />
           </template>
         </el-table-column>
       </el-table>
@@ -126,224 +107,228 @@
 </template>
 
 <script>
-import { ref, reactive, watch, nextTick } from 'vue';
+  import { ref, reactive, watch, nextTick } from 'vue';
 
-export default {
-  name: 'GoodsSpecEditor'
-};
+  export default {
+    name: 'GoodsSpecEditor',
+  };
 </script>
 
 <script setup>
-const props = defineProps({
-  modelValue: {
-    type: Array,
-    default: () => []
-  }
-});
+  const props = defineProps({
+    modelValue: {
+      type: Array,
+      default: () => [],
+    },
+  });
 
-const emit = defineEmits(['update:modelValue']);
+  const emit = defineEmits(['update:modelValue']);
 
-// 规格名称
-const specNames = ref([
-  { name: '', values: [], inputVisible: false, inputValue: '' }
-]);
+  // 规格名称
+  const specNames = ref([{ name: '', values: [], inputVisible: false, inputValue: '' }]);
 
-// 规格组合
-const specCombinations = ref([]);
+  // 规格组合
+  const specCombinations = ref([]);
 
-// 规格值输入框引用
-const specValueInput = ref();
+  // 规格值输入框引用
+  const specValueInput = ref();
 
-// 添加规格名称
-const addSpecName = () => {
-  if (specNames.value.length < 3) {
-    specNames.value.push({
-      name: '',
-      values: [],
-      inputVisible: false,
-      inputValue: ''
-    });
-  }
-};
-
-// 删除规格名称
-const removeSpecName = (index) => {
-  specNames.value.splice(index, 1);
-  updateSpecCombinations();
-};
-
-// 显示规格值输入框
-const showSpecValueInput = (specIndex) => {
-  specNames.value[specIndex].inputVisible = true;
-  nextTick(() => {
-    specValueInput.value?.[specIndex]?.focus();
-  });
-};
-
-// 确认添加规格值
-const confirmSpecValue = (specIndex) => {
-  const spec = specNames.value[specIndex];
-  const value = spec.inputValue.trim();
-  
-  if (value && !spec.values.includes(value)) {
-    spec.values.push(value);
+  // 添加规格名称
+  const addSpecName = () => {
+    if (specNames.value.length < 3) {
+      specNames.value.push({
+        name: '',
+        values: [],
+        inputVisible: false,
+        inputValue: '',
+      });
+    }
+  };
+
+  // 删除规格名称
+  const removeSpecName = (index) => {
+    specNames.value.splice(index, 1);
     updateSpecCombinations();
-  }
-  
-  spec.inputVisible = false;
-  spec.inputValue = '';
-};
-
-// 删除规格值
-const removeSpecValue = (specIndex, valueIndex) => {
-  specNames.value[specIndex].values.splice(valueIndex, 1);
-  updateSpecCombinations();
-};
-
-// 更新规格组合
-const updateSpecCombinations = () => {
-  const validSpecs = specNames.value.filter(spec => 
-    spec.name.trim() && spec.values.length > 0
-  );
-  
-  if (validSpecs.length === 0) {
-    specCombinations.value = [];
-    emit('update:modelValue', []);
-    return;
-  }
-  
-  // 生成所有可能的组合
-  const combinations = generateCombinations(validSpecs);
-  
-  // 保留已有的价格、库存等信息
-  const existingData = new Map();
-  specCombinations.value.forEach(item => {
-    const key = validSpecs.map((_, index) => item[`spec_${index}`]).join('|');
-    existingData.set(key, {
-      price: item.price,
-      stock: item.stock,
-      weight: item.weight,
-      sku: item.sku
-    });
-  });
-  
-  specCombinations.value = combinations.map(combination => {
-    const key = combination.join('|');
-    const existing = existingData.get(key) || {};
-    
-    const item = {
-      price: existing.price || '',
-      stock: existing.stock || '',
-      weight: existing.weight || '',
-      sku: existing.sku || ''
-    };
-    
-    // 添加规格值
-    combination.forEach((value, index) => {
-      item[`spec_${index}`] = value;
+  };
+
+  // 显示规格值输入框
+  const showSpecValueInput = (specIndex) => {
+    specNames.value[specIndex].inputVisible = true;
+    nextTick(() => {
+      specValueInput.value?.[specIndex]?.focus();
     });
-    
-    return item;
-  });
-  
-  // 发送更新事件
-  emit('update:modelValue', specCombinations.value);
-};
-
-// 生成规格组合
-const generateCombinations = (specs) => {
-  if (specs.length === 0) return [];
-  if (specs.length === 1) return specs[0].values.map(v => [v]);
-  
-  const result = [];
-  const generate = (current, remaining) => {
-    if (remaining.length === 0) {
-      result.push([...current]);
+  };
+
+  // 确认添加规格值
+  const confirmSpecValue = (specIndex) => {
+    const spec = specNames.value[specIndex];
+    const value = spec.inputValue.trim();
+
+    if (value && !spec.values.includes(value)) {
+      spec.values.push(value);
+      updateSpecCombinations();
+    }
+
+    spec.inputVisible = false;
+    spec.inputValue = '';
+  };
+
+  // 删除规格值
+  const removeSpecValue = (specIndex, valueIndex) => {
+    specNames.value[specIndex].values.splice(valueIndex, 1);
+    updateSpecCombinations();
+  };
+
+  // 更新规格组合
+  const updateSpecCombinations = () => {
+    const validSpecs = specNames.value.filter((spec) => spec.name.trim() && spec.values.length > 0);
+
+    if (validSpecs.length === 0) {
+      specCombinations.value = [];
+      emit('update:modelValue', []);
       return;
     }
-    
-    const [first, ...rest] = remaining;
-    first.values.forEach(value => {
-      generate([...current, value], rest);
+
+    // 生成所有可能的组合
+    const combinations = generateCombinations(validSpecs);
+
+    // 保留已有的价格、库存等信息
+    const existingData = new Map();
+    specCombinations.value.forEach((item) => {
+      const key = validSpecs.map((_, index) => item[`spec_${index}`]).join('|');
+      existingData.set(key, {
+        price: item.price,
+        stock: item.stock,
+        weight: item.weight,
+        sku: item.sku,
+      });
+    });
+
+    specCombinations.value = combinations.map((combination) => {
+      const key = combination.join('|');
+      const existing = existingData.get(key) || {};
+
+      const item = {
+        price: existing.price || '',
+        stock: existing.stock || '',
+        weight: existing.weight || '',
+        sku: existing.sku || '',
+      };
+
+      // 添加规格值
+      combination.forEach((value, index) => {
+        item[`spec_${index}`] = value;
+      });
+
+      return item;
     });
+
+    // 发送更新事件
+    emit('update:modelValue', specCombinations.value);
   };
-  
-  generate([], specs);
-  return result;
-};
-
-// 监听外部数据变化
-watch(() => props.modelValue, (newValue) => {
-  if (newValue && newValue.length > 0) {
-    // 从外部数据恢复规格设置
-    // 这里可以根据需要实现数据恢复逻辑
-  }
-}, { immediate: true });
 
-// 监听规格组合变化
-watch(specCombinations, (newValue) => {
-  emit('update:modelValue', newValue);
-}, { deep: true });
+  // 生成规格组合
+  const generateCombinations = (specs) => {
+    if (specs.length === 0) return [];
+    if (specs.length === 1) return specs[0].values.map((v) => [v]);
+
+    const result = [];
+    const generate = (current, remaining) => {
+      if (remaining.length === 0) {
+        result.push([...current]);
+        return;
+      }
+
+      const [first, ...rest] = remaining;
+      first.values.forEach((value) => {
+        generate([...current, value], rest);
+      });
+    };
+
+    generate([], specs);
+    return result;
+  };
+
+  // 监听外部数据变化
+  watch(
+    () => props.modelValue,
+    (newValue) => {
+      if (newValue && newValue.length > 0) {
+        // 从外部数据恢复规格设置
+        // 这里可以根据需要实现数据恢复逻辑
+      }
+    },
+    { immediate: true },
+  );
+
+  // 监听规格组合变化
+  watch(
+    specCombinations,
+    (newValue) => {
+      emit('update:modelValue', newValue);
+    },
+    { deep: true },
+  );
 </script>
 
 <style lang="scss" scoped>
-.goods-spec-editor {
-  .spec-names {
-    margin-bottom: 30px;
-    
-    h4 {
-      margin: 0 0 15px 0;
-      font-size: 16px;
-      font-weight: 500;
-      color: #303133;
-    }
-    
-    .spec-name-item {
-      display: flex;
-      align-items: center;
-      margin-bottom: 10px;
-    }
-  }
-  
-  .spec-values {
-    margin-bottom: 30px;
-    
-    h4 {
-      margin: 0 0 15px 0;
-      font-size: 16px;
-      font-weight: 500;
-      color: #303133;
-    }
-    
-    .spec-value-group {
-      display: flex;
-      align-items: flex-start;
-      margin-bottom: 15px;
-      
-      .spec-value-label {
-        width: 100px;
+  .goods-spec-editor {
+    .spec-names {
+      margin-bottom: 30px;
+
+      h4 {
+        margin: 0 0 15px 0;
+        font-size: 16px;
         font-weight: 500;
-        color: #606266;
-        line-height: 32px;
-        flex-shrink: 0;
+        color: #303133;
       }
-      
-      .spec-value-list {
-        flex: 1;
+
+      .spec-name-item {
         display: flex;
-        flex-wrap: wrap;
         align-items: center;
+        margin-bottom: 10px;
       }
     }
-  }
-  
-  .spec-combinations {
-    h4 {
-      margin: 0 0 15px 0;
-      font-size: 16px;
-      font-weight: 500;
-      color: #303133;
+
+    .spec-values {
+      margin-bottom: 30px;
+
+      h4 {
+        margin: 0 0 15px 0;
+        font-size: 16px;
+        font-weight: 500;
+        color: #303133;
+      }
+
+      .spec-value-group {
+        display: flex;
+        align-items: flex-start;
+        margin-bottom: 15px;
+
+        .spec-value-label {
+          width: 100px;
+          font-weight: 500;
+          color: #606266;
+          line-height: 32px;
+          flex-shrink: 0;
+        }
+
+        .spec-value-list {
+          flex: 1;
+          display: flex;
+          flex-wrap: wrap;
+          align-items: center;
+        }
+      }
+    }
+
+    .spec-combinations {
+      h4 {
+        margin: 0 0 15px 0;
+        font-size: 16px;
+        font-weight: 500;
+        color: #303133;
+      }
     }
   }
-}
 </style>

+ 28 - 11
src/app/shop/admin/order/order/components/status-steps.vue

@@ -13,12 +13,19 @@
       </template>
     </el-step>
     <el-step
-      :title="props.orderDetail.status == 'pending' && props.orderDetail.pay_mode=='offline'?'货到付款':'买家付款'">
+      :title="
+        props.orderDetail.status == 'pending' && props.orderDetail.pay_mode == 'offline'
+          ? '货到付款'
+          : '买家付款'
+      "
+    >
       <template #description>
-          <div>{{ props.orderDetail.status == 'pending' &&
-              props.orderDetail.pay_mode=='offline'?props.orderDetail.ext?.pending_date:props.orderDetail.paid_time
-              }}</div>
-          <div class="step-status">待发货</div>
+        <div>{{
+          props.orderDetail.status == 'pending' && props.orderDetail.pay_mode == 'offline'
+            ? props.orderDetail.ext?.pending_date
+            : props.orderDetail.paid_time
+        }}</div>
+        <div class="step-status">待发货</div>
       </template>
     </el-step>
     <el-step title="商家发货">
@@ -48,12 +55,19 @@
       </template>
     </el-step>
     <el-step
-      :title="props.orderDetail.status == 'pending' && props.orderDetail.pay_mode=='offline'?'货到付款':'买家付款'">
+      :title="
+        props.orderDetail.status == 'pending' && props.orderDetail.pay_mode == 'offline'
+          ? '货到付款'
+          : '买家付款'
+      "
+    >
       <template #description>
-          <div>{{ props.orderDetail.status == 'pending' &&
-              props.orderDetail.pay_mode=='offline'?props.orderDetail.ext?.pending_date:props.orderDetail.paid_time
-              }}</div>
-          <div class="step-status">待发货</div>
+        <div>{{
+          props.orderDetail.status == 'pending' && props.orderDetail.pay_mode == 'offline'
+            ? props.orderDetail.ext?.pending_date
+            : props.orderDetail.paid_time
+        }}</div>
+        <div class="step-status">待发货</div>
       </template>
     </el-step>
     <el-step title="商家发货">
@@ -83,7 +97,10 @@
   function changeOrderStep() {
     if (props.orderDetail.status == 'unpaid') {
       state.orderStep = 1;
-    } else if (props.orderDetail.status == 'paid' || (props.orderDetail.status == 'pending' && props.orderDetail.pay_mode == 'offline')) {
+    } else if (
+      props.orderDetail.status == 'paid' ||
+      (props.orderDetail.status == 'pending' && props.orderDetail.pay_mode == 'offline')
+    ) {
       state.orderStep = 2;
       switch (props.orderDetail.status_code) {
         case 'nosend':

+ 10 - 2
src/assets/css/sa-reset.scss

@@ -37,8 +37,16 @@ figcaption {
   border: none;
   background: none;
   font-weight: normal;
-  font-family: avenir, -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei,
-    Source Han Sans SC, Noto Sans CJK SC, sans-serif;
+  font-family:
+    avenir,
+    -apple-system,
+    BlinkMacSystemFont,
+    Helvetica Neue,
+    PingFang SC,
+    Microsoft YaHei,
+    Source Han Sans SC,
+    Noto Sans CJK SC,
+    sans-serif;
   box-sizing: border-box;
   -webkit-tap-highlight-color: transparent;
   -webkit-font-smoothing: antialiased;

+ 7 - 5
src/assets/css/skins/index.scss

@@ -73,8 +73,9 @@ html:root {
   --el-font-size-base: 14px;
   --el-font-size-small: 13px;
   --el-font-size-extra-small: 12px;
-  --el-font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB',
-    'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
+  --el-font-family:
+    'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑',
+    Arial, sans-serif;
   --el-font-weight-primary: 500;
   --el-font-line-height-primary: 24px;
   --el-index-normal: 1;
@@ -92,8 +93,8 @@ html:root {
     var(--el-transition-function-ease-in-out-bezier);
   --el-transition-fade: opacity var(--el-transition-duration)
     var(--el-transition-function-fast-bezier);
-  --el-transition-md-fade: transform var(--el-transition-duration)
-      var(--el-transition-function-fast-bezier),
+  --el-transition-md-fade:
+    transform var(--el-transition-duration) var(--el-transition-function-fast-bezier),
     opacity var(--el-transition-duration) var(--el-transition-function-fast-bezier);
   --el-transition-fade-linear: opacity var(--el-transition-duration-fast) linear;
   --el-transition-border: border-color var(--el-transition-duration-fast)
@@ -177,7 +178,8 @@ html:root {
   --el-box-shadow: 0 12px 32px 4px rgba(0, 0, 0, 0.04), 0 8px 20px rgba(0, 0, 0, 0.08);
   --el-box-shadow-light: 0 0 12px rgba(0, 0, 0, 0.12);
   --el-box-shadow-lighter: 0 0 6px rgba(0, 0, 0, 0.12);
-  --el-box-shadow-dark: 0 16px 48px 16px rgba(0, 0, 0, 0.08), 0 12px 32px rgba(0, 0, 0, 0.12),
+  --el-box-shadow-dark:
+    0 16px 48px 16px rgba(0, 0, 0, 0.08), 0 12px 32px rgba(0, 0, 0, 0.12),
     0 8px 16px -8px rgba(0, 0, 0, 0.16);
   --el-disabled-bg-color: var(--sa-background-hex-hover);
   --el-disabled-text-color: var(--sa-place);

+ 12 - 8
src/sheep/components/sa-file/components/file-cropper.vue

@@ -5,7 +5,11 @@
         <img ref="cropperRef" :src="checkUrl(modal.params.cropper.url)" />
       </div>
       <div class="wh">
-        <div class="sa-m-b-10">宽:{{ cropperWh.width }} <span class="sa-m-l-4 sa-m-r-4"></span> 高:{{ cropperWh.height }}</div>
+        <div class="sa-m-b-10"
+          >宽:{{ cropperWh.width }} <span class="sa-m-l-4 sa-m-r-4"></span> 高:{{
+            cropperWh.height
+          }}</div
+        >
         <div>
           质量:
           <el-select v-model="imageSmoothingQuality" placeholder="Select">
@@ -39,8 +43,8 @@
 
   const cropperRef = ref(null);
   const saCropper = ref(null);
-  const cropperWh=ref({})
-  const imageSmoothingQuality=ref('low')
+  const cropperWh = ref({});
+  const imageSmoothingQuality = ref('low');
   async function callback() {
     if (props.modal.params.type == 'select') {
       const files = dataURLtoFile(
@@ -82,12 +86,12 @@
       const image = unref(cropperRef);
       saCropper.value = new Cropper(image, {
         viewMode: 1,
-        crop: (e)=> {
-          cropperWh.value={
+        crop: (e) => {
+          cropperWh.value = {
             width: e.detail.width.toFixed(0),
             height: e.detail.height.toFixed(0),
-          }
-        }
+          };
+        },
       });
     });
   });
@@ -102,7 +106,7 @@
       height: 300px;
     }
   }
-  .wh{
+  .wh {
     line-height: 20px;
     margin-top: 10px;
     font-size: 14px;

+ 31 - 26
src/sheep/components/sa-video.vue

@@ -1,54 +1,59 @@
 <template>
-    <video class="sa-video" :src="checkUrl(url)" :width="size" :height="size" @click="previewVisible = true"></video>
-    <el-dialog class="sa-dialog-video sa-dialog" v-model="previewVisible" fullscreen>
-        <video :src="checkUrl(url)" controls></video>
-    </el-dialog>
+  <video
+    class="sa-video"
+    :src="checkUrl(url)"
+    :width="size"
+    :height="size"
+    @click="previewVisible = true"
+  ></video>
+  <el-dialog class="sa-dialog-video sa-dialog" v-model="previewVisible" fullscreen>
+    <video :src="checkUrl(url)" controls></video>
+  </el-dialog>
 </template>
-  
+
 <script>
-export default {
+  export default {
     name: 'SaVideo',
-};
+  };
 </script>
-  
+
 <script setup>
-import { ref } from 'vue';
-import { checkUrl } from '@/sheep/utils/checkUrlSuffix';
+  import { ref } from 'vue';
+  import { checkUrl } from '@/sheep/utils/checkUrlSuffix';
 
-const props = defineProps(['url', 'size',]);
+  const props = defineProps(['url', 'size']);
 
-const previewVisible = ref(false);
+  const previewVisible = ref(false);
 </script>
-  
+
 <style lang="scss" scoped>
-.sa-video {
+  .sa-video {
     cursor: pointer;
-}
+  }
 </style>
 
 <style lang="scss">
-.sa-dialog-video {
+  .sa-dialog-video {
     --el-dialog-bg-color: transparent;
 
     .el-dialog__header {
-        border-bottom: none !important;
+      border-bottom: none !important;
     }
 
     .el-dialog__headerbtn {
-        top: 40px;
-        right: 40px;
-        font-size: 24px;
+      top: 40px;
+      right: 40px;
+      font-size: 24px;
     }
 
     .el-dialog__close {
-        color: #fff !important;
+      color: #fff !important;
     }
 
     .el-dialog__body {
-        display: flex;
-        align-items: center;
-        justify-content: center;
+      display: flex;
+      align-items: center;
+      justify-content: center;
     }
-}
+  }
 </style>
-  

+ 27 - 2
src/sheep/config/api-routing.js

@@ -33,6 +33,10 @@ class ApiRoutingManager {
 
     // 兜底域名
     this.fallbackBaseUrl = import.meta.env.SHEEP_API_FALLBACK_BASE_URL || baseURL;
+
+    // 检查是否启用了代理
+    this.useProxy = import.meta.env.SHEEP_USE_PROXY === 'true';
+    this.proxyTarget = import.meta.env.SHEEP_PROXY_TARGET;
   }
 
   /**
@@ -41,7 +45,23 @@ class ApiRoutingManager {
    * @returns {Object} 处理后的配置
    */
   processRequest(config) {
-    if (!this.enabled) return config;
+    // 添加调试日志
+
+    // 如果启用了代理,直接返回原始配置,让Vite代理处理
+    if (this.useProxy && this.proxyTarget) {
+      // 当使用代理时,baseURL应该为空或者使用相对路径,让Vite代理处理
+      const processedConfig = {
+        ...config,
+        baseURL: '',
+        url: config.url.startsWith('/') ? config.url : '/' + config.url,
+      };
+      return processedConfig;
+    }
+
+    if (!this.enabled) {
+      console.log('API路由系统未启用');
+      return config;
+    }
 
     const originalUrl = config.url;
     let processedUrl = originalUrl;
@@ -83,11 +103,16 @@ class ApiRoutingManager {
       matchedModule = 'common';
     }
 
-    return {
+    const result = {
       ...config,
       url: processedUrl,
       baseURL: targetBaseUrl,
     };
+
+    // 添加调试日志
+    console.log('API路由处理后:', result);
+
+    return result;
   }
 }
 

+ 2 - 4
src/sheep/config/index.js

@@ -11,12 +11,10 @@ switch (import.meta.env.MODE) {
     baseURL = import.meta.env.SHEEP_BASE_URL;
 }
 
-if(baseURL === '/') {
+if (baseURL === '/') {
   baseURL = window.location.origin;
 }
 
 const version = import.meta.env.SHEEP_VERSION;
-console.log(
-  `SheepJS ${version}  https://www.sheepjs.com/`,
-);
+console.log(`SheepJS ${version}  https://www.sheepjs.com/`);
 export { baseURL, version };

+ 10 - 10
src/sheep/mock/data/notification.js

@@ -5,20 +5,20 @@
 // 通知类型数据
 export const notificationTypeData = {
   error: 0,
-  msg: "消息类型",
+  msg: '消息类型',
   data: {
     unread_num: 0,
     notification_type: [
       {
-        label: "系统消息",
-        value: "system",
-        unread_num: 0
+        label: '系统消息',
+        value: 'system',
+        unread_num: 0,
       },
       {
-        label: "商城消息",
-        value: "shop",
-        unread_num: 0
-      }
-    ]
-  }
+        label: '商城消息',
+        value: 'shop',
+        unread_num: 0,
+      },
+    ],
+  },
 };

+ 26 - 23
src/sheep/mock/data/order-detail.js

@@ -9,39 +9,39 @@ export const orderDetailData = {
   status: 'completed',
   status_text: '已完成',
   status_desc: '订单已完成,感谢您的购买',
-  
+
   // 订单轨迹
   status_steps: [
     {
       status: 'created',
       status_text: '提交订单',
       time: '2025/05/06 12:30:00',
-      completed: true
+      completed: true,
     },
     {
       status: 'paid',
       status_text: '付款',
       time: '2025/05/06 12:35:00',
-      completed: true
+      completed: true,
     },
     {
       status: 'shipped',
       status_text: '发货',
       time: '2025/05/06 13:30:00',
-      completed: true
+      completed: true,
     },
     {
       status: 'received',
       status_text: '平台发货',
       time: '2025/05/06 14:30:00',
-      completed: true
+      completed: true,
     },
     {
       status: 'completed',
       status_text: '用户收货',
       time: '2025/05/10 12:30:00',
-      completed: true
-    }
+      completed: true,
+    },
   ],
 
   // 基本信息
@@ -54,14 +54,15 @@ export const orderDetailData = {
   mobile: '88042251008',
   pay_amount: '1,000',
   actual_amount: '1,000',
-  
+
   // 用户信息
   user_id: 1001,
   user: {
     id: 1001,
     nickname: 'Aamer Khan',
     mobile: '88042251008',
-    avatar: 'https://mall-oss.trust-will.com/storage/default/20250701/7bf12c56300454532244dec2aff808eb.jpg?x-oss-process=image/resize,w_200,h_200'
+    avatar:
+      'https://mall-oss.trust-will.com/storage/default/20250701/7bf12c56300454532244dec2aff808eb.jpg?x-oss-process=image/resize,w_200,h_200',
   },
 
   // 商品信息
@@ -70,20 +71,22 @@ export const orderDetailData = {
       id: 1,
       goods_id: 100,
       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_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_num: 1,
-      goods_price: '1,000'
-    }
+      goods_price: '1,000',
+    },
   ],
 
   // 收货信息
   address: {
     consignee: 'Aamer Khan',
     mobile: '88042251008',
-    address: '35/66 The Bliss Koolpunt Ville 15, 1304H-HWB San Kamphaeng, San Kamphaeng District, Chiang Mai 50130',
+    address:
+      '35/66 The Bliss Koolpunt Ville 15, 1304H-HWB San Kamphaeng, San Kamphaeng District, Chiang Mai 50130',
     express_company: 'DHL',
-    express_no: 'DH47058JBM6938'
+    express_no: 'DH47058JBM6938',
   },
 
   // 拼团信息
@@ -96,7 +99,7 @@ export const orderDetailData = {
         order_sn: '2025050612300120',
         join_time: '2025/05/06 12:30:30',
         pay_time: '2025/05/06 12:31:30',
-        commission: '৳10'
+        commission: '৳10',
       },
       {
         nickname: 'ABC-1',
@@ -104,7 +107,7 @@ export const orderDetailData = {
         order_sn: '2025050612300120',
         join_time: '2025/05/06 12:30:30',
         pay_time: '2025/05/06 12:31:30',
-        commission: '৳10'
+        commission: '৳10',
       },
       {
         nickname: 'ABC-1',
@@ -112,7 +115,7 @@ export const orderDetailData = {
         order_sn: '2025050612300120',
         join_time: '2025/06/06 12:30:30',
         pay_time: '2025/06/06 12:31:30',
-        commission: '৳10'
+        commission: '৳10',
       },
       {
         nickname: 'ABC-1',
@@ -120,7 +123,7 @@ export const orderDetailData = {
         order_sn: '2025050612300120',
         join_time: '2025/06/06 12:30:30',
         pay_time: '2025/06/06 12:31:30',
-        commission: '৳10'
+        commission: '৳10',
       },
       {
         nickname: 'ABC-1',
@@ -128,9 +131,9 @@ export const orderDetailData = {
         order_sn: '2025050612300120',
         join_time: '2025/06/06 12:30:30',
         pay_time: '2025/06/06 12:31:30',
-        commission: '৳10'
-      }
-    ]
+        commission: '৳10',
+      },
+    ],
   },
 
   // 时间信息
@@ -144,12 +147,12 @@ export const orderDetailData = {
 
   // 备注
   memo: '',
-  remark: '请尽快发货,谢谢!'
+  remark: '请尽快发货,谢谢!',
 };
 
 // 订单详情响应
 export const orderDetailResponse = {
   error: 0,
   msg: '获取成功',
-  data: orderDetailData
+  data: orderDetailData,
 };

+ 2 - 1
src/sheep/mock/data/profile.js

@@ -18,7 +18,8 @@ export const profileData = {
   create_time: '2025-01-01 00:00:00',
   update_time: '2025-01-15 10:30:00',
   status: 'normal',
-  token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwibmFtZSI6ImFkbWluIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c',
+  token:
+    'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwibmFtZSI6ImFkbWluIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c',
 };
 
 export default profileData;

+ 1 - 1
src/sheep/mock/handlers/notification.js

@@ -9,7 +9,7 @@ export const notificationHandlers = [
   // 获取通知类型接口
   http.get('https://shop.trust-will.com/admin/notification/notificationType', async () => {
     await delay(200);
-    
+
     // 直接返回通知类型数据
     return HttpResponse.json(notificationTypeData);
   }),

+ 6 - 3
src/sheep/request/export.js

@@ -16,7 +16,10 @@ export const EXPORT = async (url, params) => {
 
   if (res.data.type === 'application/octet-stream') {
     const contentType = res.headers['content-type'];
-    const filename = contentType.substring(contentType.lastIndexOf('name=') + 5, contentType.length);
+    const filename = contentType.substring(
+      contentType.lastIndexOf('name=') + 5,
+      contentType.length,
+    );
 
     const downloadurl = window.URL.createObjectURL(new Blob([res.data]));
     const link = document.createElement('a');
@@ -29,7 +32,7 @@ export const EXPORT = async (url, params) => {
     reader.onload = () => {
       const msg = JSON.parse(reader.result).msg;
       ElMessage.error(msg || '操作失败');
-    }
-    reader.readAsText(res.data)
+    };
+    reader.readAsText(res.data);
   }
 };

+ 5 - 2
src/sheep/utils/checkUrlSuffix.js

@@ -34,14 +34,17 @@ function suffix(type, params) {
   if (width && height) {
     size = width + 'x' + height;
   }
-   
+
   switch (type) {
     case 'aliyun':
       // 裁剪
       if (!isEmpty(gravity) && gravity != 'center') {
         // 指定了裁剪区域
         mode = 'mfit';
-        crop_str = '/crop,g_' + gravityFormat(type, gravity) + `${width && height ? ',w_' + width + ',h_' + height : ''}`;
+        crop_str =
+          '/crop,g_' +
+          gravityFormat(type, gravity) +
+          `${width && height ? ',w_' + width + ',h_' + height : ''}`;
       }
 
       // 质量压缩

+ 13 - 11
vite.config.js

@@ -45,16 +45,18 @@ export default (command, mode) => {
       hmr: {
         overlay: true,
       },
-      // proxy: {
-      //   '/mall': {
-      //     target: 'http://192.168.0.100:8101/',
-      //     changeOrigin: true,
-      //   },
-      //   '/operating': {
-      //     target: 'http://192.168.0.100:8301/',
-      //     changeOrigin: true,
-      //   },
-      // },
+      // 动态代理配置
+      proxy:
+        env.SHEEP_USE_PROXY === 'true'
+          ? {
+              // 代理所有 API 请求
+              '^/.*': {
+                target: env.SHEEP_PROXY_TARGET,
+                changeOrigin: true,
+                secure: false,
+              },
+            }
+          : {},
     },
     build: {
       chunkSizeWarningLimit: 2000,
@@ -64,4 +66,4 @@ export default (command, mode) => {
       port: env.SHEEP_PREVIEW_PORT,
     },
   };
-};
+};