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

Merge branch 'main' into Fanld

FanLide 10 месяцев назад
Родитель
Сommit
78bd179b89
44 измененных файлов с 334 добавлено и 125 удалено
  1. 5 4
      .env
  2. 1 1
      .env.dev
  3. 0 2
      .env.test
  4. 1 0
      .gitignore
  5. 1 1
      .vscode/settings.json
  6. 136 0
      bash/run.sh
  7. 4 4
      index.html
  8. 0 0
      public/logo111.gif
  9. 2 2
      src/components/Cropper/src/CopperModal.vue
  10. 2 2
      src/components/Cropper/src/Cropper.vue
  11. 2 2
      src/components/Error/src/Error.vue
  12. 2 1
      src/components/Materials/src/editorMaterials.vue
  13. 1 1
      src/components/common/AppImage.vue
  14. 2 1
      src/layout/components/LocaleDropdown/index.ts
  15. 48 0
      src/layout/components/LocaleDropdown/src/LocaleSelect.vue
  16. 3 2
      src/layout/components/Logo/src/Logo.vue
  17. 1 1
      src/layout/components/Menu/src/Menu.vue
  18. 0 1
      src/layout/components/Menu/src/components/useRenderMenuTitle.tsx
  19. 2 1
      src/layout/components/UserInfo/src/UserInfo.vue
  20. 7 3
      src/locales/en.ts
  21. 6 3
      src/locales/ja.ts
  22. 10 6
      src/locales/zh-CN.ts
  23. 1 1
      src/main.ts
  24. 2 1
      src/store/modules/permission.ts
  25. 3 3
      src/store/modules/user.ts
  26. 20 20
      src/utils/routerHelper.ts
  27. 5 5
      src/views/Login/Login.vue
  28. 17 32
      src/views/Login/components/LoginForm.vue
  29. 2 1
      src/views/Profile/components/UserAvatar.vue
  30. 3 2
      src/views/mall/cashier/index.vue
  31. 10 3
      src/views/mall/member/user/UserForm.vue
  32. 2 1
      src/views/mall/member/user/index.vue
  33. 7 0
      src/views/mall/order/storeOrder/OrderDetail.vue
  34. 2 1
      src/views/mall/order/storeOrder/index.vue
  35. 3 1
      src/views/mall/shop/ads/index.vue
  36. 2 1
      src/views/mall/shop/service/index.vue
  37. 2 1
      src/views/mall/store/shop/index.vue
  38. 3 2
      src/views/score/order/OrderDetail.vue
  39. 2 1
      src/views/score/order/index.vue
  40. 2 1
      src/views/score/product/index.vue
  41. 3 2
      src/views/score/scoreads/index.vue
  42. 3 3
      src/views/system/notice/index.vue
  43. 1 1
      src/views/system/sms/template/SmsTemplateForm.vue
  44. 3 4
      types/router.d.ts

+ 5 - 4
.env

@@ -1,5 +1,5 @@
 # 标题
-VITE_APP_TITLE=FastEat点餐管理系统
+VITE_APP_TITLE=Tabemate Pro  オーダーシステム
 
 # 项目本地运行端口号
 VITE_PORT=8000
@@ -17,10 +17,11 @@ VITE_APP_CAPTCHA_ENABLE=false
 VITE_APP_DOCALERT_ENABLE=true
 
 # 百度统计
-VITE_APP_BAIDU_CODE = a1ff8825baa73c3a78eb96aa40325abc
+# VITE_APP_BAIDU_CODE = a1ff8825baa73c3a78eb96aa40325abc
+VITE_APP_BAIDU_CODE =
 
 # 百度地图ak
-VITE_BAIDU_MAP_AK = m1YRfvvQt9dPVNuPSieTEDgRhZkIznSn
-
+# VITE_BAIDU_MAP_AK = m1YRfvvQt9dPVNuPSieTEDgRhZkIznSn
+VITE_BAIDU_MAP_AK = 
 
 # // https://api.ifoodme.com/doc.html#/home  接口文档地址

+ 1 - 1
.env.dev

@@ -38,7 +38,7 @@ VITE_BASE_PATH=/
 VITE_OUT_DIR=dist
 
 # 商城H5会员端域名
-VITE_MALL_H5_DOMAIN='http://mall.fasteatjp.com'
+VITE_MALL_H5_DOMAIN='https://mall.ifoodme.com'
 
 # 验证码的开关
 VITE_APP_CAPTCHA_ENABLE=false

+ 0 - 2
.env.test

@@ -5,8 +5,6 @@ VITE_DEV=false
 
 # 请求路径
 VITE_BASE_URL='http://localhost:48081'
-#VITE_BASE_URL='http://111.229.149.174:8082'
-#VITE_BASE_URL='https://api.ifoodme.com'
 
 # 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务
 VITE_UPLOAD_TYPE=server

+ 1 - 0
.gitignore

@@ -8,3 +8,4 @@ pnpm-debug
 auto-*.d.ts
 .idea
 .history
+.zip

+ 1 - 1
.vscode/settings.json

@@ -137,7 +137,7 @@
     "*.ts": "$(capture).test.ts, $(capture).test.tsx",
     "*.tsx": "$(capture).test.ts, $(capture).test.tsx",
     "*.env": "$(capture).env.*",
-    "package.json": "pnpm-lock.yaml,yarn.lock,LICENSE,README*,CHANGELOG*,CNAME,.gitattributes,.eslintrc-auto-import.json,.gitignore,prettier.config.js,stylelint.config.js,commitlint.config.js,.stylelintignore,.prettierignore,.gitpod.yml,.eslintrc.js,.eslintignore"
+    "package.json": "pnpm-lock.yaml,yarn.lock,LICENSE,README*,CHANGELOG*,CNAME,.gitattributes,.eslintrc-auto-import.json,prettier.config.js,stylelint.config.js,commitlint.config.js,.stylelintignore,.prettierignore,.gitpod.yml,.eslintrc.js,.eslintignore"
   },
   "terminal.integrated.scrollback": 10000,
   "nuxt.isNuxtApp": false

+ 136 - 0
bash/run.sh

@@ -0,0 +1,136 @@
+#!/bin/bash
+
+# 配置
+SOURCE_DIR="dist-prod"              # 打包生成的源文件夹
+ZIP_NAME="dc.ifoodme.com.zip"       # 输出的 ZIP 文件名
+TEMP_DIR="/tmp/dc.ifoodme.com"      # 临时目录,用于构建目标结构
+TARGET_DIR="dc.ifoodme.com"         # ZIP 中的目标目录名
+BUILD_CMD="pnpm run build:prod"     # 打包命令
+
+# FTP 配置
+FTP_SERVER="104.233.167.88"
+FTP_PORT="21"
+FTP_USER="admin"        # 这里替换成你的 FTP 用户名
+FTP_PASS="snF1szwjJZcJ"        # 这里替换成你的 FTP 密码
+FTP_TARGET_DIR="/"
+
+# 颜色输出
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+NC='\033[0m' # No Color
+
+# 检查命令是否存在
+command_exists() {
+    command -v "$1" >/dev/null 2>&1
+}
+
+# 检查依赖
+check_dependencies() {
+    for cmd in pnpm zip unzip curl; do
+        if ! command_exists "$cmd"; then
+            echo -e "${RED}错误:需要安装 $cmd${NC}"
+            exit 1
+        fi
+    done
+}
+
+# 检查并删除旧 ZIP 文件
+check_and_remove_zip() {
+    if [ -f "$ZIP_NAME" ]; then
+        echo "检测到旧 ZIP 文件,删除中..."
+        rm -f "$ZIP_NAME"
+        echo -e "${GREEN}旧 ZIP 文件已删除${NC}"
+    fi
+}
+
+# 执行打包
+run_build() {
+    echo "开始执行打包: $BUILD_CMD..."
+    if ! $BUILD_CMD; then
+        echo -e "${RED}打包失败${NC}"
+        exit 1
+    fi
+    echo -e "${GREEN}打包完成${NC}"
+}
+
+# 检查源文件夹
+check_source() {
+    if [ ! -d "$SOURCE_DIR" ]; then
+        echo -e "${RED}错误:源文件夹 $SOURCE_DIR 不存在${NC}"
+        exit 1
+    fi
+    if [ ! -f "$SOURCE_DIR/index.html" ]; then
+        echo -e "${RED}错误:$SOURCE_DIR 中没有 index.html 文件${NC}"
+        exit 1
+    fi
+}
+
+# 打包 ZIP
+create_zip() {
+    echo "开始打包 ZIP..."
+
+    # 创建临时目录并复制文件
+    mkdir -p "$TEMP_DIR"
+    cp -r "$SOURCE_DIR"/* "$TEMP_DIR"
+
+    # 重命名临时目录为目标目录名
+    mv "$TEMP_DIR" "$TARGET_DIR"
+
+    # 打包为 ZIP
+    zip -r "$ZIP_NAME" "$TARGET_DIR" >/dev/null
+    if [ $? -eq 0 ]; then
+        echo -e "${GREEN}打包成功:$ZIP_NAME${NC}"
+    else
+        echo -e "${RED}打包失败${NC}"
+        exit 1
+    fi
+}
+
+# FTP 上传
+upload_ftp() {
+    echo "开始上传文件到 FTP 服务器 $FTP_SERVER:$FTP_PORT ..."
+
+    curl -T "$ZIP_NAME" --ftp-create-dirs -u "$FTP_USER:$FTP_PASS" "ftp://$FTP_SERVER:$FTP_PORT$FTP_TARGET_DIR/$ZIP_NAME"
+
+    if [ $? -eq 0 ]; then
+        echo -e "${GREEN}文件上传成功:$FTP_TARGET_DIR/$ZIP_NAME${NC}"
+    else
+        echo -e "${RED}文件上传失败${NC}"
+        exit 1
+    fi
+}
+
+# 测试解压(可选)
+test_unzip() {
+    echo "测试解压..."
+    mkdir -p test_unzip
+    unzip -o "$ZIP_NAME" -d test_unzip >/dev/null
+    if [ -f "test_unzip/$TARGET_DIR/index.html" ]; then
+        echo -e "${GREEN}解压测试成功:test_unzip/$TARGET_DIR/index.html 存在${NC}"
+    else
+        echo -e "${RED}解压测试失败:未生成正确的目录结构${NC}"
+        exit 1
+    fi
+}
+
+# 清理
+cleanup() {
+    echo "清理临时文件..."
+    rm -rf "$TARGET_DIR" test_unzip
+    echo -e "${GREEN}清理完成${NC}"
+}
+
+# 主函数
+main() {
+    check_dependencies
+    check_and_remove_zip  # 先检查并删除旧的 ZIP 文件
+    run_build
+    check_source
+    create_zip
+    upload_ftp
+    cleanup
+    echo -e "${GREEN}所有任务完成!${NC}"
+}
+
+# 执行
+main

+ 4 - 4
index.html

@@ -7,11 +7,11 @@
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <meta
       name="keywords"
-      content="FastEat 在线点餐系统"
+      content="Tabemate Pro  オーダーシステム"
     />
     <meta
       name="description"
-      content="FastEat 在线点餐系统"
+      content="Tabemate Pro  オーダーシステム"
     />
     <title>%VITE_APP_TITLE%</title>
   </head>
@@ -136,8 +136,8 @@
       <div class="app-loading">
         <div class="app-loading-wrap">
           <div class="app-loading-title">
-            <img src="/logo.gif" class="app-loading-logo" alt="Logo" />
-            <div class="app-loading-title">%VITE_APP_TITLE%</div>
+            <img src="/logo111.gif" class="app-loading-logo" alt="Logo" />
+            <div class="app-loading-title">Tabemate Pro  オーダーシステムへようこそ</div>
           </div>
           <div class="app-loading-item">
             <div class="app-loading-outter"></div>

+ 0 - 0
public/logo.gif → public/logo111.gif


+ 2 - 2
src/components/Cropper/src/CopperModal.vue

@@ -95,7 +95,7 @@
         </div>
         <div :class="`${prefixCls}-right`">
           <div :class="`${prefixCls}-preview`">
-            <img v-if="previewSource" :alt="t('cropper.preview')" :src="previewSource" />
+            <img v-if="previewSource" :alt="t('cropper.preview')" :src="convertImageUrl(previewSource)" />
           </div>
           <template v-if="previewSource">
             <div :class="`${prefixCls}-group`">
@@ -120,7 +120,7 @@ import { useI18n } from 'vue-i18n'
 import type { CropendResult, Cropper } from './types'
 import { propTypes } from '@/utils/propTypes'
 import { CropperImage } from '@/components/Cropper'
-
+import { convertImageUrl } from '@/utils/image-helper'
 defineOptions({ name: 'CopperModal' })
 
 const props = defineProps({

+ 2 - 2
src/components/Cropper/src/Cropper.vue

@@ -5,7 +5,7 @@
       ref="imgElRef"
       :alt="alt"
       :crossorigin="crossorigin"
-      :src="src"
+      :src="convertImageUrl(src)"
       :style="getImageStyle"
     />
   </div>
@@ -17,7 +17,7 @@ import 'cropperjs/dist/cropper.css'
 import { useDesign } from '@/hooks/web/useDesign'
 import { propTypes } from '@/utils/propTypes'
 import { useDebounceFn } from '@vueuse/core'
-
+import { convertImageUrl } from '@/utils/image-helper'
 defineOptions({ name: 'Cropper' })
 
 type Options = Cropper.Options

+ 2 - 2
src/components/Error/src/Error.vue

@@ -3,7 +3,7 @@ import pageError from '@/assets/svgs/404.svg'
 import networkError from '@/assets/svgs/500.svg'
 import noPermission from '@/assets/svgs/403.svg'
 import { propTypes } from '@/utils/propTypes'
-
+import { convertImageUrl } from '@/utils/image-helper'
 defineOptions({ name: 'Error' })
 
 interface ErrorMap {
@@ -48,7 +48,7 @@ const btnClick = () => {
 <template>
   <div class="flex justify-center">
     <div class="text-center">
-      <img :src="errorMap[type].url" alt="" width="350" />
+      <img :src="convertImageUrl(errorMap[type].url)" alt="" width="350" />
       <div class="text-14px text-[var(--el-color-info)]">{{ errorMap[type].message }}</div>
       <div class="mt-20px">
         <ElButton type="primary" @click="btnClick">{{ errorMap[type].buttonText }}</ElButton>

+ 2 - 1
src/components/Materials/src/editorMaterials.vue

@@ -135,6 +135,7 @@ import {
 import { getPage, addObj, delObj } from '@/api/tools/material'
 import { getAccessToken } from '@/utils/auth'
 import '../../../../public/UEditor/dialogs/internal'
+import { convertImageUrl } from '@/utils/image-helper'
 
 const props = defineProps({
   value: {
@@ -384,7 +385,7 @@ function sureUrls() {
 
   let str = ''
   urls.value.forEach(item => {
-    str += '<img src="' + item + '">'
+    str += '<img src="' + convertImageUrl(item) + '">'
   })
   nowEditor.dialog.close(true)
   nowEditor.editor.setContent(str, true)

+ 1 - 1
src/components/common/AppImage.vue

@@ -24,7 +24,7 @@
  */
 -->
 <template>
-  <img :src="processedSrc" :alt="alt" v-bind="$attrs" @error="handleError" />
+  <img :src="convertImageUrl(processedSrc)" :alt="alt" v-bind="$attrs" @error="handleError" />
 </template>
 
 <script setup lang="ts">

+ 2 - 1
src/layout/components/LocaleDropdown/index.ts

@@ -1,3 +1,4 @@
 import LocaleDropdown from './src/LocaleDropdown.vue'
+import LocaleSelect from './src/LocaleSelect.vue'
 
-export { LocaleDropdown }
+export { LocaleDropdown, LocaleSelect }

+ 48 - 0
src/layout/components/LocaleDropdown/src/LocaleSelect.vue

@@ -0,0 +1,48 @@
+<script lang="ts" setup>
+import { useLocaleStore } from '@/store/modules/locale'
+import { useLocale } from '@/hooks/web/useLocale'
+import { propTypes } from '@/utils/propTypes'
+import { useDesign } from '@/hooks/web/useDesign'
+
+defineOptions({ name: 'LocaleSelect' }) // 修改组件名称
+
+const { getPrefixCls } = useDesign()
+
+const prefixCls = getPrefixCls('locale-select') // 修改类名前缀
+
+defineProps({
+  color: propTypes.string.def('')
+})
+
+const localeStore = useLocaleStore()
+
+const langMap = computed(() => localeStore.getLocaleMap)
+
+const currentLang = computed({
+  get: () => localeStore.getCurrentLocale.lang,
+  set: (lang: LocaleType) => {
+    if (lang === unref(currentLang)) return
+    // 需要重新加载页面让整个语言多初始化
+    window.location.reload()
+    localeStore.setCurrentLocale({
+      lang
+    })
+    const { changeLocale } = useLocale()
+    changeLocale(lang)
+  }
+})
+</script>
+
+<template>
+  <ElSelect
+    :class="prefixCls"
+    v-model="currentLang"
+  >
+    <ElOption
+      v-for="item in langMap"
+      :key="item.lang"
+      :label="item.name"
+      :value="item.lang"
+    />
+  </ElSelect>
+</template>

+ 3 - 2
src/layout/components/Logo/src/Logo.vue

@@ -73,7 +73,7 @@ watch(
       <div
         v-if="show"
         :class="[
-          'ml-10px text-16px font-700',
+          'ml-10px text-14px font-700',
           {
             'text-[var(--logo-title-text-color)]': layout === 'classic',
             'text-[var(--top-header-text-color)]':
@@ -81,7 +81,8 @@ watch(
           }
         ]"
       >
-        {{ title }}
+      <div>Tabemate Pro</div>
+      <div>オーダーシステム</div>
       </div>
     </router-link>
   </div>

+ 1 - 1
src/layout/components/Menu/src/Menu.vue

@@ -144,7 +144,7 @@ $prefix-cls: #{$namespace}-menu;
 
     // 设置子菜单悬停的高亮和背景色
     .#{$elNamespace}-sub-menu__title,
-    .#{$elNamespace}-menu-item {
+    .#{$elNamespace}-menu-item {            
       &:hover {
         color: var(--left-menu-text-active-color) !important;
         background-color: var(--left-menu-bg-color) !important;

+ 0 - 1
src/layout/components/Menu/src/components/useRenderMenuTitle.tsx

@@ -6,7 +6,6 @@ export const useRenderMenuTitle = () => {
   const renderMenuTitle = (meta: RouteMeta) => {
     const { t } = useI18n()
     const { title = 'Please set title', icon } = meta
-    console.log("🚀 ~ renderMenuTitle ~ title:", title)
 
     return icon ? (
       <>

+ 2 - 1
src/layout/components/UserInfo/src/UserInfo.vue

@@ -8,6 +8,7 @@ import { useUserStore } from '@/store/modules/user'
 import LockDialog from './components/LockDialog.vue'
 import LockPage from './components/LockPage.vue'
 import { useLockStore } from '@/store/modules/lock'
+import {convertImageUrl} from '@/utils/image-helper'
 
 defineOptions({ name: 'UserInfo' })
 
@@ -57,7 +58,7 @@ const toDocument = () => {
 <template>
   <ElDropdown class="custom-hover" :class="prefixCls" trigger="click">
     <div class="flex items-center">
-      <ElAvatar :src="avatar" alt="" class="w-[calc(var(--logo-height)-25px)] rounded-[50%]" />
+      <ElAvatar :src="convertImageUrl(avatar)" alt="" class="w-[calc(var(--logo-height)-25px)] rounded-[50%]" />
       <span class="pl-[5px] text-14px text-[var(--top-header-text-color)] <lg:hidden">
         {{ userName }}
       </span>

+ 7 - 3
src/locales/en.ts

@@ -147,11 +147,12 @@ export default {
     small: 'Small'
   },
   login: {
-    welcome: 'Welcome to FastEat',
-    message: 'Welcome to FastEat',
+    welcome: 'Welcome to Tabemate Pro',
+    message: 'Welcome to Tabemate Pro',
     tenantname: 'Tenant Name',
     username: 'User Name',
     password: 'Password',
+    userType: 'User Type',
     code: 'Verification Code',
     login: 'Login',
     relogin: 'Re-login',
@@ -1096,6 +1097,8 @@ export default {
     cashPayment: 'Cash',
     userName: 'User Name',
     phoneNumber: 'Phone number',
+    userType: 'User Type',
+    level: 'Level',
     pleaseEnterTheOrderNumber: 'Please enter the order number',
     pleaseEnterYourName: 'Please enter your name',
     pleaseEnterYourPhoneNumber: 'Please enter your phone number',
@@ -1227,6 +1230,7 @@ export default {
     userAccountCannotBeEmpty: 'User account cannot be empty',
     userNicknameCannotBeEmpty: 'Nickname cannot be empty',
     phoneNumberCannotBeEmpty: "User's mobile phone number cannot be empty",
+    userTypeCannotBeEmpty: "User's user type cannot be empty",
     phoneNumber1: 'Mobile phone number',
     selectMember: 'Select Member',
     select: 'Select',
@@ -2393,4 +2397,4 @@ export default {
     scord: 'Seconds'
   },
   'OAuth 2.0': 'OAuth 2.0' // 避免菜单名是 OAuth 2.0 时,一直 warn 报错
-}
+}

+ 6 - 3
src/locales/ja.ts

@@ -147,11 +147,12 @@ export default {
     small: '小'
   },
   login: {
-    welcome: 'FastEat 注文システムへようこそ',
-    message: 'FastEat 注文システム',
+    welcome: 'Tabemate Pro  オーダーシステムへようこそ',
+    message: 'Tabemate Pro  オーダーシステム',
     tenantname: 'テナント名',
     username: 'ユーザー名',
     password: 'パスワード',
+    userType: 'ユーザータイプ',
     code: '確認コード',
     login: 'ログイン',
     relogin: '再ログイン',
@@ -1098,6 +1099,8 @@ export default {
     cashPayment: '現金支払い',
     userName: 'ユーザー名',
     phoneNumber: 'ユーザー電話番号',
+    userType: 'ユーザータイプ',
+    level: 'レベル',
     pleaseEnterTheOrderNumber: '注文番号を入力してください',
     pleaseEnterYourName: 'ユーザー名を入力してください',
     pleaseEnterYourPhoneNumber: 'ユーザー電話番号を入力してください',
@@ -1164,6 +1167,7 @@ export default {
     categoryNameCannotBeEmpty: '分類名は空にできません',
     personCountCannotBeEmpty: '人数は空にできません',
     categorySortCannotBeEmpty: '分類順序は空にできません',
+    userTypeCannotBeEmpty: "ユーザーのユーザータイプは空にすることはできません",
     wechatMiniProgram: '微信ミニプログラム',
     officialAccount: '公式アカウント',
     h5: 'H5',
@@ -1185,7 +1189,6 @@ export default {
     commissionAmount: '手数料金額',
     consecutiveSignInDays: '連続サインイン日数',
     loginIp: 'ログインIP',
-    level: 'レベル',
     promotionId: 'プロモーションID',
     purchaseCount: '購入回数',
     subordinateCount: '下位者数',

+ 10 - 6
src/locales/zh-CN.ts

@@ -4,7 +4,7 @@ export default {
     selectText: '请选择',
     startTimeText: '开始时间',
     endTimeText: '结束时间',
-    login: '登录',
+    login: 'ログイン',
     required: '该项为必填项',
     loginOut: '退出系统',
     document: '项目文档',
@@ -147,18 +147,19 @@ export default {
     small: '小'
   },
   login: {
-    welcome: '欢迎使用FastEat点餐系统',
-    message: '欢迎使用FastEat点餐系统',
+    welcome: 'Tabemate Pro  オーダーシステムへようこそ',
+    message: 'Tabemate Pro  オーダーシステム',
     tenantname: '租户名称',
     username: '用户名',
     password: '密码',
+    userType: '类型',
     code: '验证码',
-    login: '登录',
+    login: 'ログイン',
     relogin: '重新登录',
     otherLogin: '其他登录方式',
     register: '注册',
     checkPassword: '确认密码',
-    remember: '记住我',
+    remember: 'ログイン状態を保持',
     hasUser: '已有账号?去登录',
     forgetPassword: '忘记密码?',
     tenantNamePlaceholder: '请输入租户名称',
@@ -421,7 +422,7 @@ export default {
     },
     login: {
       backSignIn: '返回',
-      signInFormTitle: '登录',
+      signInFormTitle: 'ログイン',
       ssoFormTitle: '三方授权',
       mobileSignInFormTitle: '手机登录',
       qrSignInFormTitle: '二维码登录',
@@ -1098,6 +1099,8 @@ export default {
     cashPayment: '现金支付',
     userName: '用户姓名',
     phoneNumber: '用户电话',
+    userType: '用户类型',
+    level: '等级',
     pleaseEnterTheOrderNumber: '请输入订单号',
     pleaseEnterYourName: '请输入用户姓名',
     pleaseEnterYourPhoneNumber: '请输入用户电话',
@@ -1229,6 +1232,7 @@ export default {
     userAccountCannotBeEmpty: '用户账户不能为空',
     userNicknameCannotBeEmpty: '用户昵称不能为空',
     phoneNumberCannotBeEmpty: '用户手机号码不能为空',
+    userTypeCannotBeEmpty: '用户类型不能为空',
     phoneNumber1: '手机号码',
     selectMember: '选择会员',
     select: '选择',

+ 1 - 1
src/main.ts

@@ -83,4 +83,4 @@ const setupAll = async () => {
 
 setupAll()
 
-Logger.prettyPrimary(`欢迎使用`, import.meta.env.VITE_APP_TITLE)
+Logger.prettyPrimary(`Tabemate Pro  オーダーシステムへようこそ`)

+ 2 - 1
src/store/modules/permission.ts

@@ -38,7 +38,8 @@ export const usePermissionStore = defineStore('permission', {
         if (wsCache.get(CACHE_KEY.ROLE_ROUTERS)) {
           res = wsCache.get(CACHE_KEY.ROLE_ROUTERS) as AppCustomRouteRecordRaw[]
         }
-        const routerMap: AppRouteRecordRaw[] = generateRoute(res)
+        const lang = wsCache.get(CACHE_KEY.LANG)
+        const routerMap: AppRouteRecordRaw[] = generateRoute(res,lang)
         // 动态路由,404一定要放到最后面
         this.addRouters = routerMap.concat([
           {

+ 3 - 3
src/store/modules/user.ts

@@ -54,9 +54,9 @@ export const useUserStore = defineStore('admin-user', {
         return null
       }
       let userInfo = wsCache.get(CACHE_KEY.USER)
-      if (!userInfo) {
-        userInfo = await getInfo()
-      }
+      // if (!userInfo) {
+      userInfo = await getInfo()
+      // }
       this.permissions = userInfo.permissions
       this.roles = userInfo.roles
       this.user = userInfo.user

+ 20 - 20
src/utils/routerHelper.ts

@@ -61,20 +61,30 @@ export const getRawRoute = (route: RouteLocationNormalized): RouteLocationNormal
 }
 
 // 后端控制路由生成
-export const generateRoute = (routes: AppCustomRouteRecordRaw[]): AppRouteRecordRaw[] => {
+export const generateRoute = (routes: AppCustomRouteRecordRaw[], lang): AppRouteRecordRaw[] => {
   const res: AppRouteRecordRaw[] = []
   const modulesRoutesKeys = Object.keys(modules)
   for (const route of routes) {
     // 1. 生成 meta 菜单元数据
+    let title = route.nameEn
+    switch (lang) {
+      case 'zh-CN':
+        title = route.name
+        break
+      case 'en':
+        title = route.nameEn
+        break
+      case 'ja':
+        title = route.nameJp
+        break
+    }
+
     const meta = {
-      title: route.name,
+      title: title,
       icon: route.icon,
       hidden: !route.visible,
       noCache: !route.keepAlive,
-      alwaysShow:
-        route.children &&
-        route.children.length === 1 &&
-        (route.alwaysShow !== undefined ? route.alwaysShow : true)
+      alwaysShow: route.children && route.children.length === 1 && (route.alwaysShow !== undefined ? route.alwaysShow : true)
     } as any
     // 特殊逻辑:如果后端配置的 MenuDO.component 包含 ?,则表示需要传递参数
     // 此时,我们需要解析参数,并且将参数放到 meta.query 中
@@ -89,10 +99,7 @@ export const generateRoute = (routes: AppCustomRouteRecordRaw[]): AppRouteRecord
     // 路由地址转首字母大写驼峰,作为路由名称,适配keepAlive
     let data: AppRouteRecordRaw = {
       path: route.path.indexOf('?') > -1 ? route.path.split('?')[0] : route.path,
-      name:
-        route.componentName && route.componentName.length > 0
-          ? route.componentName
-          : toCamelCase(route.path, true),
+      name: route.componentName && route.componentName.length > 0 ? route.componentName : toCamelCase(route.path, true),
       redirect: route.redirect,
       meta: meta
     }
@@ -105,10 +112,7 @@ export const generateRoute = (routes: AppCustomRouteRecordRaw[]): AppRouteRecord
       meta.alwaysShow = true
       const childrenData: AppRouteRecordRaw = {
         path: '',
-        name:
-          route.componentName && route.componentName.length > 0
-            ? route.componentName
-            : toCamelCase(route.path, true),
+        name: route.componentName && route.componentName.length > 0 ? route.componentName : toCamelCase(route.path, true),
         redirect: route.redirect,
         meta: meta
       }
@@ -141,7 +145,7 @@ export const generateRoute = (routes: AppCustomRouteRecordRaw[]): AppRouteRecord
         data.component = modules[modulesRoutesKeys[index]]
       }
       if (route.children) {
-        data.children = generateRoute(route.children)
+        data.children = generateRoute(route.children, lang)
       }
     }
     res.push(data as AppRouteRecordRaw)
@@ -218,11 +222,7 @@ const promoteRouteLevel = (route: AppRouteRecordRaw) => {
 }
 
 // 添加所有子菜单
-const addToChildren = (
-  routes: RouteRecordNormalized[],
-  children: AppRouteRecordRaw[],
-  routeModule: AppRouteRecordRaw
-) => {
+const addToChildren = (routes: RouteRecordNormalized[], children: AppRouteRecordRaw[], routeModule: AppRouteRecordRaw) => {
   for (let index = 0; index < children.length; index++) {
     const child = children[index]
     const route = routes.find((item) => item.name === child.name)

+ 5 - 5
src/views/Login/Login.vue

@@ -10,7 +10,7 @@
         <!-- 左上角的 logo + 系统标题 -->
         <div class="flex items-center relative text-white">
           <img alt="" class="w-48px h-48px mr-10px" src="@/assets/imgs/logo.png" />
-          <span class="text-20px font-bold">{{ underlineToHump(appStore.getTitle) }}</span>
+          <span class="text-20px font-bold">Tabemate Pro  オーダーシステム</span>
         </div>
         <!-- 左边的背景图 + 欢迎语 -->
         <div class="flex justify-center items-center h-[calc(100%-60px)]">
@@ -20,7 +20,7 @@
             tag="div"
           >
             <img key="1" alt="" class="w-500px" src="@/assets/imgs/login_bg.png" />
-            <div key="2" class="text-3xl text-white" style="text-align: center;">{{ t('login.welcome') }}</div>
+            <div key="2" class="text-3xl text-white" style="text-align: center;">Tabemate Pro  オーダーシステムへようこそ</div>
             <!-- <div key="3" class="mt-5 font-normal text-white text-14px">
               {{ t('login.message') }}
             </div> -->
@@ -30,9 +30,9 @@
       <div class="flex-1 p-30px <sm:p-10px dark:bg-v-dark relative">
         <!-- 右上角的主题、语言选择 -->
         <div class="flex justify-between items-center text-white @2xl:justify-end @xl:justify-end">
-          <div class="flex items-center @2xl:hidden @xl:hidden">
-            <img alt="" class="w-48px h-48px mr-10px" src="@/assets/imgs/logo.png" />
-            <span class="text-20px font-bold">{{ underlineToHump(appStore.getTitle) }}</span>
+          <div class="flex items-center @2xl:hidden xl:hidden">
+            <img alt="" class="w-48px h-48px mr-10px @gl:hidden" src="@/assets/imgs/logo.png" />
+            <span class="text-20px font-bold c-black">Tabemate Pro  オーダーシステム</span>
           </div>
           <div class="flex justify-end items-center space-x-10px">
             <!-- <ThemeSwitch /> -->

+ 17 - 32
src/views/Login/components/LoginForm.vue

@@ -15,8 +15,13 @@
           <LoginFormTitle style="width: 100%" />
         </el-form-item>
       </el-col>
+      <el-col v-if="locale" :span="24" style="padding-left: 10px; padding-right: 10px">
+        <el-form-item>
+          <LocaleSelect />
+        </el-form-item>
+      </el-col>
       <el-col :span="24" style="padding-left: 10px; padding-right: 10px">
-       <el-form-item v-if="loginData.tenantEnable === 'true'" prop="tenantName">
+        <el-form-item v-if="loginData.tenantEnable === 'true'" prop="tenantName">
           <el-input
             v-model="loginData.loginForm.tenantName"
             :placeholder="t('login.tenantNamePlaceholder')"
@@ -28,11 +33,7 @@
       </el-col>
       <el-col :span="24" style="padding-left: 10px; padding-right: 10px">
         <el-form-item prop="username">
-          <el-input
-            v-model="loginData.loginForm.username"
-            :placeholder="t('login.usernamePlaceholder')"
-            :prefix-icon="iconAvatar"
-          />
+          <el-input v-model="loginData.loginForm.username" :placeholder="t('login.usernamePlaceholder')" :prefix-icon="iconAvatar" />
         </el-form-item>
       </el-col>
       <el-col :span="24" style="padding-left: 10px; padding-right: 10px">
@@ -47,10 +48,7 @@
           />
         </el-form-item>
       </el-col>
-      <el-col
-        :span="24"
-        style="padding-left: 10px; padding-right: 10px; margin-top: -20px; margin-bottom: -20px"
-      >
+      <el-col :span="24" style="padding-left: 10px; padding-right: 10px; margin-top: -20px; margin-bottom: -20px">
         <el-form-item>
           <el-row justify="space-between" style="width: 100%">
             <el-col :span="6">
@@ -63,23 +61,10 @@
       </el-col>
       <el-col :span="24" style="padding-left: 10px; padding-right: 10px">
         <el-form-item>
-          <XButton
-            :loading="loginLoading"
-            :title="t('login.login')"
-            class="w-[100%]"
-            type="primary"
-            @click="getCode()"
-          />
+          <XButton :loading="loginLoading" :title="t('login.login')" class="w-[100%]" type="primary" @click="getCode()" />
         </el-form-item>
       </el-col>
-      <Verify
-        ref="verify"
-        :captchaType="captchaType"
-        :imgSize="{ width: '400px', height: '200px' }"
-        mode="pop"
-        @success="handleLogin"
-      />
-   
+      <Verify ref="verify" :captchaType="captchaType" :imgSize="{ width: '400px', height: '200px' }" mode="pop" @success="handleLogin" />
     </el-row>
   </el-form>
 </template>
@@ -94,7 +79,8 @@ import * as authUtil from '@/utils/auth'
 import { usePermissionStore } from '@/store/modules/permission'
 import * as LoginApi from '@/api/login'
 import { LoginStateEnum, useFormValid, useLoginState } from './useLogin'
-
+import { LocaleSelect } from '@/layout/components/LocaleDropdown'
+import { useAppStore } from '@/store/modules/app'
 const { t } = useI18n()
 //const message = useMessage()
 const iconAvatar = useIcon({ icon: 'ep:avatar' })
@@ -108,7 +94,8 @@ const redirect = ref<string>('')
 const loginLoading = ref(false)
 const verify = ref()
 const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字
-
+const appStore = useAppStore()
+const locale = computed(() => appStore.getLocale)
 const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN)
 
 const LoginRules = {
@@ -124,19 +111,17 @@ const loginData = reactive({
     tenantName: 'yshop',
     //username: 'yshop002',
     //password: '123456789',
-    username: 'admin',
-    password: 'admin123',
+    username: '',
+    password: '',
     captchaVerification: '',
     rememberMe: false
   }
 })
 
-
-
 // 获取验证码
 const getCode = async () => {
   // 情况一,未开启:则直接登录
-  console.log('oginData.captchaEnable:',loginData.captchaEnable)
+  console.log('oginData.captchaEnable:', loginData.captchaEnable)
   if (loginData.captchaEnable === 'false') {
     await handleLogin({})
   } else {

+ 2 - 1
src/views/Profile/components/UserAvatar.vue

@@ -4,7 +4,7 @@
       ref="cropperRef"
       :btnProps="{ preIcon: 'ant-design:cloud-upload-outlined' }"
       :showBtn="false"
-      :value="img"
+      :value="convertImageUrl(img)"
       width="120px"
       @change="handelUpload"
     />
@@ -15,6 +15,7 @@ import { propTypes } from '@/utils/propTypes'
 import { uploadAvatar } from '@/api/system/user/profile'
 import { CropperAvatar } from '@/components/Cropper'
 import { useUserStore } from '@/store/modules/user'
+import { convertImageUrl } from '@/utils/image-helper'
 const { t } = useI18n()
 
 

+ 3 - 2
src/views/mall/cashier/index.vue

@@ -106,7 +106,7 @@
 
                 <div class="goods-item" :key="idx" v-for="(item,idx) in productList">
                     <div class="item" @click="clickGoods(item.id)"  >
-                      <img class="image" lazy :src="item.image" />
+                      <img class="image" lazy :src="convertImageUrl(item.image)" />
                       <div class="goods-name">{{item.storeName}}</div>
                       <div class="goods-price">¥{{item.price}}</div>
                     </div>
@@ -164,6 +164,7 @@ import * as ShopApi from '@/api/mall/store/shop'
 import * as CashierApi from '@/api/mall/cashier'
 import type { TabsPaneContext } from 'element-plus'
 import { formatPast,formatDate } from '@/utils/formatTime'
+import {convertImageUrl} from '@/utils/image-helper'
 import settlement from './settlement.vue'
 // import payResult from './payResult.vue'
 // import scanPay from './scanPay.vue'
@@ -718,4 +719,4 @@ onMounted(() => {
 }
 
 
-</style>
+</style>

+ 10 - 3
src/views/mall/member/user/UserForm.vue

@@ -16,6 +16,12 @@
       <el-form-item :label="t('mall.phoneNumber')" prop="mobile">
         <el-input v-model="formData.mobile" :placeholder="t('mall.pleaseEnterPhoneNumber')" />
       </el-form-item>
+      <el-form-item :label="t('mall.userType')" prop="userType">
+        <el-select v-model="formData.userType" placeholder="请选择" style="width: 240px">
+          <el-option label="会员(面向 c 端,普通用户)" :value="1" />
+          <el-option label="管理员(面向 b 端,管理后台)" :value="2" />
+        </el-select>
+      </el-form-item>
       <el-form-item :label="t('mall.realName')" prop="realName">
         <el-input v-model="formData.realName" :placeholder="t('mall.pleaseEnterRealName')" />
       </el-form-item>
@@ -34,9 +40,9 @@
       <el-form-item :label="t('mall.userPoints')" prop="integral">
         <el-input v-model="formData.integral" :placeholder="t('mall.pleaseEnterUserRemainingPoints')" />
       </el-form-item>
-      <!-- <el-form-item label="等级" prop="level">
+      <el-form-item :label="t('mall.level')" prop="level">
         <el-input v-model="formData.level" placeholder="请输入等级" />
-      </el-form-item> -->
+      </el-form-item>
       <!-- <el-form-item label="是否为推广员" prop="isPromoter">
         <el-input v-model="formData.isPromoter" placeholder="请输入是否为推广员" />
       </el-form-item> -->
@@ -95,7 +101,8 @@ const formData = ref({
 const formRules = reactive({
   username: [{ required: true, message: t('mall.userAccountCannotBeEmpty'), trigger: 'blur' }],
   nickname: [{ required: true, message: t('mall.userNicknameCannotBeEmpty'), trigger: 'blur' }],
-  mobile: [{ required: true, message: t('mall.phoneNumberCannotBeEmpty'), trigger: 'blur' }]
+  mobile: [{ required: true, message: t('mall.phoneNumberCannotBeEmpty'), trigger: 'blur' }],
+  userType: [{ required: true, message: t('mall.userTypeCannotBeEmpty'), trigger: 'blur' }]
 })
 const formRef = ref() // 表单 Ref
 

+ 2 - 1
src/views/mall/member/user/index.vue

@@ -69,7 +69,7 @@
       <el-table-column :label="t('mall.userNickname')" align="center" prop="nickname" />
       <el-table-column :label="t('mall.userAvatar')" align="center" prop="avatar">
         <template #default="scope">
-        <el-image style="width: 50px; height: 50px" :src="scope.row.avatar" />
+        <el-image style="width: 50px; height: 50px" :src="convertImageUrl(scope.row.avatar)" />
         </template>
       </el-table-column>
       <el-table-column :label="t('mall.phoneNumber')" align="center" prop="mobile" />
@@ -128,6 +128,7 @@ import * as UserApi from '@/api/member/user'
 import UserForm from './UserForm.vue'
 import UserDetail from './UserDetail.vue'
 import Yue from './yue.vue'
+import { convertImageUrl } from '@/utils/image-helper'
 const message = useMessage() // 消息弹窗
 // const { t } = useI18n() // 国际化
 

+ 7 - 0
src/views/mall/order/storeOrder/OrderDetail.vue

@@ -32,6 +32,13 @@
                       item.uidType == 'user' ? t('mall.userOrdering') : t('mall.staffOrderingOnBehalf')
                     }}</span>
                     <span style="color: #5ac725">({{ item.isOrder == 0 ? t('mall.mealNotServed') : t('mall.mealServed') }})</span>
+                  <el-divider />
+                  <div class="flex align-center" v-for="(good,index2) in item.appDeskOrderGoodsVos" :key="index2">
+                    <div><el-image :src="convertImageUrl(good.image)" style="width: 70px;height: 70px;" /></div>
+                    <div class="flex  flex-1 flex-column ml-2 font-size-sm">
+                        <div class="flex justify-between"><span class="font-weight-bolder">{{good.title}}</span><span style="color: #f56c6c;">{{good.spec}}</span></div>
+                        <div class="flex justify-between mt-1"><span>¥{{good.price}}</span><span>x{{good.number}}</span></div>
+                    </div>
                   </div>
                 </div>
               </div>

+ 2 - 1
src/views/mall/order/storeOrder/index.vue

@@ -277,6 +277,7 @@ import StoreOrderRefund from './StoreOrderRefund.vue'
 import OrderDetail from './OrderDetail.vue'
 import OrderRecord from './OrderRecord.vue'
 import type { TabsPaneContext } from 'element-plus'
+import { convertImageUrl } from '@/utils/image-helper'
 import MailLogDetail from '@/views/system/mail/log/MailLogDetail.vue'
 import { convertImageUrl } from '@/utils/image-helper' // 导入图片URL处理工具
 
@@ -299,7 +300,7 @@ const queryParams = reactive({
 })
 const queryFormRef = ref() // 搜索的表单
 const exportLoading = ref(false) // 导出的加载中
-
+const VITE_BASE_URL = import.meta.env.VITE_BASE_URL
 const activeName = ref('')
 const orderStatus = ref('')
 const payStatus = ref('')

+ 3 - 1
src/views/mall/shop/ads/index.vue

@@ -42,7 +42,7 @@
       <el-table-column label="id" align="center" prop="id" />
       <el-table-column :label="t('mall.image')" align="center" prop="image">
         <template #default="scope">
-          <el-image style="width: 100px; height: 100px" :src="scope.row.image"  />
+          <el-image style="width: 100px; height: 100px" :src="convertImageUrl(scope.row.image)"  />
         </template>
       </el-table-column>
       <el-table-column :label="t('mall.isAvailable')" align="center" prop="isSwitch">
@@ -98,6 +98,8 @@ import { dateFormatter } from '@/utils/formatTime'
 import download from '@/utils/download'
 import * as AdsApi from '@/api/mall/shop/ads'
 import AdsForm from './AdsForm.vue'
+import { convertImageUrl } from '@/utils/image-helper'
+
 const message = useMessage() // 消息弹窗
 const { t } = useI18n() // 国际化
 

+ 2 - 1
src/views/mall/shop/service/index.vue

@@ -43,7 +43,7 @@
       <el-table-column :label="t('mall.title')" align="center" prop="name" />
       <el-table-column :label="t('mall.icon')" align="center" prop="image">
         <template #default="scope">
-          <el-image style="width: 100px; height: 100px" :src="scope.row.image"  />
+          <el-image style="width: 100px; height: 100px" :src="convertImageUrl(scope.row.image)"  />
         </template>
       </el-table-column>
       <el-table-column :label="t('mall.type')" align="center" prop="type">
@@ -110,6 +110,7 @@ import { dateFormatter } from '@/utils/formatTime'
 import download from '@/utils/download'
 import * as ServiceApi from '@/api/mall/shop/service'
 import ServiceForm from './ServiceForm.vue'
+import { convertImageUrl } from '@/utils/image-helper'
 const message = useMessage() // 消息弹窗
 const { t } = useI18n() // 国际化
 

+ 2 - 1
src/views/mall/store/shop/index.vue

@@ -53,7 +53,7 @@
       <el-table-column :label="t('mall.storePhone')" align="center" prop="mobile" width="150" />
       <el-table-column :label="t('mall.storeImage')" align="center" prop="image" width="150">
         <template #default="scope">
-          <el-image style="width: 100px; height: 100px" :src="scope.row.image"  />
+          <el-image style="width: 100px; height: 100px" :src="convertImageUrl(scope.row.image)"  />
         </template>
       </el-table-column>
       <el-table-column :label="t('mall.longitude')" align="center" prop="lng" width="150" />
@@ -136,6 +136,7 @@ import { dateFormatter, dateFormatter2 } from '@/utils/formatTime'
 import download from '@/utils/download'
 import * as ShopApi from '@/api/mall/store/shop'
 import ShopForm from './ShopForm.vue'
+import { convertImageUrl } from '@/utils/image-helper'
 const message = useMessage() // 消息弹窗
 const { t } = useI18n() // 国际化
 

+ 3 - 2
src/views/score/order/OrderDetail.vue

@@ -9,7 +9,7 @@
       </el-descriptions>
       <el-descriptions :title="t('score.productDetails')" :column="2">
         <el-descriptions-item :label="t('score.goodsPicture')">
-          <el-image style="width: 40px; height: 40px" :src="product.image" :fit="fit" />
+          <el-image style="width: 40px; height: 40px" :src="convertImageUrl(product.image)" :fit="fit" />
         </el-descriptions-item>
         <el-descriptions-item :label="t('score.productName')">{{ product.title }}</el-descriptions-item>
         <el-descriptions-item :label="t('score.price')">{{ product.score }}{{t('mp.points')}}</el-descriptions-item>
@@ -56,6 +56,7 @@
 <script setup lang="ts">
 import * as OrderApi from '@/api/score/order'
 import { formatDate } from '@/utils/formatTime'
+import { convertImageUrl } from '@/utils/image-helper'
 //const message = useMessage() // 消息弹窗
 
 const { t } = useI18n() // 国际化
@@ -87,4 +88,4 @@ const getLogistic = async(deliverySn,deliveryId) => {
 }
 </script>
 <style scoped>
-</style>
+</style>

+ 2 - 1
src/views/score/order/index.vue

@@ -69,7 +69,7 @@
         <template #default="score">
           <div class="tabBox">
               <div class="tabBox_img">
-                  <img :src="score.row.scoreProductRespVO.image" />
+                  <img :src="convertImageUrl(score.row.scoreProductRespVO.image)" />
               </div>
               <span class="tabBox_tit">{{ score.row.scoreProductRespVO.title }}</span>
               <span class="tabBox_pice">{{ '积分'+ score.row.scoreProductRespVO.score + ' x '+ score.row.number}}</span>
@@ -161,6 +161,7 @@ import download from '@/utils/download'
 import * as OrderApi from '@/api/score/order'
 import OrderForm from './OrderForm.vue'
 import OrderDetail from './OrderDetail.vue'
+import { convertImageUrl } from '@/utils/image-helper'
 const message = useMessage() // 消息弹窗
 const { t } = useI18n() // 国际化
 

+ 2 - 1
src/views/score/product/index.vue

@@ -40,7 +40,7 @@
       <el-table-column :label="t('score.productCategory')" align="center" prop="cateName" />
       <el-table-column :label="t('score.mainPicture')" align="center" prop="image" >
         <template #default="score">
-          <el-image style="width: 100px; height: 100px" :src="score.row.image"  />
+          <el-image style="width: 100px; height: 100px" :src="convertImageUrl(score.row.image)"  />
         </template>
       </el-table-column>
       <el-table-column :label="t('score.pointsConsumption')" align="center" prop="score" />
@@ -101,6 +101,7 @@ import { dateFormatter } from '@/utils/formatTime'
 import download from '@/utils/download'
 import * as ProductApi from '@/api/score/product'
 import ProductForm from './ProductForm.vue'
+import { convertImageUrl } from '@/utils/image-helper'
 const message = useMessage() // 消息弹窗
 const { t } = useI18n() // 国际化
 

+ 3 - 2
src/views/score/scoreads/index.vue

@@ -27,7 +27,7 @@
       <el-table-column label="id" align="center" prop="id" />
       <el-table-column :label="t('score.picture')" align="center" prop="image">
         <template #default="score">
-          <el-image style="width: 100px; height: 50px" :src="score.row.image"  />
+          <el-image style="width: 100px; height: 50px" :src="convertImageUrl(score.row.image)"  />
         </template>
       </el-table-column>
       <el-table-column :label="t('score.availability')" align="center" prop="isSwitch">
@@ -83,6 +83,7 @@ import { dateFormatter } from '@/utils/formatTime'
 import download from '@/utils/download'
 import { AdsApi, AdsVO } from '@/api/score/scoreads'
 import AdsForm from './AdsForm.vue'
+import { convertImageUrl } from '@/utils/image-helper'
 
 /** 积分商城广告图管理 列表 */
 defineOptions({ name: 'ScoreAds' })
@@ -167,4 +168,4 @@ const handleExport = async () => {
 onMounted(() => {
   getList()
 })
-</script>
+</script>

+ 3 - 3
src/views/system/notice/index.vue

@@ -56,9 +56,9 @@
           <template #default="scope">
             <el-image
               style="width: 100px; height: 100px"
-              :src="scope.row.picUrl"
+              :src="convertImageUrl(scope.row.picUrl)"
               :zoom-rate="1.2"
-              :preview-src-list="[scope.row.picUrl]"
+              :preview-src-list="[convertImageUrl(scope.row.picUrl)]"
               :initial-index="0"
               :z-index="900"
               :hide-on-click-modal="true"
@@ -125,7 +125,7 @@ import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { dateFormatter } from '@/utils/formatTime'
 import * as NoticeApi from '@/api/system/notice'
 import NoticeForm from './NoticeForm.vue'
-
+import { convertImageUrl } from '@/utils/image-helper'
 defineOptions({ name: 'SystemNotice' })
 
 const message = useMessage() // 消息弹窗

+ 1 - 1
src/views/system/sms/template/SmsTemplateForm.vue

@@ -50,7 +50,7 @@
           </el-radio>
         </el-radio-group>
       </el-form-item>
-      <el-form-item :label="t('mall.smsAPITemplateNumber')" prop="apiTemplateId">
+      <el-form-item :label="t('system.smsAPITemplateNumber')" prop="apiTemplateId">
         <el-input v-model="formData.apiTemplateId" :placeholder="t('mall.pleaseEnterTheTemplateNumberOfTheSmsAPI')" />
       </el-form-item>
       <el-form-item :label="t('public.remark')" prop="remark">

+ 3 - 4
types/router.d.ts

@@ -48,10 +48,7 @@ declare module 'vue-router' {
   }
 }
 
-type Component<T = any> =
-  | ReturnType<typeof defineComponent>
-  | (() => Promise<typeof import('*.vue')>)
-  | (() => Promise<T>)
+type Component<T = any> = ReturnType<typeof defineComponent> | (() => Promise<typeof import('*.vue')>) | (() => Promise<T>)
 
 declare global {
   interface AppRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> {
@@ -67,6 +64,8 @@ declare global {
   interface AppCustomRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> {
     icon: any
     name: string
+    nameEn: string
+    nameJp: string
     meta: RouteMeta
     component: string
     componentName?: string