Просмотр исходного кода

feat:激活promptx和消息国际化配置

叶静 1 месяц назад
Родитель
Сommit
ff29a4f037

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

@@ -69,4 +69,10 @@
     </content>
     <tags>#其他</tags>
   </item>
+  <item id="mem_1756274781913_yjtc2v5mn" time="2025/08/27 14:06">
+    <content>
+      用户明确要求:在开发过程中,除非用户明确要求创建测试文档或测试文件,否则不要主动创建任何测试相关的文件。专注于业务功能的实现,测试文件的创建需要用户明确指示。
+    </content>
+    <tags>#其他</tags>
+  </item>
 </memory>

+ 25 - 9
.promptx/pouch.json

@@ -1,26 +1,42 @@
 {
-  "currentState": "initialized",
+  "currentState": "memory_saved",
   "stateHistory": [
     {
       "from": "initial",
       "command": "init",
-      "timestamp": "2025-08-25T03:12:11.315Z",
+      "timestamp": "2025-08-27T06:03:45.046Z",
       "args": [
         {
-          "workingDirectory": "d:\\work\\bandhu-buy\\admin"
+          "workingDirectory": "d:\\work\\bandhu-buy\\admin",
+          "ideType": "cursor"
         }
       ]
     },
     {
       "from": "initialized",
-      "command": "init",
-      "timestamp": "2025-08-25T08:16:36.354Z",
+      "command": "welcome",
+      "timestamp": "2025-08-27T06:03:51.921Z",
+      "args": []
+    },
+    {
+      "from": "service_discovery",
+      "command": "action",
+      "timestamp": "2025-08-27T06:04:13.164Z",
       "args": [
-        {
-          "workingDirectory": "d:\\work\\bandhu-buy\\admin"
-        }
+        "vue3-expert"
+      ]
+    },
+    {
+      "from": "role_activated_with_memory",
+      "command": "remember",
+      "timestamp": "2025-08-27T06:06:21.909Z",
+      "args": [
+        "vue3-expert",
+        "用户明确要求:在开发过程中,除非用户明确要求创建测试文档或测试文件,否则不要主动创建任何测试相关的文件。专注于业务功能的实现,测试文件的创建需要用户明确指示。",
+        "--tags",
+        "开发规范 测试策略 用户偏好"
       ]
     }
   ],
-  "lastUpdated": "2025-08-25T08:16:36.385Z"
+  "lastUpdated": "2025-08-27T06:06:21.921Z"
 }

+ 11 - 11
.promptx/resource/project.registry.json

@@ -4,8 +4,8 @@
   "metadata": {
     "version": "2.0.0",
     "description": "project 级资源注册表",
-    "createdAt": "2025-08-25T08:16:36.364Z",
-    "updatedAt": "2025-08-25T08:16:36.369Z",
+    "createdAt": "2025-08-27T06:03:45.068Z",
+    "updatedAt": "2025-08-27T06:03:45.092Z",
     "resourceCount": 3
   },
   "resources": [
@@ -17,9 +17,9 @@
       "description": "执行模式,定义具体的行为模式",
       "reference": "@project://.promptx/resource/role/vue3-expert/execution/vue3-development.execution.md",
       "metadata": {
-        "createdAt": "2025-08-25T08:16:36.366Z",
-        "updatedAt": "2025-08-25T08:16:36.366Z",
-        "scannedAt": "2025-08-25T08:16:36.366Z",
+        "createdAt": "2025-08-27T06:03:45.078Z",
+        "updatedAt": "2025-08-27T06:03:45.078Z",
+        "scannedAt": "2025-08-27T06:03:45.078Z",
         "path": "role/vue3-expert/execution/vue3-development.execution.md"
       }
     },
@@ -31,9 +31,9 @@
       "description": "思维模式,指导AI的思考方式",
       "reference": "@project://.promptx/resource/role/vue3-expert/thought/vue3-thinking.thought.md",
       "metadata": {
-        "createdAt": "2025-08-25T08:16:36.368Z",
-        "updatedAt": "2025-08-25T08:16:36.368Z",
-        "scannedAt": "2025-08-25T08:16:36.368Z",
+        "createdAt": "2025-08-27T06:03:45.085Z",
+        "updatedAt": "2025-08-27T06:03:45.085Z",
+        "scannedAt": "2025-08-27T06:03:45.085Z",
         "path": "role/vue3-expert/thought/vue3-thinking.thought.md"
       }
     },
@@ -45,9 +45,9 @@
       "description": "专业角色,提供特定领域的专业能力",
       "reference": "@project://.promptx/resource/role/vue3-expert/vue3-expert.role.md",
       "metadata": {
-        "createdAt": "2025-08-25T08:16:36.368Z",
-        "updatedAt": "2025-08-25T08:16:36.368Z",
-        "scannedAt": "2025-08-25T08:16:36.368Z",
+        "createdAt": "2025-08-27T06:03:45.091Z",
+        "updatedAt": "2025-08-27T06:03:45.091Z",
+        "scannedAt": "2025-08-27T06:03:45.091Z",
         "path": "role/vue3-expert/vue3-expert.role.md"
       }
     }

+ 22 - 12
src/app/shop/admin/content/notification/edit.vue

@@ -1,28 +1,38 @@
 <template>
-  <el-container v-loading="loading" element-loading-text="加载中...">
+  <el-container v-loading="loading" :element-loading-text="t('modules.notification.loading')">
     <el-main>
-      <el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
-        <el-form-item label="消息标题" prop="title">
-          <el-input v-model="form.model.title" placeholder="请填写消息标题"></el-input>
+      <el-form :model="form.model" :rules="form.rules" ref="formRef" :label-width="formLabelWidth">
+        <el-form-item :label="t('modules.notification.messageTitle')" prop="title">
+          <el-input v-model="form.model.title" :placeholder="t('modules.notification.enterMessageTitle')"></el-input>
         </el-form-item>
-        <el-form-item label="消息内容" prop="message">
-          <el-input v-model="form.model.message" type="textarea" :rows="5" placeholder="请填写消息内容"></el-input>
+        <el-form-item :label="t('modules.notification.messageContent')" prop="message">
+          <el-input v-model="form.model.message" type="textarea" :rows="5"
+            :placeholder="t('modules.notification.enterMessageContent')"></el-input>
         </el-form-item>
-        <el-form-item label="页面路径" prop="pages">
-          <el-input v-model="form.model.pages" placeholder="请填写页面路径(可选)"></el-input>
+        <el-form-item :label="t('modules.notification.pagePath')" prop="pages">
+          <el-input v-model="form.model.pages" :placeholder="t('modules.notification.enterPagePath')"></el-input>
         </el-form-item>
       </el-form>
     </el-main>
     <el-footer class="sa-footer--submit">
-      <el-button v-if="modal.params.type == 'add'" type="primary" @click="confirm">保存</el-button>
-      <el-button v-if="modal.params.type == 'edit'" type="primary" @click="confirm">更新</el-button>
+      <el-button v-if="modal.params.type == 'add'" type="primary" @click="confirm">{{ t('modules.notification.save')
+      }}</el-button>
+      <el-button v-if="modal.params.type == 'edit'" type="primary" @click="confirm">{{ t('modules.notification.update')
+      }}</el-button>
     </el-footer>
   </el-container>
 </template>
 <script setup>
 import { cloneDeep } from 'lodash';
 import { onMounted, reactive, ref, unref } from 'vue';
+import { useI18n } from 'vue-i18n';
+import { useFormConfig } from '@/hooks/useFormConfig';
 import { api } from '../content.service';
+
+const { t } = useI18n();
+
+// 使用表单配置hooks
+const { formLabelWidth } = useFormConfig({ enWidth: '140px' });
 const emit = defineEmits(['modalCallBack']);
 const props = defineProps({
   modal: {
@@ -38,8 +48,8 @@ const form = reactive({
     pages: '',
   },
   rules: {
-    title: [{ required: true, message: '请填写消息标题', trigger: 'blur' }],
-    message: [{ required: true, message: '请填写消息内容', trigger: 'blur' }],
+    title: [{ required: true, message: t('modules.notification.messageTitleRequired'), trigger: 'blur' }],
+    message: [{ required: true, message: t('modules.notification.messageContentRequired'), trigger: 'blur' }],
   },
 });
 const loading = ref(false);

+ 31 - 23
src/app/shop/admin/content/notification/index.vue

@@ -8,10 +8,10 @@
         </sa-search-simple>
       </div>
       <div class="sa-title sa-flex sa-row-between">
-        <div class="label sa-flex">消息推送</div>
+        <div class="label sa-flex">{{ t('modules.notification.title') }}</div>
         <div>
           <el-button class="sa-button-refresh" icon="RefreshRight" @click="getData()"></el-button>
-          <el-button icon="Plus" type="primary" @click="addRow">新建</el-button>
+          <el-button icon="Plus" type="primary" @click="addRow">{{ t('modules.notification.create') }}</el-button>
         </div>
       </div>
     </el-header>
@@ -24,45 +24,48 @@
 
           <el-table-column prop="id" label="ID" min-width="100" sortable="custom">
           </el-table-column>
-          <el-table-column label="消息标题" min-width="150">
+          <el-table-column :label="t('modules.notification.messageTitle')" min-width="150">
             <template #default="scope">
               <span class="sa-table-line-1">
                 {{ scope.row.title || '-' }}
               </span>
             </template>
           </el-table-column>
-          <el-table-column label="消息内容" min-width="200">
+          <el-table-column :label="t('modules.notification.messageContent')" min-width="200">
             <template #default="scope">
               <span class="sa-table-line-2">
                 {{ scope.row.message || '-' }}
               </span>
             </template>
           </el-table-column>
-          <el-table-column label="页面路径" min-width="150">
+          <el-table-column :label="t('modules.notification.pagePath')" min-width="150">
             <template #default="scope">
               <span class="sa-table-line-1">
                 {{ scope.row.pages || '-' }}
               </span>
             </template>
           </el-table-column>
-          <el-table-column label="创建时间" min-width="160">
+          <el-table-column :label="t('modules.notification.createTime')" min-width="160">
             <template #default="scope">
               {{ scope.row.createTime || '-' }}
             </template>
           </el-table-column>
-          <el-table-column label="更新时间" min-width="160">
+          <el-table-column :label="t('modules.notification.updateTime')" min-width="160">
             <template #default="scope">
               {{ scope.row.updateTime || '-' }}
             </template>
           </el-table-column>
-          <el-table-column fixed="right" label="操作" min-width="180">
+          <el-table-column fixed="right" :label="t('modules.notification.actions')" min-width="180">
             <template #default="scope">
-              <el-button class="is-link" type="primary" @click="editRow(scope.row)">编辑</el-button>
-              <el-button class="is-link" type="success" @click="sendRow(scope.row)">发送</el-button>
-              <el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消" title="确认删除这条记录?"
+              <el-button class="is-link" type="primary" @click="editRow(scope.row)">{{ t('modules.notification.edit')
+              }}</el-button>
+              <el-button class="is-link" type="success" @click="sendRow(scope.row)">{{ t('modules.notification.send')
+              }}</el-button>
+              <el-popconfirm width="fit-content" :confirm-button-text="t('modules.notification.confirm')"
+                :cancel-button-text="t('modules.notification.cancel')" :title="t('modules.notification.confirmDelete')"
                 @confirm="deleteApi(scope.row.id)">
                 <template #reference>
-                  <el-button class="is-link" type="danger"> 删除 </el-button>
+                  <el-button class="is-link" type="danger">{{ t('modules.notification.delete') }}</el-button>
                 </template>
               </el-popconfirm>
             </template>
@@ -78,24 +81,27 @@
   </el-container>
 </template>
 <script setup>
-import { onMounted, reactive, ref } from 'vue';
+import { onMounted, reactive, ref, computed } from 'vue';
+import { useI18n } from 'vue-i18n';
 import { api } from '../content.service';
 import { ElMessage } from 'element-plus';
 import { useModal } from '@/sheep/hooks';
 import { usePagination } from '@/sheep/hooks';
 import notificationEdit from './edit.vue';
 import notificationSend from './send.vue';
+
+const { t } = useI18n();
 const { pageData } = usePagination();
 
-// 搜索字段配置
-const searchFields = reactive({
+// 搜索字段配置 - 使用计算属性以支持语言切换
+const searchFields = computed(() => ({
   title: {
     type: 'input',
-    label: '消息标题',
-    placeholder: '请输入消息标题',
+    label: t('modules.notification.messageTitle'),
+    placeholder: t('modules.notification.enterMessageTitle'),
     width: 200,
   },
-});
+}));
 // 默认搜索值
 const defaultSearchValues = reactive({
   title: '',
@@ -133,6 +139,7 @@ async function getData(page, searchParams = null) {
     }
   } catch (error) {
     console.error('获取数据失败:', error);
+    ElMessage.error(t('modules.notification.getDataFailed'));
     table.data = [];
   }
   loading.value = false;
@@ -147,7 +154,7 @@ function fieldFilter({ prop, order }) {
 function addRow() {
   useModal(
     notificationEdit,
-    { title: '新建消息', type: 'add' },
+    { title: t('modules.notification.createMessage'), type: 'add' },
     {
       confirm: () => {
         getData();
@@ -159,7 +166,7 @@ function editRow(row) {
   useModal(
     notificationEdit,
     {
-      title: '编辑消息',
+      title: t('modules.notification.editMessage'),
       type: 'edit',
       id: row.id,
     },
@@ -175,14 +182,14 @@ function sendRow(row) {
   useModal(
     notificationSend,
     {
-      title: '发送消息',
+      title: t('modules.notification.sendMessage'),
       id: row.id,
       templateData: row,
     },
     {
       confirm: () => {
         // 发送成功后可以刷新数据或显示提示
-        console.log('消息发送完成');
+        console.log(t('modules.notification.messageSendComplete'));
       },
     },
   );
@@ -192,11 +199,12 @@ async function deleteApi(id) {
   try {
     const { code } = await api.notification.delete(id);
     if (code == 200) {
-      ElMessage.success('删除成功');
+      ElMessage.success(t('modules.notification.deleteSuccess'));
       getData();
     }
   } catch (error) {
     console.error('删除失败:', error);
+    ElMessage.error(t('modules.notification.deleteFailed'));
   }
 }
 

+ 19 - 10
src/app/shop/admin/content/notification/send.vue

@@ -1,43 +1,51 @@
 <template>
   <el-container>
     <el-main>
-      <el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="120px">
-        <el-form-item label="消息标题">
+      <el-form :model="form.model" :rules="form.rules" ref="formRef" :label-width="formLabelWidth">
+        <el-form-item :label="t('modules.notification.messageTitle')">
           <el-input v-model="templateTitle" readonly />
         </el-form-item>
 
-        <el-form-item label="消息内容">
+        <el-form-item :label="t('modules.notification.messageContent')">
           <el-input v-model="templateMessage" type="textarea" :rows="3" readonly />
         </el-form-item>
 
-        <el-form-item label="页面路径" v-if="templatePages">
+        <el-form-item :label="t('modules.notification.pagePath')" v-if="templatePages">
           <el-input v-model="templatePages" readonly />
         </el-form-item>
 
-        <el-form-item label="接收用户" prop="uids">
+        <el-form-item :label="t('modules.notification.receivingUsers')" prop="uids">
           <el-button type="primary" @click="openUserSelect" plain>
             <el-icon>
               <Plus />
             </el-icon>
-            选择用户 ({{ form.model.uids.length }})
+            {{ t('modules.notification.selectUsers') }} ({{ form.model.uids.length }})
           </el-button>
         </el-form-item>
       </el-form>
     </el-main>
     <el-footer class="sa-footer--submit">
-      <el-button type="primary" @click="confirm" :loading="sending">发送消息</el-button>
+      <el-button type="primary" @click="confirm" :loading="sending">{{ sending ? t('modules.notification.sending') :
+        t('modules.notification.sendingMessage') }}</el-button>
     </el-footer>
   </el-container>
 </template>
 
 <script setup>
 import { reactive, ref, computed } from 'vue';
+import { useI18n } from 'vue-i18n';
+import { useFormConfig } from '@/hooks/useFormConfig';
 import { ElMessage } from 'element-plus';
 import { Plus } from '@element-plus/icons-vue';
 import { useModal } from '@/sheep/hooks';
 import { api } from '../content.service';
 import UserSelect from '@/app/shop/admin/user/list/select.vue';
 
+const { t } = useI18n();
+
+// 使用表单配置hooks
+const { formLabelWidth } = useFormConfig({ enWidth: '160px' });
+
 const emit = defineEmits(['modalCallBack']);
 const props = defineProps({
   modal: {
@@ -60,11 +68,11 @@ const form = reactive({
   },
   rules: {
     uids: [
-      { required: true, message: '请选择接收用户', trigger: 'blur' },
+      { required: true, message: t('modules.notification.selectUsersRequired'), trigger: 'blur' },
       {
         validator: (_, value, callback) => {
           if (!value || value.length === 0) {
-            callback(new Error('请选择至少一个用户'));
+            callback(new Error(t('modules.notification.selectAtLeastOneUser')));
           } else {
             callback();
           }
@@ -107,11 +115,12 @@ async function confirm() {
       });
 
       if (code == 200) {
-        ElMessage.success('消息发送成功');
+        ElMessage.success(t('modules.notification.sendSuccess'));
         emit('modalCallBack', { event: 'confirm' });
       }
     } catch (error) {
       console.error('发送失败:', error);
+      ElMessage.error(t('modules.notification.sendFailed'));
     }
     sending.value = false;
   });

+ 3 - 3
src/app/shop/admin/order/order.service.js

@@ -26,9 +26,9 @@ export const ORDER_STATUS = {
 
   // 拼团状态
   PINK_STATUS: {
-    1: { text: '未开奖', type: 'warning' },
-    2: { text: '已开奖', type: 'success' },
-    3: { text: '开奖失败', type: 'danger' },
+    1: { text: '未成团', type: 'warning' },
+    2: { text: '已成团', type: 'success' },
+    3: { text: '成团失败', type: 'danger' },
   },
 
   // 中奖状态

+ 472 - 483
src/app/shop/admin/order/order/detail.vue

@@ -5,13 +5,8 @@
       <div class="order-track sa-m-b-46">
         <h3 class="sa-m-b-20">订单轨迹</h3>
         <el-steps :active="getActiveStep()" align-center>
-          <el-step
-            v-for="(step, index) in orderSteps"
-            :key="index"
-            :title="step.title"
-            :description="step.description"
-            :status="step.status"
-          />
+          <el-step v-for="(step, index) in orderSteps" :key="index" :title="step.title" :description="step.description"
+            :status="step.status" />
         </el-steps>
       </div>
 
@@ -62,7 +57,7 @@
           <el-col :span="6">
             <div class="info-item">
               <span class="label">用户名:</span>
-              <span class="value">{{ state.orderDetail.realName || '--' }}</span>
+              <span class="value">{{ state.realName || '--' }}</span>
             </div>
           </el-col>
           <el-col :span="6">
@@ -119,7 +114,7 @@
               >取消</el-button
             >
           </template>
-          <template v-if="!memoForm.flag">
+<template v-if="!memoForm.flag">
             <div v-if="state.orderDetail.memo" class="sa-m-r-12">
               {{ state.orderDetail.memo }}
             </div>
@@ -131,26 +126,25 @@
               >{{ state.orderDetail.memo ? '修改' : '添加' }}备注</el-button
             >
           </template>
-        </div>
-        <div class="remark sa-m-t-12">
-          <span class="label">买家留言:</span>
-          <span class="value">{{ state.orderDetail.remark || '暂无留言' }}</span>
-        </div>
-      </div> -->
+</div>
+<div class="remark sa-m-t-12">
+  <span class="label">买家留言:</span>
+  <span class="value">{{ state.orderDetail.remark || '暂无留言' }}</span>
+</div>
+</div> -->
 
       <!-- 操作按钮 -->
       <div class="action-buttons sa-m-b-26">
         <!-- 取消订单按钮 - 只在待支付状态显示 -->
-        <el-button v-if="state.orderDetail.status === 1" type="warning" plain @click="onCancelOrder"
-          >取消订单</el-button
-        >
+        <el-button v-if="state.orderDetail.status === 1" type="warning" plain @click="onCancelOrder">取消订单</el-button>
         <!-- 立即发货按钮 - 待发货状态显示 -->
         <el-button type="primary" @click="onDispatch">立即发货测试</el-button>
-        <el-button type="primary" @click="onDispatch" v-if="state.orderDetail.status === 5"
-          >立即发货</el-button
-        >
-        <!-- 全部退款按钮 - 在已支付、待发货、待收货状态显示 -->
-        <el-button type="danger" plain @click="onRefund">全部退款</el-button>
+        <el-button type="primary" @click="onDispatch" v-if="state.orderDetail.status === 5">立即发货</el-button>
+        <!-- 全部退款按钮 - 订单状态已支付且拼团状态未成团时显示 -->
+        <el-button v-if="state.orderDetail.status === 3 && state.orderDetail.pinkStatus === 1" type="danger" plain
+          @click="onRefund">
+          退款
+        </el-button>
       </div>
       <!-- 商品信息 -->
       <div class="goods-content sa-m-b-16">
@@ -158,11 +152,7 @@
         <el-table class="sa-table" :data="state.orderDetail.orderInfoVO" stripe border>
           <el-table-column label="商品图片" width="100" align="center">
             <template #default="{ row }">
-              <el-image
-                :src="row.image"
-                style="width: 60px; height: 60px; border-radius: 4px"
-                fit="cover"
-              />
+              <el-image :src="row.image" style="width: 60px; height: 60px; border-radius: 4px" fit="cover" />
             </template>
           </el-table-column>
           <el-table-column label="商品名称" prop="productName" />
@@ -200,9 +190,7 @@
 
       <!-- 拼团信息 -->
       <div class="group-content" v-if="state.pinkList && state.pinkList.length > 0">
-        <div class="sa-title sa-m-b-10"
-          >拼团信息({{ state.pinkList[0]?.people || '未知' }}人团)</div
-        >
+        <div class="sa-title sa-m-b-10">拼团信息({{ state.pinkList[0]?.people || '未知' }}人团)</div>
         <el-table class="sa-table" :data="state.pinkList" stripe border>
           <el-table-column label="用户名" min-width="120" align="center">
             <template #default="{ row }">
@@ -242,445 +230,469 @@
   </el-container>
 </template>
 <script setup>
-  import { onMounted, reactive, ref, computed } from 'vue';
-  import { ElMessage, ElMessageBox } from 'element-plus';
-  import {
-    api,
-    getOrderStatusInfo,
-    getPinkStatusInfo,
-    getWinStatusInfo,
-    getPayTypeText,
-  } from '../order.service';
-  import { useModal } from '@/sheep/hooks';
-  import OrderDispatch from './dispatch.vue';
-  import OrderRefund from './refund.vue';
-  import UserDetail from '../../user/list/detail.vue';
-  import OrderDetailC from './detail.vue';
-
-  const emit = defineEmits(['modalCallBack']);
-  const props = defineProps(['modal']);
-
-  const state = reactive({
-    orderDetail: {}, // 订单详情
-    pinkList: [], // 拼团信息列表
-  });
-
-  // loading状态
-  const loading = ref(false);
-
-  // 订单步骤配置
-  const stepConfig = [
-    { key: 'create_order', title: '提交订单', waitText: '未提交' },
-    { key: 'payment', title: '付款', waitText: '未支付' },
-    { key: 'group_start', title: '开团', waitText: '未开团' },
-    { key: 'platform_ship', title: '平台发货', waitText: '未发货' },
-    { key: 'user_receive', title: '用户收货', waitText: '未收货' },
-  ];
-
-  // 计算订单步骤
-  const orderSteps = computed(() => {
-    const trackData = state.orderDetail.orderStatusVO || [];
-    const steps = [];
-
-    stepConfig.forEach((config, index) => {
-      const trackItem = trackData[index];
-
-      if (trackItem) {
-        // 有对应的轨迹数据,显示为已完成
-        steps.push({
-          title: config.title,
-          description: trackItem.createTime,
-          status: 'finish',
-        });
-      } else {
-        // 没有对应的轨迹数据,显示为等待状态
-        steps.push({
-          title: config.title,
-          description: config.waitText,
-          status: 'wait',
-        });
-      }
-    });
-
-    return steps;
-  });
-
-  // 备注表单
-  const memoForm = reactive({
-    flag: false,
-    data: '',
+import { onMounted, reactive, ref, computed } from 'vue';
+import { ElMessage, ElMessageBox } from 'element-plus';
+import {
+  api,
+  getOrderStatusInfo,
+  getPinkStatusInfo,
+  getWinStatusInfo,
+  getPayTypeText,
+} from '../order.service';
+import { useModal } from '@/sheep/hooks';
+import OrderDispatch from './dispatch.vue';
+import OrderRefund from './refund.vue';
+import UserDetail from '../../user/list/detail.vue';
+import OrderDetailC from './detail.vue';
+
+const emit = defineEmits(['modalCallBack']);
+const props = defineProps(['modal']);
+
+const state = reactive({
+  orderDetail: {}, // 订单详情
+  pinkList: [], // 拼团信息列表
+});
+
+// loading状态
+const loading = ref(false);
+
+// 订单步骤配置
+const stepConfig = [
+  { key: 'create_order', title: '提交订单', waitText: '未提交' },
+  { key: 'payment', title: '付款', waitText: '未支付' },
+  { key: 'group_start', title: '开团', waitText: '未开团' },
+  { key: 'platform_ship', title: '平台发货', waitText: '未发货' },
+  { key: 'user_receive', title: '用户收货', waitText: '未收货' },
+];
+
+// 计算订单步骤
+const orderSteps = computed(() => {
+  const trackData = state.orderDetail.orderStatusVO || [];
+  const steps = [];
+
+  stepConfig.forEach((config, index) => {
+    const trackItem = trackData[index];
+
+    if (trackItem) {
+      // 有对应的轨迹数据,显示为已完成
+      steps.push({
+        title: config.title,
+        description: trackItem.createTime,
+        status: 'finish',
+      });
+    } else {
+      // 没有对应的轨迹数据,显示为等待状态
+      steps.push({
+        title: config.title,
+        description: config.waitText,
+        status: 'wait',
+      });
+    }
   });
 
-  // 获取订单详情
-  async function getOrderDetail() {
-    try {
-      loading.value = true;
-      const { code, data } = await api.order.detail(props.modal.params.id);
-      if (code == 200) {
-        state.orderDetail = data;
-        // 获取拼团信息
-        await getPinkList(data.id);
-      }
-    } catch (error) {
-      console.error('获取订单详情失败:', error);
-      ElMessage.error('获取订单详情失败');
-    } finally {
-      loading.value = false;
+  return steps;
+});
+
+// 备注表单
+const memoForm = reactive({
+  flag: false,
+  data: '',
+});
+
+// 获取订单详情
+async function getOrderDetail() {
+  try {
+    loading.value = true;
+    const { code, data } = await api.order.detail(props.modal.params.id);
+    if (code == 200) {
+      state.orderDetail = data;
+      // 获取拼团信息
+      await getPinkList(data.id);
     }
+  } catch (error) {
+    console.error('获取订单详情失败:', error);
+    ElMessage.error('获取订单详情失败');
+  } finally {
+    loading.value = false;
   }
-
-  // 获取拼团信息
-  async function getPinkList(orderId) {
-    if (!orderId) return;
-    try {
-      const { code, data } = await api.order.getPinkList(orderId);
-      if (code == 200) {
-        state.pinkList = data || [];
-      }
-    } catch (error) {
-      console.error('获取拼团信息失败:', error);
-      state.pinkList = [];
+}
+
+// 获取拼团信息
+async function getPinkList(orderId) {
+  if (!orderId) return;
+  try {
+    const { code, data } = await api.order.getPinkList(orderId);
+    if (code == 200) {
+      state.pinkList = data || [];
     }
+  } catch (error) {
+    console.error('获取拼团信息失败:', error);
+    state.pinkList = [];
   }
-
-  // 获取激活步骤
-  function getActiveStep() {
-    const trackData = state.orderDetail.orderStatusVO || [];
-    // 返回已完成步骤的数量减1(因为 el-steps 的 active 是从0开始的索引)
-    return Math.max(0, trackData.length - 1);
-  }
-
-  // 通用状态处理函数
-  const getStatusText = (type, value) => {
-    const statusMap = {
-      order: getOrderStatusInfo,
-      pink: getPinkStatusInfo,
-      win: getWinStatusInfo,
-    };
-    return statusMap[type]?.(value)?.text || '未知';
+}
+
+// 获取激活步骤
+function getActiveStep() {
+  const trackData = state.orderDetail.orderStatusVO || [];
+  // 返回已完成步骤的数量减1(因为 el-steps 的 active 是从0开始的索引)
+  return Math.max(0, trackData.length - 1);
+}
+
+// 通用状态处理函数
+const getStatusText = (type, value) => {
+  const statusMap = {
+    order: getOrderStatusInfo,
+    pink: getPinkStatusInfo,
+    win: getWinStatusInfo,
   };
-
-  const getStatusType = (type, value) => {
-    const statusMap = {
-      order: getOrderStatusInfo,
-      pink: getPinkStatusInfo,
-      win: getWinStatusInfo,
-    };
-    return statusMap[type]?.(value)?.type || 'info';
+  return statusMap[type]?.(value)?.text || '未知';
+};
+
+const getStatusType = (type, value) => {
+  const statusMap = {
+    order: getOrderStatusInfo,
+    pink: getPinkStatusInfo,
+    win: getWinStatusInfo,
   };
-
-  // 拼接完整地址
-  function getFullAddress(addressInfo) {
-    if (!addressInfo) return '--';
-
-    const parts = [];
-    if (addressInfo.province) parts.push(addressInfo.province);
-    if (addressInfo.city) parts.push(addressInfo.city);
-    if (addressInfo.district) parts.push(addressInfo.district);
-    if (addressInfo.detail) parts.push(addressInfo.detail);
-    if (addressInfo.postCode) parts.push(addressInfo.postCode);
-
-    return parts.length > 0 ? parts.join('') : '--';
+  return statusMap[type]?.(value)?.type || 'info';
+};
+
+// 拼接完整地址
+function getFullAddress(addressInfo) {
+  if (!addressInfo) return '--';
+
+  const parts = [];
+  if (addressInfo.province) parts.push(addressInfo.province);
+  if (addressInfo.city) parts.push(addressInfo.city);
+  if (addressInfo.district) parts.push(addressInfo.district);
+  if (addressInfo.detail) parts.push(addressInfo.detail);
+  if (addressInfo.postCode) parts.push(addressInfo.postCode);
+
+  return parts.length > 0 ? parts.join('') : '--';
+}
+
+// 打开用户详情
+function openUserDetail(uid) {
+  if (!uid) {
+    ElMessage.warning('用户ID不存在');
+    return;
   }
 
-  // 打开用户详情
-  function openUserDetail(uid) {
-    if (!uid) {
-      ElMessage.warning('用户ID不存在');
-      return;
-    }
-
-    useModal(
-      UserDetail,
-      {
-        title: '用户详情',
-        id: uid,
+  useModal(
+    UserDetail,
+    {
+      title: '用户详情',
+      id: uid,
+    },
+    {
+      success: () => {
+        // 用户详情关闭后的回调,如果需要的话
       },
-      {
-        success: () => {
-          // 用户详情关闭后的回调,如果需要的话
-        },
-      },
-    );
-  }
-
-  // 取消订单
-  async function onCancelOrder() {
-    try {
-      await ElMessageBox.confirm('确定要取消这个订单吗?', '提示', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning',
-      });
+    },
+  );
+}
+
+// 取消订单
+async function onCancelOrder() {
+  try {
+    await ElMessageBox.confirm('确定要取消这个订单吗?', '提示', {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning',
+    });
 
-      const { code, message } = await api.order.cancel(String(state.orderDetail.id));
-      if (code == 200) {
-        ElMessage.success('订单取消成功');
+    const { code, message } = await api.order.cancel(String(state.orderDetail.id));
+    if (code == 200) {
+      ElMessage.success('订单取消成功');
+      getOrderDetail(); // 刷新订单详情
+    } else {
+      ElMessage.error(message || '取消订单失败');
+    }
+  } catch (error) { }
+}
+
+// 立即发货
+function onDispatch() {
+  useModal(
+    OrderDispatch,
+    {
+      title: '订单发货',
+      data: state.orderDetail,
+    },
+    {
+      success: () => {
         getOrderDetail(); // 刷新订单详情
-      } else {
-        ElMessage.error(message || '取消订单失败');
-      }
-    } catch (error) {}
-  }
-
-  // 立即发货
-  function onDispatch() {
-    useModal(
-      OrderDispatch,
-      {
-        title: '订单发货',
-        data: state.orderDetail,
-      },
-      {
-        success: () => {
-          getOrderDetail(); // 刷新订单详情
-        },
       },
-    );
-  }
-
-  // 全部退款
-  async function onRefund() {
-    try {
-      await ElMessageBox.confirm('确定要对这个订单进行全部退款吗?', '提示', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning',
-      });
-
-      const { code, message } = await api.order.refund(String(state.orderDetail.id));
-      if (code == 200) {
-        ElMessage.success('退款提交成功');
-        getOrderDetail(); // 刷新订单详情
-      } else {
-        ElMessage.error(message || '退款申请失败');
-      }
-    } catch (error) {}
-  }
-
-  // 打开订单详情
-  function openOrderDetail(orderId) {
-    if (!orderId) {
-      ElMessage.warning('订单ID不存在');
-      return;
-    }
+    },
+  );
+}
+
+// 全部退款
+async function onRefund() {
+  try {
+    await ElMessageBox.confirm('确定要对这个订单进行全部退款吗?', '提示', {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning',
+    });
 
-    // 如果是当前订单,不需要打开新窗口
-    if (orderId === state.orderDetail.orderId) {
-      ElMessage.info('这是当前订单');
-      return;
+    const { code, message } = await api.order.refund(String(state.orderDetail.id));
+    if (code == 200) {
+      ElMessage.success('退款提交成功');
+      getOrderDetail(); // 刷新订单详情
+    } else {
+      ElMessage.error(message || '退款申请失败');
     }
-
-    // 需要先根据订单号查找订单ID,然后打开订单详情
-    // 这里假设需要调用接口根据订单号获取订单ID
-    openOrderDetailByOrderId(orderId);
+  } catch (error) { }
+}
+
+// 打开订单详情
+function openOrderDetail(orderId) {
+  if (!orderId) {
+    ElMessage.warning('订单ID不存在');
+    return;
   }
 
-  // 根据订单号打开订单详情
-  async function openOrderDetailByOrderId(orderId) {
-    try {
-      // 这里需要根据实际情况调用接口获取订单ID
-      // 暂时直接使用订单号作为ID打开
-      useModal(
-        OrderDetailC,
-        {
-          title: '订单详情',
-          type: 'detail',
-          id: orderId, // 这里可能需要转换为数据库ID
-        },
-        {
-          success: () => {
-            // 订单详情关闭后的回调
-          },
-        },
-      );
-    } catch (error) {
-      console.error('打开订单详情失败:', error);
-      ElMessage.error('打开订单详情失败');
-    }
+  // 如果是当前订单,不需要打开新窗口
+  if (orderId === state.orderDetail.orderId) {
+    ElMessage.info('这是当前订单');
+    return;
   }
 
-  // 发货
-  function onOpenDispatch() {
-    // 检查订单数据是否完整
-    if (!state.orderDetail || !state.orderDetail.orderInfoVO) {
-      ElMessage.error('订单数据加载中,请稍后再试');
-      return;
-    }
+  // 需要先根据订单号查找订单ID,然后打开订单详情
+  // 这里假设需要调用接口根据订单号获取订单ID
+  openOrderDetailByOrderId(orderId);
+}
 
+// 根据订单号打开订单详情
+async function openOrderDetailByOrderId(orderId) {
+  try {
+    // 这里需要根据实际情况调用接口获取订单ID
+    // 暂时直接使用订单号作为ID打开
     useModal(
-      OrderDispatch,
+      OrderDetailC,
       {
-        title: '订单发货',
-        data: state.orderDetail,
+        title: '订单详情',
+        type: 'detail',
+        id: orderId, // 这里可能需要转换为数据库ID
       },
       {
         success: () => {
-          getOrderDetail();
+          // 订单详情关闭后的回调
         },
       },
     );
+  } catch (error) {
+    console.error('打开订单详情失败:', error);
+    ElMessage.error('打开订单详情失败');
+  }
+}
+
+// 发货
+function onOpenDispatch() {
+  // 检查订单数据是否完整
+  if (!state.orderDetail || !state.orderDetail.orderInfoVO) {
+    ElMessage.error('订单数据加载中,请稍后再试');
+    return;
   }
 
-  // 退款
-  function onOpenRefund() {
-    useModal(
-      OrderRefund,
-      {
-        title: '订单退款',
-        width: '600px',
-        params: {
-          id: state.orderDetail.id,
-        },
+  useModal(
+    OrderDispatch,
+    {
+      title: '订单发货',
+      data: state.orderDetail,
+    },
+    {
+      success: () => {
+        getOrderDetail();
       },
-      {
-        success: () => {
-          getOrderDetail();
-        },
+    },
+  );
+}
+
+// 退款
+function onOpenRefund() {
+  useModal(
+    OrderRefund,
+    {
+      title: '订单退款',
+      width: '600px',
+      params: {
+        id: state.orderDetail.id,
       },
-    );
-  }
-
-  // 联系用户
-  async function onContactUser() {
-    try {
-      const { code } = await api.order.contact(state.orderDetail.id);
-      if (code == 200) {
-        ElMessage.success('已发送联系信息');
-      }
-    } catch (err) {
-      ElMessage.error('联系用户失败');
+    },
+    {
+      success: () => {
+        getOrderDetail();
+      },
+    },
+  );
+}
+
+// 联系用户
+async function onContactUser() {
+  try {
+    const { code } = await api.order.contact(state.orderDetail.id);
+    if (code == 200) {
+      ElMessage.success('已发送联系信息');
     }
+  } catch (err) {
+    ElMessage.error('联系用户失败');
   }
-
-  // 导出订单
-  async function onExportOrder() {
-    try {
-      const { code, data } = await api.order.export(state.orderDetail.id);
-      if (code == 200) {
-        ElMessage.success('导出成功');
-        if (data.download_url) {
-          window.open(data.download_url);
-        }
+}
+
+// 导出订单
+async function onExportOrder() {
+  try {
+    const { code, data } = await api.order.export(state.orderDetail.id);
+    if (code == 200) {
+      ElMessage.success('导出成功');
+      if (data.download_url) {
+        window.open(data.download_url);
       }
-    } catch (err) {
-      ElMessage.error('导出订单失败');
     }
+  } catch (err) {
+    ElMessage.error('导出订单失败');
   }
-
-  // 关闭订单
-  async function onCloseOrder() {
-    try {
-      const { code } = await api.order.close(state.orderDetail.id);
-      if (code == 200) {
-        ElMessage.success('订单已关闭');
-        getOrderDetail();
-      }
-    } catch (err) {
-      ElMessage.error('关闭订单失败');
+}
+
+// 关闭订单
+async function onCloseOrder() {
+  try {
+    const { code } = await api.order.close(state.orderDetail.id);
+    if (code == 200) {
+      ElMessage.success('订单已关闭');
+      getOrderDetail();
     }
+  } catch (err) {
+    ElMessage.error('关闭订单失败');
   }
-
-  // 修改备注标志
-  function onChangeMemoFlag(memo) {
-    memoForm.flag = true;
-    memoForm.data = memo || '';
-  }
-
-  // 确认备注
-  async function onConfirmMemo() {
-    try {
-      const { code } = await api.order.editMemo(state.orderDetail.id, { memo: memoForm.data });
-      if (code == 200) {
-        ElMessage.success('备注更新成功');
-        memoForm.flag = false;
-        getOrderDetail();
-      }
-    } catch (err) {
-      ElMessage.error('备注更新失败');
+}
+
+// 修改备注标志
+function onChangeMemoFlag(memo) {
+  memoForm.flag = true;
+  memoForm.data = memo || '';
+}
+
+// 确认备注
+async function onConfirmMemo() {
+  try {
+    const { code } = await api.order.editMemo(state.orderDetail.id, { memo: memoForm.data });
+    if (code == 200) {
+      ElMessage.success('备注更新成功');
+      memoForm.flag = false;
+      getOrderDetail();
     }
+  } catch (err) {
+    ElMessage.error('备注更新失败');
   }
+}
 
-  onMounted(() => {
-    getOrderDetail();
-  });
+onMounted(() => {
+  getOrderDetail();
+});
 </script>
 
 <style lang="scss" scoped>
-  .order-detail {
-    padding: 20px;
-    .order-track {
-      h3 {
-        font-size: 16px;
-        font-weight: 600;
-        color: var(--sa-title);
-      }
+.order-detail {
+  padding: 20px;
+
+  .order-track {
+    h3 {
+      font-size: 16px;
+      font-weight: 600;
+      color: var(--sa-title);
     }
+  }
 
-    .basic-info {
-      h3 {
-        font-size: 16px;
-        font-weight: 600;
-        color: var(--sa-title);
-      }
+  .basic-info {
+    h3 {
+      font-size: 16px;
+      font-weight: 600;
+      color: var(--sa-title);
+    }
 
-      .info-item {
-        display: flex;
-        align-items: center;
-        margin-bottom: 8px;
+    .info-item {
+      display: flex;
+      align-items: center;
+      margin-bottom: 8px;
 
-        .label {
-          flex-shrink: 0;
-          color: var(--sa-subfont);
-          font-size: 14px;
-        }
+      .label {
+        flex-shrink: 0;
+        color: var(--sa-subfont);
+        font-size: 14px;
+      }
 
-        .value {
-          color: var(--sa-subtitle);
-          font-size: 14px;
-          font-weight: 500;
-        }
+      .value {
+        color: var(--sa-subtitle);
+        font-size: 14px;
+        font-weight: 500;
       }
     }
+  }
 
-    .action-buttons {
-      .el-button {
-        margin-right: 12px;
-      }
+  .action-buttons {
+    .el-button {
+      margin-right: 12px;
+    }
+  }
+
+  .goods-content,
+  .address-content,
+  .group-content,
+  .memo-info {
+    .sa-title {
+      font-size: 16px;
+      font-weight: 600;
+      color: var(--sa-title);
     }
 
-    .goods-content,
-    .address-content,
-    .group-content,
-    .memo-info {
-      .sa-title {
-        font-size: 16px;
-        font-weight: 600;
-        color: var(--sa-title);
-      }
+    .sa-table {
+      border-radius: 8px;
+      overflow: hidden;
+      border: 1px solid #dcdfe6;
 
-      .sa-table {
-        border-radius: 8px;
-        overflow: hidden;
-        border: 1px solid #dcdfe6;
+      :deep(.el-table) {
+        border: none;
+        border-radius: 0;
+      }
 
-        :deep(.el-table) {
-          border: none;
-          border-radius: 0;
-        }
+      :deep(.el-table__header-wrapper) {
+        background: var(--sa-table-header-bg, #f5f7fa);
 
-        :deep(.el-table__header-wrapper) {
+        .el-table__header {
           background: var(--sa-table-header-bg, #f5f7fa);
 
-          .el-table__header {
-            background: var(--sa-table-header-bg, #f5f7fa);
+          th {
+            background: var(--sa-table-header-bg, #f5f7fa) !important;
+            font-weight: 600;
+            color: var(--sa-title, #303133);
+            border-bottom: 1px solid #dcdfe6;
+            border-right: 1px solid #dcdfe6;
 
-            th {
-              background: var(--sa-table-header-bg, #f5f7fa) !important;
-              font-weight: 600;
-              color: var(--sa-title, #303133);
+            &:first-child {
+              border-left: none;
+            }
+
+            &:last-child {
+              border-right: none;
+            }
+          }
+        }
+      }
+
+      :deep(.el-table__body-wrapper) {
+        .el-table__body {
+          tr {
+            &:hover {
+              background: #f5f7fa !important;
+            }
+
+            td {
               border-bottom: 1px solid #dcdfe6;
               border-right: 1px solid #dcdfe6;
+              border-left: none;
 
               &:first-child {
                 border-left: none;
@@ -690,109 +702,86 @@
                 border-right: none;
               }
             }
-          }
-        }
-
-        :deep(.el-table__body-wrapper) {
-          .el-table__body {
-            tr {
-              &:hover {
-                background: #f5f7fa !important;
-              }
 
-              td {
-                border-bottom: 1px solid #dcdfe6;
-                border-right: 1px solid #dcdfe6;
-                border-left: none;
-
-                &:first-child {
-                  border-left: none;
-                }
-
-                &:last-child {
-                  border-right: none;
-                }
-              }
-
-              &:last-child td {
-                border-bottom: none;
-              }
+            &:last-child td {
+              border-bottom: none;
             }
           }
         }
+      }
 
-        // 确保边框完整性
-        :deep(.el-table--border) {
-          border: none;
-
-          &::after {
-            display: none;
-          }
+      // 确保边框完整性
+      :deep(.el-table--border) {
+        border: none;
 
-          &::before {
-            display: none;
-          }
+        &::after {
+          display: none;
         }
 
-        :deep(.el-table--border .el-table__cell) {
-          border-right: 1px solid #dcdfe6;
-          border-left: none;
-
-          &:first-child {
-            border-left: none;
-          }
-
-          &:last-child {
-            border-right: none;
-          }
+        &::before {
+          display: none;
         }
+      }
 
-        // 修复表格底部和左侧边框
-        :deep(.el-table__body) {
+      :deep(.el-table--border .el-table__cell) {
+        border-right: 1px solid #dcdfe6;
+        border-left: none;
+
+        &:first-child {
           border-left: none;
-          border-bottom: none;
         }
 
-        :deep(.el-table__header) {
-          border-left: none;
+        &:last-child {
+          border-right: none;
         }
       }
+
+      // 修复表格底部和左侧边框
+      :deep(.el-table__body) {
+        border-left: none;
+        border-bottom: none;
+      }
+
+      :deep(.el-table__header) {
+        border-left: none;
+      }
     }
+  }
 
-    .group-content {
-      .sa-table {
-        width: 100% !important;
+  .group-content {
+    .sa-table {
+      width: 100% !important;
 
-        :deep(.el-table) {
-          width: 100% !important;
-        }
+      :deep(.el-table) {
+        width: 100% !important;
+      }
 
-        :deep(.el-table__header-wrapper) {
-          width: 100% !important;
-        }
+      :deep(.el-table__header-wrapper) {
+        width: 100% !important;
+      }
 
-        :deep(.el-table__body-wrapper) {
-          width: 100% !important;
-        }
+      :deep(.el-table__body-wrapper) {
+        width: 100% !important;
       }
     }
+  }
 
-    .memo-info {
-      .memo {
-        margin-bottom: 12px;
-      }
+  .memo-info {
+    .memo {
+      margin-bottom: 12px;
+    }
 
-      .remark {
-        .label {
-          color: var(--sa-subfont);
-          font-size: 14px;
-        }
+    .remark {
+      .label {
+        color: var(--sa-subfont);
+        font-size: 14px;
+      }
 
-        .value {
-          color: var(--sa-subtitle);
-          font-size: 14px;
-        }
+      .value {
+        color: var(--sa-subtitle);
+        font-size: 14px;
       }
     }
   }
+}
 </style>

+ 23 - 18
src/app/shop/admin/user/list/select.vue

@@ -12,8 +12,8 @@
             <sa-empty />
           </template>
           <el-table-column v-if="modal.params.multiple" type="selection" width="48"></el-table-column>
-          <el-table-column prop="id" label="用户ID" align="center" width="80" />
-          <el-table-column label="用户信息" min-width="200">
+          <el-table-column prop="id" :label="t('modules.userSelect.userId')" align="center" width="80" />
+          <el-table-column :label="t('modules.userSelect.userInfo')" min-width="200">
             <template #default="scope">
               <div class="user-info">
                 <el-avatar :src="scope.row.headPic" :size="40">
@@ -22,28 +22,29 @@
                   </el-icon>
                 </el-avatar>
                 <div class="user-details">
-                  <div class="user-name">{{ scope.row.nickname || scope.row.name || '未设置昵称' }}</div>
-                  <div class="user-phone">{{ scope.row.phoneNo || '未绑定手机' }}</div>
+                  <div class="user-name">{{ scope.row.nickname || scope.row.name || t('modules.userSelect.noNickname')
+                  }}</div>
+                  <div class="user-phone">{{ scope.row.phoneNo || t('modules.userSelect.noPhone') }}</div>
                 </div>
               </div>
             </template>
           </el-table-column>
-          <el-table-column label="注册时间" align="center">
+          <el-table-column :label="t('modules.userSelect.registerTime')" align="center">
             <template #default="scope">
               {{ scope.row.createTime || '-' }}
             </template>
           </el-table-column>
-          <el-table-column label="状态" align="center" width="100">
+          <el-table-column :label="t('modules.userSelect.status')" align="center" width="100">
             <template #default="scope">
               <el-tag :type="scope.row.status === 1 ? 'success' : 'danger'">
-                {{ scope.row.status === 1 ? '正常' : '禁用' }}
+                {{ scope.row.status === 1 ? t('modules.userSelect.normal') : t('modules.userSelect.disabled') }}
               </el-tag>
             </template>
           </el-table-column>
-          <el-table-column v-if="!modal.params.multiple" label="操作" width="80">
+          <el-table-column v-if="!modal.params.multiple" :label="t('modules.userSelect.actions')" width="80">
             <template #default="scope">
               <el-button link type="primary" @click="singleSelect(scope.row)">
-                选择
+                {{ t('modules.userSelect.select') }}
               </el-button>
             </template>
           </el-table-column>
@@ -52,7 +53,7 @@
       <el-footer class="sa-footer--submit" :class="modal.params.multiple ? 'sa-row-between' : 'sa-row-right'">
         <sa-pagination :pageData="pageData" layout="total, prev, pager, next" @updateFn="getData" />
         <el-button v-if="modal.params.multiple" type="primary" @click="confirm">
-          确认选择
+          {{ t('modules.userSelect.confirmSelect') }}
         </el-button>
       </el-footer>
     </el-container>
@@ -60,32 +61,35 @@
 </template>
 
 <script setup>
-import { nextTick, onMounted, reactive, ref } from 'vue';
+import { nextTick, onMounted, reactive, ref, computed } from 'vue';
+import { useI18n } from 'vue-i18n';
 import { User } from '@element-plus/icons-vue';
 import { ElMessage } from 'element-plus';
 import { usePagination } from '@/sheep/hooks';
 import { api } from '../user.service';
 
+const { t } = useI18n();
+
 const { pageData } = usePagination();
 
 const emit = defineEmits(['modalCallBack']);
 const props = defineProps(['modal']);
 
-// 搜索字段配置
-const searchFields = reactive({
+// 搜索字段配置 - 使用计算属性以支持语言切换
+const searchFields = computed(() => ({
   name: {
     type: 'input',
-    label: '用户账号',
-    placeholder: '请输入用户账号',
+    label: t('modules.userSelect.userAccount'),
+    placeholder: t('modules.userSelect.enterUserAccount'),
     width: 150,
   },
   phone: {
     type: 'input',
-    label: '用户手机',
-    placeholder: '请输入手机号',
+    label: t('modules.userSelect.userPhone'),
+    placeholder: t('modules.userSelect.enterPhoneNumber'),
     width: 150,
   },
-});
+}));
 
 // 默认搜索值
 const defaultSearchValues = reactive({
@@ -132,6 +136,7 @@ async function getData(page, searchParams = {}) {
     }
   } catch (error) {
     console.error('获取用户列表失败:', error);
+    ElMessage.error(t('modules.userSelect.getUserListFailed'));
     table.list = [];
   } finally {
     loading.value = false;

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

@@ -1121,7 +1121,69 @@
       "smsTemplate": "SMS Template",
       "smsRecord": "SMS Record",
       "smsContent": "SMS Content",
-      "smsStatus": "SMS Status",
+      "smsStatus": "SMS Status"
+    },
+    "notification": {
+      "title": "Message Push",
+      "messageTitle": "Message Title",
+      "messageContent": "Message Content",
+      "pagePath": "Page Path",
+      "createTime": "Create Time",
+      "updateTime": "Update Time",
+      "actions": "Actions",
+      "edit": "Edit",
+      "send": "Send",
+      "delete": "Delete",
+      "create": "Create",
+      "createMessage": "Create Message",
+      "editMessage": "Edit Message",
+      "sendMessage": "Send Message",
+      "save": "Save",
+      "update": "Update",
+      "loading": "Loading...",
+      "enterMessageTitle": "Please enter message title",
+      "enterMessageContent": "Please enter message content",
+      "enterPagePath": "Please enter page path (optional)",
+      "messageTitleRequired": "Please enter message title",
+      "messageContentRequired": "Please enter message content",
+      "confirmDelete": "Are you sure you want to delete this record?",
+      "confirm": "Confirm",
+      "cancel": "Cancel",
+      "deleteSuccess": "Delete successful",
+      "sendSuccess": "Message sent successfully",
+      "selectUsers": "Select Users",
+      "selectUsersPlaceholder": "Select Users",
+      "selectUsersRequired": "Please select receiving users",
+      "selectAtLeastOneUser": "Please select at least one user",
+      "receivingUsers": "Receiving Users",
+      "sendingMessage": "Send Message",
+      "sending": "Sending...",
+      "messageSendComplete": "Message sending completed",
+      "getDetailFailed": "Failed to get details",
+      "submitFailed": "Submit failed",
+      "sendFailed": "Send failed",
+      "deleteFailed": "Delete failed",
+      "getDataFailed": "Failed to get data"
+    },
+    "userSelect": {
+      "userAccount": "User Account",
+      "userPhone": "User Phone",
+      "enterUserAccount": "Please enter user account",
+      "enterPhoneNumber": "Please enter phone number",
+      "userId": "User ID",
+      "userInfo": "User Info",
+      "registerTime": "Register Time",
+      "status": "Status",
+      "actions": "Actions",
+      "select": "Select",
+      "confirmSelect": "Confirm Selection",
+      "normal": "Normal",
+      "disabled": "Disabled",
+      "noNickname": "No nickname set",
+      "noPhone": "No phone bound",
+      "getUserListFailed": "Failed to get user list"
+    },
+    "report": {
       "dataReport": "Data Report",
       "salesReport": "Sales Report",
       "userReport": "User Report",

+ 63 - 1
src/locales/zh-CN/index.json

@@ -1123,7 +1123,69 @@
       "smsTemplate": "短信模板",
       "smsRecord": "短信记录",
       "smsContent": "短信内容",
-      "smsStatus": "发送状态",
+      "smsStatus": "发送状态"
+    },
+    "notification": {
+      "title": "消息推送",
+      "messageTitle": "消息标题",
+      "messageContent": "消息内容",
+      "pagePath": "页面路径",
+      "createTime": "创建时间",
+      "updateTime": "更新时间",
+      "actions": "操作",
+      "edit": "编辑",
+      "send": "发送",
+      "delete": "删除",
+      "create": "新建",
+      "createMessage": "新建消息",
+      "editMessage": "编辑消息",
+      "sendMessage": "发送消息",
+      "save": "保存",
+      "update": "更新",
+      "loading": "加载中...",
+      "enterMessageTitle": "请输入消息标题",
+      "enterMessageContent": "请填写消息内容",
+      "enterPagePath": "请填写页面路径(可选)",
+      "messageTitleRequired": "请填写消息标题",
+      "messageContentRequired": "请填写消息内容",
+      "confirmDelete": "确认删除这条记录?",
+      "confirm": "确认",
+      "cancel": "取消",
+      "deleteSuccess": "删除成功",
+      "sendSuccess": "消息发送成功",
+      "selectUsers": "选择用户",
+      "selectUsersPlaceholder": "选择用户",
+      "selectUsersRequired": "请选择接收用户",
+      "selectAtLeastOneUser": "请选择至少一个用户",
+      "receivingUsers": "接收用户",
+      "sendingMessage": "发送消息",
+      "sending": "发送中...",
+      "messageSendComplete": "消息发送完成",
+      "getDetailFailed": "获取详情失败",
+      "submitFailed": "提交失败",
+      "sendFailed": "发送失败",
+      "deleteFailed": "删除失败",
+      "getDataFailed": "获取数据失败"
+    },
+    "userSelect": {
+      "userAccount": "用户账号",
+      "userPhone": "用户手机",
+      "enterUserAccount": "请输入用户账号",
+      "enterPhoneNumber": "请输入手机号",
+      "userId": "用户ID",
+      "userInfo": "用户信息",
+      "registerTime": "注册时间",
+      "status": "状态",
+      "actions": "操作",
+      "select": "选择",
+      "confirmSelect": "确认选择",
+      "normal": "正常",
+      "disabled": "禁用",
+      "noNickname": "未设置昵称",
+      "noPhone": "未绑定手机",
+      "getUserListFailed": "获取用户列表失败"
+    },
+    "report": {
       "dataReport": "数据报表",
       "salesReport": "销售报表",
       "userReport": "用户报表",