叶静 пре 1 месец
родитељ
комит
d9519d3c40

+ 24 - 0
.promptx/memory/vue3-expert/declarative.dpml

@@ -75,4 +75,28 @@
     </content>
     <tags>#其他</tags>
   </item>
+  <item id="mem_1756276312350_spzec5ck3" time="2025/08/27 14:31">
+    <content>
+      订单列表tab切换重复请求问题的解决方案:1. 移除URL同步机制,使用纯本地状态管理;2. 简化handleTabChange逻辑,直接更新状态并调用getData;3. 优化状态参数处理,全部状态时使用null不传递status参数;4. 移除watch监听和复杂的初始化逻辑。这种方式避免了URL变化和tab切换同时触发请求的问题。
+    </content>
+    <tags>#其他</tags>
+  </item>
+  <item id="mem_1756283767277_6971lbbb0" time="2025/08/27 16:36">
+    <content>
+      语言包重复对象定义问题:当JSON语言包中存在重复的对象键时,后面的定义会覆盖前面的定义,导致翻译丢失。解决方案是合并重复的对象,确保所有翻译键都在同一个对象中。这是Vue i18n项目中常见的配置问题。
+    </content>
+    <tags>#其他</tags>
+  </item>
+  <item id="mem_1756283798220_wxz06drnu" time="2025/08/27 16:36">
+    <content>
+      项目开发环境支持热更新(HMR),一般情况下修改代码、样式、语言包等文件后不需要重启开发服务器,Vite会自动检测文件变化并进行热更新。只有在修改配置文件(如vite.config.js、package.json等)或遇到特殊情况时才需要重启服务器。开发时应该依赖热更新功能提高开发效率。
+    </content>
+    <tags>#其他</tags>
+  </item>
+  <item id="mem_1756285264035_ks4xu9edk" time="2025/08/27 17:01">
+    <content>
+      全局硬编码消息国际化替换:将项目中所有硬编码的ElMessage提示(如&#x27;保存成功&#x27;、&#x27;删除成功&#x27;等)替换为国际化函数调用t(&#x27;message.saveSuccess&#x27;)。这包括:1. 识别所有硬编码中文提示;2. 在语言包中添加对应翻译;3. 使用t()函数替换硬编码字符串;4. 确保中英文翻译完整。这是Vue i18n项目国际化的重要步骤。
+    </content>
+    <tags>#流程管理</tags>
+  </item>
 </memory>

+ 45 - 1
.promptx/pouch.json

@@ -36,7 +36,51 @@
         "--tags",
         "开发规范 测试策略 用户偏好"
       ]
+    },
+    {
+      "from": "memory_saved",
+      "command": "remember",
+      "timestamp": "2025-08-27T06:31:52.347Z",
+      "args": [
+        "vue3-expert",
+        "订单列表tab切换重复请求问题的解决方案:1. 移除URL同步机制,使用纯本地状态管理;2. 简化handleTabChange逻辑,直接更新状态并调用getData;3. 优化状态参数处理,全部状态时使用null不传递status参数;4. 移除watch监听和复杂的初始化逻辑。这种方式避免了URL变化和tab切换同时触发请求的问题。",
+        "--tags",
+        "性能优化 重复请求 状态管理"
+      ]
+    },
+    {
+      "from": "memory_saved",
+      "command": "remember",
+      "timestamp": "2025-08-27T08:36:07.267Z",
+      "args": [
+        "vue3-expert",
+        "语言包重复对象定义问题:当JSON语言包中存在重复的对象键时,后面的定义会覆盖前面的定义,导致翻译丢失。解决方案是合并重复的对象,确保所有翻译键都在同一个对象中。这是Vue i18n项目中常见的配置问题。",
+        "--tags",
+        "国际化 语言包 JSON配置"
+      ]
+    },
+    {
+      "from": "memory_saved",
+      "command": "remember",
+      "timestamp": "2025-08-27T08:36:38.213Z",
+      "args": [
+        "vue3-expert",
+        "项目开发环境支持热更新(HMR),一般情况下修改代码、样式、语言包等文件后不需要重启开发服务器,Vite会自动检测文件变化并进行热更新。只有在修改配置文件(如vite.config.js、package.json等)或遇到特殊情况时才需要重启服务器。开发时应该依赖热更新功能提高开发效率。",
+        "--tags",
+        "开发环境 热更新 HMR Vite"
+      ]
+    },
+    {
+      "from": "memory_saved",
+      "command": "remember",
+      "timestamp": "2025-08-27T09:01:04.033Z",
+      "args": [
+        "vue3-expert",
+        "全局硬编码消息国际化替换:将项目中所有硬编码的ElMessage提示(如'保存成功'、'删除成功'等)替换为国际化函数调用t('message.saveSuccess')。这包括:1. 识别所有硬编码中文提示;2. 在语言包中添加对应翻译;3. 使用t()函数替换硬编码字符串;4. 确保中英文翻译完整。这是Vue i18n项目国际化的重要步骤。",
+        "--tags",
+        "国际化 ElMessage 硬编码替换"
+      ]
     }
   ],
-  "lastUpdated": "2025-08-27T06:06:21.921Z"
+  "lastUpdated": "2025-08-27T09:01:04.045Z"
 }

+ 1 - 1
src/app/admin/views/auth/role/index.vue

@@ -72,7 +72,7 @@ async function getData(page, searchParams = {}) {
 
   try {
     const { code, data } = await admin.auth.role.roleList({
-      page: 0,
+      page: pageData.page,
       size: pageData.size,
       ...searchParams,
     });

+ 1 - 1
src/app/admin/views/payment/edit.vue

@@ -106,7 +106,7 @@ async function confirm() {
         : await api.payment.channel.update(submitForm);
 
     if (code == 200) {
-      ElMessage.success('保存成功');
+      ElMessage.success(t('message.saveSuccess'));
       emit('modalCallBack', { event: 'confirm' });
     }
   });

+ 2 - 0
src/app/shop/admin/content/notification/edit.vue

@@ -26,6 +26,7 @@
 import { cloneDeep } from 'lodash';
 import { onMounted, reactive, ref, unref } from 'vue';
 import { useI18n } from 'vue-i18n';
+import { ElMessage } from 'element-plus';
 import { useFormConfig } from '@/hooks/useFormConfig';
 import { api } from '../content.service';
 
@@ -77,6 +78,7 @@ async function confirm() {
           ? await api.notification.add(submitForm)
           : await api.notification.edit(props.modal.params.id, submitForm);
       if (code == 200) {
+        ElMessage.success(t('message.saveSuccess'));
         emit('modalCallBack', { event: 'confirm' });
       }
     } catch (error) {

+ 0 - 1
src/app/shop/admin/content/notification/index.vue

@@ -199,7 +199,6 @@ async function deleteApi(id) {
   try {
     const { code } = await api.notification.delete(id);
     if (code == 200) {
-      ElMessage.success(t('modules.notification.deleteSuccess'));
       getData();
     }
   } catch (error) {

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

@@ -10,12 +10,7 @@
       <div class="search-form">
         <el-form :inline="true" :model="searchForm">
           <el-form-item label="快递公司">
-            <el-input
-              v-model="searchForm.name"
-              placeholder="请输入快递公司名称"
-              clearable
-              style="width: 200px"
-            />
+            <el-input v-model="searchForm.name" placeholder="请输入快递公司名称" clearable style="width: 200px" />
           </el-form-item>
           <el-form-item>
             <el-button type="primary" @click="handleSearch">搜索</el-button>
@@ -43,112 +38,106 @@
       </el-table>
 
       <div class="pagination">
-        <el-pagination
-          v-model:current-page="pagination.page"
-          v-model:page-size="pagination.pageSize"
-          :page-sizes="[10, 20, 50, 100]"
-          :total="pagination.total"
-          layout="total, sizes, prev, pager, next, jumper"
-          @size-change="handleSizeChange"
-          @current-change="handleCurrentChange"
-        />
+        <el-pagination v-model:current-page="pagination.page" v-model:page-size="pagination.pageSize"
+          :page-sizes="[10, 20, 50, 100]" :total="pagination.total" layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange" @current-change="handleCurrentChange" />
       </div>
     </el-card>
   </div>
 </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 = () => {
+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 {
     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 {
-      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();
+  }
+  pagination.total = tableData.value.length;
+};
+
+// 重置
+const handleReset = () => {
+  searchForm.name = '';
+  initData();
+};
+
+// 编辑
+const handleEdit = (row) => {
+  ElMessage.info(t('message.editFeatureNotDeveloped'));
+};
+
+// 删除
+const handleDelete = (row) => {
+  ElMessageBox.confirm('确定要删除这个快递公司吗?', '提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning',
+  }).then(() => {
+    ElMessage.success(t('message.deleteSuccess'));
   });
+};
+
+// 分页大小改变
+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>

+ 2 - 0
src/app/shop/admin/goods/category/edit.vue

@@ -24,6 +24,7 @@
 import { cloneDeep } from 'lodash';
 import { onMounted, reactive, ref, unref } from 'vue';
 import { useI18n } from 'vue-i18n';
+import { ElMessage } from 'element-plus';
 import { useFormConfig } from '@/hooks/useFormConfig';
 import { api } from '../goods.service';
 
@@ -69,6 +70,7 @@ async function confirm() {
         ? await api.category.add(submitForm)
         : await api.category.edit(submitForm);
     if (code == '200') {
+      ElMessage.success(t('message.saveSuccess'));
       emit('modalCallBack', { event: 'confirm' });
     }
   });

+ 744 - 866
src/app/shop/admin/goods/goods/tab-edit.vue

@@ -1,11 +1,7 @@
 <template>
   <el-container>
     <el-header>
-      <el-tabs
-        class="sa-tabs bg-#fff sa-m-t-10 z-999"
-        v-model="activeTab"
-        @tab-change="handleTabChange"
-      >
+      <el-tabs class="sa-tabs bg-#fff sa-m-t-10 z-999" v-model="activeTab" @tab-change="handleTabChange">
         <el-tab-pane name="basic">
           <template #label>
             <div class="sa-flex" :class="basicFormErrors ? 'is-error' : ''">
@@ -44,37 +40,19 @@
             <!-- 左侧表单 -->
             <el-col :span="14">
               <el-form-item label="商品分类" prop="cateId" required>
-                <el-select
-                  v-model="basicFormData.cateId"
-                  placeholder="请选择商品分类"
-                  clearable
-                  style="width: 100%"
-                >
-                  <el-option
-                    v-for="category in categoryOptions"
-                    :key="category.id"
-                    :label="category.name"
-                    :value="category.id"
-                  />
+                <el-select v-model="basicFormData.cateId" placeholder="请选择商品分类" clearable style="width: 100%">
+                  <el-option v-for="category in categoryOptions" :key="category.id" :label="category.name"
+                    :value="category.id" />
                 </el-select>
               </el-form-item>
 
               <el-form-item label="商品名称" prop="storeName" required>
-                <el-input
-                  v-model="basicFormData.storeName"
-                  placeholder="请填写商品名称(限100字符)"
-                  maxlength="100"
-                  show-word-limit
-                />
+                <el-input v-model="basicFormData.storeName" placeholder="请填写商品名称(限100字符)" maxlength="100"
+                  show-word-limit />
               </el-form-item>
 
               <el-form-item label="副标题" prop="keyword">
-                <el-input
-                  v-model="basicFormData.keyword"
-                  placeholder="请填写副标题(限50字符)"
-                  maxlength="50"
-                  show-word-limit
-                />
+                <el-input v-model="basicFormData.keyword" placeholder="请填写副标题(限50字符)" maxlength="50" show-word-limit />
               </el-form-item>
 
               <el-form-item label="商品品牌" prop="itemBrand" required>
@@ -82,14 +60,8 @@
               </el-form-item>
 
               <el-form-item label="商品介绍" prop="storeInfo">
-                <el-input
-                  v-model="basicFormData.storeInfo"
-                  type="textarea"
-                  :rows="4"
-                  placeholder="请填写商品介绍(限500字符)"
-                  maxlength="500"
-                  show-word-limit
-                />
+                <el-input v-model="basicFormData.storeInfo" type="textarea" :rows="4" placeholder="请填写商品介绍(限500字符)"
+                  maxlength="500" show-word-limit />
               </el-form-item>
 
               <el-form-item label="运费模板" prop="tempId">
@@ -98,9 +70,7 @@
 
               <el-form-item label="商品货号" prop="itemNumber" required>
                 <el-input v-model="basicFormData.itemNumber" placeholder="请填写商品货号" />
-                <div class="form-tip ml-10px"
-                  >如果您不输入商品货号,系统将自动生成一个唯一的货号</div
-                >
+                <div class="form-tip ml-10px">如果您不输入商品货号,系统将自动生成一个唯一的货号</div>
               </el-form-item>
 
               <el-form-item label="商品售价" prop="price" required>
@@ -124,24 +94,12 @@
               </el-form-item>
 
               <el-form-item label="商品库存" prop="stock" required>
-                <el-input
-                  v-model="basicFormData.stock"
-                  placeholder="请输入商品库存"
-                  type="number"
-                  min="0"
-                />
-                <div class="form-tip ml-10px"
-                  >该设置只对单品有效,当商品存在多规格货品时为不可编辑状态,库存数值取决于货品数量</div
-                >
+                <el-input v-model="basicFormData.stock" placeholder="请输入商品库存" type="number" min="0" />
+                <div class="form-tip ml-10px">该设置只对单品有效,当商品存在多规格货品时为不可编辑状态,库存数值取决于货品数量</div>
               </el-form-item>
 
               <el-form-item label="库存预警值" prop="stockThreshold">
-                <el-input
-                  v-model="basicFormData.stockThreshold"
-                  placeholder="请输入库存预警值"
-                  type="number"
-                  min="0"
-                />
+                <el-input v-model="basicFormData.stockThreshold" placeholder="请输入库存预警值" type="number" min="0" />
               </el-form-item>
 
               <el-form-item label="商品状态" prop="isShow" required>
@@ -159,41 +117,20 @@
             <!-- 右侧图片上传 -->
             <el-col :span="10">
               <el-form-item label="商品主图" prop="image" required>
-                <sa-upload-image
-                  v-model="basicFormData.image"
-                  :max-count="5"
-                  :accept="['jpg', 'jpeg', 'png']"
-                  :max-size="5"
-                  :direct-upload="true"
-                  :size="100"
-                  placeholder="上传商品主图"
-                />
+                <sa-upload-image v-model="basicFormData.image" :max-count="5" :accept="['jpg', 'jpeg', 'png']"
+                  :max-size="5" :direct-upload="true" :size="100" placeholder="上传商品主图" />
                 <div class="form-tip">作用于商城列表、分享图片;建议尺寸:750*750 px</div>
               </el-form-item>
 
               <el-form-item label="轮播图" prop="sliderImage">
-                <sa-upload-image
-                  v-model="basicFormData.sliderImage"
-                  :max-count="5"
-                  :accept="['jpg', 'jpeg', 'png']"
-                  :max-size="5"
-                  :direct-upload="true"
-                  :size="100"
-                  placeholder="上传轮播图"
-                />
+                <sa-upload-image v-model="basicFormData.sliderImage" :max-count="5" :accept="['jpg', 'jpeg', 'png']"
+                  :max-size="5" :direct-upload="true" :size="100" placeholder="上传轮播图" />
                 <div class="form-tip">作用于商品详情顶部轮播显示,轮播图可以拖拽调整顺序</div>
               </el-form-item>
 
               <el-form-item label="详情图" prop="flatPattern" required>
-                <sa-upload-image
-                  v-model="basicFormData.flatPattern"
-                  :max-count="10"
-                  :accept="['jpg', 'jpeg', 'png']"
-                  :max-size="5"
-                  :direct-upload="true"
-                  :size="100"
-                  placeholder="上传详情图"
-                />
+                <sa-upload-image v-model="basicFormData.flatPattern" :max-count="10" :accept="['jpg', 'jpeg', 'png']"
+                  :max-size="5" :direct-upload="true" :size="100" placeholder="上传详情图" />
                 <div class="form-tip">详情图片,用于商品详情页展示</div>
               </el-form-item>
             </el-col>
@@ -212,12 +149,7 @@
 
         <!-- 有商品ID时显示属性表单 -->
         <div>
-          <el-form
-            ref="attributesFormRef"
-            :model="attributesFormData"
-            :rules="attributesRules"
-            label-width="120px"
-          >
+          <el-form ref="attributesFormRef" :model="attributesFormData" :rules="attributesRules" label-width="120px">
             <!-- 多规格设置 -->
             <el-card class="spec-card">
               <template #header>
@@ -232,12 +164,8 @@
                   <div class="sku-key sa-flex sa-row-between">
                     <div class="sa-flex">
                       <div class="sa-m-r-16">规格名称</div>
-                      <el-input
-                        v-model="s.name"
-                        placeholder="请输入规格名称"
-                        class="sku-key-input"
-                        @input="buildSkuPriceTable"
-                      ></el-input>
+                      <el-input v-model="s.name" placeholder="请输入规格名称" class="sku-key-input"
+                        @input="buildSkuPriceTable"></el-input>
                     </div>
                     <el-icon @click="deleteMainSku(k)" class="sku-key-icon">
                       <CircleCloseFilled />
@@ -246,20 +174,13 @@
                   <div class="sku-value sa-flex sa-flex-wrap">
                     <div class="sku-value-title sa-m-r-16 sa-m-b-16 sa-flex"> 规格值 </div>
                     <div v-for="(sc, c) in s.children" :key="c" class="sku-value-box sa-m-b-16">
-                      <el-input
-                        v-model="sc.name"
-                        placeholder="请输入规格值"
-                        class="sku-value-input"
-                        @input="buildSkuPriceTable"
-                      ></el-input>
+                      <el-input v-model="sc.name" placeholder="请输入规格值" class="sku-value-input"
+                        @input="buildSkuPriceTable"></el-input>
                       <el-icon @click="deleteChildrenSku(k, c)" class="sku-value-icon">
                         <CircleCloseFilled />
                       </el-icon>
                     </div>
-                    <div
-                      @click="addChildrenSku(k)"
-                      class="sku-value-add sa-m-r-24 sa-m-b-16 sa-flex cursor-pointer"
-                    >
+                    <div @click="addChildrenSku(k)" class="sku-value-add sa-m-r-24 sa-m-b-16 sa-flex cursor-pointer">
                       添加规格值
                     </div>
                   </div>
@@ -272,24 +193,11 @@
               <!-- 批量设置 -->
               <div class="sa-m-t-20" v-if="attributesFormData.sku_prices.length > 0">
                 <el-form-item label="批量设置" label-width="80px">
-                  <div
-                    class="sku sa-m-r-20"
-                    v-for="(item, index) in attributesFormData.skus"
-                    :key="index"
-                  >
-                    <el-select
-                      v-model="item.batchId"
-                      placeholder="请选择规格"
-                      class="sa-w-150"
-                      clearable
-                    >
+                  <div class="sku sa-m-r-20" v-for="(item, index) in attributesFormData.skus" :key="index">
+                    <el-select v-model="item.batchId" placeholder="请选择规格" class="sa-w-150" clearable>
                       <template v-for="(citem, cindex) in item.children">
-                        <el-option
-                          :key="cindex"
-                          :label="citem.name"
-                          :value="citem.temp_id"
-                          v-if="citem.temp_id && citem.name"
-                        ></el-option>
+                        <el-option :key="cindex" :label="citem.name" :value="citem.temp_id"
+                          v-if="citem.temp_id && citem.name"></el-option>
                       </template>
                     </el-select>
                   </div>
@@ -298,35 +206,22 @@
                   </div>
                 </el-form-item>
                 <div class="sa-flex sa-flex-wrap">
-                  <el-select
-                    v-model="allEditObj.price"
-                    placeholder="请选择售价(৳)"
-                    class="sa-w-200 sa-m-r-10 sa-m-b-10"
-                    clearable
-                  >
+                  <el-select v-model="allEditObj.price" placeholder="请选择售价(৳)" class="sa-w-200 sa-m-r-10 sa-m-b-10"
+                    clearable>
                     <el-option :value="300" label="300৳" />
                     <el-option :value="500" label="500৳" />
                     <el-option :value="1000" label="1000৳" />
                     <el-option :value="2000" label="2000৳" />
                     <el-option :value="3000" label="3000৳" />
                   </el-select>
-                  <el-input
-                    v-model="allEditObj.stock"
-                    placeholder="请输入库存(件)"
-                    class="sa-w-200 sa-m-r-10 sa-m-b-10"
-                  >
+                  <el-input v-model="allEditObj.stock" placeholder="请输入库存(件)" class="sa-w-200 sa-m-r-10 sa-m-b-10">
                     <template #prepend>库存(件)</template>
                   </el-input>
-                  <el-input
-                    v-model="allEditObj.stock_warning"
-                    placeholder="请输入库存预警值(件)"
-                    class="sa-w-200 sa-m-r-10 sa-m-b-10"
-                  >
+                  <el-input v-model="allEditObj.stock_warning" placeholder="请输入库存预警值(件)"
+                    class="sa-w-200 sa-m-r-10 sa-m-b-10">
                     <template #prepend>库存预警值(件)</template>
                   </el-input>
-                  <el-button type="primary" @click="batchEdit" class="sa-m-b-10"
-                    >批量设置</el-button
-                  >
+                  <el-button type="primary" @click="batchEdit" class="sa-m-b-10">批量设置</el-button>
                 </div>
               </div>
 
@@ -354,25 +249,13 @@
                         </td>
                       </template>
                       <td class="image">
-                        <sa-upload-image
-                          v-model="item.imageList"
-                          :max-count="1"
-                          :accept="['jpg', 'jpeg', 'png']"
-                          :max-size="5"
-                          :direct-upload="true"
-                          :size="30"
-                          :show-tip="false"
-                          :compact="true"
-                          placeholder=""
-                        />
+                        <sa-upload-image v-model="item.imageList" :max-count="1" :accept="['jpg', 'jpeg', 'png']"
+                          :max-size="5" :direct-upload="true" :size="30" :show-tip="false" :compact="true"
+                          placeholder="" />
                       </td>
                       <td>
-                        <el-select
-                          v-model="item.price"
-                          placeholder="选择价格"
-                          size="small"
-                          :class="{ 'is-error': !item.price || item.price <= 0 }"
-                        >
+                        <el-select v-model="item.price" placeholder="选择价格" size="small"
+                          :class="{ 'is-error': !item.price || item.price <= 0 }">
                           <el-option :value="300" label="300" />
                           <el-option :value="500" label="500" />
                           <el-option :value="1000" label="1000" />
@@ -381,37 +264,18 @@
                         </el-select>
                       </td>
                       <td class="stock">
-                        <el-input
-                          v-model="item.stock"
-                          placeholder="请输入库存"
-                          size="small"
-                          type="number"
-                          :step="1"
-                          :min="0"
-                          :class="{ 'is-error': !item.stock || item.stock < 0 }"
-                        ></el-input>
+                        <el-input v-model="item.stock" placeholder="请输入库存" size="small" type="number" :step="1" :min="0"
+                          :class="{ 'is-error': !item.stock || item.stock < 0 }"></el-input>
                       </td>
                       <td class="stock_warning">
-                        <el-input
-                          v-model="item.stock_warning"
-                          placeholder="请输入预警值"
-                          size="small"
-                          type="number"
-                          :step="1"
-                          :min="0"
-                        ></el-input>
+                        <el-input v-model="item.stock_warning" placeholder="请输入预警值" size="small" type="number" :step="1"
+                          :min="0"></el-input>
                       </td>
                       <td class="sn">
-                        <el-input
-                          v-model="item.sn"
-                          placeholder="请输入SKU编码"
-                          size="small"
-                        ></el-input>
+                        <el-input v-model="item.sn" placeholder="请输入SKU编码" size="small"></el-input>
                       </td>
                       <td>
-                        <el-button type="danger" size="small" text @click="deleteSkuPrice(i)"
-                          >删除</el-button
-                        >
+                        <el-button type="danger" size="small" text @click="deleteSkuPrice(i)">删除</el-button>
                       </td>
                     </tr>
                   </tbody>
@@ -436,12 +300,7 @@
 
       <!-- 商品属性Tab的按钮 -->
       <template v-else-if="activeTab === 'attributes'">
-        <el-button
-          type="primary"
-          @click="saveAttributes"
-          :loading="savingStates.attributes"
-          size="large"
-        >
+        <el-button type="primary" @click="saveAttributes" :loading="savingStates.attributes" size="large">
           保存商品属性
         </el-button>
       </template>
@@ -455,780 +314,799 @@
 </template>
 
 <script setup>
-  import { onMounted, reactive, ref, computed, nextTick } from 'vue';
-  import { WarningFilled, CircleCheckFilled, CircleCloseFilled } from '@element-plus/icons-vue';
-  import { api } from '../goods.service';
-  const emit = defineEmits(['modalCallBack']);
-  const props = defineProps({
-    modal: {
-      type: Object,
-      required: true,
+import { onMounted, reactive, ref, computed, nextTick } from 'vue';
+import { WarningFilled, CircleCheckFilled, CircleCloseFilled } from '@element-plus/icons-vue';
+import { api } from '../goods.service';
+const emit = defineEmits(['modalCallBack']);
+const props = defineProps({
+  modal: {
+    type: Object,
+    required: true,
+  },
+});
+
+// 从modal参数中获取类型和ID
+const type = computed(() => props.modal?.params?.type || 'add');
+const goodsIdFromProps = computed(() => props.modal?.params?.id || null);
+
+// 响应式数据
+const activeTab = ref('basic');
+const goodsId = ref(goodsIdFromProps.value);
+const isEdit = computed(() => type.value === 'edit');
+
+// 保存状态
+const savingStates = reactive({
+  basic: false,
+  attributes: false,
+  all: false,
+});
+
+// 保存成功状态
+const basicSaved = ref(false);
+const attributesSaved = ref(false);
+
+// 表单错误状态
+const basicFormErrors = ref(false);
+const attributesFormErrors = ref(false);
+
+// 表单引用
+const basicFormRef = ref(null);
+const attributesFormRef = ref(null);
+
+// 分类选项
+const categoryOptions = ref([]);
+
+// 基本信息表单数据
+const basicFormData = reactive({
+  id: '',
+  cateId: '',
+  storeName: '',
+  keyword: '',
+  itemBrand: '',
+  storeInfo: '',
+  tempId: 1,
+  itemNumber: '',
+  price: '',
+  otPrice: '',
+  stock: '',
+  stockThreshold: '',
+  isShow: 1,
+  itemSupplier: '',
+  sort: 0,
+  isHot: 0,
+  isNew: 0,
+  isBest: 0,
+  isGood: 0,
+  isBenefit: 0,
+  isPostage: 1,
+  cost: '',
+  vipPrice: '',
+  image: [],
+  sliderImage: [],
+  flatPattern: [],
+});
+
+// 商品属性表单数据
+const attributesFormData = reactive({
+  specType: 1, // 规格 0单 1多,默认多规格
+  skus: [
+    {
+      id: 0,
+      temp_id: 1,
+      name: '',
+      batchId: '',
+      pid: 0,
+      children: [],
     },
-  });
-
-  // 从modal参数中获取类型和ID
-  const type = computed(() => props.modal?.params?.type || 'add');
-  const goodsIdFromProps = computed(() => props.modal?.params?.id || null);
-
-  // 响应式数据
-  const activeTab = ref('basic');
-  const goodsId = ref(goodsIdFromProps.value);
-  const isEdit = computed(() => type.value === 'edit');
-
-  // 保存状态
-  const savingStates = reactive({
-    basic: false,
-    attributes: false,
-    all: false,
-  });
-
-  // 保存成功状态
-  const basicSaved = ref(false);
-  const attributesSaved = ref(false);
-
-  // 表单错误状态
-  const basicFormErrors = ref(false);
-  const attributesFormErrors = ref(false);
-
-  // 表单引用
-  const basicFormRef = ref(null);
-  const attributesFormRef = ref(null);
-
-  // 分类选项
-  const categoryOptions = ref([]);
-
-  // 基本信息表单数据
-  const basicFormData = reactive({
-    id: '',
-    cateId: '',
-    storeName: '',
-    keyword: '',
-    itemBrand: '',
-    storeInfo: '',
-    tempId: 1,
-    itemNumber: '',
-    price: '',
-    otPrice: '',
-    stock: '',
-    stockThreshold: '',
-    isShow: 1,
-    itemSupplier: '',
-    sort: 0,
-    isHot: 0,
-    isNew: 0,
-    isBest: 0,
-    isGood: 0,
-    isBenefit: 0,
-    isPostage: 1,
-    cost: '',
-    vipPrice: '',
-    image: [],
-    sliderImage: [],
-    flatPattern: [],
-  });
-
-  // 商品属性表单数据
-  const attributesFormData = reactive({
-    specType: 1, // 规格 0单 1多,默认多规格
-    skus: [
-      {
-        id: 0,
-        temp_id: 1,
-        name: '',
-        batchId: '',
-        pid: 0,
-        children: [],
-      },
-    ],
-    sku_prices: [],
-  });
+  ],
+  sku_prices: [],
+});
+
+// 基本信息验证规则
+const basicRules = {
+  cateId: [{ required: true, message: '请选择商品分类', trigger: 'change' }],
+  storeName: [{ required: true, message: '请填写商品名称', trigger: 'blur' }],
+  itemBrand: [{ required: true, message: '请填写商品品牌', trigger: 'blur' }],
+  itemNumber: [{ required: true, message: '请填写商品货号', trigger: 'blur' }],
+  price: [{ required: true, message: '请填写商品售价', trigger: 'blur' }],
+  stock: [{ required: true, message: '请填写商品库存', trigger: 'blur' }],
+  isShow: [{ required: true, message: '请选择商品状态', trigger: 'change' }],
+  itemSupplier: [{ required: true, message: '请填写商品供应商', trigger: 'blur' }],
+  image: [{ required: true, message: '请上传商品主图', trigger: 'change' }],
+  flatPattern: [{ required: true, message: '请上传商品详情图', trigger: 'change' }],
+};
+
+// 商品属性验证规则
+const attributesRules = {
+  specType: [{ required: true, message: '请选择规格类型', trigger: 'change' }],
+};
+
+// 图片数组转换为逗号分隔字符串的函数
+const convertImagesToString = (imageArray) => {
+  return Array.isArray(imageArray) ? imageArray.join(',') : '';
+};
+
+// 图片字符串转换为数组的函数
+const convertStringToImages = (imageString) => {
+  if (!imageString) return [];
+  return imageString.split(',').filter((img) => img.trim());
+};
+
+// Tab切换处理
+const handleTabChange = (tabName) => {
+  if (tabName === 'attributes' && !goodsId.value && !isEdit.value) {
+    nextTick(() => {
+      ElMessage.info('提示:保存商品属性需要先保存基本信息');
+    });
+  }
+};
 
-  // 基本信息验证规则
-  const basicRules = {
-    cateId: [{ required: true, message: '请选择商品分类', trigger: 'change' }],
-    storeName: [{ required: true, message: '请填写商品名称', trigger: 'blur' }],
-    itemBrand: [{ required: true, message: '请填写商品品牌', trigger: 'blur' }],
-    itemNumber: [{ required: true, message: '请填写商品货号', trigger: 'blur' }],
-    price: [{ required: true, message: '请填写商品售价', trigger: 'blur' }],
-    stock: [{ required: true, message: '请填写商品库存', trigger: 'blur' }],
-    isShow: [{ required: true, message: '请选择商品状态', trigger: 'change' }],
-    itemSupplier: [{ required: true, message: '请填写商品供应商', trigger: 'blur' }],
-    image: [{ required: true, message: '请上传商品主图', trigger: 'change' }],
-    flatPattern: [{ required: true, message: '请上传商品详情图', trigger: 'change' }],
-  };
+// 保存基本信息
+const saveBasicInfo = async () => {
+  savingStates.basic = true;
+  basicFormErrors.value = false;
 
-  // 商品属性验证规则
-  const attributesRules = {
-    specType: [{ required: true, message: '请选择规格类型', trigger: 'change' }],
-  };
+  const valid = await basicFormRef.value?.validate().catch(() => false);
+  if (!valid) {
+    basicFormErrors.value = true;
+    savingStates.basic = false;
+    return false;
+  }
 
-  // 图片数组转换为逗号分隔字符串的函数
-  const convertImagesToString = (imageArray) => {
-    return Array.isArray(imageArray) ? imageArray.join(',') : '';
+  const submitData = {
+    ...basicFormData,
+    image: convertImagesToString(basicFormData.image),
+    sliderImage: convertImagesToString(basicFormData.sliderImage),
+    flatPattern: convertImagesToString(basicFormData.flatPattern),
   };
 
-  // 图片字符串转换为数组的函数
-  const convertStringToImages = (imageString) => {
-    if (!imageString) return [];
-    return imageString.split(',').filter((img) => img.trim());
-  };
+  const { code, data } = isEdit.value
+    ? await api.goods.edit(goodsId.value, submitData)
+    : await api.goods.add(submitData);
 
-  // Tab切换处理
-  const handleTabChange = (tabName) => {
-    if (tabName === 'attributes' && !goodsId.value && !isEdit.value) {
-      nextTick(() => {
-        ElMessage.info('提示:保存商品属性需要先保存基本信息');
-      });
+  if (code === '200') {
+    if (!isEdit.value) {
+      goodsId.value = data.id;
+      basicFormData.id = data.id;
     }
-  };
+    basicSaved.value = true;
+    savingStates.basic = false;
+    return true;
+  }
 
-  // 保存基本信息
-  const saveBasicInfo = async () => {
-    savingStates.basic = true;
-    basicFormErrors.value = false;
+  basicFormErrors.value = true;
+  savingStates.basic = false;
+  return false;
+};
 
-    const valid = await basicFormRef.value?.validate().catch(() => false);
+// 保存商品属性(内部方法)
+const saveAttributesInternal = async () => {
+  try {
+    // 验证属性表单
+    const valid = await attributesFormRef.value?.validate().catch(() => false);
     if (!valid) {
-      basicFormErrors.value = true;
-      savingStates.basic = false;
+      attributesFormErrors.value = true;
+      ElMessage.error('请完善商品属性');
       return false;
     }
 
+    // 验证SKU
+    if (!validateSku()) {
+      attributesFormErrors.value = true;
+      return false;
+    }
+
+    // 准备属性数据 - 转换为后端需要的格式
     const submitData = {
-      ...basicFormData,
-      image: convertImagesToString(basicFormData.image),
-      sliderImage: convertImagesToString(basicFormData.sliderImage),
-      flatPattern: convertImagesToString(basicFormData.flatPattern),
+      goodsId: goodsId.value,
+      specType: attributesFormData.specType,
+      attrValue: generateAttrValueData(),
+      attr: generateAttrData(),
     };
 
-    const { code, data } = isEdit.value
-      ? await api.goods.edit(goodsId.value, submitData)
-      : await api.goods.add(submitData);
-
-    if (code === '200') {
-      if (!isEdit.value) {
-        goodsId.value = data.id;
-        basicFormData.id = data.id;
-      }
-      basicSaved.value = true;
-      savingStates.basic = false;
-      return true;
-    }
+    // 这里调用属性保存接口(待实现)
+    const { code, data } = await api.rule.add(submitData);
+    console.log(code, data);
 
-    basicFormErrors.value = true;
-    savingStates.basic = false;
+    // 临时模拟成功
+    attributesSaved.value = true;
+    ElMessage.success(t('message.goodsAttributeSaveSuccess'));
+    return true;
+  } catch (error) {
+    attributesFormErrors.value = true;
+    ElMessage.error('保存失败:' + error.message);
     return false;
-  };
-
-  // 保存商品属性(内部方法)
-  const saveAttributesInternal = async () => {
-    try {
-      // 验证属性表单
-      const valid = await attributesFormRef.value?.validate().catch(() => false);
-      if (!valid) {
-        attributesFormErrors.value = true;
-        ElMessage.error('请完善商品属性');
-        return false;
-      }
-
-      // 验证SKU
-      if (!validateSku()) {
-        attributesFormErrors.value = true;
-        return false;
-      }
-
-      // 准备属性数据 - 转换为后端需要的格式
-      const submitData = {
-        goodsId: goodsId.value,
-        specType: attributesFormData.specType,
-        attrValue: generateAttrValueData(),
-        attr: generateAttrData(),
-      };
-
-      // 这里调用属性保存接口(待实现)
-      const { code, data } = await api.rule.add(submitData);
-      console.log(code, data);
-
-      // 临时模拟成功
-      attributesSaved.value = true;
-      ElMessage.success('商品属性保存成功');
-      return true;
-    } catch (error) {
-      attributesFormErrors.value = true;
-      ElMessage.error('保存失败:' + error.message);
-      return false;
-    }
-  };
+  }
+};
+
+// 保存商品属性(对外方法)
+const saveAttributes = async () => {
+  try {
+    savingStates.attributes = true;
+    attributesFormErrors.value = false;
+
+    // 检查依赖
+    if (!goodsId.value && !isEdit.value) {
+      const result = await ElMessageBox.confirm(
+        '保存商品属性需要先保存基本信息,是否现在保存基本信息?',
+        '提示',
+        {
+          confirmButtonText: '保存基本信息并继续',
+          cancelButtonText: '取消',
+          type: 'warning',
+        },
+      );
+
+      if (result === 'confirm') {
+        // 先保存基本信息
+        const basicSaved = await saveBasicInfo();
 
-  // 保存商品属性(对外方法)
-  const saveAttributes = async () => {
-    try {
-      savingStates.attributes = true;
-      attributesFormErrors.value = false;
-
-      // 检查依赖
-      if (!goodsId.value && !isEdit.value) {
-        const result = await ElMessageBox.confirm(
-          '保存商品属性需要先保存基本信息,是否现在保存基本信息?',
-          '提示',
-          {
-            confirmButtonText: '保存基本信息并继续',
-            cancelButtonText: '取消',
-            type: 'warning',
-          },
-        );
-
-        if (result === 'confirm') {
-          // 先保存基本信息
-          const basicSaved = await saveBasicInfo();
-
-          if (basicSaved) {
-            // 基本信息保存成功后,保存属性
-            await saveAttributesInternal();
-          }
+        if (basicSaved) {
+          // 基本信息保存成功后,保存属性
+          await saveAttributesInternal();
         }
-        return;
       }
-
-      // 直接保存属性
-      await saveAttributesInternal();
-    } finally {
-      savingStates.attributes = false;
+      return;
     }
-  };
 
-  // 保存全部
-  const saveAll = async () => {
-    try {
-      savingStates.all = true;
-
-      // 1. 如果没有商品ID,先保存基本信息
-      if (!goodsId.value && !isEdit.value) {
-        const basicSaved = await saveBasicInfo();
-        if (!basicSaved) return;
-      }
+    // 直接保存属性
+    await saveAttributesInternal();
+  } finally {
+    savingStates.attributes = false;
+  }
+};
 
-      // 2. 如果属性有修改,保存属性
-      await saveAttributesInternal();
+// 保存全部
+const saveAll = async () => {
+  try {
+    savingStates.all = true;
 
-      ElMessage.success('保存成功');
-      emit('modalCallBack', { event: 'confirm' });
-    } catch (error) {
-      ElMessage.error('保存失败:' + error.message);
-    } finally {
-      savingStates.all = false;
+    // 1. 如果没有商品ID,先保存基本信息
+    if (!goodsId.value && !isEdit.value) {
+      const basicSaved = await saveBasicInfo();
+      if (!basicSaved) return;
     }
-  };
 
-  // 关闭对话框
-  const closeDialog = () => {
-    emit('modalCallBack', { event: 'close' });
-  };
-
-  // SKU相关方法
-  const countId = ref(2);
-  const childrenModal = [];
-  const isResetSku = ref(0);
+    // 2. 如果属性有修改,保存属性
+    await saveAttributesInternal();
 
-  // 批量操作相关变量
-  const allEditObj = ref({
-    price: 0,
-    stock: 0,
-    stock_warning: 0,
+    ElMessage.success(t('message.saveSuccess'));
+    emit('modalCallBack', { event: 'confirm' });
+  } catch (error) {
+    ElMessage.error(t('message.saveFailed') + ':' + error.message);
+  } finally {
+    savingStates.all = false;
+  }
+};
+
+// 关闭对话框
+const closeDialog = () => {
+  emit('modalCallBack', { event: 'close' });
+};
+
+// SKU相关方法
+const countId = ref(2);
+const childrenModal = [];
+const isResetSku = ref(0);
+
+// 批量操作相关变量
+const allEditObj = ref({
+  price: 0,
+  stock: 0,
+  stock_warning: 0,
+});
+
+// 添加主规格
+const addMainSku = () => {
+  attributesFormData.skus.push({
+    id: 0,
+    temp_id: countId.value++,
+    name: '',
+    batchId: '',
+    pid: 0,
+    children: [],
   });
+  buildSkuPriceTable();
+};
 
-  // 添加主规格
-  const addMainSku = () => {
-    attributesFormData.skus.push({
-      id: 0,
-      temp_id: countId.value++,
-      name: '',
-      batchId: '',
-      pid: 0,
-      children: [],
-    });
-    buildSkuPriceTable();
-  };
+// 删除主规格
+const deleteMainSku = (k) => {
+  let data = attributesFormData.skus[k];
 
   // 删除主规格
-  const deleteMainSku = (k) => {
-    let data = attributesFormData.skus[k];
-
-    // 删除主规格
-    attributesFormData.skus.splice(k, 1);
+  attributesFormData.skus.splice(k, 1);
 
-    // 如果当前删除的主规格存在子规格,则清空 skuPrice
-    if (data.children.length > 0) {
-      attributesFormData.sku_prices = [];
-      isResetSku.value = 1;
+  // 如果当前删除的主规格存在子规格,则清空 skuPrice
+  if (data.children.length > 0) {
+    attributesFormData.sku_prices = [];
+    isResetSku.value = 1;
+  }
+  buildSkuPriceTable();
+};
+
+// 添加子规格
+const addChildrenSku = (k) => {
+  let isExist = false;
+  attributesFormData.skus[k].children.forEach((e) => {
+    if (e.name == childrenModal[k] && e.name != '') {
+      isExist = true;
     }
-    buildSkuPriceTable();
-  };
+  });
+  if (isExist) {
+    ElMessage.warning('子规格已存在');
+    return false;
+  }
 
-  // 添加子规格
-  const addChildrenSku = (k) => {
-    let isExist = false;
-    attributesFormData.skus[k].children.forEach((e) => {
-      if (e.name == childrenModal[k] && e.name != '') {
-        isExist = true;
-      }
-    });
-    if (isExist) {
-      ElMessage.warning('子规格已存在');
-      return false;
-    }
+  attributesFormData.skus[k].children.push({
+    id: 0,
+    temp_id: countId.value++,
+    name: childrenModal[k] || '',
+    pid: attributesFormData.skus[k].id,
+  });
+  childrenModal[k] = '';
 
-    attributesFormData.skus[k].children.push({
-      id: 0,
-      temp_id: countId.value++,
-      name: childrenModal[k] || '',
-      pid: attributesFormData.skus[k].id,
+  // 如果是添加的第一个子规格,清空 skuPrice
+  if (attributesFormData.skus[k].children.length == 1) {
+    attributesFormData.sku_prices = [];
+    isResetSku.value = 1;
+  }
+  buildSkuPriceTable();
+};
+
+// 删除子规格
+const deleteChildrenSku = (k, i) => {
+  let data = attributesFormData.skus[k].children[i];
+  attributesFormData.skus[k].children.splice(i, 1);
+
+  // 查询 sku_prices 中包含被删除的子规格的项,然后移除
+  let deleteArr = [];
+  attributesFormData.sku_prices.forEach((item, index) => {
+    item.goods_sku_text.forEach((e) => {
+      if (e == data.name) {
+        deleteArr.push(index);
+      }
     });
-    childrenModal[k] = '';
-
-    // 如果是添加的第一个子规格,清空 skuPrice
-    if (attributesFormData.skus[k].children.length == 1) {
-      attributesFormData.sku_prices = [];
-      isResetSku.value = 1;
-    }
-    buildSkuPriceTable();
-  };
+  });
+  deleteArr.sort(function (a, b) {
+    return b - a;
+  });
+  // 移除有相关子规格的项
+  deleteArr.forEach((idx) => {
+    attributesFormData.sku_prices.splice(idx, 1);
+  });
 
-  // 删除子规格
-  const deleteChildrenSku = (k, i) => {
-    let data = attributesFormData.skus[k].children[i];
-    attributesFormData.skus[k].children.splice(i, 1);
-
-    // 查询 sku_prices 中包含被删除的子规格的项,然后移除
-    let deleteArr = [];
-    attributesFormData.sku_prices.forEach((item, index) => {
-      item.goods_sku_text.forEach((e) => {
-        if (e == data.name) {
-          deleteArr.push(index);
-        }
+  // 当前规格项,所有子规格都被删除,清空 sku_prices
+  if (attributesFormData.skus[k].children.length <= 0) {
+    attributesFormData.sku_prices = [];
+    isResetSku.value = 1;
+  }
+  buildSkuPriceTable();
+};
+
+// 组成新的规格
+const buildSkuPriceTable = () => {
+  let arr = [];
+  // 遍历sku子规格生成新数组,然后执行递归笛卡尔积
+  attributesFormData.skus.forEach((s1) => {
+    let children = s1.children;
+    let childrenIdArray = [];
+    if (children.length > 0) {
+      children.forEach((s2) => {
+        childrenIdArray.push(s2.temp_id);
       });
-    });
-    deleteArr.sort(function (a, b) {
-      return b - a;
-    });
-    // 移除有相关子规格的项
-    deleteArr.forEach((idx) => {
-      attributesFormData.sku_prices.splice(idx, 1);
-    });
-
-    // 当前规格项,所有子规格都被删除,清空 sku_prices
-    if (attributesFormData.skus[k].children.length <= 0) {
-      attributesFormData.sku_prices = [];
-      isResetSku.value = 1;
+      // 如果 children 子规格数量为 0,则不渲染当前规格
+      arr.push(childrenIdArray);
     }
-    buildSkuPriceTable();
-  };
-
-  // 组成新的规格
-  const buildSkuPriceTable = () => {
-    let arr = [];
-    // 遍历sku子规格生成新数组,然后执行递归笛卡尔积
-    attributesFormData.skus.forEach((s1) => {
-      let children = s1.children;
-      let childrenIdArray = [];
-      if (children.length > 0) {
-        children.forEach((s2) => {
-          childrenIdArray.push(s2.temp_id);
-        });
-        // 如果 children 子规格数量为 0,则不渲染当前规格
-        arr.push(childrenIdArray);
-      }
-    });
-    recursionSku(arr, 0, []);
-  };
-
-  // 递归找笛卡尔规格集合
-  const recursionSku = (arr, k, temp) => {
-    if (k == arr.length && k != 0) {
-      let tempDetail = [];
-      let tempDetailIds = [];
-      temp.forEach((item) => {
-        for (let sku of attributesFormData.skus) {
-          for (let child of sku.children) {
-            if (item == child.temp_id) {
-              tempDetail.push(child.name);
-              tempDetailIds.push(child.temp_id);
-            }
+  });
+  recursionSku(arr, 0, []);
+};
+
+// 递归找笛卡尔规格集合
+const recursionSku = (arr, k, temp) => {
+  if (k == arr.length && k != 0) {
+    let tempDetail = [];
+    let tempDetailIds = [];
+    temp.forEach((item) => {
+      for (let sku of attributesFormData.skus) {
+        for (let child of sku.children) {
+          if (item == child.temp_id) {
+            tempDetail.push(child.name);
+            tempDetailIds.push(child.temp_id);
           }
         }
-      });
-      let flag = false; // 默认添加新的
-      for (let i = 0; i < attributesFormData.sku_prices.length; i++) {
-        if (
-          attributesFormData.sku_prices[i].goods_sku_temp_ids.join(',') == tempDetailIds.join(',')
-        ) {
-          flag = i;
-          break;
-        }
-      }
-
-      if (flag === false) {
-        attributesFormData.sku_prices.push({
-          id: 0,
-          temp_id: attributesFormData.sku_prices.length + 1,
-          goods_sku_ids: '',
-          goods_id: 0,
-          image: '',
-          imageList: [],
-          price: 0,
-          stock: 0,
-          stock_warning: 0,
-          sn: '',
-          goods_sku_text: tempDetail,
-          goods_sku_temp_ids: tempDetailIds,
-        });
-      } else {
-        attributesFormData.sku_prices[flag].goods_sku_text = tempDetail;
-        attributesFormData.sku_prices[flag].goods_sku_temp_ids = tempDetailIds;
-      }
-      return;
-    }
-    if (arr.length) {
-      for (let i = 0; i < arr[k].length; i++) {
-        temp[k] = arr[k][i];
-        recursionSku(arr, k + 1, temp);
-      }
-    }
-  };
-
-  // 批量操作
-  const batchEdit = () => {
-    const batchIds = attributesFormData.skus
-      .map((item) => item.batchId)
-      .filter((item) => Boolean(item));
-    attributesFormData.sku_prices.forEach((item) => {
-      if (
-        batchIds.length ? batchIds.every((citem) => item.goods_sku_temp_ids.includes(citem)) : true
-      ) {
-        const { price, stock, stock_warning } = allEditObj.value;
-        if (price) item.price = price;
-        if (stock) item.stock = stock;
-        if (stock_warning) item.stock_warning = stock_warning;
       }
     });
-
-    // 清空输入框
-    allEditObj.value = {
-      price: 0,
-      stock: 0,
-      stock_warning: 0,
-    };
-
-    // 清空选择的规格
-    attributesFormData.skus.forEach((item) => {
-      item.batchId = '';
-    });
-
-    ElMessage.success('批量设置成功');
-  };
-
-  // 删除规格组合
-  const deleteSkuPrice = (index) => {
-    attributesFormData.sku_prices.splice(index, 1);
-    ElMessage.success('删除成功');
-  };
-
-  // SKU校验
-  const validateSku = () => {
-    if (attributesFormData.sku_prices.length === 0) {
-      ElMessage.error('请先添加商品规格');
-      return false;
-    }
-
+    let flag = false; // 默认添加新的
     for (let i = 0; i < attributesFormData.sku_prices.length; i++) {
-      const item = attributesFormData.sku_prices[i];
-      if (!item.price || item.price <= 0) {
-        ElMessage.error(`第${i + 1}个规格的销售价格不能为空且必须大于0`);
-        return false;
-      }
-      if (item.stock === null || item.stock === undefined || item.stock < 0) {
-        ElMessage.error(`第${i + 1}个规格的商品库存不能为空且不能小于0`);
-        return false;
+      if (
+        attributesFormData.sku_prices[i].goods_sku_temp_ids.join(',') == tempDetailIds.join(',')
+      ) {
+        flag = i;
+        break;
       }
     }
-    return true;
-  };
 
-  // 生成后端需要的 attrValue 数据格式
-  const generateAttrValueData = () => {
-    return attributesFormData.sku_prices.map((item) => {
-      // 构建规格属性对象,如 {"颜色": "红色", "尺寸": "S"}
-      const attrObj = {};
-      const attrValueObj = {};
-
-      // 根据 goods_sku_text 和对应的规格名称构建属性对象
-      item.goods_sku_text.forEach((value, index) => {
-        const specName = attributesFormData.skus[index]?.name;
-        if (specName) {
-          attrObj[specName] = value;
-          attrValueObj[specName] = value;
-        }
+    if (flag === false) {
+      attributesFormData.sku_prices.push({
+        id: 0,
+        temp_id: attributesFormData.sku_prices.length + 1,
+        goods_sku_ids: '',
+        goods_id: 0,
+        image: '',
+        imageList: [],
+        price: 0,
+        stock: 0,
+        stock_warning: 0,
+        sn: '',
+        goods_sku_text: tempDetail,
+        goods_sku_temp_ids: tempDetailIds,
       });
+    } else {
+      attributesFormData.sku_prices[flag].goods_sku_text = tempDetail;
+      attributesFormData.sku_prices[flag].goods_sku_temp_ids = tempDetailIds;
+    }
+    return;
+  }
+  if (arr.length) {
+    for (let i = 0; i < arr[k].length; i++) {
+      temp[k] = arr[k][i];
+      recursionSku(arr, k + 1, temp);
+    }
+  }
+};
+
+// 批量操作
+const batchEdit = () => {
+  const batchIds = attributesFormData.skus
+    .map((item) => item.batchId)
+    .filter((item) => Boolean(item));
+  attributesFormData.sku_prices.forEach((item) => {
+    if (
+      batchIds.length ? batchIds.every((citem) => item.goods_sku_temp_ids.includes(citem)) : true
+    ) {
+      const { price, stock, stock_warning } = allEditObj.value;
+      if (price) item.price = price;
+      if (stock) item.stock = stock;
+      if (stock_warning) item.stock_warning = stock_warning;
+    }
+  });
 
-      return {
-        image: item.imageList && item.imageList.length > 0 ? item.imageList[0] : '',
-        price: item.price || '0',
-        stock: item.stock || 0,
-        barCode: item.sn || '',
-        stock_warning: item.stock_warning || 0,
-        attrValue: JSON.stringify(attrValueObj),
-        ...attrObj, // 展开规格属性,如 "颜色": "红色", "尺寸": "S"
-        id: 0,
-        productId: 0,
-      };
-    });
+  // 清空输入框
+  allEditObj.value = {
+    price: 0,
+    stock: 0,
+    stock_warning: 0,
   };
 
-  // 生成后端需要的 attr 数据格式
-  const generateAttrData = () => {
-    return attributesFormData.skus
-      .filter((sku) => sku.name && sku.children.length > 0)
-      .map((sku) => ({
-        attrName: sku.name,
-        attrValues: sku.children.map((child) => child.name).join(','),
-      }));
-  };
+  // 清空选择的规格
+  attributesFormData.skus.forEach((item) => {
+    item.batchId = '';
+  });
 
-  // 获取分类数据
-  const getCategoryData = async () => {
-    const { code, data } = await api.category.list({ size: 100 });
-    code === '200' &&
-      (categoryOptions.value = data.list.map((cat) => ({
-        label: cat.name,
-        value: cat.id,
-        id: cat.id,
-        name: cat.name,
-      })));
-  };
+  ElMessage.success('批量设置成功');
+};
 
-  // 加载商品详情
-  const loadGoodsDetail = async () => {
-    if (!goodsId.value) return;
+// 删除规格组合
+const deleteSkuPrice = (index) => {
+  attributesFormData.sku_prices.splice(index, 1);
+  ElMessage.success(t('message.deleteSuccess'));
+};
 
-    const { code, data } = await api.goods.detail(goodsId.value);
-    if (code === '200') {
-      // 转换图片字段
-      data.image = convertStringToImages(data.image);
-      data.sliderImage = convertStringToImages(data.sliderImage);
-      data.flatPattern = convertStringToImages(data.flatPattern);
+// SKU校验
+const validateSku = () => {
+  if (attributesFormData.sku_prices.length === 0) {
+    ElMessage.error('请先添加商品规格');
+    return false;
+  }
 
-      Object.assign(basicFormData, data);
-      basicSaved.value = true;
+  for (let i = 0; i < attributesFormData.sku_prices.length; i++) {
+    const item = attributesFormData.sku_prices[i];
+    if (!item.price || item.price <= 0) {
+      ElMessage.error(`第${i + 1}个规格的销售价格不能为空且必须大于0`);
+      return false;
     }
-  };
-
-  // 初始化
-  const init = async () => {
-    await getCategoryData();
-
-    if (isEdit.value && goodsId.value) {
-      await loadGoodsDetail();
+    if (item.stock === null || item.stock === undefined || item.stock < 0) {
+      ElMessage.error(`第${i + 1}个规格的商品库存不能为空且不能小于0`);
+      return false;
     }
-  };
+  }
+  return true;
+};
+
+// 生成后端需要的 attrValue 数据格式
+const generateAttrValueData = () => {
+  return attributesFormData.sku_prices.map((item) => {
+    // 构建规格属性对象,如 {"颜色": "红色", "尺寸": "S"}
+    const attrObj = {};
+    const attrValueObj = {};
+
+    // 根据 goods_sku_text 和对应的规格名称构建属性对象
+    item.goods_sku_text.forEach((value, index) => {
+      const specName = attributesFormData.skus[index]?.name;
+      if (specName) {
+        attrObj[specName] = value;
+        attrValueObj[specName] = value;
+      }
+    });
 
-  // 组件挂载
-  onMounted(() => {
-    init();
+    return {
+      image: item.imageList && item.imageList.length > 0 ? item.imageList[0] : '',
+      price: item.price || '0',
+      stock: item.stock || 0,
+      barCode: item.sn || '',
+      stock_warning: item.stock_warning || 0,
+      attrValue: JSON.stringify(attrValueObj),
+      ...attrObj, // 展开规格属性,如 "颜色": "红色", "尺寸": "S"
+      id: 0,
+      productId: 0,
+    };
   });
+};
+
+// 生成后端需要的 attr 数据格式
+const generateAttrData = () => {
+  return attributesFormData.skus
+    .filter((sku) => sku.name && sku.children.length > 0)
+    .map((sku) => ({
+      attrName: sku.name,
+      attrValues: sku.children.map((child) => child.name).join(','),
+    }));
+};
+
+// 获取分类数据
+const getCategoryData = async () => {
+  const { code, data } = await api.category.list({ size: 100 });
+  code === '200' &&
+    (categoryOptions.value = data.list.map((cat) => ({
+      label: cat.name,
+      value: cat.id,
+      id: cat.id,
+      name: cat.name,
+    })));
+};
+
+// 加载商品详情
+const loadGoodsDetail = async () => {
+  if (!goodsId.value) return;
+
+  const { code, data } = await api.goods.detail(goodsId.value);
+  if (code === '200') {
+    // 转换图片字段
+    data.image = convertStringToImages(data.image);
+    data.sliderImage = convertStringToImages(data.sliderImage);
+    data.flatPattern = convertStringToImages(data.flatPattern);
+
+    Object.assign(basicFormData, data);
+    basicSaved.value = true;
+  }
+};
+
+// 初始化
+const init = async () => {
+  await getCategoryData();
+
+  if (isEdit.value && goodsId.value) {
+    await loadGoodsDetail();
+  }
+};
+
+// 组件挂载
+onMounted(() => {
+  init();
+});
 </script>
 
 <style scoped lang="scss">
-  .goods-edit {
-    height: 100%;
-
-    .el-header {
-      height: auto;
-      padding: 0;
-    }
+.goods-edit {
+  height: 100%;
 
-    .el-main {
-      padding: 20px;
-    }
+  .el-header {
+    height: auto;
+    padding: 0;
   }
 
-  .tab-placeholder {
+  .el-main {
+    padding: 20px;
+  }
+}
+
+.tab-placeholder {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  min-height: 300px;
+}
+
+.tab-disabled-tip {
+  font-size: 12px;
+  color: var(--el-color-info);
+  margin-left: 4px;
+}
+
+.is-error {
+  color: var(--el-color-danger);
+}
+
+.text-success {
+  color: var(--el-color-success);
+}
+
+.spec-card {
+  .card-header {
     display: flex;
-    justify-content: center;
+    justify-content: space-between;
     align-items: center;
-    min-height: 300px;
+    font-weight: 500;
   }
+}
 
-  .tab-disabled-tip {
-    font-size: 12px;
-    color: var(--el-color-info);
-    margin-left: 4px;
-  }
+.sku-wrap {
+  width: 100%;
+  border: 1px solid #d9d9d9;
+  padding: 8px;
+  box-sizing: border-box;
 
-  .is-error {
-    color: var(--el-color-danger);
-  }
+  .sku {
+    width: 100%;
+    min-height: 100px;
 
-  .text-success {
-    color: var(--el-color-success);
-  }
+    .sku-key {
+      width: 100%;
+      height: 40px;
+      color: var(--sa-subtitle);
+      padding: 0 16px;
+      background: var(--sa-table-header-bg);
+      font-size: 14px;
 
-  .spec-card {
-    .card-header {
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      font-weight: 500;
+      .sku-key-input {
+        width: 120px;
+      }
+
+      .sku-key-icon {
+        color: var(--el-color-primary);
+      }
     }
-  }
 
-  .sku-wrap {
-    width: 100%;
-    border: 1px solid #d9d9d9;
-    padding: 8px;
-    box-sizing: border-box;
-    .sku {
-      width: 100%;
-      min-height: 100px;
-      .sku-key {
-        width: 100%;
-        height: 40px;
-        color: var(--sa-subtitle);
-        padding: 0 16px;
-        background: var(--sa-table-header-bg);
-        font-size: 14px;
-        .sku-key-input {
-          width: 120px;
-        }
-        .sku-key-icon {
-          color: var(--el-color-primary);
-        }
+    .sku-value {
+      padding: 12px 0 0 30px;
+      font-size: 14px;
+      color: var(--sa-subtitle);
+
+      .sku-value-title {
+        height: 32px;
       }
-      .sku-value {
-        padding: 12px 0 0 30px;
-        font-size: 14px;
-        color: var(--sa-subtitle);
-        .sku-value-title {
-          height: 32px;
-        }
-        .sku-value-box {
-          position: relative;
-          margin-right: 24px;
-          .sku-value-input {
-            width: 104px;
-          }
-          .sku-value-icon {
-            position: absolute;
-            right: -8px;
-            top: -8px;
-            width: 16px;
-            height: 16px;
-            color: var(--el-color-primary);
-          }
-        }
-        .sku-value-add {
+
+      .sku-value-box {
+        position: relative;
+        margin-right: 24px;
+
+        .sku-value-input {
           width: 104px;
-          height: 32px;
-          font-size: 14px;
+        }
+
+        .sku-value-icon {
+          position: absolute;
+          right: -8px;
+          top: -8px;
+          width: 16px;
+          height: 16px;
           color: var(--el-color-primary);
         }
       }
-    }
-    .sku-tools {
-      width: 100%;
-      height: 40px;
-      color: #434343;
-      padding-left: 16px;
-      background: var(--sa-table-header-bg);
-      font-size: 12px;
-    }
-  }
 
-  .sku-table-wrap {
-    width: 100%;
-    overflow: auto;
-    margin-top: 16px;
-    .sku-table {
-      width: 100%;
-      border: 1px solid var(--sa-border);
-      tbody {
-        font-size: 12px;
-      }
-      th {
-        font-size: 12px;
-        color: var(--subtitle);
+      .sku-value-add {
+        width: 104px;
         height: 32px;
-        line-height: 1;
-        padding-left: 12px;
-        box-sizing: border-box;
-        text-align: left;
-      }
-      td {
-        min-width: 88px;
-        padding: 0 10px;
-        height: 40px;
-        box-sizing: border-box;
-        &.image {
-          min-width: 48px;
-        }
-        &.stock {
-          min-width: 138px;
-        }
-        &.stock_warning {
-          min-width: 168px;
-        }
-        &.sn {
-          min-width: 116px;
-        }
+        font-size: 14px;
+        color: var(--el-color-primary);
       }
     }
   }
 
-  :deep(.el-tabs__header) {
-    margin: 0;
+  .sku-tools {
+    width: 100%;
+    height: 40px;
+    color: #434343;
+    padding-left: 16px;
+    background: var(--sa-table-header-bg);
+    font-size: 12px;
   }
+}
 
-  :deep(.el-tabs__nav-wrap::after) {
-    height: 1px;
-  }
+.sku-table-wrap {
+  width: 100%;
+  overflow: auto;
+  margin-top: 16px;
 
-  :deep(.el-tabs__item) {
-    padding: 0 20px;
-    font-size: 14px;
-  }
+  .sku-table {
+    width: 100%;
+    border: 1px solid var(--sa-border);
 
-  :deep(.el-tabs__nav) {
-    border: none;
-  }
+    tbody {
+      font-size: 12px;
+    }
 
-  .form-tip {
-    font-size: 12px;
-    color: var(--el-color-info);
-    margin-top: 4px;
-    line-height: 1.4;
-  }
+    th {
+      font-size: 12px;
+      color: var(--subtitle);
+      height: 32px;
+      line-height: 1;
+      padding-left: 12px;
+      box-sizing: border-box;
+      text-align: left;
+    }
 
-  .mt-1px {
-    margin-top: 1px;
-  }
+    td {
+      min-width: 88px;
+      padding: 0 10px;
+      height: 40px;
+      box-sizing: border-box;
 
-  /* 必填项样式 */
-  .required {
-    color: #f56c6c;
-    margin-right: 4px;
-  }
+      &.image {
+        min-width: 48px;
+      }
 
-  /* 错误状态样式 */
-  .is-error .el-input__wrapper {
-    border-color: #f56c6c !important;
-    box-shadow: 0 0 0 1px #f56c6c inset !important;
-  }
+      &.stock {
+        min-width: 138px;
+      }
 
-  .warning-title {
-    font-size: 12px;
-    color: #909399;
-  }
+      &.stock_warning {
+        min-width: 168px;
+      }
 
-  .th-center {
-    text-align: center;
+      &.sn {
+        min-width: 116px;
+      }
+    }
   }
+}
+
+:deep(.el-tabs__header) {
+  margin: 0;
+}
+
+:deep(.el-tabs__nav-wrap::after) {
+  height: 1px;
+}
+
+:deep(.el-tabs__item) {
+  padding: 0 20px;
+  font-size: 14px;
+}
+
+:deep(.el-tabs__nav) {
+  border: none;
+}
+
+.form-tip {
+  font-size: 12px;
+  color: var(--el-color-info);
+  margin-top: 4px;
+  line-height: 1.4;
+}
+
+.mt-1px {
+  margin-top: 1px;
+}
+
+/* 必填项样式 */
+.required {
+  color: #f56c6c;
+  margin-right: 4px;
+}
+
+/* 错误状态样式 */
+.is-error .el-input__wrapper {
+  border-color: #f56c6c !important;
+  box-shadow: 0 0 0 1px #f56c6c inset !important;
+}
+
+.warning-title {
+  font-size: 12px;
+  color: #909399;
+}
+
+.th-center {
+  text-align: center;
+}
 </style>

+ 4 - 4
src/app/shop/admin/marketing/group/index.vue

@@ -334,7 +334,7 @@ async function updateActivityGoods(activityId, goodsList) {
     });
 
     if (code === '200') {
-      ElMessage.success('商品设置成功');
+      ElMessage.success(t('message.updateSuccess'));
       getData(); // 刷新列表
     }
   } catch (error) {
@@ -348,14 +348,14 @@ async function deleteRow(id) {
   try {
     const { code, message } = await api.group.delete({ id });
     if (code === '200') {
-      ElMessage.success('删除成功');
+      ElMessage.success(t('message.deleteSuccess'));
       getData();
     } else {
-      ElMessage.error(message || '删除失败');
+      ElMessage.error(message || t('message.deleteFailed'));
     }
   } catch (error) {
     console.error('删除失败:', error);
-    ElMessage.error('删除失败');
+    ElMessage.error(t('message.deleteFailed'));
   }
 }
 async function batchHandle(type) {

+ 5 - 5
src/app/shop/admin/order/order/detail.vue

@@ -374,7 +374,7 @@ function getFullAddress(addressInfo) {
 // 打开用户详情
 function openUserDetail(uid) {
   if (!uid) {
-    ElMessage.warning('用户ID不存在');
+    ElMessage.warning(t('message.userIdNotExist'));
     return;
   }
 
@@ -438,10 +438,10 @@ async function onRefund() {
 
     const { code, message } = await api.order.refund(String(state.orderDetail.id));
     if (code == 200) {
-      ElMessage.success('退款提交成功');
+      ElMessage.success(t('message.refundSuccess'));
       getOrderDetail(); // 刷新订单详情
     } else {
-      ElMessage.error(message || '退款申请失败');
+      ElMessage.error(message || t('message.refundFailed'));
     }
   } catch (error) { }
 }
@@ -449,13 +449,13 @@ async function onRefund() {
 // 打开订单详情
 function openOrderDetail(orderId) {
   if (!orderId) {
-    ElMessage.warning('订单ID不存在');
+    ElMessage.warning(t('message.orderIdNotExist'));
     return;
   }
 
   // 如果是当前订单,不需要打开新窗口
   if (orderId === state.orderDetail.orderId) {
-    ElMessage.info('这是当前订单');
+    ElMessage.info(t('message.currentOrder'));
     return;
   }
 

+ 28 - 45
src/app/shop/admin/order/order/index.vue

@@ -164,8 +164,7 @@ export default {
 };
 </script>
 <script setup>
-import { onMounted, reactive, ref, watch } from 'vue';
-import { useRoute, useRouter } from 'vue-router';
+import { onMounted, reactive, ref } from 'vue';
 import { ElMessage, ElMessageBox } from 'element-plus';
 import { api, getOrderStatusInfo, getPinkStatusInfo } from '../order.service';
 import { useModal, usePagination } from '@/sheep/hooks';
@@ -174,9 +173,6 @@ import OrderBatchDispatch from './batchDispatch.vue';
 import OrderDetail from './detail.vue';
 import UserEdit from '../../user/list/edit.vue';
 
-const route = useRoute();
-const router = useRouter();
-
 // 搜索字段配置
 const searchFields = reactive({
   orderId: {
@@ -214,12 +210,12 @@ const defaultSearchValues = reactive({
   createTime: [],
 });
 
-// 当前状态标签 - 从URL参数初始化
-const currentStatus = ref(route.query.status || 'all');
+// 当前状态标签 - 默认为全部
+const currentStatus = ref('all');
 
 // 状态映射 - 根据新的状态机定义
 const statusMap = {
-  all: {}, // 全部 - 不传订单状态参数
+  all: null, // 全部 - 不传订单状态参数,使用null而不是空对象
   to_pay: { status: 1 }, // 待支付:订单状态为1
   cancellation: { status: 2 }, // 订单取消:订单状态为2
   paid: { status: 3 }, // 已支付:订单状态为3
@@ -246,18 +242,10 @@ const handleReset = () => {
 
 // 标签切换处理
 const handleTabChange = (status) => {
-  // 立即更新tab状态,不依赖接口结果
+  // 立即更新tab状态
   currentStatus.value = status;
 
-  // 同步URL参数
-  router.replace({
-    query: {
-      ...route.query,
-      status: status === 'all' ? undefined : status, // 'all'状态不需要在URL中显示
-    },
-  });
-
-  // 直接调用 getData,会自动使用当前的搜索条件和状态
+  // 直接调用getData,重置到第一页
   getData(1);
 };
 
@@ -303,23 +291,34 @@ async function getData(page, searchParams = null) {
     const finalSearchParams = searchParams !== null ? searchParams : currentSearchParams.value;
 
     // 根据当前状态添加筛选条件
-    const statusParams = statusMap[currentStatus.value] || {};
-    const allParams = { ...finalSearchParams, ...statusParams };
+    const statusParams = statusMap[currentStatus.value];
 
-    // 构建请求参数
+    // 构建请求参数 - 只有当statusParams不为null时才合并状态参数
     const requestData = {
       page: pageData.page,
       size: pageData.size,
-      ...allParams,
+      ...finalSearchParams,
     };
 
+    // 只有当statusParams存在时才添加状态参数
+    if (statusParams) {
+      Object.assign(requestData, statusParams);
+    }
+
     // 处理时间范围搜索
-    if (allParams.createTime && allParams.createTime.length === 2) {
-      requestData.startTime = allParams.createTime[0];
-      requestData.endTime = allParams.createTime[1];
+    if (requestData.createTime && requestData.createTime.length === 2) {
+      requestData.startTime = requestData.createTime[0];
+      requestData.endTime = requestData.createTime[1];
       delete requestData.createTime;
     }
 
+    // 调试信息
+    console.log('订单列表请求参数:', {
+      currentStatus: currentStatus.value,
+      statusParams,
+      requestData
+    });
+
     const { code, data } = await api.order.list(requestData);
 
     if (code == '200') {
@@ -353,10 +352,10 @@ async function onExport() {
   exportLoading.value = true;
   try {
     // 构建导出参数:合并搜索条件、当前tab状态和分页参数
-    const statusParams = statusMap[currentStatus.value] || {};
+    const statusParams = statusMap[currentStatus.value];
     const exportParams = {
       ...currentSearchParams.value,
-      ...statusParams,
+      ...(statusParams || {}),
       // 添加分页参数,与列表保持一致
       page: pageData.page,
       size: pageData.size,
@@ -502,25 +501,9 @@ function onSend(row) {
   );
 }
 
-// 监听路由参数变化,同步状态
-watch(
-  () => route.query.status,
-  (newStatus) => {
-    if (newStatus && newStatus !== currentStatus.value) {
-      currentStatus.value = newStatus;
-      // 获取对应状态参数并刷新数据
-      const statusParams = statusMap[newStatus] || {};
-      const mergedParams = { ...currentSearchParams.value, ...statusParams };
-      getData(1, mergedParams);
-    }
-  },
-  { immediate: false }
-);
-
 onMounted(() => {
-  // 初始化时根据URL状态加载数据
-  const statusParams = statusMap[currentStatus.value] || {};
-  getData(1, statusParams);
+  // 页面初始化时加载数据
+  getData(1);
 });
 </script>
 <style lang="scss" scoped>

+ 1 - 1
src/app/shop/admin/user/list/edit.vue

@@ -137,7 +137,7 @@ async function confirm() {
         ? await api.list.add(submitForm)
         : await api.list.edit({ id: props.modal.params.id, ...submitForm });
     if (code == '200') {
-      ElMessage.success('保存成功');
+      ElMessage.success(t('message.saveSuccess'));
       emit('modalCallBack', { event: 'confirm' });
     }
   });

+ 10 - 1
src/locales/en-US/index.json

@@ -367,7 +367,16 @@
     "noData": "No data",
     "noSearchResult": "No search results found",
     "loadMore": "Load more",
-    "noMore": "No more data"
+    "noMore": "No more data",
+    "submitSuccess": "Submit successful",
+    "refundSuccess": "Refund submitted successfully",
+    "refundFailed": "Refund application failed",
+    "userIdNotExist": "User ID does not exist",
+    "orderIdNotExist": "Order ID does not exist",
+    "currentOrder": "This is the current order",
+    "passwordChangeSuccess": "Password changed successfully, please login again",
+    "editFeatureNotDeveloped": "Edit feature is under development",
+    "goodsAttributeSaveSuccess": "Product attributes saved successfully"
   },
   "error": {
     "pageNotFound": "Page Not Found",

+ 29 - 21
src/locales/zh-CN/index.json

@@ -363,7 +363,16 @@
     "noData": "暂无数据",
     "noSearchResult": "没有找到相关数据",
     "loadMore": "加载更多",
-    "noMore": "没有更多数据了"
+    "noMore": "没有更多数据了",
+    "submitSuccess": "提交成功",
+    "refundSuccess": "退款提交成功",
+    "refundFailed": "退款申请失败",
+    "userIdNotExist": "用户ID不存在",
+    "orderIdNotExist": "订单ID不存在",
+    "currentOrder": "这是当前订单",
+    "passwordChangeSuccess": "密码修改成功,请重新登录",
+    "editFeatureNotDeveloped": "编辑功能待开发",
+    "goodsAttributeSaveSuccess": "商品属性保存成功"
   },
   "error": {
     "pageNotFound": "未找到页面",
@@ -537,26 +546,7 @@
       "channelStatusUpdateSuccess": "通道状态更新成功",
       "channelStatusUpdateFailed": "通道状态更新失败"
     },
-    "finance": {
-      "financeReport": "财务报表",
-      "timeRange": "时间范围",
-      "exportReport": "导出报表",
-      "exporting": "导出中...",
-      "serialNumber": "序号",
-      "subjectName": "科目名称",
-      "alias": "别名",
-      "balanceDirection": "余额方向",
-      "initialBalance": "初始日余额",
-      "debitAmount": "借方发生额",
-      "creditAmount": "贷方发生额",
-      "endBalance": "日余额",
-      "debit": "借",
-      "credit": "贷",
-      "unknown": "未知",
-      "exportSuccess": "导出成功",
-      "exportFailed": "导出失败",
-      "noDataToExport": "暂无数据可导出"
-    },
+
     "commission": {
       "title": "佣金管理",
       "commissionNo": "佣金单号",
@@ -750,6 +740,24 @@
       "accountType": "账户类型"
     },
     "finance": {
+      "financeReport": "财务报表",
+      "timeRange": "时间范围",
+      "exportReport": "导出报表",
+      "exporting": "导出中...",
+      "serialNumber": "序号",
+      "subjectName": "科目名称",
+      "alias": "别名",
+      "balanceDirection": "余额方向",
+      "initialBalance": "初始日余额",
+      "debitAmount": "借方发生额",
+      "creditAmount": "贷方发生额",
+      "endBalance": "日余额",
+      "debit": "借",
+      "credit": "贷",
+      "unknown": "未知",
+      "exportSuccess": "导出成功",
+      "exportFailed": "导出失败",
+      "noDataToExport": "暂无数据可导出",
       "title": "财务",
       "commissionManagement": "佣金管理",
       "financialReport": "财务报表",

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

@@ -224,7 +224,7 @@ function changePassword() {
     {
       confirm: () => {
         // 密码修改成功后,调用注销方法退出登录
-        ElMessage.success('密码修改成功,请重新登录');
+        ElMessage.success(t('message.passwordChangeSuccess'));
         setTimeout(() => {
           accountStore.logout();
         }, 500); // 延迟1.5秒后退出登录,让用户看到成功提示

+ 14 - 7
src/sheep/request/crud.js

@@ -2,6 +2,10 @@ import { request } from './index';
 import $storage from '@/sheep/utils/storage';
 import { ElMessage } from 'element-plus';
 
+// 检测是否为mall前缀的接口
+const isMallAPI = (url) => {
+  return url.startsWith('/mall') || url.startsWith('mall');
+};
 // CRUD 配置常量
 const CRUD_VERSIONS = {
   V1: 'v1', // 旧版本 CRUD
@@ -23,7 +27,7 @@ const DEFAULT_CRUD_CONFIG = {
     detail: 'POST',
     add: 'POST',
     edit: 'POST',
-    delete: 'POST',
+    delete: 'DELETE',
   },
 };
 
@@ -74,6 +78,7 @@ export const LIST = (url, data, options = {}) => {
 export const DETAIL = (url, id, options = {}) => {
   const config = getCrudConfig(options);
   const method = config.methods.detail;
+  const isMall = isMallAPI(url);
 
   if (config.version === CRUD_VERSIONS.V2) {
     // 新版本:使用 RESTful 风格的 URL
@@ -85,8 +90,8 @@ export const DETAIL = (url, id, options = {}) => {
     // 旧版本:使用参数传递 ID
     return request({
       url: url + config.endpoints.detail,
-      method,
-      ...(method === 'GET' ? { params: { id } } : { data: { id } }),
+      method: isMall ? 'GET' : 'POST', // mall用GET,其他用POST
+      params: { id },
     });
   }
 };
@@ -108,6 +113,7 @@ export const ADD = (url, data, options = {}) => {
 // 编辑&更新
 export const EDIT = (url, id, data, options = {}) => {
   const config = getCrudConfig(options);
+  const isMall = isMallAPI(url);
 
   if (config.version === CRUD_VERSIONS.V2) {
     // 新版本:使用 RESTful 风格的 URL
@@ -123,8 +129,8 @@ export const EDIT = (url, id, data, options = {}) => {
     // 旧版本:将 ID 包含在数据中
     return request({
       url: url + config.endpoints.edit,
-      method: config.methods.edit,
-      data: { id, ...data },
+      method: isMall ? 'PUT' : 'POST', // mall用PUT,其他用POST
+      data: id,
       options: {
         showSuccessMessage: false,
       },
@@ -136,6 +142,7 @@ export const EDIT = (url, id, data, options = {}) => {
 export const DELETE = (url, id, options = {}) => {
   const config = getCrudConfig(options);
   const method = config.methods.delete;
+  const isMall = isMallAPI(url);
 
   if (config.version === CRUD_VERSIONS.V2) {
     // 新版本:使用 RESTful 风格的 URL
@@ -150,8 +157,8 @@ export const DELETE = (url, id, options = {}) => {
     // 旧版本:使用参数传递 ID
     return request({
       url: url + config.endpoints.delete,
-      method,
-      ...(method === 'GET' ? { params: { id } } : { data: { id } }),
+      method: isMall ? 'DELETE' : 'POST', // mall用DELETE,其他用POST
+      params: id,
       options: {
         showSuccessMessage: true,
       },