Sfoglia il codice sorgente

feat: 交付伙伴弹窗接口对接完成,页面多语言完成,优化MD5引入方式

lixuan 4 settimane fa
parent
commit
5a342b2290

+ 17 - 7
apps/web-velofex/src/api/core/user.ts

@@ -616,11 +616,11 @@ export async function addUserToApplicationApi(
  */
 export async function deleteUserFromApplicationApi(
   userId: string,
-  enterprise_code: string[],
+  enterpriseIdList: string[],
 ) {
   return requestClient.post<UserApi.AssociateUserResult>(
     '/api/user/doDeleteUserEnterprise',
-    { userId, enterprise_code },
+    { userId, enterpriseIdList },
   );
 }
 
@@ -702,11 +702,21 @@ export async function getAssociatedProjectsApi(userId: string) {
 /**
  * 添加项目到用户
  */
-export async function addProjectToUserApi(projectId: string, userId: string) {
-  return requestClient.post<UserApi.UserResult>('/api/user/addProject', {
-    projectId,
-    userId,
-  });
+export async function addProjectToUserApi(
+  enterpriseIdList: string[],
+  userId: string,
+  roleTypes?: string,
+  expiredTime?: string,
+) {
+  return requestClient.post<UserApi.UserResult>(
+    '/api/user/doAddUserEnterprise',
+    {
+      enterpriseIdList,
+      userId,
+      roleTypes,
+      expiredTime,
+    },
+  );
 }
 
 /**

+ 1 - 1
apps/web-velofex/src/components/login/login.vue

@@ -8,7 +8,7 @@ import { useAccessStore, useUserStore } from '@vben/stores';
 
 import { $t } from '@/locales';
 import { message } from 'antdv-next';
-import MD5 from 'crypto-js/md5';
+import { MD5 } from 'crypto-js/md5';
 
 import {
   createAccountApi,

+ 60 - 0
apps/web-velofex/src/locales/langs/en-US/page.json

@@ -224,5 +224,65 @@
       "save": "Save",
       "cancel": "Cancel"
     }
+  },
+  "deliveryPartners": {
+    "breadcrumb": "Dashboard / Delivery Partners",
+    "account": "Account:",
+    "name": "Name:",
+    "expiredTime": "Valid Until:",
+    "cellPhone": "Bound Phone:",
+    "emailAddress": "Email:",
+    "accessId": "User Key:",
+    "status": "Status:",
+    "action": "Action:",
+    "loading": "Loading...",
+    "edit": "Edit",
+    "resetPassword": "Reset Password",
+    "delete": "Delete",
+    "deleteConfirm": "Are you sure to delete this user?",
+    "deleteDescription": "Cannot be recovered after deletion",
+    "deleteSuccess": "Delete successfully!",
+    "saveSuccess": "Save successfully!",
+    "addProjectSuccess": "Project added successfully!",
+    "deleteProjectSuccess": "Project deleted successfully!",
+    "resetPasswordSuccess": "Password reset successfully!",
+    "enterPassword": "Please enter the password to reset",
+    "enterExpiredTime": "Please select expiration time",
+    "modal": {
+      "addTitle": "Add User",
+      "editTitle": "Edit User",
+      "addProjectTitle": "Add Project",
+      "basic": "Basic",
+      "projects": "Associated Projects",
+      "chineseName": "Chinese Name",
+      "enterChineseName": "Please enter Chinese name",
+      "englishName": "English Name",
+      "enterEnglishName": "Please enter English name",
+      "account": "Account",
+      "enterAccount": "Please enter account",
+      "cellPhone": "Bound Phone",
+      "enterCellPhone": "Please enter bound phone",
+      "emailAddress": "Email",
+      "enterEmailAddress": "Please enter email",
+      "gogsEmail": "Git Account/Email",
+      "enterGogsEmail": "Please enter Git account/email",
+      "expiredTime": "Valid Until",
+      "selectExpiredTime": "Please select valid date",
+      "isActive": "Activate Now",
+      "password": "Password",
+      "enterPassword": "Please enter password",
+      "name": "Name",
+      "projectName": "Project Name",
+      "projectCode": "Project Code",
+      "role": "Role",
+      "action": "Action",
+      "add": "Add",
+      "delete": "Delete",
+      "cancel": "Cancel",
+      "save": "Save",
+      "searchProject": "Search project",
+      "totalProjects": "Total {total} projects",
+      "deleteProjectConfirm": "Are you sure to delete this associated project?"
+    }
   }
 }

+ 60 - 0
apps/web-velofex/src/locales/langs/zh-CN/page.json

@@ -224,5 +224,65 @@
       "save": "保存",
       "cancel": "取消"
     }
+  },
+  "deliveryPartners": {
+    "breadcrumb": "首页 / 交付合作伙伴",
+    "account": "账号:",
+    "name": "名称:",
+    "expiredTime": "有效期:",
+    "cellPhone": "绑定手机:",
+    "emailAddress": "邮箱:",
+    "accessId": "用户秘钥:",
+    "status": "状态:",
+    "action": "操作:",
+    "loading": "加载中...",
+    "edit": "编辑",
+    "resetPassword": "重置密码",
+    "delete": "删除",
+    "deleteConfirm": "确定要删除此用户吗?",
+    "deleteDescription": "删除后无法恢复",
+    "deleteSuccess": "删除成功!",
+    "saveSuccess": "保存成功!",
+    "addProjectSuccess": "添加项目成功!",
+    "deleteProjectSuccess": "删除项目成功!",
+    "resetPasswordSuccess": "密码重置成功!",
+    "enterPassword": "请输入要重置的密码",
+    "enterExpiredTime": "请选择过期时间",
+    "modal": {
+      "addTitle": "添加用户",
+      "editTitle": "编辑用户",
+      "addProjectTitle": "添加项目",
+      "basic": "基本",
+      "projects": "关联项目",
+      "chineseName": "中文姓名",
+      "enterChineseName": "请输入中文姓名",
+      "englishName": "英文姓名",
+      "enterEnglishName": "请输入英文姓名",
+      "account": "账号",
+      "enterAccount": "请输入账号",
+      "cellPhone": "绑定手机",
+      "enterCellPhone": "请输入绑定手机",
+      "emailAddress": "邮箱",
+      "enterEmailAddress": "请输入邮箱",
+      "gogsEmail": "Git账户/邮箱",
+      "enterGogsEmail": "请输入Git账户/邮箱",
+      "expiredTime": "有效期",
+      "selectExpiredTime": "请选择有效期",
+      "isActive": "是否启用",
+      "password": "密码",
+      "enterPassword": "请输入密码",
+      "name": "名称",
+      "projectName": "项目名称",
+      "projectCode": "项目代码",
+      "role": "角色",
+      "action": "操作",
+      "add": "添加",
+      "delete": "删除",
+      "cancel": "取消",
+      "save": "保存",
+      "searchProject": "搜索项目",
+      "totalProjects": "共 {total} 个项目",
+      "deleteProjectConfirm": "确定要删除此关联项目吗?"
+    }
   }
 }

+ 1 - 1
apps/web-velofex/src/views/dashboard/application-management/application-modal.vue

@@ -456,7 +456,7 @@ async function handleGenerateKey() {
         ? (keyData.value.startTime as Dayjs).format('YYYY-MM-DD')
         : '',
       encrypt_type: 1,
-      enterprise_code: 'SL_tsex1',
+      enterprise_code: formData.value.code,
       error_msg: keyData.value.errorDescription,
       is_permanent: keyData.value.isPermanent,
       period_day: keyData.value.validDays,

+ 131 - 46
apps/web-velofex/src/views/dashboard/delivery-partners/delivery-partners-modal.vue

@@ -3,6 +3,7 @@ import type { TablePaginationConfig } from 'antdv-next';
 
 import { computed, ref, watch } from 'vue';
 
+import { $t } from '@/locales';
 import {
   Button,
   DatePicker,
@@ -10,10 +11,11 @@ import {
   Menu,
   message,
   Modal,
+  Select,
   Switch,
   Table,
 } from 'antdv-next';
-import MD5 from 'crypto-js/md5';
+import { MD5 } from 'crypto-js/md5';
 import dayjs, { Dayjs } from 'dayjs';
 import localeData from 'dayjs/plugin/localeData';
 import weekday from 'dayjs/plugin/weekday';
@@ -65,13 +67,13 @@ const selectedProjects = ref<any[]>([]);
 const menuItems = computed(() => [
   {
     key: 'basic',
-    label: '基本',
-    title: '基本',
+    label: $t('deliveryPartners.modal.basic'),
+    title: $t('deliveryPartners.modal.basic'),
   },
   {
     key: 'projects',
-    label: '关联项目',
-    title: '关联项目',
+    label: $t('deliveryPartners.modal.projects'),
+    title: $t('deliveryPartners.modal.projects'),
   },
 ]);
 
@@ -82,6 +84,13 @@ const projectPagination = ref({
   total: 0,
 });
 
+const roleOptions = [
+  { value: '普通人员', label: '普通人员' },
+  { value: '兼职人员', label: '兼职人员' },
+  { value: '内部人员', label: '内部人员' },
+  { value: '管理员', label: '管理员' },
+];
+
 async function fetchAssociatedProjects() {
   try {
     const result = await getAssociatedProjectsApi(formData.value.id);
@@ -106,6 +115,9 @@ async function fetchAvailableProjects() {
       ],
     });
     if (result?.result?.model) {
+      result.result.model.forEach((item: any) => {
+        item.roleTypes = '普通人员';
+      });
       allProjects.value = result.result.model;
       projectPagination.value.total = result.result.totalCount;
     }
@@ -192,7 +204,7 @@ async function handleSave() {
     if (result?.isSuccess) {
       emit('save', data);
       isOpen.value = false;
-      message.success('保存成功');
+      message.success($t('deliveryPartners.saveSuccess'));
     }
   } catch {}
 }
@@ -222,10 +234,19 @@ function handleProjectPageChange(pagination: TablePaginationConfig) {
 }
 
 async function handleProjectSelect(project: any) {
+  if (!project.expiredTime) {
+    message.error($t('deliveryPartners.enterExpiredTime'));
+    return;
+  }
   try {
-    const result = await addProjectToUserApi(project.id, formData.value.id);
+    const result = await addProjectToUserApi(
+      [project.id],
+      formData.value.id,
+      project.roleTypes,
+      project.expiredTime ? project.expiredTime.format('YYYY-MM-DD') : '',
+    );
     if (result?.isSuccess) {
-      message.success('添加项目成功');
+      message.success($t('deliveryPartners.addProjectSuccess'));
       fetchAssociatedProjects();
       projectModalOpen.value = false;
     }
@@ -234,11 +255,11 @@ async function handleProjectSelect(project: any) {
 
 async function handleProjectDelete(project: any) {
   Modal.confirm({
-    title: '删除确认',
-    content: '确定要删除此关联项目吗?',
-    okText: '是',
+    title: $t('btn.delete'),
+    content: $t('deliveryPartners.modal.deleteProjectConfirm'),
+    okText: $t('btn.yes'),
     okType: 'danger',
-    cancelText: '否',
+    cancelText: $t('btn.no'),
     type: 'warning',
     onOk: async () => {
       try {
@@ -246,7 +267,7 @@ async function handleProjectDelete(project: any) {
           project.id,
         ]);
         if (result?.isSuccess) {
-          message.success('删除项目成功');
+          message.success($t('deliveryPartners.deleteProjectSuccess'));
           fetchAssociatedProjects();
         }
       } catch {}
@@ -277,7 +298,11 @@ function resetFormData() {
   <Modal
     v-model:open="isOpen"
     :footer="null"
-    :title="props.mode === 'add' ? '添加用户' : '编辑用户'"
+    :title="
+      props.mode === 'add'
+        ? $t('deliveryPartners.modal.addTitle')
+        : $t('deliveryPartners.modal.editTitle')
+    "
     width="1200px"
   >
     <div class="flex h-[600px]">
@@ -298,66 +323,84 @@ function resetFormData() {
         <div v-show="activeMenu === 'basic'" class="space-y-4">
           <div class="grid grid-cols-2 gap-4">
             <div class="flex flex-col gap-2">
-              <label class="text-sm font-medium">中文姓名</label>
+              <label class="text-sm font-medium">{{
+                $t('deliveryPartners.modal.chineseName')
+              }}</label>
               <Input
                 v-model:value="formData.chineseName"
-                placeholder="请输入中文姓名"
+                :placeholder="$t('deliveryPartners.modal.enterChineseName')"
               />
             </div>
             <div class="flex flex-col gap-2">
-              <label class="text-sm font-medium">英文姓名</label>
+              <label class="text-sm font-medium">{{
+                $t('deliveryPartners.modal.englishName')
+              }}</label>
               <Input
                 v-model:value="formData.englishName"
-                placeholder="请输入英文姓名"
+                :placeholder="$t('deliveryPartners.modal.enterEnglishName')"
               />
             </div>
             <div class="flex flex-col gap-2">
-              <label class="text-sm font-medium">账号</label>
+              <label class="text-sm font-medium">{{
+                $t('deliveryPartners.modal.account')
+              }}</label>
               <Input
                 v-model:value="formData.account"
                 :disabled="props.mode === 'edit'"
-                placeholder="请输入账号"
+                :placeholder="$t('deliveryPartners.modal.enterAccount')"
               />
             </div>
             <div class="flex flex-col gap-2">
-              <label class="text-sm font-medium">绑定手机</label>
+              <label class="text-sm font-medium">{{
+                $t('deliveryPartners.modal.cellPhone')
+              }}</label>
               <Input
                 v-model:value="formData.cellPhone"
-                placeholder="请输入绑定手机"
+                :placeholder="$t('deliveryPartners.modal.enterCellPhone')"
               />
             </div>
             <div class="flex flex-col gap-2">
-              <label class="text-sm font-medium">邮箱</label>
+              <label class="text-sm font-medium">{{
+                $t('deliveryPartners.modal.emailAddress')
+              }}</label>
               <Input
                 v-model:value="formData.emailAddress"
-                placeholder="请输入邮箱"
+                :placeholder="$t('deliveryPartners.modal.enterEmailAddress')"
               />
             </div>
             <div class="flex flex-col gap-2">
-              <label class="text-sm font-medium">Git账户/邮箱</label>
+              <label class="text-sm font-medium">{{
+                $t('deliveryPartners.modal.gogsEmail')
+              }}</label>
               <Input
                 v-model:value="formData.gogs_email"
-                placeholder="请输入Git账户/邮箱"
+                :placeholder="$t('deliveryPartners.modal.enterGogsEmail')"
               />
             </div>
             <div class="flex flex-col gap-2">
-              <label class="text-sm font-medium">有效期</label>
+              <label class="text-sm font-medium">{{
+                $t('deliveryPartners.modal.expiredTime')
+              }}</label>
               <DatePicker
                 v-model:value="formData.expiredTime"
+                :placeholder="$t('deliveryPartners.modal.selectExpiredTime')"
                 format="YYYY-MM-DD"
-                placeholder="请选择有效期"
                 style="width: 100%"
               />
             </div>
             <div class="flex flex-col gap-2">
-              <label class="text-sm font-medium">是否启用</label>
+              <label class="text-sm font-medium">{{
+                $t('deliveryPartners.modal.isActive')
+              }}</label>
               <Switch v-model:checked="formData.isActive" class="w-[40px]" />
             </div>
             <div v-if="props.mode === 'add'" class="flex flex-col gap-2">
-              <label class="text-sm font-medium">密码</label>
+              <label class="text-sm font-medium">{{
+                $t('deliveryPartners.modal.password')
+              }}</label>
               <Input
                 v-model:value="formData.password"
-                placeholder="请输入密码"
+                :placeholder="$t('deliveryPartners.modal.enterPassword')"
                 type="password"
               />
             </div>
@@ -366,23 +409,36 @@ function resetFormData() {
 
         <div v-show="activeMenu === 'projects'" class="space-y-4">
           <div class="mb-4 flex items-center justify-between">
-            <Button type="primary" @click="handleAddProject"> 添加项目 </Button>
+            <Button type="primary" @click="handleAddProject">
+              {{ $t('deliveryPartners.modal.add') }}
+              {{ $t('deliveryPartners.modal.projects') }}
+            </Button>
           </div>
 
           <Table
             :columns="[
               {
-                title: '项目名称',
+                title: $t('deliveryPartners.modal.projectName'),
                 dataIndex: 'name',
                 key: 'name',
               },
               {
-                title: '项目代码',
+                title: $t('deliveryPartners.modal.projectCode'),
                 dataIndex: 'code',
                 key: 'code',
               },
               {
-                title: '操作',
+                title: $t('deliveryPartners.modal.role'),
+                dataIndex: 'roleTypes',
+                key: 'roleTypes',
+              },
+              {
+                title: $t('deliveryPartners.modal.expiredTime'),
+                dataIndex: 'expiredTime',
+                key: 'expiredTime',
+              },
+              {
+                title: $t('deliveryPartners.modal.action'),
                 key: 'action',
                 width: 100,
               },
@@ -398,7 +454,7 @@ function resetFormData() {
                   size="small"
                   @click="handleProjectDelete(record)"
                 >
-                  删除
+                  {{ $t('deliveryPartners.modal.delete') }}
                 </Button>
               </template>
             </template>
@@ -411,40 +467,54 @@ function resetFormData() {
       v-if="activeMenu === 'basic'"
       class="flex justify-end gap-2 border-t pt-4"
     >
-      <Button @click="handleCancel"> 取消 </Button>
-      <Button type="primary" @click="handleSave"> 保存 </Button>
+      <Button @click="handleCancel">
+        {{ $t('deliveryPartners.modal.cancel') }}
+      </Button>
+      <Button type="primary" @click="handleSave">
+        {{ $t('deliveryPartners.modal.save') }}
+      </Button>
     </div>
 
     <Modal
       v-model:open="projectModalOpen"
       :footer="null"
-      title="添加项目"
-      width="700"
+      :title="$t('deliveryPartners.modal.addProjectTitle')"
+      width="760"
     >
       <div class="space-y-4">
         <Input
           v-model:value="projectSearchKeyword"
-          placeholder="搜索项目"
+          :placeholder="$t('deliveryPartners.modal.searchProject')"
           @change="handleProjectSearch"
         />
         <Table
           :columns="[
             {
-              title: '项目名称',
+              title: $t('deliveryPartners.modal.projectName'),
               dataIndex: 'name',
               key: 'name',
               ellipsis: true,
               width: 120,
             },
             {
-              title: '项目代码',
+              title: $t('deliveryPartners.modal.projectCode'),
               dataIndex: 'code',
               key: 'code',
               ellipsis: true,
               width: 120,
             },
             {
-              title: '操作',
+              title: $t('deliveryPartners.modal.role'),
+              key: 'roleTypes',
+              width: 150,
+            },
+            {
+              title: $t('deliveryPartners.modal.expiredTime'),
+              key: 'expiredTime',
+              width: 150,
+            },
+            {
+              title: $t('deliveryPartners.modal.action'),
               key: 'action',
             },
           ]"
@@ -454,20 +524,35 @@ function resetFormData() {
             pageSize: projectPagination.pageSize,
             total: projectPagination.total,
             showSizeChanger: true,
-            showTotal: (total: number) => `共 ${total} 个项目`,
+            showTotal: (total: number) =>
+              $t('deliveryPartners.modal.totalProjects', { total }),
           }"
           :scroll="{ y: 460 }"
           class="project-table"
           @change="handleProjectPageChange"
         >
           <template #bodyCell="{ column, record }">
+            <template v-if="column.key === 'roleTypes'">
+              <Select
+                v-model:value="record.roleTypes"
+                :options="roleOptions"
+                style="width: 120px"
+              />
+            </template>
+            <template v-if="column.key === 'expiredTime'">
+              <DatePicker
+                v-model:value="record.expiredTime"
+                format="YYYY-MM-DD"
+                style="width: 120px"
+              />
+            </template>
             <template v-if="column.key === 'action'">
               <Button
                 size="small"
                 type="primary"
                 @click="handleProjectSelect(record)"
               >
-                添加
+                {{ $t('deliveryPartners.modal.add') }}
               </Button>
             </template>
           </template>

+ 51 - 30
apps/web-velofex/src/views/dashboard/delivery-partners/index.vue

@@ -13,7 +13,7 @@ import {
   Select,
   Table,
 } from 'antdv-next';
-import MD5 from 'crypto-js/md5';
+import { MD5 } from 'crypto-js/md5';
 
 import {
   deleteUserApi,
@@ -154,18 +154,18 @@ async function deleteUser(item: any) {
     const result = await deleteUserApi(item);
     if (result?.result) {
       fetchUserList();
-      message.success('删除成功');
+      message.success($t('deliveryPartners.deleteSuccess'));
     }
   } catch {}
 }
 
 function handleDelete(item: any) {
   Modal.confirm({
-    title: '删除确认',
-    content: '确定要删除此用户吗?',
-    okText: '是',
+    title: $t('btn.delete'),
+    content: $t('deliveryPartners.deleteConfirm'),
+    okText: $t('btn.yes'),
     okType: 'danger',
-    cancelText: '否',
+    cancelText: $t('btn.no'),
     onOk() {
       deleteUser(item);
     },
@@ -175,7 +175,7 @@ function handleDelete(item: any) {
 
 async function handleResetPasswordConfirm() {
   if (!newPassword.value) {
-    message.error('请输入要重置的密码');
+    message.error($t('deliveryPartners.enterPassword'));
     return;
   }
 
@@ -187,10 +187,13 @@ async function handleResetPasswordConfirm() {
       newPassword: encryptedPassword,
     });
     if (result?.result) {
-      message.success('密码重置成功');
+      message.success($t('deliveryPartners.resetPasswordSuccess'));
       resetPasswordModalOpen.value = false;
+      loading.value = false;
     }
-  } catch {}
+  } catch {
+    loading.value = false;
+  }
 }
 
 async function fetchPartnersList() {
@@ -233,7 +236,7 @@ onMounted(() => {
   <div class="p-5">
     <div class="mb-4 flex items-center justify-between">
       <div class="text-sm text-[#462424] text-gray-500">
-        {{ $t('homeModule.deliveryPartners') }}
+        {{ $t('deliveryPartners.breadcrumb') }}
       </div>
       <div
         class="flex cursor-pointer items-center gap-[9px] text-[16px] font-bold text-[#462424]"
@@ -259,7 +262,9 @@ onMounted(() => {
     <div class="mb-4 space-y-4">
       <div class="flex items-center gap-4">
         <div class="flex flex-col gap-1">
-          <label class="text-[11px] text-[#000]">账号</label>
+          <label class="text-[11px] text-[#000]">{{
+            $t('deliveryPartners.modal.account')
+          }}</label>
           <Input
             v-model:value="searchParams.account"
             class="h-[42px] w-[138px] rounded-[11px] border-[#707070]"
@@ -267,7 +272,9 @@ onMounted(() => {
           />
         </div>
         <div class="flex flex-col gap-1">
-          <label class="text-[11px] text-[#000]">中文姓名</label>
+          <label class="text-[11px] text-[#000]">{{
+            $t('deliveryPartners.modal.chineseName')
+          }}</label>
           <Input
             v-model:value="searchParams.chineseName"
             class="h-[42px] w-[97.81px] rounded-[11px] border-[#707070]"
@@ -275,7 +282,9 @@ onMounted(() => {
           />
         </div>
         <div class="flex flex-col gap-1">
-          <label class="text-[11px] text-[#000]">英文姓名</label>
+          <label class="text-[11px] text-[#000]">{{
+            $t('deliveryPartners.modal.englishName')
+          }}</label>
           <Input
             v-model:value="searchParams.englishName"
             class="h-[42px] w-[138px] rounded-[11px] border-[#707070]"
@@ -285,7 +294,9 @@ onMounted(() => {
       </div>
       <div class="flex items-center gap-4">
         <div class="flex flex-col gap-1">
-          <label class="text-[11px] text-[#000]">绑定手机</label>
+          <label class="text-[11px] text-[#000]">{{
+            $t('deliveryPartners.modal.cellPhone')
+          }}</label>
           <Input
             v-model:value="searchParams.cellPhone"
             class="h-[42px] w-[138px] rounded-[11px] border-[#707070]"
@@ -293,7 +304,9 @@ onMounted(() => {
           />
         </div>
         <div class="flex flex-col gap-1">
-          <label class="text-[11px] text-[#000]">邮箱</label>
+          <label class="text-[11px] text-[#000]">{{
+            $t('deliveryPartners.modal.emailAddress')
+          }}</label>
           <Input
             v-model:value="searchParams.emailAddress"
             class="h-[42px] w-[168px] rounded-[11px] border-[#707070]"
@@ -310,7 +323,9 @@ onMounted(() => {
           />
         </div>
         <div class="ml-[58px] flex flex-col gap-1">
-          <label class="text-[11px] text-[#000]">是否启用</label>
+          <label class="text-[11px] text-[#000]">{{
+            $t('deliveryPartners.modal.isActive')
+          }}</label>
           <div class="flex h-[42px] items-center gap-2">
             <label
               class="flex cursor-pointer items-center gap-2 text-sm"
@@ -403,52 +418,54 @@ onMounted(() => {
       </div>
     </div>
 
-    <div v-if="loading" class="py-8 text-center">加载中...</div>
+    <div v-if="loading" class="py-8 text-center">
+      {{ $t('deliveryPartners.loading') }}
+    </div>
     <div v-else>
       <Table
         :columns="[
           {
-            title: '账号',
+            title: $t('deliveryPartners.modal.account'),
             dataIndex: 'account',
             key: 'account',
             width: 130,
           },
           {
-            title: '名称',
+            title: $t('deliveryPartners.modal.name'),
             dataIndex: 'name',
             width: 130,
             key: 'name',
           },
           {
-            title: '有效期',
+            title: $t('deliveryPartners.modal.expiredTime'),
             dataIndex: 'expiredTime',
             key: 'expiredTime',
             width: 130,
           },
           {
-            title: '绑定手机',
+            title: $t('deliveryPartners.modal.cellPhone'),
             dataIndex: 'cellPhone',
             width: 130,
             key: 'cellPhone',
           },
           {
-            title: '邮箱',
+            title: $t('deliveryPartners.modal.emailAddress'),
             dataIndex: 'emailAddress',
             width: 130,
             key: 'emailAddress',
           },
           {
-            title: '用户秘钥',
+            title: $t('deliveryPartners.accessId'),
             dataIndex: 'accessId',
             key: 'accessId',
           },
           {
-            title: '状态',
+            title: $t('deliveryPartners.status'),
             width: 130,
             key: 'status',
           },
           {
-            title: '操作',
+            title: $t('deliveryPartners.action'),
             key: 'action',
           },
         ]"
@@ -459,8 +476,10 @@ onMounted(() => {
       >
         <template #bodyCell="{ column, record }">
           <template v-if="column.key === 'status'">
-            <span v-if="record.isActive" class="text-green-600">启用</span>
-            <span v-else class="text-red-600">禁用</span>
+            <span v-if="record.isActive" class="text-green-600">{{
+              $t('btn.yes')
+            }}</span>
+            <span v-else class="text-red-600">{{ $t('btn.no') }}</span>
           </template>
           <template v-if="column.key === 'action'">
             <div class="flex gap-2">
@@ -565,16 +584,18 @@ onMounted(() => {
 
     <Modal
       v-model:open="resetPasswordModalOpen"
-      title="重置密码"
+      :title="$t('deliveryPartners.resetPassword')"
       width="500"
       @ok="handleResetPasswordConfirm"
     >
       <div class="space-y-4">
         <div class="flex flex-col gap-2">
-          <label class="text-sm font-medium">新密码</label>
+          <label class="text-sm font-medium">{{
+            $t('deliveryPartners.modal.password')
+          }}</label>
           <Input
             v-model:value="newPassword"
-            placeholder="请输入新密码"
+            :placeholder="$t('deliveryPartners.modal.enterPassword')"
             type="password"
           />
         </div>

+ 2 - 4
apps/web-velofex/src/views/dashboard/home/delivery-partners.vue

@@ -65,10 +65,7 @@ watch(
 </script>
 
 <template>
-  <div
-    class="info-card border-box h-[217px] w-full cursor-pointer rounded-lg p-5 shadow-md"
-    @click="handleNavigate"
-  >
+  <div class="info-card border-box h-[217px] w-full rounded-lg p-5 shadow-md">
     <div class="items-flex-start flex justify-between">
       <div>
         <h2 class="text-lg font-bold">
@@ -80,6 +77,7 @@ watch(
         alt="more"
         class="h-[29px] w-[29px] cursor-pointer"
         src="@/assets/image/home-more.png"
+        @click="handleNavigate"
       />
     </div>
     <p

+ 1 - 1
apps/web-velofex/src/views/dashboard/sales-partners/sales-partners-modal.vue

@@ -11,7 +11,7 @@ import {
   Switch,
   Upload,
 } from 'antdv-next';
-import MD5 from 'crypto-js/md5';
+import { MD5 } from 'crypto-js/md5';
 import dayjs from 'dayjs';
 
 import { createPartnerApi, getLangByKeyApi, updatePartnerApi } from '#/api';