From 231ac88c8b79acbbcca646a7d1d1e9ac4e536ab7 Mon Sep 17 00:00:00 2001 From: Lewis_yan Date: Wed, 8 Apr 2026 17:11:39 +0800 Subject: [PATCH 01/24] =?UTF-8?q?feat(i18n):=20=E5=90=88=E5=B9=B6=20django?= =?UTF-8?q?-vue3-admin=20i18n=20=E5=9B=BD=E9=99=85=E5=8C=96=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 后端: - 添加 LocaleMiddleware 和 Django i18n 配置 (LANGUAGES/LOCALE_PATHS) - Users.language 字段支持用户语言偏好 - Menu/MenuButton name_en/name_zh_tw 多语言字段 - WebRouterSerializer get_title() 语言感知返回 - update_language API endpoint 前端: - vue-i18n 升级为 deepMerge + fast-crud i18n 集成 - 新增 19 个模块的 3 种语言翻译 (zh-CN/en/zh-TW) - 导航栏语言切换器: 刷新路由 + 后端持久化 - router/backEnd.ts 支持 language 参数和 refreshRoutesForI18n --- backend/application/settings.py | 17 + backend/dvadmin/system/models.py | 14 +- backend/dvadmin/system/views/menu.py | 18 +- backend/dvadmin/system/views/menu_button.py | 18 +- backend/dvadmin/system/views/user.py | 13 + backend/dvadmin/utils/middleware.py | 53 +++ backend/locale/en/LC_MESSAGES/django.po | 259 +++++++++++++ backend/locale/zh_Hans/LC_MESSAGES/django.po | 267 +++++++++++++ web/src/i18n/fs/zh-tw.ts | 115 ++++++ web/src/i18n/index.ts | 77 ++-- web/src/i18n/lang/en.ts | 366 +++++++++++++++--- web/src/i18n/lang/zh-cn.ts | 370 ++++++++++++++++--- web/src/i18n/lang/zh-tw.ts | 369 +++++++++++++++--- web/src/i18n/pages/areas/en.ts | 62 ++++ web/src/i18n/pages/areas/zh-cn.ts | 62 ++++ web/src/i18n/pages/areas/zh-tw.ts | 62 ++++ web/src/i18n/pages/columns/en.ts | 35 ++ web/src/i18n/pages/columns/zh-cn.ts | 35 ++ web/src/i18n/pages/columns/zh-tw.ts | 35 ++ web/src/i18n/pages/config/en.ts | 110 ++++++ web/src/i18n/pages/config/zh-cn.ts | 110 ++++++ web/src/i18n/pages/config/zh-tw.ts | 110 ++++++ web/src/i18n/pages/demo/en.ts | 77 ++++ web/src/i18n/pages/demo/zh-cn.ts | 64 ++++ web/src/i18n/pages/demo/zh-tw.ts | 72 ++++ web/src/i18n/pages/dept/en.ts | 126 +++++++ web/src/i18n/pages/dept/zh-cn.ts | 126 +++++++ web/src/i18n/pages/dept/zh-tw.ts | 0 web/src/i18n/pages/dictionary/en.ts | 114 ++++++ web/src/i18n/pages/dictionary/zh-cn.ts | 103 ++++++ web/src/i18n/pages/dictionary/zh-tw.ts | 104 ++++++ web/src/i18n/pages/downloadCenter/en.ts | 30 ++ web/src/i18n/pages/downloadCenter/zh-cn.ts | 30 ++ web/src/i18n/pages/downloadCenter/zh-tw.ts | 30 ++ web/src/i18n/pages/fileList/en.ts | 58 +++ web/src/i18n/pages/fileList/zh-cn.ts | 58 +++ web/src/i18n/pages/fileList/zh-tw.ts | 58 +++ web/src/i18n/pages/home/en.ts | 41 ++ web/src/i18n/pages/home/zh-cn.ts | 41 ++ web/src/i18n/pages/home/zh-tw.ts | 0 web/src/i18n/pages/layout/en.ts | 72 ++++ web/src/i18n/pages/layout/zh-cn.ts | 71 ++++ web/src/i18n/pages/layout/zh-tw.ts | 72 ++++ web/src/i18n/pages/loginLog/en.ts | 72 ++++ web/src/i18n/pages/loginLog/zh-cn.ts | 72 ++++ web/src/i18n/pages/loginLog/zh-tw.ts | 72 ++++ web/src/i18n/pages/menu/en.ts | 162 ++++++++ web/src/i18n/pages/menu/zh-cn.ts | 162 ++++++++ web/src/i18n/pages/menu/zh-tw.ts | 162 ++++++++ web/src/i18n/pages/messageCenter/en.ts | 68 ++++ web/src/i18n/pages/messageCenter/zh-cn.ts | 68 ++++ web/src/i18n/pages/messageCenter/zh-tw.ts | 68 ++++ web/src/i18n/pages/operationLog/en.ts | 65 ++++ web/src/i18n/pages/operationLog/zh-cn.ts | 65 ++++ web/src/i18n/pages/operationLog/zh-tw.ts | 65 ++++ web/src/i18n/pages/personal/en.ts | 64 ++++ web/src/i18n/pages/personal/zh-cn.ts | 64 ++++ web/src/i18n/pages/personal/zh-tw.ts | 64 ++++ web/src/i18n/pages/role/en.ts | 91 +++++ web/src/i18n/pages/role/zh-cn.ts | 91 +++++ web/src/i18n/pages/role/zh-tw.ts | 0 web/src/i18n/pages/taskLog/en.ts | 34 ++ web/src/i18n/pages/taskLog/zh-cn.ts | 34 ++ web/src/i18n/pages/taskLog/zh-tw.ts | 34 ++ web/src/i18n/pages/taskManage/en.ts | 73 ++++ web/src/i18n/pages/taskManage/zh-cn.ts | 73 ++++ web/src/i18n/pages/taskManage/zh-tw.ts | 73 ++++ web/src/i18n/pages/user/en.ts | 129 +++++++ web/src/i18n/pages/user/zh-cn.ts | 129 +++++++ web/src/i18n/pages/user/zh-tw.ts | 129 +++++++ web/src/i18n/pages/whitelist/en.ts | 60 +++ web/src/i18n/pages/whitelist/zh-cn.ts | 60 +++ web/src/i18n/pages/whitelist/zh-tw.ts | 60 +++ web/src/layout/navBars/breadcrumb/user.vue | 12 +- web/src/router/backEnd.ts | 28 +- web/src/settings.ts | 3 +- 76 files changed, 6160 insertions(+), 170 deletions(-) create mode 100644 backend/locale/en/LC_MESSAGES/django.po create mode 100644 backend/locale/zh_Hans/LC_MESSAGES/django.po create mode 100644 web/src/i18n/fs/zh-tw.ts create mode 100644 web/src/i18n/pages/areas/en.ts create mode 100644 web/src/i18n/pages/areas/zh-cn.ts create mode 100644 web/src/i18n/pages/areas/zh-tw.ts create mode 100644 web/src/i18n/pages/columns/en.ts create mode 100644 web/src/i18n/pages/columns/zh-cn.ts create mode 100644 web/src/i18n/pages/columns/zh-tw.ts create mode 100644 web/src/i18n/pages/config/en.ts create mode 100644 web/src/i18n/pages/config/zh-cn.ts create mode 100644 web/src/i18n/pages/config/zh-tw.ts create mode 100644 web/src/i18n/pages/demo/en.ts create mode 100644 web/src/i18n/pages/demo/zh-cn.ts create mode 100644 web/src/i18n/pages/demo/zh-tw.ts create mode 100644 web/src/i18n/pages/dept/en.ts create mode 100644 web/src/i18n/pages/dept/zh-cn.ts create mode 100644 web/src/i18n/pages/dept/zh-tw.ts create mode 100644 web/src/i18n/pages/dictionary/en.ts create mode 100644 web/src/i18n/pages/dictionary/zh-cn.ts create mode 100644 web/src/i18n/pages/dictionary/zh-tw.ts create mode 100644 web/src/i18n/pages/downloadCenter/en.ts create mode 100644 web/src/i18n/pages/downloadCenter/zh-cn.ts create mode 100644 web/src/i18n/pages/downloadCenter/zh-tw.ts create mode 100644 web/src/i18n/pages/fileList/en.ts create mode 100644 web/src/i18n/pages/fileList/zh-cn.ts create mode 100644 web/src/i18n/pages/fileList/zh-tw.ts create mode 100644 web/src/i18n/pages/home/en.ts create mode 100644 web/src/i18n/pages/home/zh-cn.ts create mode 100644 web/src/i18n/pages/home/zh-tw.ts create mode 100644 web/src/i18n/pages/layout/en.ts create mode 100644 web/src/i18n/pages/layout/zh-cn.ts create mode 100644 web/src/i18n/pages/layout/zh-tw.ts create mode 100644 web/src/i18n/pages/loginLog/en.ts create mode 100644 web/src/i18n/pages/loginLog/zh-cn.ts create mode 100644 web/src/i18n/pages/loginLog/zh-tw.ts create mode 100644 web/src/i18n/pages/menu/en.ts create mode 100644 web/src/i18n/pages/menu/zh-cn.ts create mode 100644 web/src/i18n/pages/menu/zh-tw.ts create mode 100644 web/src/i18n/pages/messageCenter/en.ts create mode 100644 web/src/i18n/pages/messageCenter/zh-cn.ts create mode 100644 web/src/i18n/pages/messageCenter/zh-tw.ts create mode 100644 web/src/i18n/pages/operationLog/en.ts create mode 100644 web/src/i18n/pages/operationLog/zh-cn.ts create mode 100644 web/src/i18n/pages/operationLog/zh-tw.ts create mode 100644 web/src/i18n/pages/personal/en.ts create mode 100644 web/src/i18n/pages/personal/zh-cn.ts create mode 100644 web/src/i18n/pages/personal/zh-tw.ts create mode 100644 web/src/i18n/pages/role/en.ts create mode 100644 web/src/i18n/pages/role/zh-cn.ts create mode 100644 web/src/i18n/pages/role/zh-tw.ts create mode 100644 web/src/i18n/pages/taskLog/en.ts create mode 100644 web/src/i18n/pages/taskLog/zh-cn.ts create mode 100644 web/src/i18n/pages/taskLog/zh-tw.ts create mode 100644 web/src/i18n/pages/taskManage/en.ts create mode 100644 web/src/i18n/pages/taskManage/zh-cn.ts create mode 100644 web/src/i18n/pages/taskManage/zh-tw.ts create mode 100644 web/src/i18n/pages/user/en.ts create mode 100644 web/src/i18n/pages/user/zh-cn.ts create mode 100644 web/src/i18n/pages/user/zh-tw.ts create mode 100644 web/src/i18n/pages/whitelist/en.ts create mode 100644 web/src/i18n/pages/whitelist/zh-cn.ts create mode 100644 web/src/i18n/pages/whitelist/zh-tw.ts diff --git a/backend/application/settings.py b/backend/application/settings.py index e9e961a..e05622f 100644 --- a/backend/application/settings.py +++ b/backend/application/settings.py @@ -73,6 +73,7 @@ MIDDLEWARE = [ "whitenoise.middleware.WhiteNoiseMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "corsheaders.middleware.CorsMiddleware", # 跨域中间件 + "dvadmin.utils.middleware.LocaleMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", @@ -152,6 +153,22 @@ USE_L10N = True USE_TZ = False +# ================================================= # +# *************** 国际化配置 (i18n) *************** # +# ================================================= # + +# Supported languages — maps frontend codes to Django locale names (D-07) +LANGUAGES = [ + ('zh-hans', 'Simplified Chinese'), + ('en', 'English'), + ('zh-hant', 'Traditional Chinese'), +] + +# Locale file paths for Django .po/.mo files (BEI-04) +LOCALE_PATHS = [ + os.path.join(BASE_DIR, "locale"), +] + # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.2/howto/static-files/ diff --git a/backend/dvadmin/system/models.py b/backend/dvadmin/system/models.py index 4dca9c9..da9a0a9 100644 --- a/backend/dvadmin/system/models.py +++ b/backend/dvadmin/system/models.py @@ -84,6 +84,14 @@ class Users(CoreModel, AbstractUser): ) login_error_count = models.IntegerField(default=0, verbose_name="登录错误次数", help_text="登录错误次数") pwd_change_count = models.IntegerField(default=0,blank=True, verbose_name="密码修改次数", help_text="密码修改次数") + language = models.CharField( + max_length=10, + default='zh-cn', + blank=True, + null=True, + verbose_name="界面语言", + help_text="界面语言" + ) objects = CustomUserManager() def set_password(self, raw_password): @@ -213,7 +221,9 @@ class Menu(CoreModel): help_text="上级菜单", ) icon = models.CharField(max_length=64, verbose_name="菜单图标", null=True, blank=True, help_text="菜单图标") - name = models.CharField(max_length=64, verbose_name="菜单名称", help_text="菜单名称") + name = models.CharField(max_length=64, verbose_name="菜单名称(默认)", help_text="菜单名称(默认语言)") + name_en = models.CharField(max_length=64, verbose_name="菜单名称(English)", blank=True, null=True, help_text="菜单名称(English)") + name_zh_tw = models.CharField(max_length=64, verbose_name="菜单名称(繁體中文)", blank=True, null=True, help_text="菜单名称(繁體中文)") sort = models.IntegerField(default=1, verbose_name="显示排序", null=True, blank=True, help_text="显示排序") ISLINK_CHOICES = ( (0, "否"), @@ -294,6 +304,8 @@ class MenuButton(CoreModel): help_text="关联菜单", ) name = models.CharField(max_length=64, verbose_name="名称", help_text="名称") + name_en = models.CharField(max_length=64, verbose_name="名称(English)", blank=True, null=True, help_text="名称(English)") + name_zh_tw = models.CharField(max_length=64, verbose_name="名称(繁體中文)", blank=True, null=True, help_text="名称(繁體中文)") value = models.CharField(unique=True, max_length=64, verbose_name="权限值", help_text="权限值") api = models.CharField(max_length=200, verbose_name="接口地址", help_text="接口地址") METHOD_CHOICES = ( diff --git a/backend/dvadmin/system/views/menu.py b/backend/dvadmin/system/views/menu.py index 33ed979..24af6e0 100644 --- a/backend/dvadmin/system/views/menu.py +++ b/backend/dvadmin/system/views/menu.py @@ -24,7 +24,7 @@ class MenuSerializer(CustomModelSerializer): hasChild = serializers.SerializerMethodField() def get_menuPermission(self, instance): - queryset = instance.menuPermission.order_by('-name').values('id', 'name', 'value') + queryset = instance.menuPermission.order_by('-name').values('id', 'name', 'name_en', 'name_zh_tw', 'value') # MenuButtonSerializer(instance.menuPermission.all(), many=True) if queryset: return queryset @@ -66,13 +66,25 @@ class WebRouterSerializer(CustomModelSerializer): 前端菜单路由的简单序列化器 """ path = serializers.CharField(source="web_path") - title = serializers.CharField(source="name") + title = serializers.SerializerMethodField() + + def get_title(self, obj): + """Return title based on request language preference (D-05)""" + request = self.context.get('request') + if not request: + return obj.name + lang = getattr(request, 'LANGUAGE_CODE', None) or 'zh-hans' + if lang == 'en': + return obj.name_en or obj.name + elif lang == 'zh-hant': + return obj.name_zh_tw or obj.name + return obj.name class Meta: model = Menu fields = ( 'id', 'parent', 'icon', 'sort', 'path', 'name', 'title', 'is_link','link_url', 'is_catalog', 'web_path', 'component', - 'component_name', 'cache', 'visible','is_iframe','is_affix', 'status') + 'component_name', 'cache', 'visible','is_iframe','is_affix', 'status', 'name_en', 'name_zh_tw') read_only_fields = ["id"] diff --git a/backend/dvadmin/system/views/menu_button.py b/backend/dvadmin/system/views/menu_button.py index c1ca7c9..1d917a1 100644 --- a/backend/dvadmin/system/views/menu_button.py +++ b/backend/dvadmin/system/views/menu_button.py @@ -25,7 +25,7 @@ class MenuButtonSerializer(CustomModelSerializer): class Meta: model = MenuButton - fields = ['id', 'name', 'value', 'api', 'method','menu'] + fields = ['id', 'name', 'name_en', 'name_zh_tw', 'value', 'api', 'method', 'menu'] read_only_fields = ["id"] @@ -94,14 +94,14 @@ class MenuButtonViewSet(CustomModelViewSet): """ menu_obj = Menu.objects.filter(id=request.data['menu']).first() result_list = [ - {'menu': menu_obj.id, 'name': '新增', 'value': f'{menu_obj.component_name}:Create', 'api': f'/api/{menu_obj.component_name}/', 'method': 1}, - {'menu': menu_obj.id, 'name': '删除', 'value': f'{menu_obj.component_name}:Delete', 'api': f'/api/{menu_obj.component_name}/{{id}}/', 'method': 3}, - {'menu': menu_obj.id, 'name': '编辑', 'value': f'{menu_obj.component_name}:Update', 'api': f'/api/{menu_obj.component_name}/{{id}}/', 'method': 2}, - {'menu': menu_obj.id, 'name': '查询', 'value': f'{menu_obj.component_name}:Search', 'api': f'/api/{menu_obj.component_name}/', 'method': 0}, - {'menu': menu_obj.id, 'name': '详情', 'value': f'{menu_obj.component_name}:Retrieve', 'api': f'/api/{menu_obj.component_name}/{{id}}/', 'method': 0}, - {'menu': menu_obj.id, 'name': '复制', 'value': f'{menu_obj.component_name}:Copy', 'api': f'/api/{menu_obj.component_name}/', 'method': 1}, - {'menu': menu_obj.id, 'name': '导入', 'value': f'{menu_obj.component_name}:Import', 'api': f'/api/{menu_obj.component_name}/import_data/', 'method': 1}, - {'menu': menu_obj.id, 'name': '导出', 'value': f'{menu_obj.component_name}:Export', 'api': f'/api/{menu_obj.component_name}/export_data/', 'method': 1},] + {'menu': menu_obj.id, 'name': '新增', 'name_en': 'Add', 'name_zh_tw': '新增', 'value': f'{menu_obj.component_name}:Create', 'api': f'/api/{menu_obj.component_name}/', 'method': 1}, + {'menu': menu_obj.id, 'name': '删除', 'name_en': 'Delete', 'name_zh_tw': '刪除', 'value': f'{menu_obj.component_name}:Delete', 'api': f'/api/{menu_obj.component_name}/{{id}}/', 'method': 3}, + {'menu': menu_obj.id, 'name': '编辑', 'name_en': 'Edit', 'name_zh_tw': '編輯', 'value': f'{menu_obj.component_name}:Update', 'api': f'/api/{menu_obj.component_name}/{{id}}/', 'method': 2}, + {'menu': menu_obj.id, 'name': '查询', 'name_en': 'Search', 'name_zh_tw': '查詢', 'value': f'{menu_obj.component_name}:Search', 'api': f'/api/{menu_obj.component_name}/', 'method': 0}, + {'menu': menu_obj.id, 'name': '详情', 'name_en': 'Detail', 'name_zh_tw': '詳情', 'value': f'{menu_obj.component_name}:Retrieve', 'api': f'/api/{menu_obj.component_name}/{{id}}/', 'method': 0}, + {'menu': menu_obj.id, 'name': '复制', 'name_en': 'Copy', 'name_zh_tw': '複製', 'value': f'{menu_obj.component_name}:Copy', 'api': f'/api/{menu_obj.component_name}/', 'method': 1}, + {'menu': menu_obj.id, 'name': '导入', 'name_en': 'Import', 'name_zh_tw': '導入', 'value': f'{menu_obj.component_name}:Import', 'api': f'/api/{menu_obj.component_name}/import_data/', 'method': 1}, + {'menu': menu_obj.id, 'name': '导出', 'name_en': 'Export', 'name_zh_tw': '導出', 'value': f'{menu_obj.component_name}:Export', 'api': f'/api/{menu_obj.component_name}/export_data/', 'method': 1},] serializer = self.get_serializer(data=result_list, many=True) serializer.is_valid(raise_exception=True) serializer.save() diff --git a/backend/dvadmin/system/views/user.py b/backend/dvadmin/system/views/user.py index 89b6533..bbf9853 100644 --- a/backend/dvadmin/system/views/user.py +++ b/backend/dvadmin/system/views/user.py @@ -10,6 +10,7 @@ from django.db.models import Q from application import dispatch from dvadmin.system.models import Users, Role, Dept from dvadmin.system.views.role import RoleSerializer +from django.utils import translation from dvadmin.utils.json_response import ErrorResponse, DetailResponse, SuccessResponse from dvadmin.utils.serializers import CustomModelSerializer from dvadmin.utils.validator import CustomUniqueValidator @@ -361,6 +362,18 @@ class UserViewSet(CustomModelViewSet): request.user.save() return DetailResponse(data=None, msg="修改成功") + @action(methods=["PUT"], detail=False, permission_classes=[IsAuthenticated]) + def update_language(self, request, *args, **kwargs): + """更新当前用户语言偏好""" + lang = request.data.get("language", "zh-cn") + valid_locales = ["zh-cn", "en", "zh-tw"] + if lang not in valid_locales: + return ErrorResponse(msg="Invalid language code") + user = request.user + user.language = lang + user.save(update_fields=["language", "modifier", "modifier_time"]) + return DetailResponse(data={"language": lang}, msg="Language updated successfully") + @action(methods=["PUT"], detail=True, permission_classes=[IsAuthenticated]) def reset_to_default_password(self, request,pk): """恢复默认密码""" diff --git a/backend/dvadmin/utils/middleware.py b/backend/dvadmin/utils/middleware.py index 1185060..4e729fe 100644 --- a/backend/dvadmin/utils/middleware.py +++ b/backend/dvadmin/utils/middleware.py @@ -8,6 +8,8 @@ from django.conf import settings from django.contrib.auth.models import AnonymousUser from django.core.exceptions import MultipleObjectsReturned from django.http import HttpResponse, HttpResponseServerError +from django.utils import translation +from django.utils.translation.trans_real import parse_accept_lang_header from django.utils.deprecation import MiddlewareMixin from dvadmin.system.models import OperationLog @@ -166,3 +168,54 @@ class HealthCheckMiddleware(object): return HttpResponseServerError("cache: cannot connect to cache.") return HttpResponse("OK") + + +class LocaleMiddleware: + """Set request locale from Accept-Language header (D-03: header always wins).""" + + # Map frontend locale codes to Django locale codes (D-07 fallback order) + LOCALE_MAP = { + 'en': 'en', + 'zh-cn': 'zh-hans', + 'zh-tw': 'zh-hant', + } + + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + lang_code = None + + # 1. Accept-Language header always wins (D-03) + accept_lang = request.META.get('HTTP_ACCEPT_LANGUAGE', '') + if accept_lang: + try: + for code, _priority in parse_accept_lang_header(accept_lang): + if code == '*': + continue + # Normalize: 'zh-CN' -> 'zh-cn' + normalized = code.lower().replace('_', '-') + if normalized in self.LOCALE_MAP: + lang_code = self.LOCALE_MAP[normalized] + break + elif code in dict(settings.LANGUAGES): + lang_code = code + break + except Exception: + pass + + # 2. Authenticated user DB preference as fallback (D-01: header wins) + if not lang_code and hasattr(request, 'user') and request.user.is_authenticated: + user_lang = getattr(request.user, 'language', None) or 'zh-cn' + lang_code = self.LOCALE_MAP.get(user_lang, user_lang) + + # 3. Default for unauthenticated/unknown (D-06: zh-CN default) + if not lang_code: + lang_code = 'zh-hans' + + translation.activate(lang_code) + request.LANGUAGE_CODE = lang_code + + response = self.get_response(request) + translation.deactivate() + return response diff --git a/backend/locale/en/LC_MESSAGES/django.po b/backend/locale/en/LC_MESSAGES/django.po new file mode 100644 index 0000000..373dfbf --- /dev/null +++ b/backend/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,259 @@ +# English translations for Django. +# Copyright (C) 2026 +# This file is distributed under the same license as the Django project. +# +msgid "" +msgstr "" +"Project-Id-Version: django-vue3-admin\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2026-03-31 00:00+0000\n" +"PO-Revision-Date: 2026-03-31 00:00+0000\n" +"Last-Translator: \n" +"Language: en\n" +"Language-Team: English\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: django-vue3-admin i18n phase 1\n" + +msgid "error" +msgstr "error" + +msgid "Endpoint address is incorrect" +msgstr "Endpoint address is incorrect" + +msgid "Delete failed: this record has related data bindings" +msgstr "Delete failed: this record has related data bindings" + +msgid "This account has been disabled. Contact an administrator to unlock it." +msgstr "This account has been disabled. Contact an administrator to unlock it." + +msgid "Date format is incorrect" +msgstr "Date format is incorrect" + +msgid "No." +msgstr "No." + +msgid "Import" +msgstr "Import" + +msgid "Template" +msgstr "Template" + +msgid "Export" +msgstr "Export" + +msgid "Update primary key (do not modify)" +msgstr "Update primary key (do not modify)" + +msgid "Please configure the corresponding export template fields." +msgstr "Please configure the corresponding export template fields." + +msgid "Please configure the corresponding import template fields." +msgstr "Please configure the corresponding import template fields." + +msgid "Please configure the corresponding import serializer." +msgstr "Please configure the corresponding import serializer." + +msgid "Please configure the corresponding export serializer." +msgstr "Please configure the corresponding export serializer." + +msgid "Import successful" +msgstr "Import successful" + +msgid "Data export task" +msgstr "Data export task" + +msgid "Import task has been created. Please go to 'Download Center' to wait for download" +msgstr "Import task has been created. Please go to 'Download Center' to wait for download" + +msgid "Create successful" +msgstr "Create successful" + +msgid "Query successful" +msgstr "Query successful" + +msgid "Update successful" +msgstr "Update successful" + +msgid "Delete successful" +msgstr "Delete successful" + +msgid "keys field not provided" +msgstr "keys field not provided" + +msgid "Verification code is required" +msgstr "Verification code is required" + +msgid "Verification code has expired" +msgstr "Verification code has expired" + +msgid "Image verification code is incorrect" +msgstr "Image verification code is incorrect" + +msgid "The account you are logging in with does not exist" +msgstr "The account you are logging in with does not exist" + +msgid "Multiple accounts found for this login. Contact an administrator to check account uniqueness" +msgstr "Multiple accounts found for this login. Contact an administrator to check account uniqueness" + +msgid "Account has been locked. Contact an administrator to unlock" +msgstr "Account has been locked. Contact an administrator to unlock" + +msgid "Username/password incorrect. Account will be locked after {} failed attempts~" +msgstr "Username/password incorrect. Account will be locked after {} failed attempts~" + +msgid "Request successful" +msgstr "Request successful" + +msgid "This interface is not yet available" +msgstr "This interface is not yet available" + +msgid "Logout successful" +msgstr "Logout successful" + +msgid "Username/password incorrect" +msgstr "Username/password incorrect" + +msgid "Username must be unique" +msgstr "Username must be unique" + +msgid "Mobile number must be unique" +msgstr "Mobile number must be unique" + +msgid "Enabled" +msgstr "Enabled" + +msgid "Disabled" +msgstr "Disabled" + +msgid "Username" +msgstr "Username" + +msgid "Full name" +msgstr "Full name" + +msgid "Email" +msgstr "Email" + +msgid "Mobile" +msgstr "Mobile" + +msgid "Gender" +msgstr "Gender" + +msgid "Account status" +msgstr "Account status" + +msgid "Last login time" +msgstr "Last login time" + +msgid "Department name" +msgstr "Department name" + +msgid "Department head" +msgstr "Department head" + +msgid "Login username" +msgstr "Login username" + +msgid "Department" +msgstr "Department" + +msgid "Role" +msgstr "Role" + +msgid "No department" +msgstr "No department" + +msgid "Parameters cannot be empty" +msgstr "Parameters cannot be empty" + +msgid "Passwords do not match" +msgstr "Passwords do not match" + +msgid "Old password is incorrect" +msgstr "Old password is incorrect" + +msgid "Invalid language code" +msgstr "Invalid language code" + +msgid "Language updated successfully" +msgstr "Language updated successfully" + +msgid "Only super administrators can reset passwords" +msgstr "Only super administrators can reset passwords" + +msgid "Password reset successful" +msgstr "Password reset successful" + +msgid "User not found" +msgstr "User not found" + +#: dvadmin/system/views/role.py +msgid "Permission key must be unique" +msgstr "Permission key must be unique" +#: dvadmin/system/views/role.py +msgid "Please select a role" +msgstr "Please select a role" +#: dvadmin/system/views/role.py +msgid "Please select a user" +msgstr "Please select a user" +#: dvadmin/system/views/role.py +msgid "Add successful" +msgstr "Add successful" +#: dvadmin/system/views/menu.py +msgid "Menu does not exist" +msgstr "Menu does not exist" +#: dvadmin/system/views/menu.py +msgid "Move up successful" +msgstr "Move up successful" +#: dvadmin/system/views/menu.py +msgid "Move down successful" +msgstr "Move down successful" +#: dvadmin/system/views/dept.py +msgid "Department does not exist" +msgstr "Department does not exist" +#: dvadmin/system/views/role_menu.py +msgid "Role parameter not provided" +msgstr "Role parameter not provided" +#: dvadmin/system/views/role_menu.py +msgid "Menu parameter not provided" +msgstr "Menu parameter not provided" +#: dvadmin/system/views/role_menu.py +msgid "Save successful" +msgstr "Save successful" +#: dvadmin/system/views/system_config.py +msgid "Variable name already exists" +msgstr "Variable name already exists" +#: dvadmin/system/views/system_config.py +msgid "Query error~" +msgstr "Query error~" +#: dvadmin/system/views/system_config.py +msgid "Association information not found" +msgstr "Association information not found" +#: dvadmin/system/views/menu_button.py +msgid "Batch creation successful" +msgstr "Batch creation successful" +#: dvadmin/system/views/menu_button.py +msgid "Add" +msgstr "Add" +#: dvadmin/system/views/menu_button.py +msgid "Edit" +msgstr "Edit" +#: dvadmin/system/views/menu_field.py +msgid "Model table does not exist" +msgstr "Model table does not exist" +#: dvadmin/system/views/menu_field.py +msgid "Field permission for '%s' already exists and cannot be duplicated" +msgstr "Field permission for '%s' already exists and cannot be duplicated" +#: dvadmin/system/views/menu_field.py +msgid "Match successful" +msgstr "Match successful" +#: dvadmin/system/views/message_center.py +msgid "You have a new message~" +msgstr "You have a new message~" +#: dvadmin/system/views/message_center.py +msgid "You viewed a message~" +msgstr "You viewed a message~" diff --git a/backend/locale/zh_Hans/LC_MESSAGES/django.po b/backend/locale/zh_Hans/LC_MESSAGES/django.po new file mode 100644 index 0000000..e9aaae8 --- /dev/null +++ b/backend/locale/zh_Hans/LC_MESSAGES/django.po @@ -0,0 +1,267 @@ +# Simplified Chinese translations for Django. +# Copyright (C) 2026 +# This file is distributed under the same license as the Django project. +# +msgid "" +msgstr "" +"Project-Id-Version: django-vue3-admin\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2026-03-31 00:00+0000\n" +"PO-Revision-Date: 2026-03-31 00:00+0000\n" +"Last-Translator: \n" +"Language: zh_Hans\n" +"Language-Team: \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: django-vue3-admin i18n phase 1\n" + +#: dvadmin/utils/json_response.py +msgid "error" +msgstr "错误" + +#: dvadmin/utils/exception.py +msgid "Endpoint address is incorrect" +msgstr "接口地址不正确" + +msgid "Delete failed: this record has related data bindings" +msgstr "删除失败:该条数据与其他数据有相关绑定" + +#: dvadmin/utils/backends.py +msgid "This account has been disabled. Contact an administrator to unlock it." +msgstr "当前用户已被禁用,请联系管理员!" + +#: dvadmin/utils/import_export.py +msgid "Date format is incorrect" +msgstr "日期格式不正确" + +#: dvadmin/utils/import_export_mixin.py +msgid "No." +msgstr "序号" + +msgid "Import" +msgstr "导入" + +msgid "Template" +msgstr "模板" + +msgid "Export" +msgstr "导出" + +msgid "Update primary key (do not modify)" +msgstr "更新主键(勿改)" + +msgid "Please configure the corresponding export template fields." +msgstr "请配置对应的导出模板字段。" + +msgid "Please configure the corresponding import template fields." +msgstr "请配置对应的导入模板字段。" + +msgid "Please configure the corresponding import serializer." +msgstr "请配置对应的导入序列化器。" + +msgid "Please configure the corresponding export serializer." +msgstr "请配置对应的导出序列化器。" + +msgid "Import successful" +msgstr "导入成功" + +msgid "Data export task" +msgstr "数据导出任务" + +msgid "Import task has been created. Please go to 'Download Center' to wait for download" +msgstr "导入任务已创建,请前往'下载中心'等待下载" + +#: dvadmin/utils/viewset.py +msgid "Create successful" +msgstr "新增成功" + +msgid "Query successful" +msgstr "获取成功" + +msgid "Update successful" +msgstr "更新成功" + +msgid "Delete successful" +msgstr "删除成功" + +msgid "keys field not provided" +msgstr "未获取到keys字段" + +#: dvadmin/system/views/login.py +msgid "Verification code is required" +msgstr "验证码不能为空" + +msgid "Verification code has expired" +msgstr "验证码已过期" + +msgid "Image verification code is incorrect" +msgstr "图片验证码错误" + +msgid "The account you are logging in with does not exist" +msgstr "您登录的账号不存在" + +msgid "Multiple accounts found for this login. Contact an administrator to check account uniqueness" +msgstr "您登录的账号存在多个,请联系管理员检查登录账号唯一性" + +msgid "Account has been locked. Contact an administrator to unlock" +msgstr "账号已被锁定,联系管理员解锁" + +msgid "Username/password incorrect. Account will be locked after {} failed attempts~" +msgstr "账号/密码错误;重试{}次后将被锁定~" + +msgid "Request successful" +msgstr "请求成功" + +msgid "This interface is not yet available" +msgstr "该接口暂未开通!" + +msgid "Logout successful" +msgstr "注销成功" + +msgid "Username/password incorrect" +msgstr "账号/密码错误" + +#: dvadmin/system/views/user.py +msgid "Username must be unique" +msgstr "账号必须唯一" + +msgid "Mobile number must be unique" +msgstr "手机号必须唯一" + +msgid "Enabled" +msgstr "启用" + +msgid "Disabled" +msgstr "停用" + +msgid "Username" +msgstr "用户账号" + +msgid "Full name" +msgstr "用户名称" + +msgid "Email" +msgstr "用户邮箱" + +msgid "Mobile" +msgstr "手机号码" + +msgid "Gender" +msgstr "用户性别" + +msgid "Account status" +msgstr "帐号状态" + +msgid "Last login time" +msgstr "最后登录时间" + +msgid "Department name" +msgstr "部门名称" + +msgid "Department head" +msgstr "部门负责人" + +msgid "Login username" +msgstr "登录账号" + +msgid "Department" +msgstr "部门" + +msgid "Role" +msgstr "角色" + +msgid "No department" +msgstr "暂无部门" + +msgid "Parameters cannot be empty" +msgstr "参数不能为空" + +msgid "Passwords do not match" +msgstr "两次密码不匹配" + +msgid "Old password is incorrect" +msgstr "旧密码不正确" + +msgid "Invalid language code" +msgstr "无效的语言代码" + +msgid "Language updated successfully" +msgstr "语言更新成功" + +msgid "Only super administrators can reset passwords" +msgstr "只允许超级管理员对其进行密码重置" + +msgid "Password reset successful" +msgstr "密码重置成功" + +msgid "User not found" +msgstr "未获取到用户" + +#: dvadmin/system/views/role.py +msgid "Permission key must be unique" +msgstr "权限字符必须唯一" +#: dvadmin/system/views/role.py +msgid "Please select a role" +msgstr "请选择角色" +#: dvadmin/system/views/role.py +msgid "Please select a user" +msgstr "请选择用户" +#: dvadmin/system/views/role.py +msgid "Add successful" +msgstr "添加成功" +#: dvadmin/system/views/menu.py +msgid "Menu does not exist" +msgstr "菜单不存在" +#: dvadmin/system/views/menu.py +msgid "Move up successful" +msgstr "上移成功" +#: dvadmin/system/views/menu.py +msgid "Move down successful" +msgstr "下移成功" +#: dvadmin/system/views/dept.py +msgid "Department does not exist" +msgstr "部门不存在" +#: dvadmin/system/views/role_menu.py +msgid "Role parameter not provided" +msgstr "未获取到角色参数" +#: dvadmin/system/views/role_menu.py +msgid "Menu parameter not provided" +msgstr "未获取到菜单参数" +#: dvadmin/system/views/role_menu.py +msgid "Save successful" +msgstr "保存成功" +#: dvadmin/system/views/system_config.py +msgid "Variable name already exists" +msgstr "已存在相同变量名" +#: dvadmin/system/views/system_config.py +msgid "Query error~" +msgstr "查询出错了~" +#: dvadmin/system/views/system_config.py +msgid "Association information not found" +msgstr "未获取到关联信息" +#: dvadmin/system/views/menu_button.py +msgid "Batch creation successful" +msgstr "批量创建成功" +#: dvadmin/system/views/menu_button.py +msgid "Add" +msgstr "新增" +#: dvadmin/system/views/menu_button.py +msgid "Edit" +msgstr "编辑" +#: dvadmin/system/views/menu_field.py +msgid "Model table does not exist" +msgstr "模型表不存在" +#: dvadmin/system/views/menu_field.py +msgid "Field permission for '%s' already exists and cannot be duplicated" +msgstr "'%s' 字段权限已有,不可重复创建" +#: dvadmin/system/views/menu_field.py +msgid "Match successful" +msgstr "匹配成功" +#: dvadmin/system/views/message_center.py +msgid "You have a new message~" +msgstr "您有一条新消息~" +#: dvadmin/system/views/message_center.py +msgid "You viewed a message~" +msgstr "您查看了一条消息~" diff --git a/web/src/i18n/fs/zh-tw.ts b/web/src/i18n/fs/zh-tw.ts new file mode 100644 index 0000000..e71eb19 --- /dev/null +++ b/web/src/i18n/fs/zh-tw.ts @@ -0,0 +1,115 @@ +// Fast-crud zh-tw locale (traditional Chinese) +export default { + name: "zh-tw", + fs: { + component: { + select: { + placeholder: "請選擇" + } + }, + addForm: { title: "新增" }, + editForm: { title: "編輯" }, + viewForm: { title: "查看" }, + rowHandle: { + title: "操作", + remove: { + text: "刪除", + confirmTitle: "刪除提示", + confirmMessage: "您確定要刪除該記錄嗎?", + success: "刪除成功!", + confirmText: "確定", + cancelText: "取消" + }, + copy: { + text: "複製" + }, + edit: { + text: "編輯" + }, + view: { + text: "查看" + } + }, + form: { + cancel: "取消", + ok: "確定", + reset: "重設", + saveRemind: { + title: "提示", + content: "表單數據有變更,是否保存", + cancel: "不保存", + ok: "保存" + }, + copy: "複製", + paste: "貼上", + copySuccess: "表單數據已複製,您可以在新增對話框中貼上" + }, + actionbar: { add: "新增" }, + toolbar: { + columnFilter: { + title: "欄位設定", + fixed: "固定", + order: "排序", + reset: "還原", + confirm: "確定", + unnamed: "未命名" + }, + search: { title: "查詢顯示" }, + refresh: { title: "重新整理" }, + compact: { title: "緊湊模式" }, + export: { title: "導出" }, + columns: { title: "欄位設定" } + }, + search: { + container: { + collapseButton: { + text: { + collapse: "收起", + expand: "展開" + } + } + }, + search: { text: "查詢" }, + reset: { text: "重設" }, + error: { + message: "查詢表單校驗失敗" + } + }, + pagination: { + showTotal: "共 {0} 條" + }, + date: { + formatter: { to: "至" } + }, + extends: { + tableSelect: { + view: "查看", + select: "選擇", + ok: "確定", + cancel: "取消" + }, + cropper: { + title: "圖片裁剪", + preview: "預覽", + reChoose: "重新選擇", + flipX: "左右翻轉", + flipY: "上下翻轉", + reset: "重設", + cancel: "取消", + confirm: "確定", + chooseImage: "+ 選擇圖片", + onlySupport: "僅支援", + sizeLimit: "大小不能超過", + sizeNoLimit: "大小不限制" + }, + fileUploader: { + text: "文件上傳", + limitTip: "文件數量不能超過 {0}", + sizeLimitTip: "文件大小不能超過 {0},當前大小:{1}", + loadError: "圖片載入失敗", + pixelLimitTip: "圖片像素尺寸不能超過 寬:{0},高:{1}", + hasUploading: "還有文件正在上傳,請等待上傳完成,或刪除它" + } + } + } +} as any; diff --git a/web/src/i18n/index.ts b/web/src/i18n/index.ts index cd0f987..01b1e91 100644 --- a/web/src/i18n/index.ts +++ b/web/src/i18n/index.ts @@ -3,50 +3,74 @@ import pinia from '/@/stores/index'; import { storeToRefs } from 'pinia'; import { useThemeConfig } from '/@/stores/themeConfig'; -// 定义语言国际化内容 - -/** - * 说明: - * 须在 pages 下新建文件夹(建议 `要国际化界面目录` 与 `i18n 目录` 相同,方便查找), - * 注意国际化定义的字段,不要与原有的定义字段相同。 - * 1、/src/i18n/lang 下的 ts 为框架的国际化内容 - * 2、/src/i18n/pages 下的 ts 为各界面的国际化内容 - */ - // element plus 自带国际化 import enLocale from 'element-plus/es/locale/lang/en'; import zhcnLocale from 'element-plus/es/locale/lang/zh-cn'; import zhtwLocale from 'element-plus/es/locale/lang/zh-tw'; +// fast-crud 国际化 +import enFsLocale from '@fast-crud/fast-crud/dist/locale/lang/en'; +import zhcnFsLocale from '@fast-crud/fast-crud/dist/locale/lang/zh-cn'; +import zhcnFsTwLocale from './fs/zh-tw'; + // 定义变量内容 const messages = {}; const element = { en: enLocale, 'zh-cn': zhcnLocale, 'zh-tw': zhtwLocale }; -const itemize = { en: [], 'zh-cn': [], 'zh-tw': [] }; +const itemize: Record = { en: [], 'zh-cn': [], 'zh-tw': [] }; const modules: Record = import.meta.glob('./**/*.ts', { eager: true }); // 对自动引入的 modules 进行分类 en、zh-cn、zh-tw -// https://vitejs.cn/vite3-cn/guide/features.html#glob-import +// glob 返回路径如: ./pages/login/zh-cn.ts +// 提取语言代码: 按 / 分割,取最后一段去掉 .ts for (const path in modules) { - const key = path.match(/(\S+)\/(\S+).ts/); - if (itemize[key![2]]) itemize[key![2]].push(modules[path].default); - else itemize[key![2]] = modules[path]; + const withoutExt = path.replace(/^\.\//, '').replace(/\.ts$/, ''); + const segs = withoutExt.split('/'); + const lang = segs[segs.length - 1]; + if (itemize[lang]) { + itemize[lang].push(modules[path].default); + } } -// 合并数组对象(非标准数组对象,数组中对象的每项 key、value 都不同) -function mergeArrObj(list: T, key: string) { - let obj = {}; - list[key].forEach((i: EmptyObjectType) => { - obj = Object.assign({}, obj, i); +// 合并数组对象(深度合并 — 深层 key 冲突时后一个文件的 value 覆盖前一个的 value) +function isObject(val: unknown): val is Record { + return val !== null && typeof val === 'object' && !Array.isArray(val); +} + +function deepMerge(target: Record, ...sources: Record[]): Record { + for (const source of sources) { + for (const key in source) { + if (isObject(target[key]) && isObject(source[key])) { + deepMerge(target[key], source[key]); + } else { + target[key] = source[key]; + } + } + } + return target; +} + +function mergeArrObj(list: any[], key: string) { + let obj: Record = {}; + list[key].forEach((i: Record) => { + deepMerge(obj, i); }); return obj; } -// 处理最终格式 +// fast-crud 原始语言标识 -> 项目语言标识映射 +const fsLocaleMap: Record = { + 'zh-cn': zhcnFsLocale, + 'en': enFsLocale, + 'zh-tw': zhcnFsTwLocale, +}; + for (const key in itemize) { messages[key] = { name: key, el: element[key].el, - message: mergeArrObj(itemize, key), + ...mergeArrObj(itemize, key), + // fast-crud 内部组件的国际化(search/reset 按钮、操作列、列设置等) + ...fsLocaleMap[key], }; } @@ -55,14 +79,13 @@ const stores = useThemeConfig(pinia); const { themeConfig } = storeToRefs(stores); // 导出语言国际化 -// https://vue-i18n.intlify.dev/guide/essentials/fallback.html#explicit-fallback-with-one-locale export const i18n = createI18n({ legacy: false, - silentTranslationWarn: true, - missingWarn: false, - silentFallbackWarn: true, + silentTranslationWarn: false, + missingWarn: true, + silentFallbackWarn: false, fallbackWarn: false, locale: themeConfig.value.globalI18n, - fallbackLocale: zhcnLocale.name, + fallbackLocale: ['zh-CN', 'en', 'zh-TW'], messages, }); diff --git a/web/src/i18n/lang/en.ts b/web/src/i18n/lang/en.ts index 01467c9..6aff4e5 100644 --- a/web/src/i18n/lang/en.ts +++ b/web/src/i18n/lang/en.ts @@ -1,34 +1,324 @@ // Define content export default { - router: { - home: 'Home', - system: 'System MGT', - config: 'General MGT', - log: 'Log MGT', - /* General Configuration */ - configSystem: 'SystemGMT', - configDict: 'DictGMT', - configArea: 'AreaGMT', - configFile: 'AttachmentGMT', - /* System Management */ - systemMenu: 'MenuGMT', - systemRole: 'RoleGMT', - systemUser: 'UserGMT', - systemDept: 'DeptMGT', - systemNotice: 'Notice Center', - systemNotice1: 'MSG-MGT', - /* Log Management */ - loginLog: 'Login Log', - operationLog: 'Operation Log', - systemApiWhiteList: 'API Whitelist', - limits: 'Permission Management', - limitsFrontEnd: 'Frontend Control', - limitsFrontEndPage: 'Page Permissions', - limitsFrontEndBtn: 'Button Permissions', - limitsBackEnd: 'Backend Control', - limitsBackEndEndPage: 'Page Permissions', - personal: 'Personal Center', - dashboard: 'Dashboard', + message: { + home: { + more: 'More', + welcomeInfo: 'Welcome back, ', + welcomeInfo1: ' This is your workspace, please work happily!', + quickNavigationTool: 'Quick Navigation Tools', + }, + footer: { + copyright: ' ❤️ Powered by tiantianxiangshang Copyright © DVAdmin Team ❤️', + }, + router: { + home: 'Home', + system: 'System MGT', + config: 'General MGT', + log: 'Log MGT', + configSystem: 'System Config', + configDict: 'Dictionary', + configArea: 'Area', + configFile: 'Attachments', + systemMenu: 'Menu Management', + systemRole: 'Role Management', + systemUser: 'User Management', + systemDept: 'Department Management', + systemNotice: 'Notification Center', + systemNotice1: 'Notification Center', + loginLog: 'Login Log', + operationLog: 'Operation Log', + systemApiWhiteList: 'API Whitelist', + limits: 'Permission Management', + limitsFrontEnd: 'Frontend Control', + limitsFrontEndPage: 'Page Permissions', + limitsFrontEndBtn: 'Button Permissions', + limitsBackEnd: 'Backend Control', + limitsBackEndEndPage: 'Page Permissions', + personal: 'Personal Center', + }, + notFound: { + foundTitle: 'Address input error, please re-enter the address~', + foundMsg: 'You can check the URL first, then re-enter or give us feedback.', + foundBtn: 'Back to Home', + }, + noAccess: { + accessTitle: 'You are not authorized, no operation permission~', + accessMsg: 'Please contact administrator', + accessBtn: 'Re-authorize', + }, + tagsView: { + refresh: 'Refresh', + close: 'Close Current', + closeOther: 'Close Other', + closeAll: 'Close All', + fullscreen: 'Fullscreen', + }, + user: { + newTitle: 'Message Center', + newDesc: 'No new messages', + title0: 'Switch Component Size', + title1: 'Switch Language', + title2: 'Search', + title3: 'Layout Settings', + title4: 'Message Center', + title5: 'Fullscreen', + title6: 'Exit Fullscreen', + dropdown1: 'Home', + dropdown2: 'Personal Center', + versionLog: 'Version Upgrade Log', + dropdownLarge: 'Large', + dropdownDefault: 'Default', + dropdownSmall: 'Small', + langZhCn: '简体中文', + langEn: 'English', + langZhTw: '繁體中文', + dropdown5: 'Log Out', + fullscreenNotSupported: 'Your browser does not support fullscreen!', + logOutTitle: 'Notice', + logOutMessage: 'You are about to log out. Continue?', + logOutConfirm: 'Confirm', + logOutCancel: 'Cancel', + logOutExit: 'Exiting...', + retry: 'Retry', + onlinePrompt: 'Reconnecting to server...', + defaultUsername: 'User', + }, + common: { + logoutPrompt: 'You have been logged out, please log in again', + prompt: 'Prompt', + networkTimeout: 'Network timeout', + networkError: 'Network connection error', + endpointNotFound: 'Endpoint not found', + authFailed: 'Authentication failed, please log in again', + requestError: 'Request error', + authExpired: 'Login authorization expired, please log in again', + accessDenied: 'Access denied', + requestAddressError: 'Request address error: {url}', + requestTimeout: 'Request timeout', + serverError: 'Internal server error', + serviceNotImplemented: 'Service not implemented', + gatewayError: 'Gateway error', + serviceUnavailable: 'Service unavailable', + gatewayTimeout: 'Gateway timeout', + httpVersionNotSupported: 'HTTP version not supported', + importTaskCreated: 'Import task created, please go to "Download Center" to wait for download', + defaultExportFilename: 'Export File', + logoutSuccess: 'Logged out successfully', + formValidationFailed: 'Form validation failed, please check', + deleteSuccess: 'Deleted successfully', + deleteFailed: 'Delete failed', + deleteConfirm: 'Are you sure you want to delete?', + weekday: { + sunday: 'Sun', + monday: 'Mon', + tuesday: 'Tue', + wednesday: 'Wed', + thursday: 'Thu', + friday: 'Fri', + saturday: 'Sat', + }, + quarter: { + first: 'I', + second: 'II', + third: 'III', + fourth: 'IV', + }, + weekdayLongPrefix: 'Day', + weekdayShortPrefix: '', + quarterLongPrefix: '', + quarterSuffix: '', + weekPrefix: 'Week', + weekSuffix: '', + greeting: { + dawn: 'Good dawn', + morning: 'Good morning', + lateMorning: 'Good late morning', + noon: 'Good noon', + afternoon: 'Good afternoon', + evening: 'Good evening', + night: 'Good evening', + lateNight: 'Good night', + }, + time: { + justNow: 'Just now', + secondsAgo: '{n}s ago', + minutesAgo: '{n}m ago', + hoursAgo: '{n}h ago', + daysAgo: '{n}d ago', + }, + }, + components: { + table: { + serialNo: 'No.', + operation: 'Operation', + deleteConfirm: 'Are you sure you want to delete?', + delete: 'Delete', + noData: 'No Data', + export: 'Export', + refresh: 'Refresh', + setting: 'Setting', + columnDisplay: 'Column Display', + dragSort: 'Drag to reorder', + selectExportData: 'Please select data to export first', + multiSelect: 'Multi-select', + }, + calendar: { + selected: 'Selected:', + clear: 'Clear', + today: 'Today:', + holidaySettings: 'Holiday Settings', + showHoliday: 'Show Holidays', + closeHoliday: 'Hide Holidays', + lunarHoliday: 'Lunar Holidays', + solarTerm: 'Solar Terms', + moreHoliday: 'More Holidays', + prevYear: 'Prev Year', + nextYear: 'Next Year', + prevMonth: 'Prev Month', + nextMonth: 'Next Month', + todayBtn: 'Today', + todayCell: 'Today', + }, + fileSelector: { + image: 'Image', + video: 'Video', + audio: 'Audio', + file: 'File', + systemImage: 'System Image', + systemVideo: 'System Video', + systemAudio: 'System Audio', + systemOther: 'System Other', + inputPlaceholder: 'Enter {name} name', + selectedCount: '{n} file(s) selected', + upload: 'Upload {type}', + netFile: 'Net {type}', + netUploadTitle: 'Network {type} Upload', + netLinkLabel: '{type} Link', + netLinkPlaceholder: 'Enter network link', + netLoading: 'Fetching network file...', + confirm: 'Confirm', + cancel: 'Cancel', + netFetchFailed: 'Failed to fetch network {type}!', + netUploadSuccess: 'Network file uploaded successfully!', + netUploadFailed: 'Network file upload failed!', + uploadSuccess: 'Uploaded successfully', + uploadFailed: 'Upload failed', + deleteSuccess: 'Deleted successfully', + deleteFailed: 'Delete failed', + emptyContent: 'No content, please upload', + selectFile: 'Please select file', + }, + iconSelector: { + searchPlaceholder: 'Search icons or click to select', + title: 'Select Icon', + noIcon: 'No matching icons', + }, + importExcel: { + title: 'Import Data', + import: 'Import', + dragDrop: 'Drop Excel file here, or', + clickUpload: 'click to upload', + uploadTip: 'Note: Only "xls" or "xlsx" format files are allowed!', + downloadTemplate: 'Download Template', + batchUpdateTemplate: 'Batch Update Template', + uploading: 'Uploading...', + confirm: 'Confirm', + cancel: 'Cancel', + importSuccess: 'Import Complete', + importSuccessMsg: 'Import successful', + }, + noticeBar: { + content: 'Notice content', + }, + editor: { + placeholder: 'Enter content...', + }, + cropper: { + title: 'Change Avatar', + preview: 'Preview', + select: 'Select', + cancel: 'Cancel', + confirm: 'Confirm', + uploadAvatar: 'Upload Avatar', + fileTypeError: 'File format error, please upload an image type such as: JPG, PNG', + }, + avatarSelector: { + title: 'Change Avatar', + select: 'Select', + preview: 'Preview', + confirm: 'Confirm', + cancel: 'Cancel', + cropper: 'Crop', + uploadAvatar: 'Upload Avatar', + selectFromGallery: 'Select from Gallery', + fileTypeError: 'File format error, please upload an image type such as: JPG, PNG', + }, + select: { + search: 'Search', + noData: 'No data', + loading: 'Loading...', + }, + svgIcon: { + selectIcon: 'Select Icon', + confirm: 'Confirm', + cancel: 'Cancel', + }, + foreignKey: { + select: 'Select', + search: 'Search', + noData: 'No data', + }, + manyToMany: { + select: 'Select', + selected: 'Selected', + available: 'Available', + add: 'Add', + addAll: 'Add All', + remove: 'Remove', + removeAll: 'Remove All', + }, + tableSelector: { + select: 'Select', + search: 'Search', + confirm: 'Confirm', + cancel: 'Cancel', + noData: 'No data', + inputPlaceholder: 'Enter keyword', + }, + }, + pages: { + common: { + updateSuccess: 'Updated successfully', + logoutSuccess: 'Logged out successfully', + }, + }, + personal: { + PersonalInfo: 'Personal Information', + PersonalInfo1: ' Idleness is the root of all evil.', + PersonalInfo2: 'DVAdmin is an efficient and user-friendly backend management system developed based on Django and Vue.js, primarily designed for rapidly building management backends for enterprise-level web applications. Utilizing a front-end and back-end separation architecture, it provides a comprehensive set of out-of-the-box functional modules, assisting developers and businesses in reducing development costs and enhancing management efficiency. (Note: The prompt text can be changed by modifying the personal.PersonalInfo2 file located in the src/i18n/lang/ directory under the frontend directory.)', + MyInfo: 'My Info', + UpdateInfo: 'Update My Info', + AccountSecurity: 'Account Security', + ChangePassword: 'Change Password', + Name: 'Name', + Dept: 'Dept', + Role: 'Role', + Mail: 'Mail', + Phone: 'Phone', + Sex: 'Sex', + PswdInfo: 'Password strength: Strong', + PhoneInfo: 'Mobile phone number linked', + MailInfo: 'Email linked', + NamePlaceholder: 'Please enter your name', + MailPlaceholder: 'Please enter your email', + PhonePlaceholder: 'Please enter your phone number', + }, + systemMenu: { + MenuList: 'Menu List', + MenuListNote: '1. A red menu indicates that it is disabled; 2. When adding a menu, if it is a directory, the component address can be left blank; 3. When adding a root node menu, the parent ID can be left blank;', + welcomeInfo1: ' 这里是您的工作台,请愉快的工作吧!', + quickNavigationTool: '快捷导航工具', + }, }, staticRoutes: { signIn: 'Login', @@ -146,18 +436,10 @@ export default { btnTwo: 'Update Now', btnTwoLoading: 'Updating', }, - home:{ - more:'More', - welcomeInfo:'Welcome back, ', - welcomeInfo1:' This is your workspace, please work happily!', - quickNavigationTool:'Quick Navigation Tools', + home: { + more: 'More', + welcomeInfo: 'Welcome back, ', + welcomeInfo1: ' This is your workspace, please work happily!', + quickNavigationTool: 'Quick Navigation Tools', }, - personal:{ - PersonalInfo:'Personal Information', - PersonalInfo1:' Idleness is the root of all evil.', - PersonalInfo2:'DVAdmin is an efficient and user-friendly backend management system developed based on Django and Vue.js, primarily designed for rapidly building management backends for enterprise-level web applications. Utilizing a front-end and back-end separation architecture, it provides a comprehensive set of out-of-the-box functional modules, assisting developers and businesses in reducing development costs and enhancing management efficiency. (Note: The prompt text can be changed by modifying the personal.PersonalInfo2 file located in the src/i18n/lang/ directory under the frontend directory.)', - MyInfo:'My Info', - UpdateInfo:'Update My Info', - AccountSecurity:'Account Security', - } }; diff --git a/web/src/i18n/lang/zh-cn.ts b/web/src/i18n/lang/zh-cn.ts index 3d28ff1..cf6fb4d 100644 --- a/web/src/i18n/lang/zh-cn.ts +++ b/web/src/i18n/lang/zh-cn.ts @@ -1,34 +1,328 @@ // 定义内容 export default { - router: { - home: '首页', - system: '系统管理', - config: '常规配置', - log: '日志管理', - /* 常规配置 */ - configSystem: '系统配置', - configDict: '字典管理', - configArea: '地区管理', - configFile: '附件管理', - /* 系统管理 */ - systemMenu: '菜单管理', - systemRole: '角色管理', - systemUser: '用户管理', - systemDept: '部门管理', - systemNotice: '通知中心', - systemNotice1: '通知中心', - /* 日志管理 */ - loginLog: '登录日志', - operationLog: '操作日志', - systemApiWhiteList: '接口白名单', - limits: '权限管理', - limitsFrontEnd: '前端控制', - limitsFrontEndPage: '页面权限', - limitsFrontEndBtn: '按钮权限', - limitsBackEnd: '后端控制', - limitsBackEndEndPage: '页面权限', - personal: '个人中心', - dashboard: '看板', + message: { + tagsView: { + refresh: '刷新', + close: '关闭当前', + closeOther: '关闭其他', + closeAll: '关闭全部', + fullscreen: '全屏', + }, + user: { + newTitle: '消息中心', + newDesc: '暂无新消息', + title0: '切换组件大小', + title1: '切换语言', + title2: '搜索', + title3: '布局配置', + title4: '消息中心', + title5: '全屏', + title6: '退出全屏', + dropdown1: '首页', + dropdown2: '个人中心', + versionLog: '版本升级日志', + dropdownLarge: '大号', + dropdownDefault: '默认', + dropdownSmall: '小号', + langZhCn: '简体中文', + langEn: 'English', + langZhTw: '繁體中文', + dropdown5: '退出登录', + fullscreenNotSupported: '您的浏览器不支持全屏!', + logOutTitle: '提示', + logOutMessage: '即将退出系统,是否继续?', + logOutConfirm: '确定', + logOutCancel: '取消', + logOutExit: '正在退出...', + retry: '重试', + onlinePrompt: '正在重新连接服务器...', + defaultUsername: '用户', + }, + home: { + more: '更多', + welcomeInfo: '欢迎回来,', + welcomeInfo1: ' 这里是您的工作台,请愉快的工作吧!', + quickNavigationTool: '快捷导航工具', + }, + footer: { + copyright: ' ❤️ Powered by tiantianxiangshang Copyright © 巨梦·DVAdmin团队 ❤️', + }, + router: { + home: '首页', + system: '系统管理', + config: '常规配置', + log: '日志管理', + /* 常规配置 */ + configSystem: '系统配置', + configDict: '字典管理', + configArea: '地区管理', + configFile: '附件管理', + /* 系统管理 */ + systemMenu: '菜单管理', + systemRole: '角色管理', + systemUser: '用户管理', + systemDept: '部门管理', + systemNotice: '通知中心', + systemNotice1: '通知中心', + /* 日志管理 */ + loginLog: '登录日志', + operationLog: '操作日志', + systemApiWhiteList: '接口白名单', + limits: '权限管理', + limitsFrontEnd: '前端控制', + limitsFrontEndPage: '页面权限', + limitsFrontEndBtn: '按钮权限', + limitsBackEnd: '后端控制', + limitsBackEndEndPage: '页面权限', + personal: '个人中心', + }, + notFound: { + foundTitle: '地址输入错误,请重新输入地址~', + foundMsg: '您可以先检查网址,然后重新输入或给我们反馈问题。', + foundBtn: '返回首页', + }, + noAccess: { + accessTitle: '您未被授权,没有操作权限~', + accessMsg: '请联系管理员', + accessBtn: '重新授权', + }, + common: { + logoutPrompt: '你已被登出,请重新登录', + prompt: '提示', + networkTimeout: '网络超时', + networkError: '网络连接错误', + endpointNotFound: '接口路径找不到', + authFailed: '登录认证失败,请重新登录', + requestError: '请求错误', + authExpired: '登录授权过期,请重新登录', + accessDenied: '拒绝访问', + requestAddressError: '请求地址出错: {url}', + requestTimeout: '请求超时', + serverError: '服务器内部错误', + serviceNotImplemented: '服务未实现', + gatewayError: '网关错误', + serviceUnavailable: '服务不可用', + gatewayTimeout: '网关超时', + httpVersionNotSupported: 'HTTP版本不受支持', + importTaskCreated: '导入任务已创建,请前往"下载中心"等待下载', + defaultExportFilename: '文件导出', + logoutSuccess: '退出登录成功', + formValidationFailed: '表单验证失败,请检查', + deleteSuccess: '删除成功', + deleteFailed: '删除失败', + deleteConfirm: '确定删除吗?', + weekday: { + sunday: '日', + monday: '一', + tuesday: '二', + wednesday: '三', + thursday: '四', + friday: '五', + saturday: '六', + }, + quarter: { + first: '一', + second: '二', + third: '三', + fourth: '四', + }, + weekdayLongPrefix: '星期', + weekdayShortPrefix: '周', + quarterLongPrefix: '第', + quarterSuffix: '季度', + weekPrefix: '第', + weekSuffix: '周', + greeting: { + dawn: '凌晨好', + morning: '早上好', + lateMorning: '上午好', + noon: '中午好', + afternoon: '下午好', + evening: '傍晚好', + night: '晚上好', + lateNight: '夜里好', + }, + time: { + justNow: '刚刚', + secondsAgo: '{n}秒前', + minutesAgo: '{n}分钟前', + hoursAgo: '{n}小时前', + daysAgo: '{n}天前', + }, + }, + components: { + table: { + serialNo: '序号', + operation: '操作', + deleteConfirm: '确定删除吗?', + delete: '删除', + noData: '暂无数据', + export: '导出', + refresh: '刷新', + setting: '设置', + columnDisplay: '列显示', + dragSort: '拖动进行排序', + selectExportData: '请先选择要导出的数据', + multiSelect: '多选', + }, + calendar: { + selected: '已选择:', + clear: '清空', + today: '今天:', + holidaySettings: '节假日设置', + showHoliday: '显示节日', + closeHoliday: '关闭节日', + lunarHoliday: '农历节日', + solarTerm: '节气', + moreHoliday: '更多节日', + prevYear: '上年', + nextYear: '下年', + prevMonth: '上月', + nextMonth: '下月', + todayBtn: '今天', + todayCell: '今天', + }, + fileSelector: { + title: '文件选择', + image: '图片', + video: '视频', + audio: '音频', + file: '文件', + systemImage: '系统图片', + systemVideo: '系统视频', + systemAudio: '系统音频', + systemOther: '系统其他', + inputPlaceholder: '请输入{name}名', + selectedCount: '一共选中 {n} 个文件', + upload: '上传{type}', + netFile: '网络{type}', + netUploadTitle: '网络{type}上传', + netLinkLabel: '{type}链接', + netLinkPlaceholder: '请输入网络连接', + netLoading: '网络文件获取中...', + confirm: '确定', + cancel: '取消', + netFetchFailed: '网络{type}获取失败!', + netUploadSuccess: '网络文件上传成功!', + netUploadFailed: '网络文件上传失败!', + uploadSuccess: '上传成功', + uploadFailed: '上传失败', + deleteSuccess: '删除成功', + deleteFailed: '删除失败', + emptyContent: '无内容,请上传', + selectFile: '请选择文件', + }, + iconSelector: { + searchPlaceholder: '请输入内容搜索图标或者选择图标', + title: '请选择图标', + noIcon: '无相关图标', + }, + importExcel: { + title: '导入数据', + import: '导入', + dragDrop: '将文件拖到此处,或', + clickUpload: '点击上传', + uploadTip: '提示:仅允许导入"xls"或"xlsx"格式文件!', + downloadTemplate: '下载导入模板', + batchUpdateTemplate: '批量更新模板', + uploading: '上传中...', + confirm: '确 定', + cancel: '取 消', + importSuccess: '导入完成', + importSuccessMsg: '导入成功', + }, + noticeBar: { + content: '公告内容', + }, + editor: { + placeholder: '请输入内容...', + }, + cropper: { + title: '更换头像', + preview: '预览', + select: '选择', + cancel: '取 消', + confirm: '更 换', + uploadAvatar: '更新头像', + fileTypeError: '文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。', + }, + avatarSelector: { + title: '修改头像', + select: '选择', + preview: '预览', + confirm: '确认', + cancel: '取消', + cropper: '裁剪', + uploadAvatar: '上传头像', + selectFromGallery: '从相册选择', + fileTypeError: '文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。', + }, + select: { + search: '搜索', + noData: '无数据', + loading: '加载中...', + }, + svgIcon: { + selectIcon: '选择图标', + confirm: '确定', + cancel: '取消', + }, + foreignKey: { + select: '选择', + search: '搜索', + noData: '无数据', + }, + manyToMany: { + select: '选择', + selected: '已选', + available: '可选', + add: '添加', + addAll: '添加全部', + remove: '移除', + removeAll: '移除全部', + }, + tableSelector: { + select: '选择', + search: '搜索', + confirm: '确定', + cancel: '取消', + noData: '无数据', + inputPlaceholder: '请输入关键词', + }, + }, + pages: { + common: { + updateSuccess: '更新成功', + logoutSuccess: '退出登录成功', + }, + }, + personal: { + PersonalInfo: '个人信息', + PersonalInfo1: ' 生活变的再糟糕,也不妨碍我变得更好!', + PersonalInfo2: 'DVAdmin 是一款基于 Django 和 Vue.js 开发的高效、易用的后台管理系统,主要用于快速构建企业级 Web 应用的管理后台。它通过前后端分离架构,提供了一整套开箱即用的功能模块,帮助开发者和企业降低开发成本、提升管理效率。(更改前端目录下src/i18n/lang/下的翻译文件中personal.PersonalInfo2可更改此提示文字)', + MyInfo: '个人信息', + UpdateInfo: '更新信息', + AccountSecurity: '账号安全', + ChangePassword: '修改密码', + Name: '昵称', + Dept: '部门', + Role: '角色', + Mail: '邮箱', + Phone: '手机', + Sex: '性别', + PswdInfo: '当前密码强度:强', + PhoneInfo: '已绑定手机', + MailInfo: '已绑定邮箱', + NamePlaceholder: '请输入姓名', + MailPlaceholder: '请输入邮箱', + PhonePlaceholder: '请输入手机号', + }, + systemMenu: { + MenuList: '菜单列表', + MenuListNote: '1.红色菜单代表状态禁用; 2.添加菜单,如果是目录,组件地址为空即可; 3.添加根节点菜单,父级ID为空即可;', + welcomeInfo1: ' 这里是您的工作台,请愉快的工作吧!', + quickNavigationTool: '快捷导航工具', + }, }, staticRoutes: { signIn: '登录', @@ -146,18 +440,10 @@ export default { btnTwo: '马上更新', btnTwoLoading: '更新中', }, - home:{ - more:'更多', - welcomeInfo:'欢迎回来,', - welcomeInfo1:' 这里是您的工作台,请愉快的工作吧!', - quickNavigationTool:'快捷导航工具', + home: { + more: '更多', + welcomeInfo: '欢迎回来,', + welcomeInfo1: ' 这里是您的工作台,请愉快的工作吧!', + quickNavigationTool: '快捷导航工具', }, - personal:{ - PersonalInfo:'个人信息', - PersonalInfo1:' 生活变的再糟糕,也不妨碍我变得更好!', - PersonalInfo2:'DVAdmin 是一款基于 Django 和 Vue.js 开发的高效、易用的后台管理系统,主要用于快速构建企业级 Web 应用的管理后台。它通过前后端分离架构,提供了一整套开箱即用的功能模块,帮助开发者和企业降低开发成本、提升管理效率。(更改前端目录下src/i18n/lang/下的翻译文件中personal.PersonalInfo2可更改此提示文字)', - MyInfo:'个人信息', - UpdateInfo:'更新信息', - AccountSecurity:'账号安全', - } }; diff --git a/web/src/i18n/lang/zh-tw.ts b/web/src/i18n/lang/zh-tw.ts index a19e526..01cc961 100644 --- a/web/src/i18n/lang/zh-tw.ts +++ b/web/src/i18n/lang/zh-tw.ts @@ -1,34 +1,325 @@ // 定義內容 export default { - router: { - home: '首頁', - system: '系統設置', - config: '常規配置', - log: '日誌管理', - /* 常規配置 */ - configSystem: '系統配置', - configDict: '字典管理', - configArea: '地區管理', - configFile: '附件管理', - /* 系統管理 */ - systemMenu: '選單管理', - systemRole: '角色管理', - systemUser: '用戶管理', - systemDept: '部門管理', - systemNotice: '通知中心', - systemNotice1: '通知中心', - /* 日誌管理 */ - loginLog: '登錄日誌', - operationLog: '操作日誌', - systemApiWhiteList: '接口白名單', - limits: '權限管理', - limitsFrontEnd: '前端控制', - limitsFrontEndPage: '頁面權限', - limitsFrontEndBtn: '按鈕權限', - limitsBackEnd: '後端控制', - limitsBackEndEndPage: '頁面權限', - personal: '個人中心', - dashboard: '看板', + message: { + home: { + more: '更多', + welcomeInfo: '歡迎回來,', + welcomeInfo1: ' 這裏是您的工作台,請愉快的工作吧!', + quickNavigationTool: '快捷導航工具', + }, + footer: { + copyright: ' ❤️ Powered by tiantianxiangshang Copyright © 巨夢·DVAmin團隊 ❤️', + }, + router: { + home: '首頁', + system: '系統設置', + config: '常規配置', + log: '日誌管理', + configSystem: '系統配置', + configDict: '字典管理', + configArea: '地區管理', + configFile: '附件管理', + systemMenu: '選單管理', + systemRole: '角色管理', + systemUser: '用戶管理', + systemDept: '部門管理', + systemNotice: '通知中心', + systemNotice1: '通知中心', + loginLog: '登錄日誌', + operationLog: '操作日誌', + systemApiWhiteList: '接口白名單', + limits: '權限管理', + limitsFrontEnd: '前端控制', + limitsFrontEndPage: '頁面權限', + limitsFrontEndBtn: '按鈕權限', + limitsBackEnd: '後端控制', + limitsBackEndEndPage: '頁面權限', + personal: '個人中心', + }, + notFound: { + foundTitle: '地址輸入錯誤,請重新輸入地址~', + foundMsg: '您可以先檢查網址,然後重新輸入或給我們反饋問題。', + foundBtn: '返回首頁', + }, + noAccess: { + accessTitle: '您未被授權,沒有操作權限~', + accessMsg: '請聯繫管理員', + accessBtn: '重新授權', + }, + tagsView: { + refresh: '重新整理', + close: '關閉當前', + closeOther: '關閉其他', + closeAll: '關閉全部', + fullscreen: '全螢幕', + }, + user: { + newTitle: '訊息中心', + newDesc: '暫無新訊息', + title0: '切換元件大小', + title1: '切換語言', + title2: '搜尋', + title3: '版面設定', + title4: '訊息中心', + title5: '全螢幕', + title6: '退出全螢幕', + dropdown1: '首頁', + dropdown2: '個人中心', + versionLog: '版本升級日誌', + dropdownLarge: '大', + dropdownDefault: '預設', + dropdownSmall: '小', + langZhCn: '簡體中文', + langEn: 'English', + langZhTw: '繁體中文', + dropdown5: '退出登入', + fullscreenNotSupported: '您的瀏覽器不支援全螢幕!', + logOutTitle: '提示', + logOutMessage: '即將退出系統,是否繼續?', + logOutConfirm: '確定', + logOutCancel: '取消', + logOutExit: '正在退出...', + retry: '重試', + onlinePrompt: '正在重新連線伺服器...', + defaultUsername: '使用者', + }, + common: { + logoutPrompt: '你已被登出,請重新登錄', + prompt: '提示', + networkTimeout: '網路超時', + networkError: '網路連接錯誤', + endpointNotFound: '接口路徑找不到', + authFailed: '登錄認證失敗,請重新登錄', + requestError: '請求錯誤', + authExpired: '登錄授權過期,請重新登錄', + accessDenied: '拒絕訪問', + requestAddressError: '請求地址出錯: {url}', + requestTimeout: '請求超時', + serverError: '伺服器內部錯誤', + serviceNotImplemented: '服務未實現', + gatewayError: '網關錯誤', + serviceUnavailable: '服務不可用', + gatewayTimeout: '網關超時', + httpVersionNotSupported: 'HTTP版本不受支持', + importTaskCreated: '導入任務已創建,請前往"下載中心"等待下載', + defaultExportFilename: '文件導出', + logoutSuccess: '退出登錄成功', + formValidationFailed: '表單驗證失敗,請檢查', + deleteSuccess: '刪除成功', + deleteFailed: '刪除失敗', + deleteConfirm: '確定刪除嗎?', + weekday: { + sunday: '日', + monday: '一', + tuesday: '二', + wednesday: '三', + thursday: '四', + friday: '五', + saturday: '六', + }, + quarter: { + first: '一', + second: '二', + third: '三', + fourth: '四', + }, + weekdayLongPrefix: '星期', + weekdayShortPrefix: '周', + quarterLongPrefix: '第', + quarterSuffix: '季度', + weekPrefix: '第', + weekSuffix: '周', + greeting: { + dawn: '凌晨好', + morning: '早上好', + lateMorning: '上午好', + noon: '中午好', + afternoon: '下午好', + evening: '傍晚好', + night: '晚上好', + lateNight: '夜裏好', + }, + time: { + justNow: '剛剛', + secondsAgo: '{n}秒前', + minutesAgo: '{n}分鐘前', + hoursAgo: '{n}小時前', + daysAgo: '{n}天前', + }, + }, + components: { + table: { + serialNo: '序號', + operation: '操作', + deleteConfirm: '確定刪除嗎?', + delete: '刪除', + noData: '暫無數據', + export: '導出', + refresh: '刷新', + setting: '設置', + columnDisplay: '列顯示', + dragSort: '拖動進行排序', + selectExportData: '請先選擇要導出的數據', + multiSelect: '多選', + }, + calendar: { + selected: '已選擇:', + clear: '清空', + today: '今天:', + holidaySettings: '節假日設置', + showHoliday: '顯示節日', + closeHoliday: '關閉節日', + lunarHoliday: '農曆節日', + solarTerm: '節氣', + moreHoliday: '更多節日', + prevYear: '上年', + nextYear: '下年', + prevMonth: '上月', + nextMonth: '下月', + todayBtn: '今天', + todayCell: '今天', + }, + fileSelector: { + title: '文件選擇', + image: '圖片', + video: '視頻', + audio: '音頻', + file: '文件', + systemImage: '系統圖片', + systemVideo: '系統視頻', + systemAudio: '系統音頻', + systemOther: '系統其他', + inputPlaceholder: '請輸入{name}名', + selectedCount: '一共選中 {n} 個文件', + upload: '上傳{type}', + netFile: '網絡{type}', + netUploadTitle: '網絡{type}上傳', + netLinkLabel: '{type}連結', + netLinkPlaceholder: '請輸入網絡連接', + netLoading: '網絡文件獲取中...', + confirm: '確定', + cancel: '取消', + netFetchFailed: '網絡{type}獲取失敗!', + netUploadSuccess: '網絡文件上傳成功!', + netUploadFailed: '網絡文件上傳失敗!', + uploadSuccess: '上傳成功', + uploadFailed: '上傳失敗', + deleteSuccess: '刪除成功', + deleteFailed: '刪除失敗', + emptyContent: '無內容,請上傳', + selectFile: '請選擇文件', + }, + iconSelector: { + searchPlaceholder: '請輸入內容搜索圖標或者選擇圖標', + title: '請選擇圖標', + noIcon: '無相關圖標', + }, + importExcel: { + title: '導入數據', + import: '導入', + dragDrop: '將文件拖到此處,或', + clickUpload: '點擊上傳', + uploadTip: '提示:僅允許導入"xls"或"xlsx"格式文件!', + downloadTemplate: '下載導入模板', + batchUpdateTemplate: '批量更新模板', + uploading: '上傳中...', + confirm: '確 定', + cancel: '取 消', + importSuccess: '導入完成', + importSuccessMsg: '導入成功', + }, + noticeBar: { + content: '公告內容', + }, + editor: { + placeholder: '請輸入內容...', + }, + cropper: { + title: '更換頭像', + preview: '預覽', + select: '選擇', + cancel: '取 消', + confirm: '更 換', + uploadAvatar: '更新頭像', + fileTypeError: '文件格式錯誤,請上傳圖片類型,如:JPG,PNG後綴的文件。', + }, + avatarSelector: { + title: '修改頭像', + select: '選擇', + preview: '預覽', + confirm: '確認', + cancel: '取消', + cropper: '裁剪', + uploadAvatar: '上傳頭像', + selectFromGallery: '從相冊選擇', + fileTypeError: '文件格式錯誤,請上傳圖片類型,如:JPG,PNG後綴的文件。', + }, + select: { + search: '搜索', + noData: '無數據', + loading: '加載中...', + }, + svgIcon: { + selectIcon: '選擇圖標', + confirm: '確定', + cancel: '取消', + }, + foreignKey: { + select: '選擇', + search: '搜索', + noData: '無數據', + }, + manyToMany: { + select: '選擇', + selected: '已選', + available: '可選', + add: '添加', + addAll: '添加全部', + remove: '移除', + removeAll: '移除全部', + }, + tableSelector: { + select: '選擇', + search: '搜索', + confirm: '確定', + cancel: '取消', + noData: '無數據', + inputPlaceholder: '請輸入關鍵詞', + }, + }, + pages: { + common: { + updateSuccess: '更新成功', + logoutSuccess: '退出登錄成功', + }, + }, + personal: { + PersonalInfo: '個人資訊', + PersonalInfo1: ' 生活變得再糟糕,也不妨礙我變得更好!', + PersonalInfo2: 'DVAdmin是一款基於Django和Vue.js開發的高效、易用的後台管理系統,主要用於快速構建企業級Web應用的管理後台,它透過前後端分離架構,提供了一整套開箱即用的功能模組,幫助開發者和企業降低開發成本、提升管理效率。(更改前端目錄下src/i18n/lang/下的翻譯文件中personal.PersonalInfo2可更改此提示文字)', + MyInfo: '個人信息', + UpdateInfo: '更新資訊', + AccountSecurity: '帳號安全', + ChangePassword: '修改密碼', + Name: '昵稱', + Dept: '部門', + Role: '角色', + Mail: '電郵信箱', + Phone: '手機', + Sex: '性別', + PswdInfo: '當前密碼強度:強', + PhoneInfo: '已綁定手機', + MailInfo: '已綁定郵箱', + NamePlaceholder: '請輸入姓名', + MailPlaceholder: '請輸入郵箱', + PhonePlaceholder: '請輸入手機號', + }, + systemMenu: { + MenuList: '菜單列表', + MenuListNote: '1.紅色菜單代表狀態禁用; 2.添加菜單,如果是目錄,組件地址為空即可; 3.添加根節點菜單,父級ID為空即可;', + welcomeInfo1: ' 这里是您的工作台,请愉快的工作吧!', + quickNavigationTool: '快捷导航工具', + }, }, staticRoutes: { signIn: '登錄', @@ -146,18 +437,10 @@ export default { btnTwo: '馬上更新', btnTwoLoading: '更新中', }, - home:{ - more:'更多', - welcomeInfo:'歡迎回來,', - welcomeInfo1:' 這裏是您的工作台,請愉快的工作吧!', - quickNavigationTool:'快捷導航工具', + home: { + more: '更多', + welcomeInfo: '歡迎回來,', + welcomeInfo1: ' 這裏是您的工作台,請愉快的工作吧!', + quickNavigationTool: '快捷導航工具', }, - personal:{ - PersonalInfo:'個人資訊', - PersonalInfo1:' 生活變得再糟糕,也不妨礙我變得更好!', - PersonalInfo2:'DVAdmin是一款基於Django和Vue.js開發的高效、易用的後台管理系統,主要用於快速構建企業級Web應用的管理後台。它透過前後端分離架構,提供了一整套開箱即用的功能模組,幫助開發者和企業降低開發成本、提升管理效率。(更改前端目錄下src/i18n/lang/下的翻譯文件中personal.PersonalInfo2可更改此提示文字)', - MyInfo:'個人信息', - UpdateInfo:'更新資訊', - AccountSecurity:'帳號安全', - } -}; \ No newline at end of file +}; diff --git a/web/src/i18n/pages/areas/en.ts b/web/src/i18n/pages/areas/en.ts new file mode 100644 index 0000000..0f14962 --- /dev/null +++ b/web/src/i18n/pages/areas/en.ts @@ -0,0 +1,62 @@ +// Define content +export default { + message: { + pages: { + areas: { + table: { + columns: { + index: 'No.', + areaName: 'Area Name', + areaCode: 'Area Code', + parentArea: 'Parent Area', + sort: 'Sort', + status: 'Status', + createTime: 'Create Time', + actions: 'Actions', + }, + }, + form: { + areaName: 'Area Name', + areaCode: 'Area Code', + parentArea: 'Parent Area', + sort: 'Sort', + status: 'Status', + areaNamePlaceholder: 'Enter area name', + areaCodePlaceholder: 'Enter area code', + sortPlaceholder: 'Enter sort', + }, + validation: { + areaNameRequired: 'Area name is required', + areaNameMaxLength: 'Area name must be 50 characters or less', + areaNameDuplicate: 'Area name already exists', + areaCodeRequired: 'Area code is required', + areaCodeMaxLength: 'Area code must be 50 characters or less', + areaCodeFormat: 'Invalid area code format', + areaCodeDuplicate: 'Area code already exists', + }, + dialog: { + addArea: 'Add Area', + editArea: 'Edit Area', + deleteConfirm: 'Delete this area?', + }, + messages: { + addSuccess: 'Added successfully', + updateSuccess: 'Updated successfully', + deleteSuccess: 'Deleted successfully', + deleteFailed: 'Delete failed', + }, + buttons: { + add: 'Add', + edit: 'Edit', + delete: 'Delete', + save: 'Save', + cancel: 'Cancel', + query: 'Query', + refresh: 'Refresh', + expandAll: 'Expand All', + collapseAll: 'Collapse All', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/areas/zh-cn.ts b/web/src/i18n/pages/areas/zh-cn.ts new file mode 100644 index 0000000..4ac86d2 --- /dev/null +++ b/web/src/i18n/pages/areas/zh-cn.ts @@ -0,0 +1,62 @@ +// 定义内容 +export default { + message: { + pages: { + areas: { + table: { + columns: { + index: '序号', + areaName: '区域名称', + areaCode: '区域编码', + parentArea: '上级区域', + sort: '排序', + status: '状态', + createTime: '创建时间', + actions: '操作', + }, + }, + form: { + areaName: '区域名称', + areaCode: '区域编码', + parentArea: '上级区域', + sort: '排序', + status: '状态', + areaNamePlaceholder: '请输入区域名称', + areaCodePlaceholder: '请输入区域编码', + sortPlaceholder: '请输入排序', + }, + validation: { + areaNameRequired: '区域名称必填', + areaNameMaxLength: '区域名称不能超过50个字符', + areaNameDuplicate: '区域名称已存在', + areaCodeRequired: '区域编码必填', + areaCodeMaxLength: '区域编码不能超过50个字符', + areaCodeFormat: '区域编码格式不正确', + areaCodeDuplicate: '区域编码已存在', + }, + dialog: { + addArea: '新增区域', + editArea: '编辑区域', + deleteConfirm: '确定删除该区域吗?', + }, + messages: { + addSuccess: '新增成功', + updateSuccess: '更新成功', + deleteSuccess: '删除成功', + deleteFailed: '删除失败', + }, + buttons: { + add: '新增', + edit: '编辑', + delete: '删除', + save: '保存', + cancel: '取消', + query: '查询', + refresh: '刷新', + expandAll: '展开全部', + collapseAll: '收起全部', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/areas/zh-tw.ts b/web/src/i18n/pages/areas/zh-tw.ts new file mode 100644 index 0000000..0b791df --- /dev/null +++ b/web/src/i18n/pages/areas/zh-tw.ts @@ -0,0 +1,62 @@ +// 定義內容 +export default { + message: { + pages: { + areas: { + table: { + columns: { + index: '序號', + areaName: '區域名稱', + areaCode: '區域編碼', + parentArea: '上級區域', + sort: '排序', + status: '狀態', + createTime: '創建時間', + actions: '操作', + }, + }, + form: { + areaName: '區域名稱', + areaCode: '區域編碼', + parentArea: '上級區域', + sort: '排序', + status: '狀態', + areaNamePlaceholder: '請輸入區域名稱', + areaCodePlaceholder: '請輸入區域編碼', + sortPlaceholder: '請輸入排序', + }, + validation: { + areaNameRequired: '區域名稱必填', + areaNameMaxLength: '區域名稱不能超過50個字符', + areaNameDuplicate: '區域名稱已存在', + areaCodeRequired: '區域編碼必填', + areaCodeMaxLength: '區域編碼不能超過50個字符', + areaCodeFormat: '區域編碼格式不正確', + areaCodeDuplicate: '區域編碼已存在', + }, + dialog: { + addArea: '新增區域', + editArea: '編輯區域', + deleteConfirm: '確定刪除該區域嗎?', + }, + messages: { + addSuccess: '新增成功', + updateSuccess: '更新成功', + deleteSuccess: '刪除成功', + deleteFailed: '刪除失敗', + }, + buttons: { + add: '新增', + edit: '編輯', + delete: '刪除', + save: '保存', + cancel: '取消', + query: '查詢', + refresh: '刷新', + expandAll: '展開全部', + collapseAll: '收起全部', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/columns/en.ts b/web/src/i18n/pages/columns/en.ts new file mode 100644 index 0000000..39e9e36 --- /dev/null +++ b/web/src/i18n/pages/columns/en.ts @@ -0,0 +1,35 @@ +// Define content +export default { + message: { + pages: { + columns: { + table: { + columns: { + index: 'No.', + keyword: 'Keyword', + fieldName: 'Field Name', + columnName: 'Column Name', + status: 'Status', + sort: 'Sort', + type: 'Data Type', + value: 'Value', + color: 'Color', + }, + }, + subTable: { + columns: { + index: 'No.', + keyword: 'Keyword', + fieldName: 'Field Name', + columnName: 'Column Name', + status: 'Status', + sort: 'Sort', + type: 'Data Type', + value: 'Value', + color: 'Color', + }, + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/columns/zh-cn.ts b/web/src/i18n/pages/columns/zh-cn.ts new file mode 100644 index 0000000..899382c --- /dev/null +++ b/web/src/i18n/pages/columns/zh-cn.ts @@ -0,0 +1,35 @@ +// 定义内容 +export default { + message: { + pages: { + columns: { + table: { + columns: { + index: '序号', + keyword: '关键词', + fieldName: '字段名', + columnName: '列名', + status: '状态', + sort: '排序', + type: '数据类型', + value: '数据值', + color: '颜色', + }, + }, + subTable: { + columns: { + index: '序号', + keyword: '关键词', + fieldName: '字段名', + columnName: '列名', + status: '状态', + sort: '排序', + type: '数据类型', + value: '数据值', + color: '颜色', + }, + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/columns/zh-tw.ts b/web/src/i18n/pages/columns/zh-tw.ts new file mode 100644 index 0000000..502b075 --- /dev/null +++ b/web/src/i18n/pages/columns/zh-tw.ts @@ -0,0 +1,35 @@ +// 定義內容 +export default { + message: { + pages: { + columns: { + table: { + columns: { + index: '序號', + keyword: '關鍵詞', + fieldName: '欄位名', + columnName: '列名', + status: '狀態', + sort: '排序', + type: '資料類型', + value: '資料值', + color: '顏色', + }, + }, + subTable: { + columns: { + index: '序號', + keyword: '關鍵詞', + fieldName: '欄位名', + columnName: '列名', + status: '狀態', + sort: '排序', + type: '資料類型', + value: '資料值', + color: '顏色', + }, + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/config/en.ts b/web/src/i18n/pages/config/en.ts new file mode 100644 index 0000000..7f77918 --- /dev/null +++ b/web/src/i18n/pages/config/en.ts @@ -0,0 +1,110 @@ +// Define content +export default { + message: { + pages: { + config: { + header: { + tagText: 'System Config: Customize your website settings here', + }, + table: { + columns: { + configName: 'Config Name', + configCode: 'Config Key', + configValue: 'Config Value', + configType: 'Config Type', + remark: 'Remark', + sort: 'Sort', + status: 'Status', + createTime: 'Create Time', + actions: 'Actions', + }, + }, + form: { + title: 'Title', + key: 'Key', + parent: 'Group', + parentPlaceholder: 'Select group', + titlePlaceholder: 'Enter title', + keyPlaceholder: 'Enter key', + formItemType: 'Form Type', + formItemTypePlaceholder: 'Select', + dictKey: 'Dict Key', + dictKeyPlaceholder: 'Enter dict key in dictionary', + validationRule: 'Validation Rule', + validationRulePlaceholder: 'Select (multiple)', + placeholder: 'Placeholder', + placeholderPlaceholder: 'Enter placeholder', + sort: 'Sort', + remark: 'Remark', + remarkPlaceholder: 'Enter remark', + }, + validation: { + parentRequired: 'Please select a group', + titleRequired: 'Title is required', + keyRequired: 'Key is required', + keyFormat: 'Only letters and numbers allowed', + keyFormat2: 'Only letters, numbers, or underscores allowed', + formItemTypeRequired: 'Form type is required', + dictKeyRequired: 'This field cannot be empty', + }, + dialog: { + addGroup: 'Add Group', + addContent: 'Add Content', + closeConfirm: 'Are you sure you want to close?', + }, + messages: { + addSuccess: 'Added successfully', + saveSuccess: 'Saved successfully', + saveFailed: 'Save failed', + uploadFailed: 'Upload failed', + uploadFailedDetail: 'Upload failed: {msg}', + invalidImage: 'Only image files (jpg/png) are allowed', + exceedFileLimit: 'File count limit exceeded', + }, + buttons: { + addGroup: 'Add Group', + addContent: 'Add Content', + createNow: 'Create Now', + cancel: 'Cancel', + confirm: 'Confirm', + save: 'Save', + submit: 'Submit', + }, + validationRules: { + required: 'Required', + email: 'Email', + emailMessage: 'Please enter a valid email address', + url: 'URL', + urlMessage: 'Please enter a valid URL', + }, + formContent: { + variableTitle: 'Variable Title', + variableName: 'Variable Name', + variableValue: 'Variable Value', + isFrontendConfig: 'Frontend Config', + actions: 'Actions', + titlePlaceholder: 'Enter title', + keyPrefix: 'Enter variable key', + selectImageTip: 'Only jpg/png images allowed', + save: 'Save', + submit: 'Submit', + deleteConfirm: 'Delete this item?', + }, + tabs: { + none: 'No Group', + addTab: 'Add Group', + addContent: 'Add Content', + }, + associationTable: { + tableLabel: 'Associated Table', + displayField: 'Display Field', + storageField: 'Storage Field', + filterCondition: 'Filter Condition', + selectTable: 'Please select', + selectField: 'Please select', + required: 'This field is required', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/config/zh-cn.ts b/web/src/i18n/pages/config/zh-cn.ts new file mode 100644 index 0000000..0d648ca --- /dev/null +++ b/web/src/i18n/pages/config/zh-cn.ts @@ -0,0 +1,110 @@ +// 定义内容 +export default { + message: { + pages: { + config: { + header: { + tagText: '系统配置:您可在此对网站进行自定义配置', + }, + table: { + columns: { + configName: '配置名称', + configCode: '配置键名', + configValue: '配置值', + configType: '配置类型', + remark: '备注', + sort: '排序', + status: '状态', + createTime: '创建时间', + actions: '操作', + }, + }, + form: { + title: '标题', + key: 'Key值', + parent: '所属分组', + parentPlaceholder: '请选择分组', + titlePlaceholder: '请输入标题', + keyPlaceholder: '请输入Key值', + formItemType: '表单类型', + formItemTypePlaceholder: '请选择', + dictKey: '字典Key', + dictKeyPlaceholder: '请输入dictionary中的key值', + validationRule: '校验规则', + validationRulePlaceholder: '请选择(可多选)', + placeholder: '提示信息', + placeholderPlaceholder: '请输入占位提示', + sort: '排序', + remark: '备注', + remarkPlaceholder: '请输入备注', + }, + validation: { + parentRequired: '请选择所属分组', + titleRequired: '请输入标题', + keyRequired: '请输入Key值', + keyFormat: '只能是英文和数字', + keyFormat2: '只能是英文、数字或下划线', + formItemTypeRequired: '请选择表单类型', + dictKeyRequired: '不能为空', + }, + dialog: { + addGroup: '添加分组', + addContent: '添加内容', + closeConfirm: '确定要关闭吗?', + }, + messages: { + addSuccess: '新增成功', + saveSuccess: '保存成功', + saveFailed: '保存失败', + uploadFailed: '上传失败', + uploadFailedDetail: '上传失败:{msg}', + invalidImage: '仅允许上传图片文件(jpg/png)', + exceedFileLimit: '超出文件数量限制', + }, + buttons: { + addGroup: '添加分组', + addContent: '添加内容', + createNow: '立即创建', + cancel: '取消', + confirm: '确定', + save: '保存', + submit: '提交', + }, + validationRules: { + required: '必填项', + email: '邮箱', + emailMessage: '请输入正确的邮箱地址', + url: 'URL地址', + urlMessage: '请输入正确的URL地址', + }, + formContent: { + variableTitle: '变量标题', + variableName: '变量名', + variableValue: '变量值', + isFrontendConfig: '前端配置', + actions: '操作', + titlePlaceholder: '请输入标题', + keyPrefix: '请输入变量Key', + selectImageTip: '只能上传jpg/png图片', + save: '保存', + submit: '提交', + deleteConfirm: '确定删除该条数据吗?', + }, + tabs: { + none: '无分组', + addTab: '添加分组', + addContent: '添加内容', + }, + associationTable: { + tableLabel: '关联表', + displayField: '显示字段', + storageField: '储存字段', + filterCondition: '过滤条件', + selectTable: '请选择', + selectField: '请选择', + required: '必填项不能为空', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/config/zh-tw.ts b/web/src/i18n/pages/config/zh-tw.ts new file mode 100644 index 0000000..73c40aa --- /dev/null +++ b/web/src/i18n/pages/config/zh-tw.ts @@ -0,0 +1,110 @@ +// 定義內容 +export default { + message: { + pages: { + config: { + header: { + tagText: '系統配置:您可在此對網站進行自訂義配置', + }, + table: { + columns: { + configName: '配置名稱', + configCode: '配置鍵名', + configValue: '配置值', + configType: '配置類型', + remark: '備註', + sort: '排序', + status: '狀態', + createTime: '創建時間', + actions: '操作', + }, + }, + form: { + title: '標題', + key: 'Key值', + parent: '所屬分組', + parentPlaceholder: '請選擇分組', + titlePlaceholder: '請輸入標題', + keyPlaceholder: '請輸入Key值', + formItemType: '表單類型', + formItemTypePlaceholder: '請選擇', + dictKey: '字典Key', + dictKeyPlaceholder: '請輸入dictionary中的key值', + validationRule: '校驗規則', + validationRulePlaceholder: '請選擇(可多選)', + placeholder: '提示資訊', + placeholderPlaceholder: '請輸入佔位提示', + sort: '排序', + remark: '備註', + remarkPlaceholder: '請輸入備註', + }, + validation: { + parentRequired: '請選擇所屬分組', + titleRequired: '請輸入標題', + keyRequired: '請輸入Key值', + keyFormat: '只能是英文和數字', + keyFormat2: '只能是英文、數字或底線', + formItemTypeRequired: '請選擇表單類型', + dictKeyRequired: '不能為空', + }, + dialog: { + addGroup: '添加分組', + addContent: '添加內容', + closeConfirm: '確定要關閉嗎?', + }, + messages: { + addSuccess: '新增成功', + saveSuccess: '保存成功', + saveFailed: '保存失敗', + uploadFailed: '上傳失敗', + uploadFailedDetail: '上傳失敗:{msg}', + invalidImage: '僅允許上傳圖片文件(jpg/png)', + exceedFileLimit: '超出文件數量限制', + }, + buttons: { + addGroup: '添加分組', + addContent: '添加內容', + createNow: '立即創建', + cancel: '取消', + confirm: '確定', + save: '保存', + submit: '提交', + }, + validationRules: { + required: '必填項', + email: '郵箱', + emailMessage: '請輸入正確的郵箱地址', + url: 'URL地址', + urlMessage: '請輸入正確的URL地址', + }, + formContent: { + variableTitle: '變量標題', + variableName: '變量名', + variableValue: '變量值', + isFrontendConfig: '前端配置', + actions: '操作', + titlePlaceholder: '請輸入標題', + keyPrefix: '請輸入變量Key', + selectImageTip: '只能上傳jpg/png圖片', + save: '保存', + submit: '提交', + deleteConfirm: '確定刪除該條數據嗎?', + }, + tabs: { + none: '無分組', + addTab: '添加分組', + addContent: '添加內容', + }, + associationTable: { + tableLabel: '關聯表', + displayField: '顯示欄位', + storageField: '儲存欄位', + filterCondition: '過濾條件', + selectTable: '請選擇', + selectField: '請選擇', + required: '必填項不能為空', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/demo/en.ts b/web/src/i18n/pages/demo/en.ts new file mode 100644 index 0000000..b7d6540 --- /dev/null +++ b/web/src/i18n/pages/demo/en.ts @@ -0,0 +1,77 @@ +// Define content +export default { + message: { + pages: { + demo: { + table: { + columns: { + index: 'No.', + keyword: 'Keyword', + testComponent: 'Test Custom Component', + loginIp: 'Login IP', + isp: 'ISP', + continent: 'Continent', + country: 'Country', + province: 'Province', + city: 'City', + district: 'District', + areaCode: 'Area Code', + countryEn: 'English Name', + countryCode: 'Short Name', + longitude: 'Longitude', + latitude: 'Latitude', + loginType: 'Login Type', + os: 'OS', + browser: 'Browser', + agent: 'Agent Info', + normalLogin: 'Normal Login', + wechatLogin: 'WeChat Login', + area_code: '区域代码', + country_english: '英文全称', + country_code: '简称', + longitude: '经度', + latitude: '纬度', + login_type: '登录类型', + os: '操作系统', + browser: '浏览器名', + agent: 'Agent信息', + }, + }, + form: { + keywordPlaceholder: 'Enter keyword', + loginIpPlaceholder: 'Enter login IP', + ispPlaceholder: 'Enter ISP', + continentPlaceholder: 'Enter continent', + countryPlaceholder: 'Enter country', + provincePlaceholder: 'Enter province', + cityPlaceholder: 'Enter city', + districtPlaceholder: 'Enter district', + areaCodePlaceholder: 'Enter area code', + countryEnPlaceholder: 'Enter English name', + countryCodePlaceholder: 'Enter short name', + longitudePlaceholder: 'Enter longitude', + latitudePlaceholder: 'Enter latitude', + loginTypePlaceholder: 'Select login type', + osPlaceholder: 'Enter OS', + browserPlaceholder: 'Enter browser', + agentPlaceholder: 'Enter agent info', + area_codePlaceholder: 'Enter area code', + country_englishPlaceholder: 'Enter English name', + country_codePlaceholder: 'Enter short name', + login_typePlaceholder: 'Select login type', + }, + buttons: { + add: 'Add', + edit: 'Edit', + delete: 'Delete', + save: 'Save', + cancel: 'Cancel', + query: 'Search', + refresh: 'Refresh', + showChart: 'Show Chart', + hideChart: 'Hide Chart', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/demo/zh-cn.ts b/web/src/i18n/pages/demo/zh-cn.ts new file mode 100644 index 0000000..2bbe9ca --- /dev/null +++ b/web/src/i18n/pages/demo/zh-cn.ts @@ -0,0 +1,64 @@ +// 定义内容 +export default { + message: { + pages: { + demo: { + table: { + columns: { + index: '序号', + keyword: '关键词', + testComponent: '测试自定义组件', + loginIp: '登录IP', + isp: '运营商', + continent: '大洲', + country: '国家', + province: '省份', + city: '城市', + district: '区县', + areaCode: '区域代码', + countryEn: '英文全称', + countryCode: '简称', + longitude: '经度', + latitude: '纬度', + loginType: '登录类型', + os: '操作系统', + browser: '浏览器名', + agent: 'Agent信息', + normalLogin: '普通登录', + wechatLogin: '微信扫码登录', + }, + }, + form: { + keywordPlaceholder: '请输入关键词', + loginIpPlaceholder: '请输入登录IP', + ispPlaceholder: '请输入运营商', + continentPlaceholder: '请输入大洲', + countryPlaceholder: '请输入国家', + provincePlaceholder: '请输入省份', + cityPlaceholder: '请输入城市', + districtPlaceholder: '请输入区县', + areaCodePlaceholder: '请输入区域代码', + countryEnPlaceholder: '请输入英文全称', + countryCodePlaceholder: '请输入简称', + longitudePlaceholder: '请输入经度', + latitudePlaceholder: '请输入纬度', + loginTypePlaceholder: '请选择登录类型', + osPlaceholder: '请输入操作系统', + browserPlaceholder: '请输入浏览器名', + agentPlaceholder: '请输入Agent信息', + }, + buttons: { + add: '新增', + edit: '编辑', + delete: '删除', + save: '保存', + cancel: '取消', + query: '查询', + refresh: '刷新', + showChart: '显示图表', + hideChart: '隐藏图表', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/demo/zh-tw.ts b/web/src/i18n/pages/demo/zh-tw.ts new file mode 100644 index 0000000..5d85a4f --- /dev/null +++ b/web/src/i18n/pages/demo/zh-tw.ts @@ -0,0 +1,72 @@ +// 定義內容 +export default { + message: { + pages: { + demo: { + table: { + columns: { + index: '序號', + keyword: '關鍵詞', + testComponent: '測試自訂元件', + loginIp: '登入IP', + isp: '運營商', + continent: '大洲', + country: '國家', + province: '省份', + city: '城市', + district: '区县', + areaCode: '區域代碼', + countryEn: '英文全稱', + countryCode: '簡稱', + longitude: '經度', + latitude: '緯度', + loginType: '登入類型', + os: '作業系統', + browser: '瀏覽器名', + agent: 'Agent資訊', + normalLogin: '普通登入', + wechatLogin: '微信掃碼登入', + area_code: '區域代碼', + country_english: '英文全稱', + country_code: '簡稱', + login_type: '登入類型', + }, + }, + form: { + keywordPlaceholder: '請輸入關鍵詞', + loginIpPlaceholder: '請輸入登入IP', + ispPlaceholder: '請輸入運營商', + continentPlaceholder: '請輸入大洲', + countryPlaceholder: '請輸入國家', + provincePlaceholder: '請輸入省份', + cityPlaceholder: '請輸入城市', + districtPlaceholder: '請輸入区县', + areaCodePlaceholder: '請輸入區域代碼', + countryEnPlaceholder: '請輸入英文全稱', + countryCodePlaceholder: '請輸入簡稱', + longitudePlaceholder: '請輸入經度', + latitudePlaceholder: '請輸入緯度', + loginTypePlaceholder: '請選擇登入類型', + osPlaceholder: '請輸入作業系統', + browserPlaceholder: '請輸入瀏覽器名', + agentPlaceholder: '請輸入Agent資訊', + area_codePlaceholder: '請輸入區域代碼', + country_englishPlaceholder: '請輸入英文全稱', + country_codePlaceholder: '請輸入簡稱', + login_typePlaceholder: '請選擇登入類型', + }, + buttons: { + add: '新增', + edit: '編輯', + delete: '刪除', + save: '儲存', + cancel: '取消', + query: '查詢', + refresh: '重新整理', + showChart: '顯示圖表', + hideChart: '隱藏圖表', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/dept/en.ts b/web/src/i18n/pages/dept/en.ts new file mode 100644 index 0000000..286d8e5 --- /dev/null +++ b/web/src/i18n/pages/dept/en.ts @@ -0,0 +1,126 @@ +// Define content +export default { + message: { + pages: { + dept: { + table: { + columns: { + deptName: 'Dept Name', + deptCode: 'Dept Code', + parentDept: 'Parent Dept', + sort: 'Sort', + status: 'Status', + createTime: 'Create Time', + actions: 'Actions', + }, + }, + form: { + parentDept: 'Parent Dept', + deptName: 'Dept Name', + deptCode: 'Dept Code', + owner: 'Leader', + remark: 'Remark', + deptNamePlaceholder: 'Please enter dept name', + deptCodePlaceholder: 'Please enter dept code', + ownerPlaceholder: 'Please enter', + remarkPlaceholder: 'Please enter remark', + }, + validation: { + deptNameRequired: 'Dept name is required', + deptCodeRequired: 'Dept code is required', + }, + dialog: { + deptConfig: 'Dept Configuration', + deleteConfirm: 'Are you sure you want to delete this department?', + deleteWarning: 'Cannot delete: this department has child departments or users', + closeConfirm: 'Are you sure you want to close?', + }, + messages: { + addSuccess: 'Added successfully', + updateSuccess: 'Updated successfully', + deleteSuccess: 'Deleted successfully', + deleteFailed: 'Delete failed', + }, + buttons: { + confirm: 'Confirm', + cancel: 'Cancel', + save: 'Save', + add: 'Add', + edit: 'Edit', + delete: 'Delete', + }, + tree: { + deptStructure: 'Dept Structure', + searchPlaceholder: 'Search dept name', + add: 'Add', + edit: 'Edit', + moveUp: 'Move Up', + moveDown: 'Move Down', + delete: 'Delete', + selectDept: 'Please select a department!', + topDept: 'Top Level', + people: 'people', + }, + user: { + deptHeader: 'Dept Info', + deptLeader: 'Leader: ', + deptCount: 'Headcount: ', + deptDesc: 'Description: ', + showChild: 'Show Sub-Depts: ', + yes: 'Yes', + no: 'No', + none: 'None', + peopleUnit: '', + import: 'Import', + resetPwd: 'Reset Password', + pwdPlaceholder: 'Please enter password', + pwdAgainPlaceholder: 'Please confirm password', + selectUser: 'Please select a user!', + inputPwd: 'Please enter password!', + pwdMismatch: 'Passwords do not match', + pwdComplexity: 'Password is too simple (must contain letters and numbers)', + changeSuccess: 'Changed successfully!', + searchPlaceholder: 'Search username/nickname', + tableColumns: { + index: '#', + keyword: 'Keyword', + keywordPlaceholder: 'Enter keyword', + username: 'Username', + usernamePlaceholder: 'Enter username', + usernameRequired: 'Username is required', + password: 'Password', + passwordPlaceholder: 'Enter password', + passwordRequired: 'Password is required', + name: 'Name', + namePlaceholder: 'Enter name', + nameRequired: 'Name is required', + dept: 'Department', + selectDeptPlaceholder: 'Select', + deptRequired: 'Required', + role: 'Role', + rolePlaceholder: 'Select role', + roleRequired: 'Required', + mobile: 'Mobile', + mobilePlaceholder: 'Enter mobile number', + mobileInvalid: 'Invalid mobile number', + email: 'Email', + emailPlaceholder: 'Enter email', + emailInvalid: 'Invalid email address', + gender: 'Gender', + userType: 'User Type', + locked: 'Locked', + avatar: 'Avatar', + actions: 'Actions', + export: 'Export', + add: 'Add', + edit: 'Edit', + delete: 'Delete', + resetPassword: 'Reset Password', + resetPasswordTooltip: 'Reset Password', + }, + deleteUserConfirm: 'Delete this user?', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/dept/zh-cn.ts b/web/src/i18n/pages/dept/zh-cn.ts new file mode 100644 index 0000000..2177452 --- /dev/null +++ b/web/src/i18n/pages/dept/zh-cn.ts @@ -0,0 +1,126 @@ +// 定义内容 +export default { + message: { + pages: { + dept: { + table: { + columns: { + deptName: '部门名称', + deptCode: '部门编码', + parentDept: '上级部门', + sort: '排序', + status: '状态', + createTime: '创建时间', + actions: '操作', + }, + }, + form: { + parentDept: '父级部门', + deptName: '部门名称', + deptCode: '部门标识', + owner: '负责人', + remark: '备注', + deptNamePlaceholder: '请输入部门名称', + deptCodePlaceholder: '请输入部门标识', + ownerPlaceholder: '请输入', + remarkPlaceholder: '请输入备注', + }, + validation: { + deptNameRequired: '部门名称必填', + deptCodeRequired: '部门标识必填', + }, + dialog: { + deptConfig: '部门配置', + deleteConfirm: '您确认删除该部门吗?', + deleteWarning: '该部门下存在子部门或用户,无法删除', + closeConfirm: '您确定要关闭?', + }, + messages: { + addSuccess: '新增成功', + updateSuccess: '更新成功', + deleteSuccess: '删除成功', + deleteFailed: '删除失败', + }, + buttons: { + confirm: '确认', + cancel: '取消', + save: '保存', + add: '新增', + edit: '编辑', + delete: '删除', + }, + tree: { + deptStructure: '部门架构', + searchPlaceholder: '请输入部门名称', + add: '新增', + edit: '编辑', + moveUp: '上移', + moveDown: '下移', + delete: '删除', + selectDept: '请选择部门!', + topDept: '顶级部门', + people: '人', + }, + user: { + deptHeader: '部门信息', + deptLeader: '部门负责人:', + deptCount: '部门人数:', + deptDesc: '部门简介:', + showChild: '显示子级:', + yes: '是', + no: '否', + none: '无', + peopleUnit: '人', + import: '导入', + resetPwd: '重设密码', + pwdPlaceholder: '请输入密码', + pwdAgainPlaceholder: '请再次输入密码', + selectUser: '请选择用户!', + inputPwd: '请输入密码!', + pwdMismatch: '两次输入密码不一致', + pwdComplexity: '您的密码复杂度太低(密码中必须包含字母、数字)', + changeSuccess: '修改成功!', + searchPlaceholder: '搜索用户名/昵称', + tableColumns: { + index: '序号', + keyword: '关键词', + keywordPlaceholder: '请输入关键词', + username: '账号', + usernamePlaceholder: '请输入账号', + usernameRequired: '账号必填项', + password: '密码', + passwordPlaceholder: '请输入密码', + passwordRequired: '密码必填项', + name: '姓名', + namePlaceholder: '请输入姓名', + nameRequired: '姓名必填项', + dept: '部门', + selectDeptPlaceholder: '请选择', + deptRequired: '必填项', + role: '角色', + rolePlaceholder: '请选择角色', + roleRequired: '必填项', + mobile: '手机号码', + mobilePlaceholder: '请输入手机号码', + mobileInvalid: '请输入正确的手机号码', + email: '邮箱', + emailPlaceholder: '请输入邮箱', + emailInvalid: '请输入正确的邮箱地址', + gender: '性别', + userType: '用户类型', + locked: '锁定', + avatar: '头像', + actions: '操作', + export: '导出', + add: '新增', + edit: '编辑', + delete: '删除', + resetPassword: '重设密码', + resetPasswordTooltip: '重设密码', + }, + deleteUserConfirm: '是否删除该用户?', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/dept/zh-tw.ts b/web/src/i18n/pages/dept/zh-tw.ts new file mode 100644 index 0000000..e69de29 diff --git a/web/src/i18n/pages/dictionary/en.ts b/web/src/i18n/pages/dictionary/en.ts new file mode 100644 index 0000000..3ef094f --- /dev/null +++ b/web/src/i18n/pages/dictionary/en.ts @@ -0,0 +1,114 @@ +// Define content +export default { + message: { + pages: { + dictionary: { + table: { + columns: { + index: 'No.', + keyword: 'Keyword', + dictName: 'Dict Name', + dictCode: 'Dict Code', + status: 'Status', + remark: 'Remark', + sort: 'Sort', + createTime: 'Create Time', + actions: 'Actions', + }, + }, + subTable: { + columns: { + index: 'No.', + keyword: 'Keyword', + label: 'Dict Label', + value: 'Dict Value', + type: 'Data Type', + status: 'Status', + sort: 'Sort', + color: 'Color', + isValue: 'Is Value', + remark: 'Remark', + createTime: 'Create Time', + actions: 'Actions', + }, + typeLabels: { + text: 'Text', + number: 'Number', + date: 'Date', + datetime: 'Datetime', + time: 'Time', + file: 'File', + boolean: 'Boolean', + images: 'Images', + }, + form: { + labelPlaceholder: 'Enter dict label', + typePlaceholder: 'Select data type', + valuePlaceholder: 'Enter dict value', + }, + validation: { + labelRequired: 'Please enter dict label', + typeRequired: 'Please select data type', + valueRequired: 'Please enter dict value', + statusRequired: 'Please select status', + sortRequired: 'Please enter sort', + }, + }, + form: { + dictName: 'Dict Name', + dictCode: 'Dict Code', + status: 'Status', + remark: 'Remark', + sort: 'Sort', + keywordPlaceholder: 'Enter keyword', + dictNamePlaceholder: 'Enter dict name', + dictCodePlaceholder: 'Enter dict code', + remarkPlaceholder: 'Enter remark', + dictLabel: 'Dict Label', + dictValue: 'Dict Value', + dictType: 'Dict Type', + dictLabelPlaceholder: 'Enter dict label', + dictValuePlaceholder: 'Enter dict value', + dictCodeHelper: 'Usage: dictionary(\'dictCode\')', + }, + validation: { + dictNameRequired: 'Dict name is required', + dictNameMaxLength: 'Dict name must be 100 characters or less', + dictNameDuplicate: 'Dict name already exists', + dictCodeRequired: 'Dict code is required', + dictCodeMaxLength: 'Dict code must be 100 characters or less', + dictCodeDuplicate: 'Dict code already exists', + dictLabelRequired: 'Dict label is required', + dictValueRequired: 'Dict value is required', + }, + dialog: { + addDict: 'Add Dict', + editDict: 'Edit Dict', + addDictData: 'Add Dict Data', + editDictData: 'Edit Dict Data', + deleteConfirm: 'Delete this dict?', + closeConfirm: 'Are you sure you want to close?', + }, + messages: { + addSuccess: 'Added successfully', + updateSuccess: 'Updated successfully', + deleteSuccess: 'Deleted successfully', + deleteFailed: 'Delete failed', + }, + buttons: { + view: 'View', + add: 'Add', + edit: 'Edit', + delete: 'Delete', + save: 'Save', + cancel: 'Cancel', + confirm: 'Confirm', + query: 'Query', + refresh: 'Refresh', + addDictData: 'Add Dict Data', + dictConfig: 'Dict Config', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/dictionary/zh-cn.ts b/web/src/i18n/pages/dictionary/zh-cn.ts new file mode 100644 index 0000000..4e1c58d --- /dev/null +++ b/web/src/i18n/pages/dictionary/zh-cn.ts @@ -0,0 +1,103 @@ +// 定义内容 +export default { + message: { + pages: { + dictionary: { + table: { + columns: { + index: '序号', + keyword: '关键词', + dictName: '字典名称', + dictCode: '字典编码', + status: '状态', + remark: '备注', + sort: '排序', + createTime: '创建时间', + actions: '操作', + }, + }, + subTable: { + columns: { + index: '序号', + keyword: '关键词', + label: '字典标签', + value: '字典键值', + type: '数据类型', + status: '状态', + sort: '排序', + color: '颜色', + isValue: '是否值', + remark: '备注', + createTime: '创建时间', + actions: '操作', + }, + form: { + labelPlaceholder: '请输入字典标签', + typePlaceholder: '请选择数据类型', + valuePlaceholder: '请输入字典键值', + }, + validation: { + labelRequired: '请输入字典标签', + typeRequired: '请选择数据类型', + valueRequired: '请输入字典键值', + statusRequired: '请选择状态', + sortRequired: '请输入排序', + }, + }, + form: { + dictName: '字典名称', + dictCode: '字典编码', + status: '状态', + remark: '备注', + sort: '排序', + keywordPlaceholder: '请输入关键词', + dictNamePlaceholder: '请输入字典名称', + dictCodePlaceholder: '请输入字典编码', + remarkPlaceholder: '请输入备注', + dictLabel: '字典标签', + dictValue: '字典键值', + dictType: '字典类型', + dictLabelPlaceholder: '请输入字典标签', + dictValuePlaceholder: '请输入字典键值', + dictCodeHelper: '使用方法:dictionary(\'字典编号\')', + }, + validation: { + dictNameRequired: '请输入字典名称', + dictNameMaxLength: '字典名称不能超过100个字符', + dictNameDuplicate: '字典名称已存在', + dictCodeRequired: '请输入字典编码', + dictCodeMaxLength: '字典编码不能超过100个字符', + dictCodeDuplicate: '字典编码已存在', + dictLabelRequired: '请输入字典标签', + dictValueRequired: '请输入字典键值', + }, + dialog: { + addDict: '新增字典', + editDict: '编辑字典', + addDictData: '新增字典数据', + editDictData: '编辑字典数据', + deleteConfirm: '确定删除该字典吗?', + closeConfirm: '您确定要关闭吗?', + }, + messages: { + addSuccess: '新增成功', + updateSuccess: '更新成功', + deleteSuccess: '删除成功', + deleteFailed: '删除失败', + }, + buttons: { + add: '新增', + edit: '编辑', + delete: '删除', + save: '保存', + cancel: '取消', + confirm: '确定', + query: '查询', + refresh: '刷新', + addDictData: '新增字典数据', + dictConfig: '字典配置', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/dictionary/zh-tw.ts b/web/src/i18n/pages/dictionary/zh-tw.ts new file mode 100644 index 0000000..44a6d37 --- /dev/null +++ b/web/src/i18n/pages/dictionary/zh-tw.ts @@ -0,0 +1,104 @@ +// 定義內容 +export default { + message: { + pages: { + dictionary: { + table: { + columns: { + index: '序號', + keyword: '關鍵詞', + dictName: '字典名稱', + dictCode: '字典編碼', + status: '狀態', + remark: '備註', + sort: '排序', + createTime: '創建時間', + actions: '操作', + }, + }, + subTable: { + columns: { + index: '序號', + keyword: '關鍵詞', + label: '字典標籤', + value: '字典鍵值', + type: '資料類型', + status: '狀態', + sort: '排序', + color: '顏色', + isValue: '是否值', + remark: '備註', + createTime: '創建時間', + actions: '操作', + }, + form: { + labelPlaceholder: '請輸入字典標籤', + typePlaceholder: '請選擇資料類型', + valuePlaceholder: '請輸入字典鍵值', + }, + validation: { + labelRequired: '請輸入字典標籤', + typeRequired: '請選擇資料類型', + valueRequired: '請輸入字典鍵值', + statusRequired: '請選擇狀態', + sortRequired: '請輸入排序', + }, + }, + form: { + dictName: '字典名稱', + dictCode: '字典編碼', + status: '狀態', + remark: '備註', + sort: '排序', + keywordPlaceholder: '請輸入關鍵詞', + dictNamePlaceholder: '請輸入字典名稱', + dictCodePlaceholder: '請輸入字典編碼', + remarkPlaceholder: '請輸入備註', + dictLabel: '字典標籤', + dictValue: '字典鍵值', + dictType: '字典類型', + dictLabelPlaceholder: '請輸入字典標籤', + dictValuePlaceholder: '請輸入字典鍵值', + dictCodeHelper: '使用方法:dictionary(\'字典編號\')', + }, + validation: { + dictNameRequired: '請輸入字典名稱', + dictNameMaxLength: '字典名稱不能超過100個字符', + dictNameDuplicate: '字典名稱已存在', + dictCodeRequired: '請輸入字典編碼', + dictCodeMaxLength: '字典編碼不能超過100個字符', + dictCodeDuplicate: '字典編碼已存在', + dictLabelRequired: '請輸入字典標籤', + dictValueRequired: '請輸入字典鍵值', + }, + dialog: { + addDict: '新增字典', + editDict: '編輯字典', + addDictData: '新增字典數據', + editDictData: '編輯字典數據', + deleteConfirm: '確定刪除該字典嗎?', + closeConfirm: '您確定要關閉嗎?', + }, + messages: { + addSuccess: '新增成功', + updateSuccess: '更新成功', + deleteSuccess: '刪除成功', + deleteFailed: '刪除失敗', + }, + buttons: { + view: '查看', + add: '新增', + edit: '編輯', + delete: '刪除', + save: '保存', + cancel: '取消', + confirm: '確定', + query: '查詢', + refresh: '刷新', + addDictData: '新增字典數據', + dictConfig: '字典配置', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/downloadCenter/en.ts b/web/src/i18n/pages/downloadCenter/en.ts new file mode 100644 index 0000000..56ffd20 --- /dev/null +++ b/web/src/i18n/pages/downloadCenter/en.ts @@ -0,0 +1,30 @@ +// Define content +export default { + message: { + pages: { + downloadCenter: { + table: { + columns: { + index: 'No.', + taskName: 'Task Name', + fileName: 'File Name', + size: 'Size (b)', + taskStatus: 'Task Status', + createTime: 'Create Time', + updateTime: 'Update Time', + }, + }, + status: { + created: 'Created', + processing: 'Processing', + completed: 'Completed', + failed: 'Failed', + }, + buttons: { + downloadFile: 'Download File', + search: 'Search', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/downloadCenter/zh-cn.ts b/web/src/i18n/pages/downloadCenter/zh-cn.ts new file mode 100644 index 0000000..c4617ca --- /dev/null +++ b/web/src/i18n/pages/downloadCenter/zh-cn.ts @@ -0,0 +1,30 @@ +// 定义内容 +export default { + message: { + pages: { + downloadCenter: { + table: { + columns: { + index: '序号', + taskName: '任务名', + fileName: '文件名', + size: '文件大小(b)', + taskStatus: '任务状态', + createTime: '创建时间', + updateTime: '更新时间', + }, + }, + status: { + created: '任务已创建', + processing: '任务进行中', + completed: '任务完成', + failed: '任务失败', + }, + buttons: { + downloadFile: '下载文件', + search: '查询', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/downloadCenter/zh-tw.ts b/web/src/i18n/pages/downloadCenter/zh-tw.ts new file mode 100644 index 0000000..3ea95b7 --- /dev/null +++ b/web/src/i18n/pages/downloadCenter/zh-tw.ts @@ -0,0 +1,30 @@ +// 定義內容 +export default { + message: { + pages: { + downloadCenter: { + table: { + columns: { + index: '序號', + taskName: '任務名', + fileName: '文件名', + size: '檔案大小(b)', + taskStatus: '任務狀態', + createTime: '創建時間', + updateTime: '更新時間', + }, + }, + status: { + created: '任務已創建', + processing: '任務進行中', + completed: '任務完成', + failed: '任務失敗', + }, + buttons: { + downloadFile: '下載檔案', + search: '查詢', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/fileList/en.ts b/web/src/i18n/pages/fileList/en.ts new file mode 100644 index 0000000..881e2db --- /dev/null +++ b/web/src/i18n/pages/fileList/en.ts @@ -0,0 +1,58 @@ +// Define content +export default { + message: { + pages: { + fileList: { + table: { + columns: { + index: 'No.', + keyword: 'Keyword', + name: 'File Name', + preview: 'Preview', + url: 'File URL', + md5sum: 'MD5', + mimeType: 'MIME Type', + fileType: 'File Type', + size: 'File Size', + uploadMethod: 'Upload Method', + createTime: 'Create Time', + }, + }, + form: { + keywordPlaceholder: 'Enter keyword', + namePlaceholder: 'Enter file name', + fileTypePlaceholder: 'Select file type', + }, + fileType: { + image: 'Image', + video: 'Video', + audio: 'Audio', + document: 'Document', + other: 'Other', + unknown: 'Unknown', + }, + tabs: { + image: 'Image', + video: 'Video', + audio: 'Audio', + other: 'Other', + }, + uploadMethod: { + default: 'Default Upload', + selector: 'File Selector Upload', + }, + buttons: { + upload: 'Upload', + add: 'Add', + edit: 'Edit', + delete: 'Delete', + }, + size: { + bytes: 'B', + kilobytes: 'KB', + megabytes: 'MB', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/fileList/zh-cn.ts b/web/src/i18n/pages/fileList/zh-cn.ts new file mode 100644 index 0000000..97242d6 --- /dev/null +++ b/web/src/i18n/pages/fileList/zh-cn.ts @@ -0,0 +1,58 @@ +// 定义内容 +export default { + message: { + pages: { + fileList: { + table: { + columns: { + index: '序号', + keyword: '关键词', + name: '文件名称', + preview: '预览', + url: '文件地址', + md5sum: '文件MD5', + mimeType: '文件类型(MIME)', + fileType: '文件类型', + size: '文件大小', + uploadMethod: '上传方式', + createTime: '创建时间', + }, + }, + form: { + keywordPlaceholder: '请输入关键词', + namePlaceholder: '请输入文件名称', + fileTypePlaceholder: '请选择文件类型', + }, + fileType: { + image: '图片', + video: '视频', + audio: '音频', + document: '文档', + other: '其他', + unknown: '未知类型', + }, + tabs: { + image: '图片', + video: '视频', + audio: '音频', + other: '其他', + }, + uploadMethod: { + default: '默认上传', + selector: '文件选择器上传', + }, + buttons: { + upload: '上传', + add: '新增', + edit: '编辑', + delete: '删除', + }, + size: { + bytes: 'B', + kilobytes: 'KB', + megabytes: 'MB', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/fileList/zh-tw.ts b/web/src/i18n/pages/fileList/zh-tw.ts new file mode 100644 index 0000000..7eb54b2 --- /dev/null +++ b/web/src/i18n/pages/fileList/zh-tw.ts @@ -0,0 +1,58 @@ +// 定義內容 +export default { + message: { + pages: { + fileList: { + table: { + columns: { + index: '序號', + keyword: '關鍵詞', + name: '文件名稱', + preview: '預覽', + url: '文件地址', + md5sum: '文件MD5', + mimeType: '文件類型(MIME)', + fileType: '文件類型', + size: '文件大小', + uploadMethod: '上傳方式', + createTime: '創建時間', + }, + }, + form: { + keywordPlaceholder: '請輸入關鍵詞', + namePlaceholder: '請輸入文件名稱', + fileTypePlaceholder: '請選擇文件類型', + }, + fileType: { + image: '圖片', + video: '視頻', + audio: '音頻', + document: '文檔', + other: '其他', + unknown: '未知類型', + }, + tabs: { + image: '圖片', + video: '視頻', + audio: '音頻', + other: '其他', + }, + uploadMethod: { + default: '預設上傳', + selector: '檔案選擇器上傳', + }, + buttons: { + upload: '上傳', + add: '新增', + edit: '編輯', + delete: '刪除', + }, + size: { + bytes: 'b', + kilobytes: 'Kb', + megabytes: 'Mb', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/home/en.ts b/web/src/i18n/pages/home/en.ts new file mode 100644 index 0000000..0319c25 --- /dev/null +++ b/web/src/i18n/pages/home/en.ts @@ -0,0 +1,41 @@ +// Define content +export default { + message: { + pages: { + home: { + statCards: { + orderStats: 'Order Statistics', + monthlyPlan: 'Monthly Plan Info', + visitStats: 'Visit Statistics', + }, + chart: { + // Line chart (政策补贴额度) + lineTitle: 'Policy Subsidy Quota', + lineLegendPreOrder: 'Pre-Order Queue', + lineLegendLatestPrice: 'Latest Transaction Price', + lineYAxisName: 'Price', + month: '', + // Pie chart (房屋建筑工程) + pieTitle: 'Building & Structural Engineering', + pieCategory1: 'Buildings & Structures', + pieCategory2: 'Special Equipment', + pieCategory3: 'General Equipment', + pieCategory4: 'Cultural Relics & Exhibits', + pieCategory5: 'Books & Archives', + // Bar chart (地热开发利用) + barTitle: 'Geothermal Development & Utilization', + barLegendSupplyTemp: 'Supply Temperature', + barLegendReturnTemp: 'Return Temperature', + barLegendPressure: 'Pressure (Mpa)', + barYAxisSupplyReturn: 'Supply/Return Temp (℃)', + }, + quickNav: { + quickNavTitle: 'Quick Navigation', + }, + notifications: { + defaultCreator: 'Unknown User', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/home/zh-cn.ts b/web/src/i18n/pages/home/zh-cn.ts new file mode 100644 index 0000000..746adbd --- /dev/null +++ b/web/src/i18n/pages/home/zh-cn.ts @@ -0,0 +1,41 @@ +// 定义内容 +export default { + message: { + pages: { + home: { + statCards: { + orderStats: '订单统计信息', + monthlyPlan: '月度计划信息', + visitStats: '访问统计信息', + }, + chart: { + // Line chart (政策补贴额度) + lineTitle: '政策补贴额度', + lineLegendPreOrder: '预购队列', + lineLegendLatestPrice: '最新成交价', + lineYAxisName: '价格', + month: '月', + // Pie chart (房屋建筑工程) + pieTitle: '房屋建筑工程', + pieCategory1: '房屋及结构物', + pieCategory2: '专用设备', + pieCategory3: '通用设备', + pieCategory4: '文物和陈列品', + pieCategory5: '图书、档案', + // Bar chart (地热开发利用) + barTitle: '地热开发利用', + barLegendSupplyTemp: '供温', + barLegendReturnTemp: '回温', + barLegendPressure: '压力值(Mpa)', + barYAxisSupplyReturn: '供回温度(℃)', + }, + quickNav: { + quickNavTitle: '快捷导航工具', + }, + notifications: { + defaultCreator: '未知用户', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/home/zh-tw.ts b/web/src/i18n/pages/home/zh-tw.ts new file mode 100644 index 0000000..e69de29 diff --git a/web/src/i18n/pages/layout/en.ts b/web/src/i18n/pages/layout/en.ts new file mode 100644 index 0000000..05b9889 --- /dev/null +++ b/web/src/i18n/pages/layout/en.ts @@ -0,0 +1,72 @@ +// 定义内容 +export default { + message: { + layout: { + configTitle: 'Interface Settings', + oneTitle: 'Global Theme', + twoTopTitle: 'Top Bar Theme', + twoTopBar: 'Top Bar Background', + twoTopBarColor: 'Top Bar Color', + twoIsTopBarColorGradual: 'Top Bar Gradient', + twoMenuTitle: 'Menu Theme', + twoMenuBar: 'Menu Background', + twoMenuBarColor: 'Menu Background Color', + twoMenuBarActiveColor: 'Menu Active Background', + twoIsMenuBarColorGradual: 'Menu Background Gradient', + twoColumnsTitle: 'Columns Menu', + twoColumnsMenuBar: 'Columns Menu Background', + twoColumnsMenuBarColor: 'Columns Menu Background Color', + twoIsColumnsMenuBarColorGradual: 'Columns Menu Gradient', + twoIsColumnsMenuHoverPreload: 'Columns Menu Hover Preload', + threeTitle: 'Interface Settings', + threeIsCollapse: 'Collapse Menu', + threeIsUniqueOpened: 'Accordion Menu', + threeIsFixedHeader: 'Fixed Header', + threeIsClassicSplitMenu: 'Classic Split Menu', + threeIsLockScreen: 'Enable Lock Screen', + threeLockScreenTime: 'Auto Lock (minutes)', + fourTitle: 'Display Settings', + fourIsDark: 'Dark Theme', + fourIsShowLogo: 'Show Logo', + fourIsBreadcrumb: 'Breadcrumb', + fourIsBreadcrumbIcon: 'Breadcrumb Icon', + fourIsTagsview: 'Tags View', + fourIsTagsviewIcon: 'Tags View Icon', + fourIsCacheTagsView: 'Fixed Tags View', + fourIsSortableTagsView: 'Draggable Tags View', + fourIsShareTagsView: 'Share Tags View', + fourIsFooter: 'Footer', + fourIsGrayscale: 'Grayscale Mode', + fourIsInvert: 'Invert Mode', + fourIsWartermark: 'Enable Watermark', + fourWartermarkText: 'Watermark Text', + fiveTitle: 'Animation', + fiveTagsStyle: 'Tags Style', + fiveAnimation: 'Page Transition', + fiveColumnsAsideStyle: 'Columns Aside Style', + fiveColumnsAsideLayout: 'Columns Aside Layout', + horizontal: 'Horizontal', + vertical: 'Vertical', + card: 'Card', + rounded: 'Rounded', + sixTitle: 'Layout Presets', + sixDefaults: 'Default', + sixClassic: 'Classic', + sixTransverse: 'Transverse', + sixColumns: 'Columns', + tipText: 'Click the button below to configure ↓', + copyText: 'Copy', + resetText: 'Reset', + selectPlaceholder: 'Please select', + style1: 'Style 1', + style4: 'Style 4', + style5: 'Style 5', + animation1: 'Slide Right', + animation2: 'Fade', + animation3: 'Opacity', + animation4: 'Slide Up', + animation5: 'Scale Fade', + animation6: 'Scroll', + }, + }, +}; diff --git a/web/src/i18n/pages/layout/zh-cn.ts b/web/src/i18n/pages/layout/zh-cn.ts new file mode 100644 index 0000000..494826c --- /dev/null +++ b/web/src/i18n/pages/layout/zh-cn.ts @@ -0,0 +1,71 @@ +// 定义内容 +export default { + message: { + layout: { + configTitle: '界面配置', + oneTitle: '整体样式', + twoTopTitle: '顶部主题', + twoTopBar: '顶栏背景色', + twoTopBarColor: '顶栏背景色渐变', + twoMenuTitle: '菜单主题', + twoMenuBar: '菜单背景色', + twoMenuBarColor: '菜单背景色渐变', + twoMenuBarActiveColor: '菜单高亮背景色', + twoIsMenuBarColorGradual: '菜单背景渐变', + twoColumnsTitle: '分栏菜单', + twoColumnsMenuBar: '分栏菜单背景色', + twoColumnsMenuBarColor: '分栏菜单背景渐变', + twoIsColumnsMenuBarColorGradual: '分栏菜单背景渐变', + twoIsColumnsMenuHoverPreload: '分栏菜单hover预加载', + threeTitle: '界面设置', + threeIsCollapse: '菜单水平折叠', + threeIsUniqueOpened: '菜单手风琴', + threeIsFixedHeader: '固定 Header', + threeIsClassicSplitMenu: '经典分割菜单', + threeIsLockScreen: '开启锁屏', + threeLockScreenTime: '自动锁屏(分钟)', + fourTitle: '显示设置', + fourIsDark: '深色主题', + fourIsShowLogo: '侧边栏 Logo', + fourIsBreadcrumb: '面包屑导航', + fourIsBreadcrumbIcon: '面包屑导航图标', + fourIsTagsview: '标签栏', + fourIsTagsviewIcon: '标签栏图标', + fourIsCacheTagsView: '是否固定标签栏', + fourIsSortableTagsView: '标签栏拖拽', + fourIsShareTagsView: '标签栏跨域联动', + fourIsFooter: '页脚', + fourIsGrayscale: '灰色模式', + fourIsInvert: '色弱模式', + fourIsWartermark: '开启水印', + fourWartermarkText: '水印文案', + fiveTitle: '动画配置', + fiveTagsStyle: '标签样式风格', + fiveAnimation: '页面切换动画', + fiveColumnsAsideStyle: '分栏菜单风格', + fiveColumnsAsideLayout: '分栏菜单布局', + horizontal: '横向', + vertical: '纵向', + card: '卡片', + rounded: '圆角', + sixTitle: '预设颜色', + sixDefaults: '默认', + sixClassic: '经典', + sixTransverse: '横向', + sixColumns: '分栏', + tipText: '点击下方按钮进行配置 ↓', + copyText: 'copy', + resetText: '重置', + selectPlaceholder: '请选择', + style1: '风格1', + style4: '风格4', + style5: '风格5', + animation1: '左侧滑入', + animation2: '渐变', + animation3: '淡入淡出', + animation4: '下方滑入', + animation5: '缩放淡入', + animation6: '卷轴', + }, + }, +}; diff --git a/web/src/i18n/pages/layout/zh-tw.ts b/web/src/i18n/pages/layout/zh-tw.ts new file mode 100644 index 0000000..afb11f2 --- /dev/null +++ b/web/src/i18n/pages/layout/zh-tw.ts @@ -0,0 +1,72 @@ +// 定義內容 +export default { + message: { + layout: { + configTitle: '介面設置', + oneTitle: '全域主題', + twoTopTitle: '頂欄主題', + twoTopBar: '頂欄背景色', + twoTopBarColor: '頂欄顏色', + twoIsTopBarColorGradual: '頂欄漸變', + twoMenuTitle: '功能表主題', + twoMenuBar: '功能表背景色', + twoMenuBarColor: '功能表背景顏色', + twoMenuBarActiveColor: '功能表當前背景色', + twoIsMenuBarColorGradual: '功能表背景漸變', + twoColumnsTitle: '分欄功能表', + twoColumnsMenuBar: '分欄功能表背景色', + twoColumnsMenuBarColor: '分欄功能表背景顏色', + twoIsColumnsMenuBarColorGradual: '分欄功能表漸變', + twoIsColumnsMenuHoverPreload: '分欄功能表懸停預載入', + threeTitle: '介面設置', + threeIsCollapse: '功能表折疊', + threeIsUniqueOpened: '功能表手風琴', + threeIsFixedHeader: '固定頂欄', + threeIsClassicSplitMenu: '經典分割功能表', + threeIsLockScreen: '開啟鎖屏', + threeLockScreenTime: '自動鎖屏(分鐘)', + fourTitle: '顯示設置', + fourIsDark: '深色主題', + fourIsShowLogo: '顯示標誌', + fourIsBreadcrumb: '麵包屑導航', + fourIsBreadcrumbIcon: '麵包屑圖標', + fourIsTagsview: '標籤頁', + fourIsTagsviewIcon: '標籤頁圖標', + fourIsCacheTagsView: '固定標籤頁', + fourIsSortableTagsView: '可拖曳標籤頁', + fourIsShareTagsView: '共用標籤頁', + fourIsFooter: '頁腳', + fourIsGrayscale: '灰階模式', + fourIsInvert: '反色模式', + fourIsWartermark: '開啟浮水印', + fourWartermarkText: '浮水印文字', + fiveTitle: '動畫配置', + fiveTagsStyle: '標籤樣式', + fiveAnimation: '頁面切換動畫', + fiveColumnsAsideStyle: '分欄側邊欄樣式', + fiveColumnsAsideLayout: '分欄側邊欄佈局', + horizontal: '橫向', + vertical: '縱向', + card: '卡片', + rounded: '圓角', + sixTitle: '佈局預設', + sixDefaults: '預設', + sixClassic: '經典', + sixTransverse: '橫向', + sixColumns: '分欄', + tipText: '點擊下方按鈕進行配置 ↓', + copyText: '複製', + resetText: '重置', + selectPlaceholder: '請選擇', + style1: '樣式1', + style4: '樣式4', + style5: '樣式5', + animation1: '左側滑入', + animation2: '漸變', + animation3: '淡入淡出', + animation4: '下方滑入', + animation5: '縮放淡入', + animation6: '卷軸', + }, + }, +}; diff --git a/web/src/i18n/pages/loginLog/en.ts b/web/src/i18n/pages/loginLog/en.ts new file mode 100644 index 0000000..9a2c7d6 --- /dev/null +++ b/web/src/i18n/pages/loginLog/en.ts @@ -0,0 +1,72 @@ +// Define content +export default { + message: { + pages: { + loginLog: { + table: { + columns: { + index: 'No.', + keyword: 'Keyword', + username: 'Username', + ip: 'IP Address', + isp: 'ISP', + continent: 'Continent', + country: 'Country', + province: 'Province', + city: 'City', + district: 'District', + areaCode: 'Area Code', + countryEnglish: 'Country (EN)', + countryCode: 'Country Code', + longitude: 'Longitude', + latitude: 'Latitude', + loginType: 'Login Type', + os: 'OS', + browser: 'Browser', + agent: 'User-Agent', + status: 'Status', + createTime: 'Login Time', + msg: 'Message', + }, + }, + status: { + success: 'Success', + failed: 'Failed', + }, + loginType: { + normal: 'Normal Login', + wechat: 'WeChat Login', + }, + form: { + keywordPlaceholder: 'Enter keyword', + usernamePlaceholder: 'Enter username', + ipPlaceholder: 'Enter IP address', + ispPlaceholder: 'Enter ISP', + continentPlaceholder: 'Enter continent', + countryPlaceholder: 'Enter country', + provincePlaceholder: 'Enter province', + cityPlaceholder: 'Enter city', + districtPlaceholder: 'Enter district', + areaCodePlaceholder: 'Enter area code', + countryEnglishPlaceholder: 'Enter country (EN)', + countryCodePlaceholder: 'Enter country code', + longitudePlaceholder: 'Enter longitude', + latitudePlaceholder: 'Enter latitude', + loginTypePlaceholder: 'Select login type', + osPlaceholder: 'Enter OS', + browserPlaceholder: 'Enter browser', + agentPlaceholder: 'Enter User-Agent', + }, + buttons: { + view: 'View', + query: 'Query', + export: 'Export', + refresh: 'Refresh', + reset: 'Reset', + loginTimeRange: 'Login Time Range', + statusFilter: 'Status', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/loginLog/zh-cn.ts b/web/src/i18n/pages/loginLog/zh-cn.ts new file mode 100644 index 0000000..44e9952 --- /dev/null +++ b/web/src/i18n/pages/loginLog/zh-cn.ts @@ -0,0 +1,72 @@ +// 定义内容 +export default { + message: { + pages: { + loginLog: { + table: { + columns: { + index: '序号', + keyword: '关键词', + username: '用户名', + ip: 'IP地址', + isp: '运营商', + continent: '大洲', + country: '国家', + province: '省份', + city: '城市', + district: '区县', + areaCode: '区域代码', + countryEnglish: '国家(英文)', + countryCode: '国家代码', + longitude: '经度', + latitude: '纬度', + loginType: '登录方式', + os: '操作系统', + browser: '浏览器', + agent: 'User-Agent', + status: '状态', + createTime: '登录时间', + msg: '提示消息', + }, + }, + status: { + success: '成功', + failed: '失败', + }, + loginType: { + normal: '普通登录', + wechat: '微信登录', + }, + form: { + keywordPlaceholder: '请输入关键词', + usernamePlaceholder: '请输入用户名', + ipPlaceholder: '请输入IP地址', + ispPlaceholder: '请输入运营商', + continentPlaceholder: '请输入大洲', + countryPlaceholder: '请输入国家', + provincePlaceholder: '请输入省份', + cityPlaceholder: '请输入城市', + districtPlaceholder: '请输入区县', + areaCodePlaceholder: '请输入区域代码', + countryEnglishPlaceholder: '请输入国家(英文)', + countryCodePlaceholder: '请输入国家代码', + longitudePlaceholder: '请输入经度', + latitudePlaceholder: '请输入纬度', + loginTypePlaceholder: '请选择登录方式', + osPlaceholder: '请输入操作系统', + browserPlaceholder: '请输入浏览器', + agentPlaceholder: '请输入User-Agent', + }, + buttons: { + view: '查看', + query: '查询', + export: '导出', + refresh: '刷新', + reset: '重置', + loginTimeRange: '登录时间范围', + statusFilter: '状态', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/loginLog/zh-tw.ts b/web/src/i18n/pages/loginLog/zh-tw.ts new file mode 100644 index 0000000..c6d0cb2 --- /dev/null +++ b/web/src/i18n/pages/loginLog/zh-tw.ts @@ -0,0 +1,72 @@ +// 定義內容 +export default { + message: { + pages: { + loginLog: { + table: { + columns: { + index: '序號', + keyword: '關鍵詞', + username: '用戶名', + ip: 'IP位址', + isp: '運營商', + continent: '大洲', + country: '國家', + province: '省份', + city: '城市', + district: '區縣', + areaCode: '區域代碼', + countryEnglish: '國家(英文)', + countryCode: '國家代碼', + longitude: '經度', + latitude: '緯度', + loginType: '登錄方式', + os: '作業系統', + browser: '瀏覽器', + agent: 'User-Agent', + status: '狀態', + createTime: '登錄時間', + msg: '提示消息', + }, + }, + status: { + success: '成功', + failed: '失敗', + }, + loginType: { + normal: '普通登錄', + wechat: '微信登錄', + }, + form: { + keywordPlaceholder: '請輸入關鍵詞', + usernamePlaceholder: '請輸入用戶名', + ipPlaceholder: '請輸入IP位址', + ispPlaceholder: '請輸入運營商', + continentPlaceholder: '請輸入大洲', + countryPlaceholder: '請輸入國家', + provincePlaceholder: '請輸入省份', + cityPlaceholder: '請輸入城市', + districtPlaceholder: '請輸入區縣', + areaCodePlaceholder: '請輸入區域代碼', + countryEnglishPlaceholder: '請輸入國家(英文)', + countryCodePlaceholder: '請輸入國家代碼', + longitudePlaceholder: '請輸入經度', + latitudePlaceholder: '請輸入緯度', + loginTypePlaceholder: '請選擇登錄方式', + osPlaceholder: '請輸入作業系統', + browserPlaceholder: '請輸入瀏覽器', + agentPlaceholder: '請輸入User-Agent', + }, + buttons: { + view: '查看', + query: '查詢', + export: '導出', + refresh: '刷新', + reset: '重置', + loginTimeRange: '登錄時間範圍', + statusFilter: '狀態', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/menu/en.ts b/web/src/i18n/pages/menu/en.ts new file mode 100644 index 0000000..020ebd8 --- /dev/null +++ b/web/src/i18n/pages/menu/en.ts @@ -0,0 +1,162 @@ +// Define content +export default { + message: { + pages: { + menu: { + tree: { + menuList: 'Menu List', + deptList: 'Department List', + deptPlaceholder: 'Enter department name', + deptInfo: '1. Department info;', + addTooltip: 'Add', + editTooltip: 'Edit', + moveUpTooltip: 'Move Up', + moveDownTooltip: 'Move Down', + deleteTooltip: 'Delete', + selectMenuWarning: 'Please select a menu!', + menuAlert: '1. Red menu means disabled status; 2. For directory type, component path can be empty; 3. For root node, parent menu can be empty; 4. Drag to reorder is supported;', + }, + table: { + columns: { + fieldName: 'Field Name', + title: 'Column Name', + actions: 'Actions', + menuName: 'Menu Name', + icon: 'Icon', + sort: 'Sort', + status: 'Status', + createTime: 'Created At', + }, + }, + form: { + fieldName: 'Field Name', + title: 'Column Name', + isCreate: 'Show on Create', + isUpdate: 'Show on Edit', + isQuery: 'Show in Search', + confirm: 'Confirm', + cancel: 'Cancel', + menuName: 'Menu Name', + parentMenu: 'Parent Menu', + path: 'Route Path', + icon: 'Icon', + component: 'Component Path', + componentName: 'Component Name', + linkUrl: 'External Link', + cache: 'Cache', + remark: 'Remark', + status: 'Status', + visible: 'Sidebar Visible', + isCatalog: 'Is Directory', + isLink: 'External Link', + isAffix: 'Is Affix', + isIframe: 'Is Iframe', + enabled: 'Enabled', + disabled: 'Disabled', + show: 'Show', + hide: 'Hide', + yes: 'Yes', + no: 'No', + menuNamePlaceholder: 'Please enter menu name', + menuNameZhCn: 'Simplified Chinese', + menuNameEn: 'English Name', + menuNameZhTw: 'Traditional Chinese', + menuNameZhCnPlaceholder: 'Enter menu name in Simplified Chinese (required)', + menuNameEnPlaceholder: 'Enter menu name in English (optional)', + menuNameZhTwPlaceholder: 'Enter menu name in Traditional Chinese (optional)', + parentMenuPlaceholder: 'Please select parent menu', + pathPlaceholder: 'Enter route path, must start with /', + componentPlaceholder: 'Enter component path', + componentNamePlaceholder: 'Please enter component name', + linkUrlPlaceholder: 'Please enter external link URL', + remarkPlaceholder: 'Please enter remark', + tokenTip: 'Enter {{token}} to automatically replace system token', + }, + fieldForm: { + fieldName: 'Field Name', + title: 'Column Name', + fieldLabel: 'Field Label', + fieldType: 'Field Type', + width: 'Width', + isSortable: 'Sortable', + isSearch: 'Searchable', + isFilterable: 'Filterable', + showInList: 'Show in List', + required: 'Required', + fieldNamePlaceholder: 'Please enter field name', + titlePlaceholder: 'Please enter column name', + widthPlaceholder: 'Please enter width', + }, + validation: { + fieldNameRequired: 'Please enter field name!', + titleRequired: 'Please enter column name!', + fieldNameFieldRequired: 'Please enter field name!', + titleFieldRequired: 'Please enter column name!', + pathRequired: 'Please enter a valid route path', + componentRequired: 'Please enter a component path', + componentNameRequired: 'Please enter a component name', + linkUrlRequired: 'Please enter an external link URL', + permissionNameRequired: 'Permission name is required', + permissionValueRequired: 'Permission key is required', + batchGenerate: 'Batch Generate', + }, + dialog: { + columnPermission: 'Column Permission', + addColumn: 'Add', + editColumn: 'Edit', + deleteColumn: 'Delete', + deleteConfirm: 'Are you sure you want to delete this field?', + automatch: 'Auto Match', + automatchSuccess: 'Matched successfully', + selectRoleAndModel: 'Please select a role and model table!', + selectModel: 'Select Model', + selected: 'Selected:', + searchPlaceholder: 'Search models...', + menuConfig: 'Menu Config', + buttonPermission: 'Button Permission Config', + columnPermissionTab: 'Column Permission Config', + deleteMenuConfirm: 'Are you sure you want to delete this menu item?', + }, + messages: { + addSuccess: 'Created successfully', + updateSuccess: 'Updated successfully', + deleteSuccess: 'Deleted successfully', + deleteFailed: 'Delete failed', + automatchSuccess: 'Matched successfully', + batchDeleteConfirm: 'Are you sure you want to batch delete {count} records?', + batchDeleteSuccess: 'Deleted successfully', + selectMenu: 'Please select a menu!', + }, + buttons: { + add: 'Add', + edit: 'Edit', + delete: 'Delete', + save: 'Save', + cancel: 'Cancel', + reset: 'Reset', + automatch: 'Auto Match', + confirm: 'Confirm', + batchDelete: 'Batch Delete', + expandAll: 'Expand All', + collapseAll: 'Collapse All', + selectMenu: 'Please select a menu', + searchPlaceholder: 'Enter keywords to search', + search: 'Keyword', + select: 'Select', + index: 'No.', + model: 'Model', + chineseName: 'Chinese Name', + fieldName: 'Field Name', + chineseNamePlaceholder: 'Please enter Chinese name', + fieldNamePlaceholder: 'Please enter field name', + permissionName: 'Permission Name', + permissionValue: 'Permission Value', + requestMethod: 'Request Method', + apiEndpoint: 'API Endpoint', + batchGenerate: 'Batch Generate', + selectMenuFirst: 'Please select a menu first', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/menu/zh-cn.ts b/web/src/i18n/pages/menu/zh-cn.ts new file mode 100644 index 0000000..41a2d2b --- /dev/null +++ b/web/src/i18n/pages/menu/zh-cn.ts @@ -0,0 +1,162 @@ +// 定义内容 +export default { + message: { + pages: { + menu: { + tree: { + menuList: '菜单列表', + deptList: '部门列表', + deptPlaceholder: '请输入部门名称', + deptInfo: '1.部门信息;', + addTooltip: '新增', + editTooltip: '编辑', + moveUpTooltip: '上移', + moveDownTooltip: '下移', + deleteTooltip: '删除', + selectMenuWarning: '请选择菜单!', + menuAlert: '1.红色菜单代表状态禁用; 2.添加菜单,如果是目录,组件地址为空即可; 3.添加根节点菜单,父级ID为空即可; 4.支持拖拽菜单;', + }, + table: { + columns: { + fieldName: '字段名', + title: '列名', + actions: '操作', + menuName: '菜单名称', + icon: '图标', + sort: '排序', + status: '状态', + createTime: '创建时间', + }, + }, + form: { + fieldName: '字段名', + title: '列名', + isCreate: '创建显示', + isUpdate: '编辑显示', + isQuery: '查询显示', + confirm: '确定', + cancel: '取消', + menuName: '菜单名称', + parentMenu: '上级菜单', + path: '路由地址', + icon: '图标', + component: '组件地址', + componentName: '组件名称', + linkUrl: '外链接', + cache: '缓存', + remark: '备注', + status: '状态', + visible: '侧边显示', + isCatalog: '是否目录', + isLink: '外链接', + isAffix: '是否固定', + isIframe: '是否内嵌', + enabled: '启用', + disabled: '禁用', + show: '显示', + hide: '隐藏', + yes: '是', + no: '否', + menuNamePlaceholder: '请输入菜单名称', + menuNameZhCn: '简体中文', + menuNameEn: '英文名称', + menuNameZhTw: '繁体中文', + menuNameZhCnPlaceholder: '请输入简体中文名称(必填)', + menuNameEnPlaceholder: '请输入英文名称(选填)', + menuNameZhTwPlaceholder: '请输入繁体中文名称(选填)', + parentMenuPlaceholder: '请选择父级菜单', + pathPlaceholder: '请输入路由地址,请以/开头', + componentPlaceholder: '输入组件地址', + componentNamePlaceholder: '请输入组件名称', + linkUrlPlaceholder: '请输入外链接地址', + remarkPlaceholder: '请输入备注', + tokenTip: '输入{{token}}可自动替换系统 token', + }, + fieldForm: { + fieldName: '字段名称', + title: '列名称', + fieldLabel: '字段标签', + fieldType: '字段类型', + width: '宽度', + isSortable: '是否可排', + isSearch: '是否搜索', + isFilterable: '是否筛选', + showInList: '列表显示', + required: '是否必填', + fieldNamePlaceholder: '请输入字段名称', + titlePlaceholder: '请输入列名称', + widthPlaceholder: '请输入宽度', + }, + validation: { + fieldNameRequired: '请输入字段名!', + titleRequired: '请输入列名!', + fieldNameFieldRequired: '请输入字段名称!', + titleFieldRequired: '请输入列名称!', + pathRequired: '请输入正确的地址', + componentRequired: '请输入组件地址', + componentNameRequired: '请输入组件名称', + linkUrlRequired: '请输入外链接地址', + permissionNameRequired: '权限名称必填', + permissionValueRequired: '权限标识必填', + batchGenerate: '批量生成', + }, + dialog: { + columnPermission: '字段权限', + addColumn: '新增', + editColumn: '编辑', + deleteColumn: '删除', + deleteConfirm: '确定删除该字段吗?', + automatch: '自动匹配', + automatchSuccess: '匹配成功', + selectRoleAndModel: '请选择角色和模型表!', + selectModel: '选择model', + selected: '已选择:', + searchPlaceholder: '搜索模型...', + menuConfig: '菜单配置', + buttonPermission: '按钮权限配置', + columnPermissionTab: '列权限配置', + deleteMenuConfirm: '您确认删除该菜单项吗?', + }, + messages: { + addSuccess: '新增成功', + updateSuccess: '更新成功', + deleteSuccess: '删除成功', + deleteFailed: '删除失败', + automatchSuccess: '匹配成功', + batchDeleteConfirm: '确定要批量删除这{count}条记录吗', + batchDeleteSuccess: '删除成功', + selectMenu: '请选择菜单!', + }, + buttons: { + add: '新增', + edit: '编辑', + delete: '删除', + save: '保存', + cancel: '取消', + reset: '重置', + automatch: '自动匹配', + confirm: '确定', + batchDelete: '批量删除', + expandAll: '展开所有', + collapseAll: '收起所有', + selectMenu: '请选择菜单', + searchPlaceholder: '输入关键词搜索', + search: '关键词', + select: '选择', + index: '序号', + model: 'model', + chineseName: '中文名', + fieldName: '字段名', + chineseNamePlaceholder: '请输入中文名', + fieldNamePlaceholder: '请输入字段名', + permissionName: '权限名称', + permissionValue: '权限值', + requestMethod: '请求方式', + apiEndpoint: '接口地址', + batchGenerate: '批量生成', + selectMenuFirst: '请选择菜单', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/menu/zh-tw.ts b/web/src/i18n/pages/menu/zh-tw.ts new file mode 100644 index 0000000..878209b --- /dev/null +++ b/web/src/i18n/pages/menu/zh-tw.ts @@ -0,0 +1,162 @@ +// 定義內容 +export default { + message: { + pages: { + menu: { + tree: { + menuList: '菜單列表', + deptList: '部門列表', + deptPlaceholder: '請輸入部門名稱', + deptInfo: '1.部門信息;', + addTooltip: '新增', + editTooltip: '編輯', + moveUpTooltip: '上移', + moveDownTooltip: '下移', + deleteTooltip: '刪除', + selectMenuWarning: '請選擇菜單!', + menuAlert: '1.紅色菜單代表狀態停用; 2.添加菜單,如果是目錄,組件地址為空即可; 3.添加根節點菜單,父級ID為空即可; 4.支持拖拽菜單;', + }, + table: { + columns: { + fieldName: '字段名', + title: '列名', + actions: '操作', + menuName: '菜單名稱', + icon: '圖標', + sort: '排序', + status: '狀態', + createTime: '創建時間', + }, + }, + form: { + fieldName: '字段名', + title: '列名', + isCreate: '創建顯示', + isUpdate: '編輯顯示', + isQuery: '查詢顯示', + confirm: '確定', + cancel: '取消', + menuName: '菜單名稱', + parentMenu: '上級菜單', + path: '路由地址', + icon: '圖標', + component: '組件地址', + componentName: '組件名稱', + linkUrl: '外鏈接', + cache: '緩存', + remark: '備註', + status: '狀態', + visible: '側邊顯示', + isCatalog: '是否目錄', + isLink: '外鏈接', + isAffix: '是否固定', + isIframe: '是否內嵌', + enabled: '啟用', + disabled: '停用', + show: '顯示', + hide: '隱藏', + yes: '是', + no: '否', + menuNamePlaceholder: '請輸入菜單名稱', + menuNameZhCn: '簡體中文', + menuNameEn: '英文名稱', + menuNameZhTw: '繁體中文', + menuNameZhCnPlaceholder: '請輸入簡體中文名稱(必填)', + menuNameEnPlaceholder: '請輸入英文名稱(選填)', + menuNameZhTwPlaceholder: '請輸入繁體中文名稱(選填)', + parentMenuPlaceholder: '請選擇上級菜單', + pathPlaceholder: '請輸入路由地址,請以/開頭', + componentPlaceholder: '輸入組件地址', + componentNamePlaceholder: '請輸入組件名稱', + linkUrlPlaceholder: '請輸入外鏈接地址', + remarkPlaceholder: '請輸入備註', + tokenTip: '輸入{{token}}可自動替換系統 token', + }, + fieldForm: { + fieldName: '字段名稱', + title: '列名稱', + fieldLabel: '字段標籤', + fieldType: '字段類型', + width: '寬度', + isSortable: '是否可排', + isSearch: '是否搜索', + isFilterable: '是否篩選', + showInList: '列表顯示', + required: '是否必填', + fieldNamePlaceholder: '請輸入字段名稱', + titlePlaceholder: '請輸入列名稱', + widthPlaceholder: '請輸入寬度', + }, + validation: { + fieldNameRequired: '請輸入字段名!', + titleRequired: '請輸入列名!', + fieldNameFieldRequired: '請輸入字段名稱!', + titleFieldRequired: '請輸入列名稱!', + pathRequired: '請輸入正確的地址', + componentRequired: '請輸入組件地址', + componentNameRequired: '請輸入組件名稱', + linkUrlRequired: '請輸入外鏈接地址', + permissionNameRequired: '權限名稱必填', + permissionValueRequired: '權限標識必填', + batchGenerate: '批量生成', + }, + dialog: { + columnPermission: '字段權限', + addColumn: '新增', + editColumn: '編輯', + deleteColumn: '刪除', + deleteConfirm: '確定刪除該字段嗎?', + automatch: '自動匹配', + automatchSuccess: '匹配成功', + selectRoleAndModel: '請選擇角色和模型表!', + selectModel: '選擇model', + selected: '已選擇:', + searchPlaceholder: '搜索模型...', + menuConfig: '菜單配置', + buttonPermission: '按鈕權限配置', + columnPermissionTab: '列權限配置', + deleteMenuConfirm: '您確認刪除該菜單項嗎?', + }, + messages: { + addSuccess: '新增成功', + updateSuccess: '更新成功', + deleteSuccess: '刪除成功', + deleteFailed: '刪除失敗', + automatchSuccess: '匹配成功', + batchDeleteConfirm: '確定要批量刪除這{count}條記錄嗎', + batchDeleteSuccess: '刪除成功', + selectMenu: '請選擇菜單!', + }, + buttons: { + add: '新增', + edit: '編輯', + delete: '刪除', + save: '保存', + cancel: '取消', + reset: '重置', + automatch: '自動匹配', + confirm: '確定', + batchDelete: '批量刪除', + expandAll: '展開所有', + collapseAll: '收起所有', + selectMenu: '請選擇菜單', + searchPlaceholder: '輸入關鍵詞搜索', + search: '關鍵詞', + select: '選擇', + index: '序號', + model: 'model', + chineseName: '中文名', + fieldName: '字段名', + chineseNamePlaceholder: '請輸入中文名', + fieldNamePlaceholder: '請輸入字段名', + permissionName: '權限名稱', + permissionValue: '權限值', + requestMethod: '請求方式', + apiEndpoint: '接口地址', + batchGenerate: '批量生成', + selectMenuFirst: '請選擇菜單', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/messageCenter/en.ts b/web/src/i18n/pages/messageCenter/en.ts new file mode 100644 index 0000000..0712efc --- /dev/null +++ b/web/src/i18n/pages/messageCenter/en.ts @@ -0,0 +1,68 @@ +// Define content +export default { + message: { + pages: { + messageCenter: { + tabs: { + myPublish: 'My Published', + myReceive: 'My Received', + unread: 'Unread', + read: 'Read', + all: 'All', + }, + table: { + columns: { + title: 'Title', + type: 'Type', + creatorName: 'Sender', + createTime: 'Send Time', + isRead: 'Status', + actions: 'Actions', + targetType: 'Target Type', + targetUser: 'Target User', + targetRole: 'Target Role', + targetDept: 'Target Dept', + content: 'Content', + }, + }, + status: { + yes: 'Read', + no: 'Unread', + }, + targetType: { + byUser: 'By User', + byRole: 'By Role', + byDept: 'By Dept', + notice: 'Notice', + }, + buttons: { + markAllRead: 'Mark All Read', + markRead: 'Mark as Read', + delete: 'Delete', + refresh: 'Refresh', + view: 'View', + export: 'Export', + add: 'Add', + }, + form: { + titlePlaceholder: 'Enter title', + phone: 'Phone', + roleName: 'Role Name', + roleKey: 'Permission Key', + deptName: 'Dept Name', + status: 'Status', + parentDept: 'Parent Dept', + }, + validation: { + titleRequired: 'Title is required', + targetTypeRequired: 'Please select target type', + required: 'Required', + }, + messages: { + markReadSuccess: 'Marked successfully', + deleteSuccess: 'Deleted successfully', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/messageCenter/zh-cn.ts b/web/src/i18n/pages/messageCenter/zh-cn.ts new file mode 100644 index 0000000..a66651d --- /dev/null +++ b/web/src/i18n/pages/messageCenter/zh-cn.ts @@ -0,0 +1,68 @@ +// 定义内容 +export default { + message: { + pages: { + messageCenter: { + tabs: { + myPublish: '我的发布', + myReceive: '我的接收', + unread: '未读', + read: '已读', + all: '全部', + }, + table: { + columns: { + title: '标题', + type: '类型', + creatorName: '发送人', + createTime: '发送时间', + isRead: '状态', + actions: '操作', + targetType: '目标类型', + targetUser: '目标用户', + targetRole: '目标角色', + targetDept: '目标部门', + content: '内容', + }, + }, + status: { + yes: '已读', + no: '未读', + }, + targetType: { + byUser: '按用户', + byRole: '按角色', + byDept: '按部门', + notice: '通知公告', + }, + buttons: { + markAllRead: '全部已读', + markRead: '标记已读', + delete: '删除', + refresh: '刷新', + view: '查看', + export: '导出', + add: '新增', + }, + form: { + titlePlaceholder: '请输入标题', + phone: '用户电话', + roleName: '角色名称', + roleKey: '权限标识', + deptName: '部门名称', + status: '状态', + parentDept: '父级部门', + }, + validation: { + titleRequired: '标题必填', + targetTypeRequired: '请选择目标类型', + required: '必填项', + }, + messages: { + markReadSuccess: '标记成功', + deleteSuccess: '删除成功', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/messageCenter/zh-tw.ts b/web/src/i18n/pages/messageCenter/zh-tw.ts new file mode 100644 index 0000000..320233d --- /dev/null +++ b/web/src/i18n/pages/messageCenter/zh-tw.ts @@ -0,0 +1,68 @@ +// 定義內容 +export default { + message: { + pages: { + messageCenter: { + tabs: { + myPublish: '我的發布', + myReceive: '我的接收', + unread: '未讀', + read: '已讀', + all: '全部', + }, + table: { + columns: { + title: '標題', + type: '類型', + creatorName: '發送人', + createTime: '發送時間', + isRead: '狀態', + actions: '操作', + targetType: '目標類型', + targetUser: '目標用戶', + targetRole: '目標角色', + targetDept: '目標部門', + content: '內容', + }, + }, + status: { + yes: '已讀', + no: '未讀', + }, + targetType: { + byUser: '按用戶', + byRole: '按角色', + byDept: '按部門', + notice: '通知公告', + }, + buttons: { + markAllRead: '全部已讀', + markRead: '標記已讀', + delete: '刪除', + refresh: '刷新', + view: '查看', + export: '導出', + add: '新增', + }, + form: { + titlePlaceholder: '請輸入標題', + phone: '用戶電話', + roleName: '角色名稱', + roleKey: '權限標識', + deptName: '部門名稱', + status: '狀態', + parentDept: '父級部門', + }, + validation: { + titleRequired: '標題必填', + targetTypeRequired: '請選擇目標類型', + required: '必填項', + }, + messages: { + markReadSuccess: '標記成功', + deleteSuccess: '刪除成功', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/operationLog/en.ts b/web/src/i18n/pages/operationLog/en.ts new file mode 100644 index 0000000..f5914c6 --- /dev/null +++ b/web/src/i18n/pages/operationLog/en.ts @@ -0,0 +1,65 @@ +// Define content +export default { + message: { + pages: { + operationLog: { + table: { + columns: { + module: 'Module', + method: 'Method', + operationType: 'Operation Type', + requestUrl: 'Request URL', + requestParam: 'Request Params', + responseCode: 'Response Code', + duration: 'Duration (ms)', + status: 'Status', + createTime: 'Operation Time', + creator: 'Operator', + remark: 'Details', + index: 'No.', + keyword: 'Keyword', + requestModule: 'Request Module', + requestPath: 'Request URL', + requestBody: 'Request Params', + requestMethod: 'Request Method', + requestMsg: 'Description', + requestIp: 'IP Address', + requestBrowser: 'Browser', + requestOs: 'OS', + jsonResult: 'Response', + creatorName: 'Operator', + }, + }, + form: { + module: 'Module', + remark: 'Details', + modulePlaceholder: 'Enter module', + remarkPlaceholder: 'Enter details', + keywordPlaceholder: 'Enter keyword', + requestModulePlaceholder: 'Enter request module', + requestPathPlaceholder: 'Enter request URL', + requestBodyPlaceholder: 'Enter request params', + requestMethodPlaceholder: 'Enter request method', + requestIpPlaceholder: 'Enter IP address', + }, + validation: { + moduleMaxLength: 'Module must be 100 characters or less', + remarkMaxLength: 'Details must be 500 characters or less', + }, + buttons: { + view: 'View', + query: 'Query', + export: 'Export', + refresh: 'Refresh', + reset: 'Reset', + timeRange: 'Operation Time Range', + operationType: 'Operation Type', + }, + messages: { + querySuccess: 'Query successful', + exportSuccess: 'Exported successfully', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/operationLog/zh-cn.ts b/web/src/i18n/pages/operationLog/zh-cn.ts new file mode 100644 index 0000000..33f6d81 --- /dev/null +++ b/web/src/i18n/pages/operationLog/zh-cn.ts @@ -0,0 +1,65 @@ +// 定义内容 +export default { + message: { + pages: { + operationLog: { + table: { + columns: { + module: '操作模块', + method: '请求方式', + operationType: '操作类型', + requestUrl: '请求地址', + requestParam: '请求参数', + responseCode: '响应码', + duration: '耗时(ms)', + status: '状态', + createTime: '操作时间', + creator: '操作人', + remark: '操作详情', + index: '序号', + keyword: '关键词', + requestModule: '请求模块', + requestPath: '请求地址', + requestBody: '请求参数', + requestMethod: '请求方法', + requestMsg: '操作说明', + requestIp: 'IP地址', + requestBrowser: '请求浏览器', + requestOs: '操作系统', + jsonResult: '返回信息', + creatorName: '操作人', + }, + }, + form: { + module: '操作模块', + remark: '操作详情', + modulePlaceholder: '请输入操作模块', + remarkPlaceholder: '请输入操作详情', + keywordPlaceholder: '请输入关键词', + requestModulePlaceholder: '请输入请求模块', + requestPathPlaceholder: '请输入请求地址', + requestBodyPlaceholder: '请输入请求参数', + requestMethodPlaceholder: '请输入请求方法', + requestIpPlaceholder: '请输入IP地址', + }, + validation: { + moduleMaxLength: '操作模块不能超过100个字符', + remarkMaxLength: '操作详情不能超过500个字符', + }, + buttons: { + view: '查看', + query: '查询', + export: '导出', + refresh: '刷新', + reset: '重置', + timeRange: '操作时间范围', + operationType: '操作类型', + }, + messages: { + querySuccess: '查询成功', + exportSuccess: '导出成功', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/operationLog/zh-tw.ts b/web/src/i18n/pages/operationLog/zh-tw.ts new file mode 100644 index 0000000..83d2880 --- /dev/null +++ b/web/src/i18n/pages/operationLog/zh-tw.ts @@ -0,0 +1,65 @@ +// 定義內容 +export default { + message: { + pages: { + operationLog: { + table: { + columns: { + module: '操作模組', + method: '請求方式', + operationType: '操作類型', + requestUrl: '請求地址', + requestParam: '請求參數', + responseCode: '響應碼', + duration: '耗時(ms)', + status: '狀態', + createTime: '操作時間', + creator: '操作人', + remark: '操作詳情', + index: '序號', + keyword: '關鍵詞', + requestModule: '請求模組', + requestPath: '請求地址', + requestBody: '請求參數', + requestMethod: '請求方式', + requestMsg: '操作說明', + requestIp: 'IP位址', + requestBrowser: '請求瀏覽器', + requestOs: '作業系統', + jsonResult: '返回資訊', + creatorName: '操作人', + }, + }, + form: { + module: '操作模組', + remark: '操作詳情', + modulePlaceholder: '請輸入操作模組', + remarkPlaceholder: '請輸入操作詳情', + keywordPlaceholder: '請輸入關鍵詞', + requestModulePlaceholder: '請輸入請求模組', + requestPathPlaceholder: '請輸入請求地址', + requestBodyPlaceholder: '請輸入請求參數', + requestMethodPlaceholder: '請輸入請求方式', + requestIpPlaceholder: '請輸入IP位址', + }, + validation: { + moduleMaxLength: '操作模組不能超過100個字符', + remarkMaxLength: '操作詳情不能超過500個字符', + }, + buttons: { + view: '查看', + query: '查詢', + export: '導出', + refresh: '刷新', + reset: '重置', + timeRange: '操作時間範圍', + operationType: '操作類型', + }, + messages: { + querySuccess: '查詢成功', + exportSuccess: '導出成功', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/personal/en.ts b/web/src/i18n/pages/personal/en.ts new file mode 100644 index 0000000..0ef7552 --- /dev/null +++ b/web/src/i18n/pages/personal/en.ts @@ -0,0 +1,64 @@ +// Define content +export default { + message: { + pages: { + personal: { + PersonalInfo1: 'Basic Info', + PersonalInfo2: 'Complete your personal information here', + info: { + myInfoTitle: 'My Information', + updateInfoTitle: 'Update Info', + accountSecurity: 'Account Security', + nickname: 'Nickname:', + department: 'Department:', + roles: 'Roles:', + currentPasswordStrength: 'Current Password Strength: Strong', + changePasswordNow: 'Change Now', + boundMobile: 'Bound Mobile:', + boundEmail: 'Bound Email:', + }, + form: { + nickname: 'Nickname', + nicknamePlaceholder: 'Please enter your nickname', + email: 'Email', + emailPlaceholder: 'Please enter your email', + mobile: 'Mobile', + mobilePlaceholder: 'Please enter your mobile number', + gender: 'Gender', + genderPlaceholder: 'Please select gender', + genderMale: 'Male', + genderFemale: 'Female', + genderSecret: 'Secret', + }, + dialog: { + passwordChange: 'Change Password', + oldPassword: 'Current Password', + newPassword: 'New Password', + confirmPassword: 'Confirm Password', + oldPasswordPlaceholder: 'Please enter your current password', + newPasswordPlaceholder: 'Please enter a new password', + confirmPasswordPlaceholder: 'Please confirm your new password', + submit: 'Submit', + }, + validation: { + nicknameRequired: 'Please enter your nickname', + mobileInvalid: 'Please enter a valid mobile number', + oldPasswordRequired: 'Please enter your current password', + sameAsOldPassword: 'New password cannot be the same as current password', + passwordComplexity: 'Password complexity too low (must contain letters and numbers)', + confirmPasswordRequired: 'Please confirm your password', + passwordMismatch: 'Passwords do not match', + formValidationFailed: 'Form validation failed, please check', + }, + messages: { + updateSuccess: 'Update successful', + passwordChangeSuccess: 'Password changed successfully', + formValidationFailed: 'Form validation failed, please check', + }, + button: { + submit: 'Submit', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/personal/zh-cn.ts b/web/src/i18n/pages/personal/zh-cn.ts new file mode 100644 index 0000000..31c8e53 --- /dev/null +++ b/web/src/i18n/pages/personal/zh-cn.ts @@ -0,0 +1,64 @@ +// 定义内容 +export default { + message: { + pages: { + personal: { + PersonalInfo1: '基本信息', + PersonalInfo2: '在这里完善你的个人信息', + info: { + myInfoTitle: '个人信息', + updateInfoTitle: '更新信息', + accountSecurity: '账号安全', + nickname: '昵称:', + department: '部门:', + roles: '角色:', + currentPasswordStrength: '当前密码强度:强', + changePasswordNow: '立即修改', + boundMobile: '已绑定手机:', + boundEmail: '已绑定邮箱:', + }, + form: { + nickname: '昵称', + nicknamePlaceholder: '请输入昵称', + email: '邮箱', + emailPlaceholder: '请输入邮箱', + mobile: '手机', + mobilePlaceholder: '请输入手机', + gender: '性别', + genderPlaceholder: '请选择性别', + genderMale: '男', + genderFemale: '女', + genderSecret: '保密', + }, + dialog: { + passwordChange: '密码修改', + oldPassword: '原密码', + newPassword: '新密码', + confirmPassword: '确认密码', + oldPasswordPlaceholder: '请输入原始密码', + newPasswordPlaceholder: '请输入新密码', + confirmPasswordPlaceholder: '请再次输入新密码', + submit: '提交', + }, + validation: { + nicknameRequired: '请输入昵称', + mobileInvalid: '请输入正确手机号', + oldPasswordRequired: '请输入原密码', + sameAsOldPassword: '原密码与新密码一致', + passwordComplexity: '您的密码复杂度太低(密码中必须包含字母、数字)', + confirmPasswordRequired: '请再次输入密码', + passwordMismatch: '两次输入密码不一致!', + formValidationFailed: '表单验证失败,请检查~', + }, + messages: { + updateSuccess: '更新成功', + passwordChangeSuccess: '密码修改成功', + formValidationFailed: '表单校验失败,请检查', + }, + button: { + submit: '提交', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/personal/zh-tw.ts b/web/src/i18n/pages/personal/zh-tw.ts new file mode 100644 index 0000000..b934480 --- /dev/null +++ b/web/src/i18n/pages/personal/zh-tw.ts @@ -0,0 +1,64 @@ +// 定義內容 +export default { + message: { + pages: { + personal: { + PersonalInfo1: '基本資訊', + PersonalInfo2: '在這裡完善您的個人資訊', + info: { + myInfoTitle: '個人資訊', + updateInfoTitle: '更新資訊', + accountSecurity: '帳號安全', + nickname: '暱稱:', + department: '部門:', + roles: '角色:', + currentPasswordStrength: '當前密碼強度:強', + changePasswordNow: '立即修改', + boundMobile: '已綁定手機:', + boundEmail: '已綁定郵箱:', + }, + form: { + nickname: '暱稱', + nicknamePlaceholder: '請輸入暱稱', + email: '郵箱', + emailPlaceholder: '請輸入郵箱', + mobile: '手機', + mobilePlaceholder: '請輸入手機', + gender: '性別', + genderPlaceholder: '請選擇性別', + genderMale: '男', + genderFemale: '女', + genderSecret: '保密', + }, + dialog: { + passwordChange: '密碼修改', + oldPassword: '原始密碼', + newPassword: '新密碼', + confirmPassword: '確認密碼', + oldPasswordPlaceholder: '請輸入原始密碼', + newPasswordPlaceholder: '請輸入新密碼', + confirmPasswordPlaceholder: '請再次輸入新密碼', + submit: '提交', + }, + validation: { + nicknameRequired: '請輸入暱稱', + mobileInvalid: '請輸入正確手機號', + oldPasswordRequired: '請輸入原始密碼', + sameAsOldPassword: '原始密碼與新密碼一致', + passwordComplexity: '您的密碼複雜度太低(密碼中必須包含字母、數字)', + confirmPasswordRequired: '請再次輸入密碼', + passwordMismatch: '兩次輸入密碼不一致!', + formValidationFailed: '表單驗證失敗,請檢查~', + }, + messages: { + updateSuccess: '更新成功', + passwordChangeSuccess: '密碼修改成功', + formValidationFailed: '表單校驗失敗,請檢查', + }, + button: { + submit: '提交', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/role/en.ts b/web/src/i18n/pages/role/en.ts new file mode 100644 index 0000000..3ee8bc8 --- /dev/null +++ b/web/src/i18n/pages/role/en.ts @@ -0,0 +1,91 @@ +// Define content +export default { + message: { + pages: { + role: { + table: { + columns: { + index: 'No.', + name: 'Role Name', + key: 'Permission Key', + sort: 'Sort', + status: 'Status', + actions: 'Actions', + }, + }, + form: { + name: 'Role Name', + key: 'Permission Key', + sort: 'Sort', + status: 'Status', + remark: 'Remark', + namePlaceholder: 'Please enter role name', + keyPlaceholder: 'Enter permission key', + sortPlaceholder: 'Please enter sort order', + remarkPlaceholder: 'Please enter remark', + }, + validation: { + nameRequired: 'Role name is required', + keyRequired: 'Permission key is required', + sortRequired: 'Sort order is required', + }, + dialog: { + addRole: 'Add Role', + editRole: 'Edit Role', + assignPermissions: 'Permission Config', + assignUsers: 'Assign Users', + deleteConfirm: 'Are you sure you want to delete this role?', + menuPermission: 'Menu Permission', + buttonPermission: 'Button Permission', + columnPermission: 'Column Field Permission', + interfacePermission: 'Interface Permission', + currentRole: 'Current authorized role:', + authorizedUsers: 'Authorized users:', + selectDataPermission: 'Please select', + customDeptPlaceholder: 'Select custom departments', + dataPermissionConfig: 'Data Permission Config', + defaultInterfacePermission: 'Default interface permission:', + configureOperationPermission: 'Configure operation interface permissions. Click the gear icon to configure data permissions.', + }, + messages: { + addSuccess: 'Created successfully', + updateSuccess: 'Updated successfully', + deleteSuccess: 'Deleted successfully', + deleteFailed: 'Delete failed', + assignSuccess: 'Assigned successfully', + saveSuccess: 'Saved successfully', + checkUsersFirst: 'Please select users first', + batchDeleteConfirm: 'Are you sure you want to delete permissions for {count} users?', + deleteUserConfirm: 'Are you sure you want to delete permissions for "{count}" users?', + }, + buttons: { + add: 'Add', + view: 'View', + edit: 'Edit', + delete: 'Delete', + save: 'Save', + cancel: 'Cancel', + reset: 'Reset', + export: 'Export', + query: 'Search', + refresh: 'Refresh', + assignPermission: 'Permission Config', + assignUsers: 'Assign Users', + batchDelete: 'Batch Delete', + confirm: 'Confirm', + }, + transfer: { + unassignedUsers: 'Unassigned Users', + assignedUsers: 'Assigned Users', + }, + dataPermission: { + ownDataOnly: 'Own data only', + deptAndBelow: 'Department and below', + deptOnly: 'Department only', + allData: 'All data', + customData: 'Custom data', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/role/zh-cn.ts b/web/src/i18n/pages/role/zh-cn.ts new file mode 100644 index 0000000..24b8abf --- /dev/null +++ b/web/src/i18n/pages/role/zh-cn.ts @@ -0,0 +1,91 @@ +// 定义内容 +export default { + message: { + pages: { + role: { + table: { + columns: { + index: '序号', + name: '角色名称', + key: '权限标识', + sort: '排序', + status: '状态', + actions: '操作', + }, + }, + form: { + name: '角色名称', + key: '权限标识', + sort: '排序', + status: '状态', + remark: '备注', + namePlaceholder: '请输入角色名称', + keyPlaceholder: '输入权限标识', + sortPlaceholder: '请输入排序', + remarkPlaceholder: '请输入备注', + }, + validation: { + nameRequired: '角色名称必填', + keyRequired: '权限标识必填', + sortRequired: '排序必填', + }, + dialog: { + addRole: '新增角色', + editRole: '编辑角色', + assignPermissions: '权限配置', + assignUsers: '授权用户', + deleteConfirm: '确定删除该角色吗?', + menuPermission: '菜单权限', + buttonPermission: '按钮权限', + columnPermission: '列字段权限', + interfacePermission: '接口权限', + currentRole: '当前授权角色:', + authorizedUsers: '授权人员:', + selectDataPermission: '请选择', + customDeptPlaceholder: '请选择自定义部门', + dataPermissionConfig: '数据权限配置', + defaultInterfacePermission: '默认接口权限:', + configureOperationPermission: '配置操作功能接口权限,配置数据权限点击小齿轮', + }, + messages: { + addSuccess: '新增成功', + updateSuccess: '更新成功', + deleteSuccess: '删除成功', + deleteFailed: '删除失败', + assignSuccess: '分配成功', + saveSuccess: '保存成功', + checkUsersFirst: '请先勾选用户', + batchDeleteConfirm: '确定要删除这{count}位用户的权限吗', + deleteUserConfirm: '确定要删除这 "{count}" 位用户的权限吗', + }, + buttons: { + add: '新增', + view: '查看', + edit: '编辑', + delete: '删除', + save: '保存', + cancel: '取消', + reset: '重置', + export: '导出', + query: '查询', + refresh: '刷新', + assignPermission: '权限配置', + assignUsers: '授权用户', + batchDelete: '批量删除', + confirm: '确定', + }, + transfer: { + unassignedUsers: '未授权用户', + assignedUsers: '已授权用户', + }, + dataPermission: { + ownDataOnly: '仅本人数据权限', + deptAndBelow: '本部门及以下数据权限', + deptOnly: '本部门数据权限', + allData: '全部数据权限', + customData: '自定数据权限', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/role/zh-tw.ts b/web/src/i18n/pages/role/zh-tw.ts new file mode 100644 index 0000000..e69de29 diff --git a/web/src/i18n/pages/taskLog/en.ts b/web/src/i18n/pages/taskLog/en.ts new file mode 100644 index 0000000..5e581f5 --- /dev/null +++ b/web/src/i18n/pages/taskLog/en.ts @@ -0,0 +1,34 @@ +// Define content +export default { + message: { + pages: { + taskLog: { + table: { + columns: { + index: 'No.', + taskId: 'Task ID', + taskName: 'Task Name', + periodicTaskName: 'Periodic Task Name', + taskKwargs: 'Parameters', + status: 'Status', + result: 'Result', + dateDone: 'Completed At', + dateCreated: 'Created At', + }, + }, + status: { + SUCCESS: 'Success', + STARTED: 'Started', + REVOKED: 'Revoked', + RETRY: 'Retrying', + RECEIVED: 'Received', + PENDING: 'Pending', + FAILURE: 'Failure', + }, + buttons: { + view: 'View', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/taskLog/zh-cn.ts b/web/src/i18n/pages/taskLog/zh-cn.ts new file mode 100644 index 0000000..cb026a8 --- /dev/null +++ b/web/src/i18n/pages/taskLog/zh-cn.ts @@ -0,0 +1,34 @@ +// 定义内容 +export default { + message: { + pages: { + taskLog: { + table: { + columns: { + index: '序号', + taskId: '任务ID', + taskName: '任务名称', + periodicTaskName: '周期任务名称', + taskKwargs: '请求参数', + status: '执行状态', + result: '执行结果', + dateDone: '执行完成时间', + dateCreated: '创建时间', + }, + }, + status: { + SUCCESS: '执行成功', + STARTED: '已开始', + REVOKED: '已取消', + RETRY: '重试中', + RECEIVED: '已收到', + PENDING: '待定中', + FAILURE: '执行失败', + }, + buttons: { + view: '查看', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/taskLog/zh-tw.ts b/web/src/i18n/pages/taskLog/zh-tw.ts new file mode 100644 index 0000000..1bdeb5a --- /dev/null +++ b/web/src/i18n/pages/taskLog/zh-tw.ts @@ -0,0 +1,34 @@ +// 定義內容 +export default { + message: { + pages: { + taskLog: { + table: { + columns: { + index: '序號', + taskId: '任務ID', + taskName: '任務名稱', + periodicTaskName: '週期任務名稱', + taskKwargs: '請求參數', + status: '執行狀態', + result: '執行結果', + dateDone: '執行完成時間', + dateCreated: '創建時間', + }, + }, + status: { + SUCCESS: '執行成功', + STARTED: '已開始', + REVOKED: '已取消', + RETRY: '重試中', + RECEIVED: '已收到', + PENDING: '待定中', + FAILURE: '執行失敗', + }, + buttons: { + view: '查看', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/taskManage/en.ts b/web/src/i18n/pages/taskManage/en.ts new file mode 100644 index 0000000..4db7c69 --- /dev/null +++ b/web/src/i18n/pages/taskManage/en.ts @@ -0,0 +1,73 @@ +// Define content +export default { + message: { + pages: { + taskManage: { + table: { + columns: { + index: 'No.', + name: 'Task Name', + task: 'Task', + lastRunAt: 'Last Run', + description: 'Description', + cron: 'Cron Expression', + kwargs: 'Parameters', + status: 'Status', + enabled: 'Enabled', + disabled: 'Disabled', + }, + }, + form: { + name: 'Task Name', + namePlaceholder: 'Please enter task name', + task: 'Task', + taskPlaceholder: 'Input task', + cron: 'Cron Expression Settings', + cronExpression: 'Cron Expression', + lastRunAt: 'Last Run', + description: 'Description', + kwargs: 'Parameters', + enabled: 'Status', + validation: { + nameRequired: 'Task name is required', + taskRequired: 'Task is required', + cronRequired: 'Expression is required', + statusRequired: 'Status is required', + }, + }, + dialog: { + taskLogs: 'Task Execution Logs', + cronSelector: 'Cron Expression Selector', + confirmStop: 'Confirm to disable this task?', + confirmEnable: 'Confirm to enable this task?', + confirmRun: 'Run this task immediately?', + confirmDelete: 'Confirm to delete this task?', + }, + messages: { + enableSuccess: 'Task enabled', + disableSuccess: 'Task disabled', + runSuccess: 'Task triggered', + deleteSuccess: 'Task deleted', + }, + buttons: { + view: 'View', + edit: 'Edit', + delete: 'Delete', + add: 'Add', + confirm: 'Confirm', + cancel: 'Cancel', + enable: 'Enabled', + disabled: 'Disabled', + runNow: 'Run Now', + taskLogs: 'Task Logs', + }, + card: { + executeTask: 'Execute Task', + cronRule: 'Cron Rule', + lastRunTime: 'Last Run Time', + }, + empty: 'No data, please add', + }, + }, + }, +}; diff --git a/web/src/i18n/pages/taskManage/zh-cn.ts b/web/src/i18n/pages/taskManage/zh-cn.ts new file mode 100644 index 0000000..3c7b93e --- /dev/null +++ b/web/src/i18n/pages/taskManage/zh-cn.ts @@ -0,0 +1,73 @@ +// 定义内容 +export default { + message: { + pages: { + taskManage: { + table: { + columns: { + index: '序号', + name: '任务名称', + task: '执行任务', + lastRunAt: '最后运行时间', + description: '备注', + cron: '表达式', + kwargs: '请求参数', + status: '状态', + enabled: '启用', + disabled: '禁用', + }, + }, + form: { + name: '任务名称', + namePlaceholder: '请输入任务名称', + task: '执行任务', + taskPlaceholder: '输入执行任务', + cron: 'Cron表达式设置', + cronExpression: 'Cron表达式', + lastRunAt: '最后运行时间', + description: '备注', + kwargs: '请求参数', + enabled: '状态', + validation: { + nameRequired: '任务名称必填', + taskRequired: '执行任务必填', + cronRequired: '表达式必填', + statusRequired: '排序必填', + }, + }, + dialog: { + taskLogs: '任务运行日志', + cronSelector: 'Cron表达式选择器', + confirmStop: '确认停用该任务?', + confirmEnable: '确认启用该任务?', + confirmRun: '立即运行该任务?', + confirmDelete: '确定删除该任务?', + }, + messages: { + enableSuccess: '任务已启用', + disableSuccess: '任务已停用', + runSuccess: '任务已触发执行', + deleteSuccess: '任务已删除', + }, + buttons: { + view: '查看', + edit: '编辑', + delete: '删除', + add: '新增', + confirm: '确定', + cancel: '取消', + enable: '已启用', + disabled: '已停用', + runNow: '立即运行', + taskLogs: '任务日志', + }, + card: { + executeTask: '执行任务', + cronRule: '定时规则', + lastRunTime: '最后运行时间', + }, + empty: '暂无数据,请添加', + }, + }, + }, +}; diff --git a/web/src/i18n/pages/taskManage/zh-tw.ts b/web/src/i18n/pages/taskManage/zh-tw.ts new file mode 100644 index 0000000..76134be --- /dev/null +++ b/web/src/i18n/pages/taskManage/zh-tw.ts @@ -0,0 +1,73 @@ +// 定義內容 +export default { + message: { + pages: { + taskManage: { + table: { + columns: { + index: '序號', + name: '任務名稱', + task: '執行任務', + lastRunAt: '最後運行時間', + description: '備註', + cron: '表達式', + kwargs: '請求參數', + status: '狀態', + enabled: '啟用', + disabled: '禁用', + }, + }, + form: { + name: '任務名稱', + namePlaceholder: '請輸入任務名稱', + task: '執行任務', + taskPlaceholder: '輸入執行任務', + cron: 'Cron表達式設置', + cronExpression: 'Cron表達式', + lastRunAt: '最後運行時間', + description: '備註', + kwargs: '請求參數', + enabled: '狀態', + validation: { + nameRequired: '任務名稱必填', + taskRequired: '執行任務必填', + cronRequired: '表達式必填', + statusRequired: '排序必填', + }, + }, + dialog: { + taskLogs: '任務運行日誌', + cronSelector: 'Cron表達式選擇器', + confirmStop: '確認停用該任務?', + confirmEnable: '確認啟用該任務?', + confirmRun: '立即運行該任務?', + confirmDelete: '確定刪除該任務?', + }, + messages: { + enableSuccess: '任務已啟用', + disableSuccess: '任務已停用', + runSuccess: '任務已觸發執行', + deleteSuccess: '任務已刪除', + }, + buttons: { + view: '查看', + edit: '編輯', + delete: '刪除', + add: '新增', + confirm: '確定', + cancel: '取消', + enable: '已啟用', + disabled: '已停用', + runNow: '立即運行', + taskLogs: '任務日誌', + }, + card: { + executeTask: '執行任務', + cronRule: '定時規則', + lastRunTime: '最後運行時間', + }, + empty: '暫無數據,請添加', + }, + }, + }, +}; diff --git a/web/src/i18n/pages/user/en.ts b/web/src/i18n/pages/user/en.ts new file mode 100644 index 0000000..cf77e78 --- /dev/null +++ b/web/src/i18n/pages/user/en.ts @@ -0,0 +1,129 @@ +// Define content +export default { + message: { + pages: { + user: { + table: { + columns: { + select: 'Select', + index: 'No.', + username: 'Username', + name: 'Full Name', + dept: 'Department', + manageDept: 'Managed Dept.', + role: 'Roles', + mobile: 'Mobile', + email: 'Email', + gender: 'Gender', + userType: 'User Type', + status: 'Status', + avatar: 'Avatar', + actions: 'Actions', + }, + }, + form: { + username: 'Username', + password: 'Password', + name: 'Full Name', + dept: 'Department', + manageDept: 'Managed Dept.', + role: 'Roles', + mobile: 'Mobile', + email: 'Email', + gender: 'Gender', + userType: 'User Type', + status: 'Status', + avatar: 'Avatar', + usernamePlaceholder: 'Please enter username', + passwordPlaceholder: 'Please enter password', + namePlaceholder: 'Please enter full name', + deptPlaceholder: 'Please select', + manageDeptPlaceholder: 'Please select', + rolePlaceholder: 'Please select roles', + mobilePlaceholder: 'Please enter mobile number', + emailPlaceholder: 'Please enter email', + genderPlaceholder: 'Please select gender', + userTypePlaceholder: 'Please select user type', + }, + validation: { + usernameRequired: 'Username is required', + passwordRequired: 'Password is required', + nameRequired: 'Full name is required', + deptRequired: 'Required', + roleRequired: 'Required', + mobileInvalid: 'Please enter a valid mobile number', + emailInvalid: 'Please enter a valid email address', + manageDeptHelper: 'Defaults to department if not selected', + }, + dialog: { + addUser: 'Add User', + editUser: 'Edit User', + assignRoles: 'Assign Roles', + deleteConfirm: 'Are you sure you want to delete this user?', + resetPassword: 'Reset Password', + resetPasswordConfirm: 'Are you sure you want to reset to the system default password?', + resetPasswordSuccess: 'Password reset successfully', + exportTitle: 'Prompt', + exportConfirm: 'Are you sure you want to export data?', + }, + messages: { + addSuccess: 'Created successfully', + updateSuccess: 'Updated successfully', + deleteSuccess: 'Deleted successfully', + deleteFailed: 'Delete failed', + importSuccess: 'Imported successfully', + exportSuccess: 'Exported successfully', + exportFailed: 'Export failed', + }, + buttons: { + add: 'Add', + edit: 'Edit', + delete: 'Delete', + save: 'Save', + cancel: 'Cancel', + reset: 'Reset', + import: 'Import', + export: 'Export', + query: 'Search', + batchAdd: 'Batch Add', + refresh: 'Refresh', + columnSetting: 'Columns', + resetPassword: 'Reset Password', + confirm: 'Confirm', + selectedCount: '{count} selected', + }, + tree: { + deptList: 'Department List', + deptPlaceholder: 'Enter department name', + deptInfo: '1. Department info;', + }, + title0: 'Switch Component Size', + title1: 'Switch Language', + title2: 'Search', + title3: 'Layout Settings', + title4: 'Message Center', + title5: 'Fullscreen', + title6: 'Exit Fullscreen', + dropdown1: 'Home', + dropdown2: 'Personal Center', + versionLog: 'Version Upgrade Log', + dropdownLarge: 'Large', + dropdownDefault: 'Default', + dropdownSmall: 'Small', + langZhCn: '简体中文', + langEn: 'English', + langZhTw: '繁體中文', + dropdown5: 'Log Out', + fullscreenNotSupported: 'Your browser does not support fullscreen!', + logOutTitle: 'Notice', + logOutMessage: 'You are about to log out. Continue?', + logOutConfirm: 'Confirm', + logOutCancel: 'Cancel', + logOutExit: 'Exiting...', + retry: 'Retry', + onlinePrompt: 'Reconnecting to server...', + defaultUsername: 'User', + }, + }, + }, +}; diff --git a/web/src/i18n/pages/user/zh-cn.ts b/web/src/i18n/pages/user/zh-cn.ts new file mode 100644 index 0000000..f0fe121 --- /dev/null +++ b/web/src/i18n/pages/user/zh-cn.ts @@ -0,0 +1,129 @@ +// 定义内容 +export default { + message: { + pages: { + user: { + table: { + columns: { + select: '选择', + index: '序号', + username: '账号', + name: '姓名', + dept: '所属部门', + manageDept: '管理部门', + role: '角色', + mobile: '手机号码', + email: '邮箱', + gender: '性别', + userType: '用户类型', + status: '状态', + avatar: '头像', + actions: '操作', + }, + }, + form: { + username: '账号', + password: '密码', + name: '姓名', + dept: '所属部门', + manageDept: '管理部门', + role: '角色', + mobile: '手机号码', + email: '邮箱', + gender: '性别', + userType: '用户类型', + status: '状态', + avatar: '头像', + usernamePlaceholder: '请输入账号', + passwordPlaceholder: '请输入密码', + namePlaceholder: '请输入姓名', + deptPlaceholder: '请选择', + manageDeptPlaceholder: '请选择', + rolePlaceholder: '请选择角色', + mobilePlaceholder: '请输入手机号码', + emailPlaceholder: '请输入邮箱', + genderPlaceholder: '请选择性别', + userTypePlaceholder: '请选择用户类型', + }, + validation: { + usernameRequired: '账号必填项', + passwordRequired: '密码必填项', + nameRequired: '姓名必填项', + deptRequired: '必填项', + roleRequired: '必填项', + mobileInvalid: '请输入正确的手机号码', + emailInvalid: '请输入正确的邮箱地址', + manageDeptHelper: '不选则默认为所属部门', + }, + dialog: { + addUser: '新增用户', + editUser: '编辑用户', + assignRoles: '分配角色', + deleteConfirm: '是否删除该用户?', + resetPassword: '重置密码', + resetPasswordConfirm: '确定重置为系统默认密码吗?', + resetPasswordSuccess: '重置密码成功', + exportTitle: '提示', + exportConfirm: '确定导出数据吗?', + }, + messages: { + addSuccess: '新增成功', + updateSuccess: '更新成功', + deleteSuccess: '删除成功', + deleteFailed: '删除失败', + importSuccess: '导入成功', + exportSuccess: '导出成功', + exportFailed: '导出失败', + }, + buttons: { + add: '新增', + edit: '编辑', + delete: '删除', + save: '保存', + cancel: '取消', + reset: '重置', + import: '导入', + export: '导出', + query: '查询', + batchAdd: '批量新增', + refresh: '刷新', + columnSetting: '列设置', + resetPassword: '重置密码', + confirm: '确定', + selectedCount: '已选中{count}条数据', + }, + tree: { + deptList: '部门列表', + deptPlaceholder: '请输入部门名称', + deptInfo: '1.部门信息;', + }, + title0: '切换组件大小', + title1: '切换语言', + title2: '搜索', + title3: '布局配置', + title4: '消息中心', + title5: '全屏', + title6: '退出全屏', + dropdown1: '首页', + dropdown2: '个人中心', + versionLog: '版本升级日志', + dropdownLarge: '大号', + dropdownDefault: '默认', + dropdownSmall: '小号', + langZhCn: '简体中文', + langEn: 'English', + langZhTw: '繁體中文', + dropdown5: '退出登录', + fullscreenNotSupported: '您的浏览器不支持全屏!', + logOutTitle: '提示', + logOutMessage: '即将退出系统,是否继续?', + logOutConfirm: '确定', + logOutCancel: '取消', + logOutExit: '正在退出...', + retry: '重试', + onlinePrompt: '正在重新连接服务器...', + defaultUsername: '用户', + }, + }, + }, +}; diff --git a/web/src/i18n/pages/user/zh-tw.ts b/web/src/i18n/pages/user/zh-tw.ts new file mode 100644 index 0000000..ecd8e8f --- /dev/null +++ b/web/src/i18n/pages/user/zh-tw.ts @@ -0,0 +1,129 @@ +// 定義內容 +export default { + message: { + pages: { + user: { + table: { + columns: { + select: '選取', + index: '序號', + username: '帳號', + name: '姓名', + dept: '所屬部門', + manageDept: '管理部門', + role: '角色', + mobile: '手機號碼', + email: '信箱', + gender: '性別', + userType: '使用者類型', + status: '狀態', + avatar: '頭像', + actions: '操作', + }, + }, + form: { + username: '帳號', + password: '密碼', + name: '姓名', + dept: '所屬部門', + manageDept: '管理部門', + role: '角色', + mobile: '手機號碼', + email: '信箱', + gender: '性別', + userType: '使用者類型', + status: '狀態', + avatar: '頭像', + usernamePlaceholder: '請輸入帳號', + passwordPlaceholder: '請輸入密碼', + namePlaceholder: '請輸入姓名', + deptPlaceholder: '請選擇', + manageDeptPlaceholder: '請選擇', + rolePlaceholder: '請選擇角色', + mobilePlaceholder: '請輸入手機號碼', + emailPlaceholder: '請輸入信箱', + genderPlaceholder: '請選擇性別', + userTypePlaceholder: '請選擇使用者類型', + }, + validation: { + usernameRequired: '帳號必填項', + passwordRequired: '密碼必填項', + nameRequired: '姓名必填項', + deptRequired: '必填項', + roleRequired: '必填項', + mobileInvalid: '請輸入正確的手機號碼', + emailInvalid: '請輸入正確的信箱地址', + manageDeptHelper: '不選則預設為所屬部門', + }, + dialog: { + addUser: '新增使用者', + editUser: '編輯使用者', + assignRoles: '分配角色', + deleteConfirm: '是否刪除該使用者?', + resetPassword: '重置密碼', + resetPasswordConfirm: '確定重置為系統預設密碼嗎?', + resetPasswordSuccess: '重置密碼成功', + exportTitle: '提示', + exportConfirm: '確定匯出資料嗎?', + }, + messages: { + addSuccess: '新增成功', + updateSuccess: '更新成功', + deleteSuccess: '刪除成功', + deleteFailed: '刪除失敗', + importSuccess: '匯入成功', + exportSuccess: '匯出成功', + exportFailed: '匯出失敗', + }, + buttons: { + add: '新增', + edit: '編輯', + delete: '刪除', + save: '儲存', + cancel: '取消', + reset: '重置', + import: '匯入', + export: '匯出', + query: '查詢', + batchAdd: '批次新增', + refresh: '重新整理', + columnSetting: '欄位設定', + resetPassword: '重置密碼', + confirm: '確定', + selectedCount: '已選取{count}筆資料', + }, + tree: { + deptList: '部門列表', + deptPlaceholder: '請輸入部門名稱', + deptInfo: '1.部門資訊;', + }, + title0: '切換元件大小', + title1: '切換語言', + title2: '搜尋', + title3: '版面設定', + title4: '訊息中心', + title5: '全螢幕', + title6: '退出全螢幕', + dropdown1: '首頁', + dropdown2: '個人中心', + versionLog: '版本升級日誌', + dropdownLarge: '大', + dropdownDefault: '預設', + dropdownSmall: '小', + langZhCn: '簡體中文', + langEn: 'English', + langZhTw: '繁體中文', + dropdown5: '退出登入', + fullscreenNotSupported: '您的瀏覽器不支援全螢幕!', + logOutTitle: '提示', + logOutMessage: '即將退出系統,是否繼續?', + logOutConfirm: '確定', + logOutCancel: '取消', + logOutExit: '正在退出...', + retry: '重試', + onlinePrompt: '正在重新連線伺服器...', + defaultUsername: '使用者', + }, + }, + }, +}; diff --git a/web/src/i18n/pages/whitelist/en.ts b/web/src/i18n/pages/whitelist/en.ts new file mode 100644 index 0000000..027c647 --- /dev/null +++ b/web/src/i18n/pages/whitelist/en.ts @@ -0,0 +1,60 @@ +// Define content +export default { + message: { + pages: { + whitelist: { + table: { + columns: { + url: 'URL', + description: 'Description', + status: 'Status', + createTime: 'Create Time', + creator: 'Created By', + actions: 'Actions', + index: 'No.', + keyword: 'Keyword', + method: 'Method', + dataPermission: 'Data Permission', + }, + }, + form: { + url: 'URL', + description: 'Description', + status: 'Status', + urlPlaceholder: 'Enter URL', + descriptionPlaceholder: 'Enter description', + keywordPlaceholder: 'Enter keyword', + urlHelper: 'Supports fuzzy matching, e.g. /api/user/* matches /api/user/1, /api/user/2', + }, + validation: { + urlRequired: 'URL is required', + urlMaxLength: 'URL must be 200 characters or less', + urlFormat: 'Invalid URL format', + urlDuplicate: 'URL already exists', + methodRequired: 'Please select a request method', + }, + dialog: { + addWhiteList: 'Add Whitelist', + editWhiteList: 'Edit Whitelist', + deleteConfirm: 'Delete this whitelist entry?', + }, + messages: { + addSuccess: 'Added successfully', + updateSuccess: 'Updated successfully', + deleteSuccess: 'Deleted successfully', + deleteFailed: 'Delete failed', + }, + buttons: { + add: 'Add', + edit: 'Edit', + delete: 'Delete', + save: 'Save', + cancel: 'Cancel', + query: 'Query', + refresh: 'Refresh', + export: 'Export', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/whitelist/zh-cn.ts b/web/src/i18n/pages/whitelist/zh-cn.ts new file mode 100644 index 0000000..2815b22 --- /dev/null +++ b/web/src/i18n/pages/whitelist/zh-cn.ts @@ -0,0 +1,60 @@ +// 定义内容 +export default { + message: { + pages: { + whitelist: { + table: { + columns: { + url: 'URL', + description: '描述', + status: '状态', + createTime: '创建时间', + creator: '创建人', + actions: '操作', + index: '序号', + keyword: '关键词', + method: '请求方法', + dataPermission: '数据权限', + }, + }, + form: { + url: 'URL', + description: '描述', + status: '状态', + urlPlaceholder: '请输入URL', + descriptionPlaceholder: '请输入描述', + keywordPlaceholder: '请输入关键词', + urlHelper: '支持模糊匹配,如 /api/user/* 可匹配 /api/user/1、/api/user/2', + }, + validation: { + urlRequired: '请输入URL', + urlMaxLength: 'URL不能超过200个字符', + urlFormat: 'URL格式不正确', + urlDuplicate: 'URL已存在', + methodRequired: '请选择请求方法', + }, + dialog: { + addWhiteList: '新增白名单', + editWhiteList: '编辑白名单', + deleteConfirm: '确定删除该白名单吗?', + }, + messages: { + addSuccess: '新增成功', + updateSuccess: '更新成功', + deleteSuccess: '删除成功', + deleteFailed: '删除失败', + }, + buttons: { + add: '新增', + edit: '编辑', + delete: '删除', + save: '保存', + cancel: '取消', + query: '查询', + refresh: '刷新', + export: '导出', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/whitelist/zh-tw.ts b/web/src/i18n/pages/whitelist/zh-tw.ts new file mode 100644 index 0000000..15affa7 --- /dev/null +++ b/web/src/i18n/pages/whitelist/zh-tw.ts @@ -0,0 +1,60 @@ +// 定義內容 +export default { + message: { + pages: { + whitelist: { + table: { + columns: { + url: 'URL', + description: '描述', + status: '狀態', + createTime: '創建時間', + creator: '創建人', + actions: '操作', + index: '序號', + keyword: '關鍵詞', + method: '請求方式', + dataPermission: '資料權限', + }, + }, + form: { + url: 'URL', + description: '描述', + status: '狀態', + urlPlaceholder: '請輸入URL', + descriptionPlaceholder: '請輸入描述', + keywordPlaceholder: '請輸入關鍵詞', + urlHelper: '支援模糊匹配,如 /api/user/* 可匹配 /api/user/1、/api/user/2', + }, + validation: { + urlRequired: '請輸入URL', + urlMaxLength: 'URL不能超過200個字符', + urlFormat: 'URL格式不正確', + urlDuplicate: 'URL已存在', + methodRequired: '請選擇請求方式', + }, + dialog: { + addWhiteList: '新增白名單', + editWhiteList: '編輯白名單', + deleteConfirm: '確定刪除該白名單嗎?', + }, + messages: { + addSuccess: '新增成功', + updateSuccess: '更新成功', + deleteSuccess: '刪除成功', + deleteFailed: '刪除失敗', + }, + buttons: { + add: '新增', + edit: '編輯', + delete: '刪除', + save: '保存', + cancel: '取消', + query: '查詢', + refresh: '刷新', + export: '導出', + }, + }, + }, + }, +}; diff --git a/web/src/layout/navBars/breadcrumb/user.vue b/web/src/layout/navBars/breadcrumb/user.vue index 24e4d19..d6cc3e5 100644 --- a/web/src/layout/navBars/breadcrumb/user.vue +++ b/web/src/layout/navBars/breadcrumb/user.vue @@ -112,6 +112,8 @@ import { useUserInfo } from '/@/stores/userInfo'; import { useThemeConfig } from '/@/stores/themeConfig'; import other from '/@/utils/other'; import mittBus from '/@/utils/mitt'; +import { refreshRoutesForI18n } from '/@/router/backEnd'; +import { request } from '/@/utils/service'; import { Session, Local } from '/@/utils/storage'; import headerImage from '/@/assets/img/headerImage.png'; import { InfoFilled } from '@element-plus/icons-vue'; @@ -228,13 +230,21 @@ const onComponentSizeChange = (size: string) => { window.location.reload(); }; // 语言切换 -const onLanguageChange = (lang: string) => { +const onLanguageChange = async (lang: string) => { Local.remove('themeConfig'); themeConfig.value.globalI18n = lang; Local.set('themeConfig', themeConfig.value); locale.value = lang; other.useTitle(); initI18nOrSize('globalI18n', 'disabledI18n'); + // 重新请求菜单(带上新语言,让后端返回对应翻译) + await refreshRoutesForI18n(); + // 持久化到后端 + try { + await request({ url: '/api/system/user/update_language/', method: 'put', data: { language: lang } }); + } catch (e) { + console.warn('Failed to persist language preference:', e); + } }; // 初始化组件大小/i18n const initI18nOrSize = (value: string, attr: keyof typeof state) => { diff --git a/web/src/router/backEnd.ts b/web/src/router/backEnd.ts index e159dea..688c1ba 100644 --- a/web/src/router/backEnd.ts +++ b/web/src/router/backEnd.ts @@ -101,7 +101,9 @@ import {SystemConfigStore} from "/@/stores/systemConfig"; import {useDeptInfoStore} from "/@/stores/modules/dept"; import {DictionaryStore} from "/@/stores/dictionary"; import {useFrontendMenuStore} from "/@/stores/frontendMenu"; +import {useThemeConfig} from "/@/stores/themeConfig"; import {toRaw} from "vue"; +import mitt from "/@/utils/mitt"; const menuApi = useMenuApi(); const layouModules: any = import.meta.glob('../layout/routerView/*.{vue,tsx}'); @@ -240,7 +242,31 @@ export function getBackEndControlRoutes() { useDeptInfoStore().requestDeptInfo() // 获取字典信息 DictionaryStore().getSystemDictionarys() - return menuApi.getSystemMenu(); + const { themeConfig } = storeToRefs(useThemeConfig(pinia)) + return menuApi.getSystemMenu({ language: themeConfig.value.globalI18n }); +} + +/** + * 根据语言重新请求后端路由菜单 + * @description 用于语言切换后刷新路由 + */ +export async function refreshRoutesForI18n() { + const { themeConfig } = storeToRefs(useThemeConfig(pinia)); + const res = await menuApi.getSystemMenu({ language: themeConfig.value.globalI18n }); + const { frameIn, frameOut } = handleMenu(res.data); + const frameInProcessed = await backEndComponent(frameIn); + dynamicRoutes[0].children = [ + ...(frameInProcessed || []), + pissupplierQuotationDetailRoute, + pisadminRfqMiscInquiryDetailRoute, + pisadminRfqMiscComparePriceRoute, + pisadminMiscMaterialsIndexRoute, + pisadminRfsOperationLogsRoute + ]; + const storesRoutesList = useRoutesList(pinia); + storesRoutesList.setRoutesList([...(dynamicRoutes[0].children || []), ...frameOut]); + // 通知侧边栏刷新菜单 + mitt.emit('getBreadcrumbIndexSetFilterRoutes'); } /** diff --git a/web/src/settings.ts b/web/src/settings.ts index cecbf2d..6f1d718 100644 --- a/web/src/settings.ts +++ b/web/src/settings.ts @@ -1,5 +1,6 @@ // 引入fast-crud import {FastCrud, useTypes} from '@fast-crud/fast-crud'; +import { i18n } from '/@/i18n'; const {getType} = useTypes(); import '@fast-crud/fast-crud/dist/style.css'; @@ -19,7 +20,7 @@ export default { app.use(ui); // 然后安装FastCrud app.use(FastCrud, { - //i18n, //i18n配置,可选,默认使用中文,具体用法请看demo里的 src/i18n/index.js 文件 + i18n, // fast-crud 国际化,支持 search/reset 按钮、操作列等界面文字 // 此处配置公共的dictRequest(字典请求) async dictRequest({dict,url}: any) { const {isTree} = dict From 0716cd293c4f2892678ecfba618d687f116a8727 Mon Sep 17 00:00:00 2001 From: Lewis_yan Date: Wed, 8 Apr 2026 17:20:05 +0800 Subject: [PATCH 02/24] =?UTF-8?q?feat(i18n):=20=E6=B7=BB=E5=8A=A0=20Menu/M?= =?UTF-8?q?enuButton/Users=20i18n=20=E5=AD=97=E6=AE=B5=E8=BF=81=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ..._name_zh_tw_menubutton_name_en_and_more.py | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 backend/dvadmin/system/migrations/0002_menu_name_en_menu_name_zh_tw_menubutton_name_en_and_more.py diff --git a/backend/dvadmin/system/migrations/0002_menu_name_en_menu_name_zh_tw_menubutton_name_en_and_more.py b/backend/dvadmin/system/migrations/0002_menu_name_en_menu_name_zh_tw_menubutton_name_en_and_more.py new file mode 100644 index 0000000..1b12516 --- /dev/null +++ b/backend/dvadmin/system/migrations/0002_menu_name_en_menu_name_zh_tw_menubutton_name_en_and_more.py @@ -0,0 +1,43 @@ +# Generated by Django 4.2.14 on 2026-04-08 17:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('system', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='menu', + name='name_en', + field=models.CharField(blank=True, help_text='菜单名称(English)', max_length=64, null=True, verbose_name='菜单名称(English)'), + ), + migrations.AddField( + model_name='menu', + name='name_zh_tw', + field=models.CharField(blank=True, help_text='菜单名称(繁體中文)', max_length=64, null=True, verbose_name='菜单名称(繁體中文)'), + ), + migrations.AddField( + model_name='menubutton', + name='name_en', + field=models.CharField(blank=True, help_text='名称(English)', max_length=64, null=True, verbose_name='名称(English)'), + ), + migrations.AddField( + model_name='menubutton', + name='name_zh_tw', + field=models.CharField(blank=True, help_text='名称(繁體中文)', max_length=64, null=True, verbose_name='名称(繁體中文)'), + ), + migrations.AddField( + model_name='users', + name='language', + field=models.CharField(blank=True, default='zh-cn', help_text='界面语言', max_length=10, null=True, verbose_name='界面语言'), + ), + migrations.AlterField( + model_name='menu', + name='name', + field=models.CharField(help_text='菜单名称(默认语言)', max_length=64, verbose_name='菜单名称(默认)'), + ), + ] From c115934a6fcec5afe1d0affea8572f0cec0edcb8 Mon Sep 17 00:00:00 2001 From: Lewis_yan Date: Wed, 8 Apr 2026 17:20:12 +0800 Subject: [PATCH 03/24] =?UTF-8?q?chore(settings):=20=E6=9B=B4=E6=96=B0=20s?= =?UTF-8?q?ettings.py=20(i18n=20=E7=9B=B8=E5=85=B3=E5=8F=98=E6=9B=B4?= =?UTF-8?q?=E5=B7=B2=E5=9C=A8=E4=B8=8A=E4=B8=80=20commit=20=E4=BD=93?= =?UTF-8?q?=E7=8E=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/application/settings.py | 56 ++++++++++++++------------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/backend/application/settings.py b/backend/application/settings.py index e05622f..d3da390 100644 --- a/backend/application/settings.py +++ b/backend/application/settings.py @@ -12,8 +12,8 @@ https://docs.djangoproject.com/en/4.1/ref/settings/ import os import sys -from pathlib import Path from datetime import timedelta +from pathlib import Path # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -44,7 +44,7 @@ DEBUG = locals().get("DEBUG", True) ALLOWED_HOSTS = locals().get("ALLOWED_HOSTS", ["*"]) # 列权限需要排除的App应用 -COLUMN_EXCLUDE_APPS = ['channels', 'captcha'] + locals().get("COLUMN_EXCLUDE_APPS", []) +COLUMN_EXCLUDE_APPS = ["channels", "captcha"] + locals().get("COLUMN_EXCLUDE_APPS", []) INSTALLED_APPS = [ "django.contrib.auth", @@ -115,8 +115,8 @@ DATABASES = { "PORT": DATABASE_PORT, "OPTIONS": { "driver": "ODBC Driver 18 for SQL Server", - "extra_params": "Encrypt=yes;TrustServerCertificate=yes" - } + "extra_params": "Encrypt=yes;TrustServerCertificate=yes", + }, } } AUTH_USER_MODEL = "system.Users" @@ -159,9 +159,9 @@ USE_TZ = False # Supported languages — maps frontend codes to Django locale names (D-07) LANGUAGES = [ - ('zh-hans', 'Simplified Chinese'), - ('en', 'English'), - ('zh-hant', 'Traditional Chinese'), + ("zh-hans", "Simplified Chinese"), + ("en", "English"), + ("zh-hant", "Traditional Chinese"), ] # Locale file paths for Django .po/.mo files (BEI-04) @@ -181,10 +181,10 @@ STATICFILES_DIRS = [ MEDIA_ROOT = "media" # 项目下的目录 MEDIA_URL = "/media/" # 跟STATIC_URL类似,指定用户可以通过这个url找到文件 -#添加以下代码以后就不用写{% load staticfiles %},可以直接引用 +# 添加以下代码以后就不用写{% load staticfiles %},可以直接引用 STATICFILES_FINDERS = ( "django.contrib.staticfiles.finders.FileSystemFinder", - "django.contrib.staticfiles.finders.AppDirectoriesFinder" + "django.contrib.staticfiles.finders.AppDirectoriesFinder", ) # 收集静态文件,必须将 MEDIA_ROOT,STATICFILES_DIRS先注释 # python manage.py collectstatic @@ -202,12 +202,8 @@ CORS_ALLOW_CREDENTIALS = True # 指明在跨域访问中,后端是否支持 # ===================================================== # # ********************* channels配置 ******************* # # ===================================================== # -ASGI_APPLICATION = 'application.asgi.application' -CHANNEL_LAYERS = { - "default": { - "BACKEND": "channels.layers.InMemoryChannelLayer" - } -} +ASGI_APPLICATION = "application.asgi.application" +CHANNEL_LAYERS = {"default": {"BACKEND": "channels.layers.InMemoryChannelLayer"}} # CHANNEL_LAYERS = { # 'default': { # 'BACKEND': 'channels_redis.core.RedisChannelLayer', @@ -274,7 +270,6 @@ LOGGING = { "class": "logging.StreamHandler", "formatter": "console", }, - }, "loggers": { "": { @@ -286,19 +281,16 @@ LOGGING = { "level": "INFO", "propagate": False, }, - 'django.db.backends': { - 'handlers': ["console", "error", "file"], - 'propagate': False, - 'level': "INFO" + "django.db.backends": { + "handlers": ["console", "error", "file"], + "propagate": False, + "level": "INFO", }, "uvicorn.error": { "level": "INFO", "handlers": ["console", "error", "file"], }, - "uvicorn.access": { - "handlers": ["console", "error", "file"], - "level": "INFO" - }, + "uvicorn.access": {"handlers": ["console", "error", "file"], "level": "INFO"}, }, } @@ -307,9 +299,9 @@ LOGGING = { # ================================================= # REST_FRAMEWORK = { - 'DEFAULT_PARSER_CLASSES': ( - 'rest_framework.parsers.JSONParser', - 'rest_framework.parsers.MultiPartParser', + "DEFAULT_PARSER_CLASSES": ( + "rest_framework.parsers.JSONParser", + "rest_framework.parsers.MultiPartParser", ), "DATETIME_FORMAT": "%Y-%m-%d %H:%M:%S", # 日期时间格式配置 "DATE_FORMAT": "%Y-%m-%d", @@ -424,7 +416,7 @@ ALL_MODELS_OBJECTS = [] # 所有app models 对象 INITIALIZE_LIST = [] INITIALIZE_RESET_LIST = [] # 表前缀 -TABLE_PREFIX = locals().get('TABLE_PREFIX', "") +TABLE_PREFIX = locals().get("TABLE_PREFIX", "") # 系统配置 SYSTEM_CONFIG = {} # 字典配置 @@ -444,11 +436,11 @@ SHARED_APPS = [] # ********** 一键导入插件配置开始 ********** # 例如: # from dvadmin_upgrade_center.settings import * # 升级中心 -from dvadmin3_celery.settings import * # celery 异步任务 +from dvadmin3_celery.settings import * # celery 异步任务 # from dvadmin_third.settings import * # 第三方用户管理 -from dvadmin_ak_sk.settings import * # 秘钥管理管理 +# from dvadmin_ak_sk.settings import * # 秘钥管理管理 # from dvadmin_tenants.settings import * # 租户管理 -#from dvadmin_social_auth.settings import * -#from dvadmin_uniapp.settings import * +# from dvadmin_social_auth.settings import * +# from dvadmin_uniapp.settings import * # ... # ********** 一键导入插件配置结束 ********** From 1ccea93eed82e3077c46fc58cfc98ea25d12345a Mon Sep 17 00:00:00 2001 From: Lewis_yan Date: Wed, 8 Apr 2026 17:30:01 +0800 Subject: [PATCH 04/24] =?UTF-8?q?chore:=20=E6=B7=BB=E5=8A=A0=20dvadmin=5Fa?= =?UTF-8?q?k=5Fsk=20=E5=88=B0=20INSTALLED=5FAPPS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/application/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/application/settings.py b/backend/application/settings.py index d3da390..47a2033 100644 --- a/backend/application/settings.py +++ b/backend/application/settings.py @@ -65,6 +65,7 @@ INSTALLED_APPS = [ "apps.pisadmin.dashboard", "apps.pissupplier", "sync", + "dvadmin_ak_sk", ] MIDDLEWARE = [ From 433ce5243a52344848b228b5abf0ae45554d694a Mon Sep 17 00:00:00 2001 From: Lewis_yan Date: Wed, 8 Apr 2026 21:25:50 +0800 Subject: [PATCH 05/24] =?UTF-8?q?feat(i18n):=20=E5=AE=8C=E6=88=90=E5=89=A9?= =?UTF-8?q?=E4=BD=99=20CRUD=20=E6=96=87=E4=BB=B6=E5=9B=BD=E9=99=85?= =?UTF-8?q?=E5=8C=96=E9=80=82=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit basicinfo: company, systemno, emailnotice, supplier_user miscprocurement: misc_materials, misc_stations, cost_template, rfqmiscellaneous pissupplier: quotation - 所有硬编码中文字符串替换为 t() i18n 调用 - 同步补充所有翻译 key (zh-cn/en/zh-tw) --- web/src/i18n/pages/basicinfo/en.ts | 112 ++++++ web/src/i18n/pages/basicinfo/zh-cn.ts | 112 ++++++ web/src/i18n/pages/basicinfo/zh-tw.ts | 112 ++++++ web/src/i18n/pages/menu/zh-cn.ts | 1 + web/src/i18n/pages/miscprocurement/en.ts | 132 +++++++ web/src/i18n/pages/miscprocurement/zh-cn.ts | 132 +++++++ web/src/i18n/pages/miscprocurement/zh-tw.ts | 132 +++++++ web/src/i18n/pages/pissupplier/en.ts | 75 ++++ web/src/i18n/pages/pissupplier/zh-cn.ts | 75 ++++ web/src/i18n/pages/pissupplier/zh-tw.ts | 75 ++++ .../views/pisadmin/basicinfo/company/crud.tsx | 31 +- .../pisadmin/basicinfo/emailnotice/crud.tsx | 81 ++--- .../pisadmin/basicinfo/supplier_user/crud.tsx | 57 ++- .../pisadmin/basicinfo/systemno/crud.tsx | 74 ++-- .../miscprocurement/cost_template/crud.tsx | 324 ++++++++++++++---- .../miscprocurement/misc_materials/crud.tsx | 32 +- .../miscprocurement/misc_stations/crud.tsx | 53 +-- .../miscprocurement/rfqmiscellaneous/crud.tsx | 175 +++++----- web/src/views/pissupplier/quotation/crud.tsx | 204 +++++------ 19 files changed, 1584 insertions(+), 405 deletions(-) create mode 100644 web/src/i18n/pages/basicinfo/en.ts create mode 100644 web/src/i18n/pages/basicinfo/zh-cn.ts create mode 100644 web/src/i18n/pages/basicinfo/zh-tw.ts create mode 100644 web/src/i18n/pages/miscprocurement/en.ts create mode 100644 web/src/i18n/pages/miscprocurement/zh-cn.ts create mode 100644 web/src/i18n/pages/miscprocurement/zh-tw.ts create mode 100644 web/src/i18n/pages/pissupplier/en.ts create mode 100644 web/src/i18n/pages/pissupplier/zh-cn.ts create mode 100644 web/src/i18n/pages/pissupplier/zh-tw.ts diff --git a/web/src/i18n/pages/basicinfo/en.ts b/web/src/i18n/pages/basicinfo/en.ts new file mode 100644 index 0000000..3ed6e07 --- /dev/null +++ b/web/src/i18n/pages/basicinfo/en.ts @@ -0,0 +1,112 @@ +// Definition +export default { + message: { + pages: { + basicinfo: { + unit: { + title: 'Unit of Measure', + unitname: 'Unit Name', + unitcode: 'Unit Code', + unitnameEn: 'Unit Name (English)', + unitnameZhTw: 'Unit Name (Traditional Chinese)', + status: 'Status', + }, + currency: { + title: 'Currency', + currencyname: 'Currency Name', + currencycode: 'Currency Code', + currencysymbol: 'Currency Symbol', + factory: 'Factory', + tax: 'Tax Rate', + currencynameEn: 'Currency Name (English)', + currencynameZhTw: 'Currency Name (Traditional Chinese)', + status: 'Status', + }, + supplier: { + title: 'Supplier Information', + companyCode: 'Company Code', + supplierId: 'Supplier ID', + supplierName: 'Supplier Full Name', + supplierShortName: 'Supplier Short Name', + vendorType: 'Vendor Type', + paymentTerms: 'Payment Terms', + transactionCurrency: 'Transaction Currency', + contactPerson: 'Contact Person', + contactPhone: 'Contact Phone', + contactEmail: 'Contact Email', + country: 'Country', + province: 'Province', + city: 'City', + address: 'Address', + status: 'Status', + }, + company: { + title: 'Company Information', + companyCode: 'Company Code', + companyName: 'Company Full Name', + companyShortName: 'Company Short Name', + companyAddress: 'Company Address', + status: 'Status', + }, + emailnotice: { + title: 'Email Notification Log', + subject: 'Email Subject', + bizType: 'Business Type', + bizId: 'Business ID', + toEmails: 'To', + ccEmails: 'CC', + bccEmails: 'BCC', + status: 'Send Status', + sentAt: 'Sent At', + attachments: 'Attachments', + lastError: 'Error Info', + messageId: 'Message ID', + retryCount: 'Retry Count', + statusPending: 'Pending', + statusSending: 'Sending', + statusSuccess: 'Sent', + statusFailed: 'Failed', + resend: 'Resend', + selectOrSearch: 'Select or search', + }, + supplierUser: { + title: 'Supplier User', + supplierId: 'Supplier ID', + supplierName: 'Supplier Full Name', + supplierRole: 'Supplier Role', + userEmail: 'Contact Email', + userName: 'Contact Person', + userPhone: 'Contact Phone', + status: 'Status', + }, + systemNo: { + title: 'Document Number Rule', + companyCode: 'Company Code', + ruleCode: 'Rule Code', + resetCycle: 'Reset Cycle', + resetCycleYy2: 'Yearly 2 (YY)', + resetCycleYyyy4: 'Yearly 4 (YYYY)', + resetCycleYymm4: 'Monthly 4 (YYMM)', + resetCycleYyyymm6: 'Monthly 6 (YYYYMM)', + resetCycleYymmdd6: 'Daily 6 (YYMMDD)', + resetCycleYyyymmdd8: 'Daily 8 (YYYYMMDD)', + ruleCodeMiscQts: 'miscQTS (Misc Quote)', + ruleCodeMiscRfs: 'miscRFS (Misc RFQ)', + prefix: 'Prefix', + factoryCode: 'Factory Code', + seqLength: 'Sequence Length', + createUser: 'Creator', + updateUser: 'Modifier', + sequenceDate: 'Sequence Date', + prevSequence: 'Previous Sequence', + currentSequence: 'Current Sequence', + lastGenerateUser: 'Last Generator', + lastGenerateTime: 'Last Generate Time', + status: 'Status', + statusAvailable: 'Available', + statusUnavailable: 'Unavailable', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/basicinfo/zh-cn.ts b/web/src/i18n/pages/basicinfo/zh-cn.ts new file mode 100644 index 0000000..9ae968e --- /dev/null +++ b/web/src/i18n/pages/basicinfo/zh-cn.ts @@ -0,0 +1,112 @@ +// 定义内容 +export default { + message: { + pages: { + basicinfo: { + unit: { + title: '计量单位', + unitname: '计量单位名称', + unitcode: '计量单位代码', + unitnameEn: '计量单位英文名', + unitnameZhTw: '计量单位繁体名', + status: '状态', + }, + currency: { + title: '货币', + currencyname: '货币名称', + currencycode: '货币代码', + currencysymbol: '货币符号', + factory: '交易厂区', + tax: '税率', + currencynameEn: '货币英文名', + currencynameZhTw: '货币繁体名', + status: '状态', + }, + supplier: { + title: '供应商信息', + companyCode: '交易厂区', + supplierId: '供应商唯一ID', + supplierName: '供应商全称', + supplierShortName: '供应商简称', + vendorType: '厂商性质', + paymentTerms: '付款条件', + transactionCurrency: '交易货币', + contactPerson: '联络人', + contactPhone: '联络人电话', + contactEmail: '联络人邮箱', + country: '国家', + province: '省州', + city: '城市', + address: '详细地址', + status: '状态', + }, + company: { + title: '公司信息', + companyCode: '公司代码', + companyName: '公司全称', + companyShortName: '公司简称', + companyAddress: '公司地址', + status: '状态', + }, + supplierUser: { + title: '供应商用户', + supplierId: '供应商唯一ID', + supplierName: '供应商全称', + supplierRole: '供应商角色', + userEmail: '联络人邮箱', + userName: '联络人', + userPhone: '联络人电话', + status: '状态', + }, + emailnotice: { + title: '邮件通知记录', + subject: '邮件主题', + bizType: '业务类型', + bizId: '业务标识', + toEmails: '收件人', + ccEmails: '抄送', + bccEmails: '密送', + status: '发送状态', + sentAt: '发送时间', + attachments: '附件', + lastError: '错误信息', + messageId: '消息ID', + retryCount: '重试次数', + statusPending: '待发送', + statusSending: '发送中', + statusSuccess: '已发送', + statusFailed: '发送失败', + resend: '重送', + selectOrSearch: '请选择或搜索', + }, + systemNo: { + title: '单据编号规则', + companyCode: '交易厂区', + ruleCode: '生成单据标识号', + resetCycle: '流水码重置类别', + resetCycleYy2: '按年2(YY)', + resetCycleYyyy4: '按年4(YYYY)', + resetCycleYymm4: '按月4(YYMM)', + resetCycleYyyymm6: '按月6(YYYYMM)', + resetCycleYymmdd6: '按日6(YYMMDD)', + resetCycleYyyymmdd8: '按日8(YYYYMMDD)', + ruleCodeMiscQts: 'miscQTS (杂采报价单)', + ruleCodeMiscRfs: 'miscRFS (杂采询价单)', + prefix: '单据头', + factoryCode: '厂区区分码', + seqLength: '流水码长度', + createUser: '单据创建人', + updateUser: '单据修改人', + sequenceDate: '流水日期', + prevSequence: '上一流水码', + currentSequence: '下一流水码', + lastGenerateUser: '单据最后产生人', + lastGenerateTime: '单据最后产生时间', + status: '可用状态', + statusAvailable: '可用', + statusUnavailable: '不可用', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/basicinfo/zh-tw.ts b/web/src/i18n/pages/basicinfo/zh-tw.ts new file mode 100644 index 0000000..23ff171 --- /dev/null +++ b/web/src/i18n/pages/basicinfo/zh-tw.ts @@ -0,0 +1,112 @@ +// 定義內容 +export default { + message: { + pages: { + basicinfo: { + unit: { + title: '計量單位', + unitname: '計量單位名稱', + unitcode: '計量單位代碼', + unitnameEn: '計量單位英文名', + unitnameZhTw: '計量單位繁體名', + status: '狀態', + }, + currency: { + title: '貨幣', + currencyname: '貨幣名稱', + currencycode: '貨幣代碼', + currencysymbol: '貨幣符號', + factory: '交易廠區', + tax: '稅率', + currencynameEn: '貨幣英文名', + currencynameZhTw: '貨幣繁體名', + status: '狀態', + }, + supplier: { + title: '供應商資訊', + companyCode: '交易廠區', + supplierId: '供應商唯一ID', + supplierName: '供應商全稱', + supplierShortName: '供應商簡稱', + vendorType: '廠商性質', + paymentTerms: '付款條件', + transactionCurrency: '交易貨幣', + contactPerson: '聯絡人', + contactPhone: '聯絡人電話', + contactEmail: '聯絡人郵箱', + country: '國家', + province: '省州', + city: '城市', + address: '詳細地址', + status: '狀態', + }, + company: { + title: '公司資訊', + companyCode: '公司代碼', + companyName: '公司全稱', + companyShortName: '公司簡稱', + companyAddress: '公司地址', + status: '狀態', + }, + emailnotice: { + title: '郵件通知記錄', + subject: '郵件主題', + bizType: '業務類型', + bizId: '業務標識', + toEmails: '收件人', + ccEmails: '抄送', + bccEmails: '密送', + status: '發送狀態', + sentAt: '發送時間', + attachments: '附件', + lastError: '錯誤資訊', + messageId: '訊息ID', + retryCount: '重試次數', + statusPending: '待發送', + statusSending: '發送中', + statusSuccess: '已發送', + statusFailed: '發送失敗', + resend: '重送', + selectOrSearch: '請選擇或搜尋', + }, + supplierUser: { + title: '供應商用戶', + supplierId: '供應商唯一ID', + supplierName: '供應商全稱', + supplierRole: '供應商角色', + userEmail: '聯絡人郵箱', + userName: '聯絡人', + userPhone: '聯絡人電話', + status: '狀態', + }, + systemNo: { + title: '單據編號規則', + companyCode: '交易廠區', + ruleCode: '生成單據識別號', + resetCycle: '流水碼重置類別', + resetCycleYy2: '按年2(YY)', + resetCycleYyyy4: '按年4(YYYY)', + resetCycleYymm4: '按月4(YYMM)', + resetCycleYyyymm6: '按月6(YYYYMM)', + resetCycleYymmdd6: '按日6(YYMMDD)', + resetCycleYyyymmdd8: '按日8(YYYYMMDD)', + ruleCodeMiscQts: 'miscQTS (雜採報價單)', + ruleCodeMiscRfs: 'miscRFS (雜採詢價單)', + prefix: '單據頭', + factoryCode: '廠區區分碼', + seqLength: '流水碼長度', + createUser: '單據創建人', + updateUser: '單據修改人', + sequenceDate: '流水日期', + prevSequence: '上一流水碼', + currentSequence: '下一流水碼', + lastGenerateUser: '單據最後產生人', + lastGenerateTime: '單據最後產生時間', + status: '可用狀態', + statusAvailable: '可用', + statusUnavailable: '不可用', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/menu/zh-cn.ts b/web/src/i18n/pages/menu/zh-cn.ts index 41a2d2b..db96b98 100644 --- a/web/src/i18n/pages/menu/zh-cn.ts +++ b/web/src/i18n/pages/menu/zh-cn.ts @@ -88,6 +88,7 @@ export default { widthPlaceholder: '请输入宽度', }, validation: { + alreadyExists: '已存在,不可重复', fieldNameRequired: '请输入字段名!', titleRequired: '请输入列名!', fieldNameFieldRequired: '请输入字段名称!', diff --git a/web/src/i18n/pages/miscprocurement/en.ts b/web/src/i18n/pages/miscprocurement/en.ts new file mode 100644 index 0000000..7a46679 --- /dev/null +++ b/web/src/i18n/pages/miscprocurement/en.ts @@ -0,0 +1,132 @@ +// Definition +export default { + message: { + pages: { + miscprocurement: { + materialInfo: { + title: 'Misc Procurement Material Info', + factory: 'Factory', + materialtype: 'Material Type', + materialtypeEn: 'Material Type (English)', + materialtypeZhTw: 'Material Type (Traditional Chinese)', + density: 'Density', + price: 'Unit Price', + status: 'Status', + }, + stationInfo: { + title: 'Misc Procurement Station Info', + companyCode: 'Company Code', + stationname: 'Station Name', + stationnameEn: 'Station Name (English)', + stationnameZhTw: 'Station Name (Traditional Chinese)', + stationcode: 'Station Code', + stationtype: 'Station Type', + unit: 'Unit', + rate: 'Rate', + status: 'Status', + }, + inquiry: { + title: 'Inquiry', + inquiryNo: 'Inquiry No', + title_label: 'Inquiry Title', + titleEn: 'Inquiry Title (English)', + titleZhTw: 'Inquiry Title (Traditional Chinese)', + purchaseType: 'Purchase Type', + materialType: 'Material Type', + template: 'Template', + currency: 'Currency', + companyCode: 'Company Code', + purchaseDept: 'Purchase Department', + buyer: 'Buyer', + quoteDeadline: 'Quote Deadline', + targetPrice: 'Target Price', + leadTimeDays: 'Lead Time (Days)', + paymentMethod: 'Payment Method', + status: 'Status', + buyingMethod: 'Buying Method', + }, + costTemplate: { + title: 'Cost Estimate Template', + templateNo: 'Template No', + templateName: 'Template Name', + templateNameEn: 'Template Name (English)', + templateNameZhTw: 'Template Name (Traditional Chinese)', + procurementCategory: 'Procurement Category', + templateDesc: 'Template Description', + status: 'Status', + }, + rfqmiscellaneous: { + title: 'Misc RFQ', + inquiryNo: 'RFQ No', + inquiryName: 'RFQ Name', + companyShortName: 'Transaction Plant', + buyingMethod: 'Buying Method', + buyingMethodInquiry: 'Inquiry', + buyingMethodBid: 'Bid', + quoteDeadline: 'Quote Deadline', + bidStartTime: 'Bid Start Time', + bidEndTime: 'Bid End Time', + buyer: 'Buyer', + currency: 'Currency', + leadTimeDays: 'Lead Time (Days)', + paymentMethod: 'Payment Method', + status: 'Status', + statusOpen: 'Open', + statusConfirmed: 'Confirmed', + statusPublished: 'Published', + statusQuoting: 'Quoting', + statusQuotingEnd: 'Quote Ended', + statusBargaining: 'Bargaining', + statusPriceAudit: 'Price Audit', + statusPriceApproved: 'Price Approved', + statusLost: 'Lost', + statusCancelled: 'Cancelled', + remark: 'Remark', + opCreate: 'RFQ Created', + opConfirm: 'RFQ Confirmed', + opPublish: 'RFQ Published', + opRestore: 'RFQ Restored', + opQuoteDeadline: 'Quote Deadline', + opSupplierQuote: 'Supplier Quoted', + opBargain: 'Bargain', + opBargainSubmit: 'Bargain Submitted', + opBargainComplete: 'Bargain Completed', + opBargainReject: 'Bargain Rejected', + newInquiry: 'New RFQ', + startBargain: 'Start Comparison', + confirm: 'Confirm', + restore: 'Restore', + publish: 'Publish', + comparePrice: 'Compare Price', + view: 'View', + edit: 'Edit', + delete: 'Delete', + selectOneFirst: 'Please select an RFQ first', + onlySupportSingle: 'Only single item operation is supported', + onlyQuotingCanBargain: 'Only quoting or quote-ended status can start price comparison', + confirmChangeToBargaining: 'Confirm to change status to [Bargaining]?', + maintainSupplierFirst: 'Please maintain RFQ supplier list first before confirming', + confirmLockAfterConfirm: 'After confirmation, the RFQ will be locked and cannot be edited. To modify, you need to [Restore] it.', + confirmRestore: 'Confirm to restore status to [Open]?', + confirmPublish: 'Confirm to change status to [Published]?', + transactionPlant: 'Transaction Plant', + purchaseCategory: 'Purchase Category', + inquiryTemplate: 'RFQ Template', + templateVersion: 'Template Version', + paymentTerm: 'Payment Terms', + totalPriceInclTax: 'Total Price Incl. Tax', + costStructure: 'Cost Structure', + supplierList: 'Supplier List', + attachments: 'Attachments', + basicInfo: 'Basic Info', + operationType: 'Operation Type', + operator: 'Operator', + operationTime: 'Operation Time', + operationDesc: 'Operation Description', + statusChange: 'Status Change', + quotationNo: 'Quotation No', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/miscprocurement/zh-cn.ts b/web/src/i18n/pages/miscprocurement/zh-cn.ts new file mode 100644 index 0000000..6bf2e64 --- /dev/null +++ b/web/src/i18n/pages/miscprocurement/zh-cn.ts @@ -0,0 +1,132 @@ +// 定义内容 +export default { + message: { + pages: { + miscprocurement: { + materialInfo: { + title: '杂采材料信息', + factory: '交易厂区', + materialtype: '材质', + materialtypeEn: '材质英文名', + materialtypeZhTw: '材质繁体名', + density: '比重', + price: '单价', + status: '状态', + }, + stationInfo: { + title: '杂采工站信息', + companyCode: '交易厂区', + stationname: '工站名称', + stationnameEn: '工站英文名', + stationnameZhTw: '工站繁体名', + stationcode: '工站代码', + stationtype: '工站类型归属', + unit: '计量单位', + rate: '费率', + status: '状态', + }, + inquiry: { + title: '询价单', + inquiryNo: '询价单号', + title_label: '询价单名称', + titleEn: '询价单英文名', + titleZhTw: '询价单繁体名', + purchaseType: '采购类别', + materialType: '材料类型', + template: '询价模版', + currency: '交易币别', + companyCode: '公司代码', + purchaseDept: '采购部门', + buyer: '采购负责人', + quoteDeadline: '报价截止时间', + targetPrice: '目标价格', + leadTimeDays: '交货周期(天)', + paymentMethod: '付款方式', + status: '状态', + buyingMethod: '采购方式', + }, + costTemplate: { + title: '成本估算模板', + templateNo: '模板编号', + templateName: '模板名称', + templateNameEn: '模板英文名', + templateNameZhTw: '模板繁体名', + procurementCategory: '采购类别', + templateDesc: '模板描述', + status: '状态', + }, + rfqmiscellaneous: { + title: '杂采询价单', + inquiryNo: '询价单号', + inquiryName: '询价单名称', + companyShortName: '交易厂区', + buyingMethod: '采购方式', + buyingMethodInquiry: '询价', + buyingMethodBid: '招标', + quoteDeadline: '报价截止时间', + bidStartTime: '投标开始时间', + bidEndTime: '投标截止时间', + buyer: '采购负责人', + currency: '币别', + leadTimeDays: '交货周期(天)', + paymentMethod: '付款方式', + status: '状态', + statusOpen: '开立', + statusConfirmed: '确认', + statusPublished: '发布', + statusQuoting: '报价中', + statusQuotingEnd: '报价结束', + statusBargaining: '比议价中', + statusPriceAudit: '价格审核', + statusPriceApproved: '核价通过(结束)', + statusLost: '落标(结束)', + statusCancelled: '作废', + remark: '备注', + opCreate: '询价单创建', + opConfirm: '询价单确认', + opPublish: '询价单发布', + opRestore: '询价单还原', + opQuoteDeadline: '报价截止', + opSupplierQuote: '供应商报价', + opBargain: '比议价', + opBargainSubmit: '议价审核提交', + opBargainComplete: '议价审核完成', + opBargainReject: '议价审核驳回', + newInquiry: '新建询价单', + startBargain: '开启比价', + confirm: '确认', + restore: '还原', + publish: '发布', + comparePrice: '比价', + view: '查看', + edit: '编辑', + delete: '删除', + selectOneFirst: '请先选择询价单', + onlySupportSingle: '仅支持单条操作', + onlyQuotingCanBargain: '仅报价中或报价结束状态可开启比价', + confirmChangeToBargaining: '确认将状态改为【比议价中】?', + maintainSupplierFirst: '请先维护询价单供应商名单后再确认', + confirmLockAfterConfirm: '确认后,该询价单将锁定并不可再编辑。如需修改,后续需执行【还原】操作', + confirmRestore: '确认将状态还原为【开立】?', + confirmPublish: '确认将状态改为【发布】?', + transactionPlant: '交易厂区', + purchaseCategory: '采购类别', + inquiryTemplate: '询价模版', + templateVersion: '模板版本', + paymentTerm: '付款条件', + totalPriceInclTax: '含税总价', + costStructure: '成本结构', + supplierList: '供应商名单', + attachments: '附件', + basicInfo: '基础信息', + operationType: '操作类型', + operator: '操作人', + operationTime: '操作时间', + operationDesc: '操作描述', + statusChange: '状态变更', + quotationNo: '报价单号', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/miscprocurement/zh-tw.ts b/web/src/i18n/pages/miscprocurement/zh-tw.ts new file mode 100644 index 0000000..e2930a1 --- /dev/null +++ b/web/src/i18n/pages/miscprocurement/zh-tw.ts @@ -0,0 +1,132 @@ +// 定義內容 +export default { + message: { + pages: { + miscprocurement: { + materialInfo: { + title: '雜採材料資訊', + factory: '交易廠區', + materialtype: '材質', + materialtypeEn: '材質英文名', + materialtypeZhTw: '材質繁體名', + density: '比重', + price: '單價', + status: '狀態', + }, + stationInfo: { + title: '雜採工站資訊', + companyCode: '交易廠區', + stationname: '工站名稱', + stationnameEn: '工站英文名', + stationnameZhTw: '工站繁體名', + stationcode: '工站代碼', + stationtype: '工站類型歸屬', + unit: '計量單位', + rate: '費率', + status: '狀態', + }, + inquiry: { + title: '詢價單', + inquiryNo: '詢價單號', + title_label: '詢價單名稱', + titleEn: '詢價單英文名', + titleZhTw: '詢價單繁體名', + purchaseType: '採購類別', + materialType: '材料類型', + template: '詢價模版', + currency: '交易幣別', + companyCode: '公司代碼', + purchaseDept: '採購部門', + buyer: '採購負責人', + quoteDeadline: '報價截止時間', + targetPrice: '目標價格', + leadTimeDays: '交貨週期(天)', + paymentMethod: '付款方式', + status: '狀態', + buyingMethod: '採購方式', + }, + costTemplate: { + title: '成本估算模版', + templateNo: '模版編號', + templateName: '模版名稱', + templateNameEn: '模版英文名', + templateNameZhTw: '模版繁體名', + procurementCategory: '採購類別', + templateDesc: '模版描述', + status: '狀態', + }, + rfqmiscellaneous: { + title: '雜採詢價單', + inquiryNo: '詢價單號', + inquiryName: '詢價單名稱', + companyShortName: '交易廠區', + buyingMethod: '採購方式', + buyingMethodInquiry: '詢價', + buyingMethodBid: '招標', + quoteDeadline: '報價截止時間', + bidStartTime: '投標開始時間', + bidEndTime: '投標截止時間', + buyer: '採購負責人', + currency: '幣別', + leadTimeDays: '交貨週期(天)', + paymentMethod: '付款方式', + status: '狀態', + statusOpen: '開立', + statusConfirmed: '確認', + statusPublished: '發布', + statusQuoting: '報價中', + statusQuotingEnd: '報價結束', + statusBargaining: '比議價中', + statusPriceAudit: '價格審核', + statusPriceApproved: '核價通過(結束)', + statusLost: '落標(結束)', + statusCancelled: '作廢', + remark: '備註', + opCreate: '詢價單創建', + opConfirm: '詢價單確認', + opPublish: '詢價單發布', + opRestore: '詢價單還原', + opQuoteDeadline: '報價截止', + opSupplierQuote: '供應商報價', + opBargain: '比議價', + opBargainSubmit: '議價審核提交', + opBargainComplete: '議價審核完成', + opBargainReject: '議價審核駁回', + newInquiry: '新建詢價單', + startBargain: '開啟比價', + confirm: '確認', + restore: '還原', + publish: '發布', + comparePrice: '比價', + view: '查看', + edit: '編輯', + delete: '刪除', + selectOneFirst: '請先選擇詢價單', + onlySupportSingle: '僅支援單條操作', + onlyQuotingCanBargain: '僅報價中或報價結束狀態可開啟比價', + confirmChangeToBargaining: '確認將狀態改為【比議價中】?', + maintainSupplierFirst: '請先維護詢價單供應商名單後再確認', + confirmLockAfterConfirm: '確認後,該詢價單將鎖定並不可再編輯。如需修改,後續需執行【還原】操作', + confirmRestore: '確認將狀態還原為【開立】?', + confirmPublish: '確認將狀態改為【發布】?', + transactionPlant: '交易廠區', + purchaseCategory: '採購類別', + inquiryTemplate: '詢價模版', + templateVersion: '模版版本', + paymentTerm: '付款條件', + totalPriceInclTax: '含稅總價', + costStructure: '成本結構', + supplierList: '供應商名單', + attachments: '附件', + basicInfo: '基本信息', + operationType: '操作類型', + operator: '操作人', + operationTime: '操作時間', + operationDesc: '操作描述', + statusChange: '狀態變更', + quotationNo: '報價單號', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/pissupplier/en.ts b/web/src/i18n/pages/pissupplier/en.ts new file mode 100644 index 0000000..a096b85 --- /dev/null +++ b/web/src/i18n/pages/pissupplier/en.ts @@ -0,0 +1,75 @@ +// Definition +export default { + message: { + pages: { + pissupplier: { + quotation: { + title: 'Supplier Quotation', + quotationNo: 'Quotation No', + inquiryNo: 'Inquiry No', + supplierCode: 'Supplier Code', + supplierName: 'Supplier Name', + supplierNameEn: 'Supplier Name (English)', + supplierNameZhTw: 'Supplier Name (Traditional Chinese)', + contactPerson: 'Contact Person', + contactPhone: 'Contact Phone', + contactEmail: 'Contact Email', + quoteDeadline: 'Quote Deadline', + paymentMethod: 'Payment Method', + status: 'Status', + isAwarded: 'Award Status', + buyingMethod: 'Buying Method', + remark: 'Remark', + buyingMethodInquiry: 'Inquiry', + buyingMethodBid: 'Bid', + bidStartTime: 'Bid Start Time', + bidEndTime: 'Bid End Time', + leadTimeDays: 'Lead Time (Days)', + statusPending: 'Pending', + statusQuoting: 'Quoting', + statusCompleted: 'Completed', + statusExpired: 'Expired', + newQuote: 'New Quote', + viewQuote: 'View Quote', + editQuote: 'Edit Quote', + submitQuote: 'Submit Quote', + saveQuote: 'Save Quote', + bidWindowExpired: 'Bid deadline has passed, cannot quote or submit', + bidWindowMissing: 'Bid project is missing bid start or end time, cannot quote or submit', + fillBasicInfoFirst: 'Please complete [Quote Basic Info] before saving.', + onlyPendingCanSave: 'Only pending/quoting status can be saved', + onlyQuotingCanSubmit: 'Only quoting status can submit quote', + fillBasicInfoBeforeSubmit: 'Please complete [Quote Basic Info] in the quotation before submitting.', + cannotSubmitNoId: 'Cannot submit: missing quotation ID', + materialCost: 'Material Cost', + processCost: 'Process Cost', + otherCost: 'Other Cost', + profit: 'Profit', + tax: 'Tax', + profitRate: 'Profit Rate', + taxRate: 'Tax Rate', + weight: 'Weight', + unitPrice: 'Unit Price', + materialFee: 'Material Fee', + processFee: 'Process Fee', + packagingFee: 'Packaging Fee', + transportFee: 'Transport Fee', + contact: 'Contact', + phone: 'Phone', + email: 'Email', + validityDays: 'Validity (Days)', + awarded: 'Awarded', + notAwarded: 'Not Awarded', + evaluating: 'Evaluating', + quoteAmount: 'Quote Amount', + quoteTime: 'Quote Time', + uploadAttachment: 'Upload Attachment', + comparePrice: 'Compare Price', + lowestPrice: 'Lowest Price', + averagePrice: 'Average Price', + inquiryTitle: 'Inquiry Title', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/pissupplier/zh-cn.ts b/web/src/i18n/pages/pissupplier/zh-cn.ts new file mode 100644 index 0000000..3b91d2b --- /dev/null +++ b/web/src/i18n/pages/pissupplier/zh-cn.ts @@ -0,0 +1,75 @@ +// 定义内容 +export default { + message: { + pages: { + pissupplier: { + quotation: { + title: '供应商报价', + quotationNo: '报价单单号', + inquiryNo: '询价单单号', + supplierCode: '供应商代码', + supplierName: '供应商名称', + supplierNameEn: '供应商英文名', + supplierNameZhTw: '供应商繁体名', + contactPerson: '联系人', + contactPhone: '联系人电话', + contactEmail: '联系人邮件', + quoteDeadline: '报价截止时间', + paymentMethod: '付款方式', + status: '状态', + isAwarded: '报价中标否', + buyingMethod: '采购方式', + remark: '报价说明及备注', + buyingMethodInquiry: '询价', + buyingMethodBid: '招标', + bidStartTime: '投标开始时间', + bidEndTime: '投标截止时间', + leadTimeDays: '交货周期(天)', + statusPending: '待报价', + statusQuoting: '报价中', + statusCompleted: '已报价', + statusExpired: '已过期', + newQuote: '新建报价单', + viewQuote: '查看报价', + editQuote: '编辑报价', + submitQuote: '提交报价', + saveQuote: '保存报价', + bidWindowExpired: '已超过投标截止时间,无法报价或提交', + bidWindowMissing: '招标项目缺少投标开始或截止时间,无法报价或提交', + fillBasicInfoFirst: '请先填写完整【报价基础信息】后再保存。', + onlyPendingCanSave: '仅未报价/报价中状态可保存', + onlyQuotingCanSubmit: '仅报价中状态可提交报价', + fillBasicInfoBeforeSubmit: '请先将报价单中的【报价基础信息】填写完整后再提交报价。', + cannotSubmitNoId: '无法提交:缺少报价单标识', + materialCost: '材料成本', + processCost: '加工成本', + otherCost: '其它成本', + profit: '利润', + tax: '税金', + profitRate: '利润率', + taxRate: '税率', + weight: '重量', + unitPrice: '单价', + materialFee: '材料费用', + processFee: '加工费', + packagingFee: '包装费', + transportFee: '运输费', + contact: '联络人', + phone: '电话', + email: '邮箱', + validityDays: '有效期(天)', + awarded: '中标', + notAwarded: '未中标', + evaluating: '评标中', + quoteAmount: '报价金额', + quoteTime: '报价时间', + uploadAttachment: '上传附件', + comparePrice: '比价', + lowestPrice: '制程最低价', + averagePrice: '平均价', + inquiryTitle: '询价单名称', + }, + }, + }, + }, +}; diff --git a/web/src/i18n/pages/pissupplier/zh-tw.ts b/web/src/i18n/pages/pissupplier/zh-tw.ts new file mode 100644 index 0000000..a51da41 --- /dev/null +++ b/web/src/i18n/pages/pissupplier/zh-tw.ts @@ -0,0 +1,75 @@ +// 定義內容 +export default { + message: { + pages: { + pissupplier: { + quotation: { + title: '供應商報價', + quotationNo: '報價單號', + inquiryNo: '詢價單號', + supplierCode: '供應商代碼', + supplierName: '供應商名稱', + supplierNameEn: '供應商英文名', + supplierNameZhTw: '供應商繁體名', + contactPerson: '聯絡人', + contactPhone: '聯絡人電話', + contactEmail: '聯絡人郵箱', + quoteDeadline: '報價截止時間', + paymentMethod: '付款方式', + status: '狀態', + isAwarded: '報價中標否', + buyingMethod: '採購方式', + remark: '報價說明及備註', + buyingMethodInquiry: '詢價', + buyingMethodBid: '招標', + bidStartTime: '投標開始時間', + bidEndTime: '投標截止時間', + leadTimeDays: '交貨週期(天)', + statusPending: '待報價', + statusQuoting: '報價中', + statusCompleted: '已報價', + statusExpired: '已過期', + newQuote: '新建報價單', + viewQuote: '查看報價', + editQuote: '編輯報價', + submitQuote: '提交報價', + saveQuote: '儲存報價', + bidWindowExpired: '已超過投標截止時間,無法報價或提交', + bidWindowMissing: '招標項目缺少投標開始或截止時間,無法報價或提交', + fillBasicInfoFirst: '請先填寫完整【報價基本信息】後再儲存。', + onlyPendingCanSave: '僅未報價/報價中狀態可儲存', + onlyQuotingCanSubmit: '僅報價中狀態可提交報價', + fillBasicInfoBeforeSubmit: '請先將報價單中的【報價基本信息】填寫完整後再提交報價。', + cannotSubmitNoId: '無法提交:缺少報價單標識', + materialCost: '材料成本', + processCost: '加工成本', + otherCost: '其它成本', + profit: '利潤', + tax: '税金', + profitRate: '利潤率', + taxRate: '税率', + weight: '重量', + unitPrice: '單價', + materialFee: '材料費用', + processFee: '加工費', + packagingFee: '包裝費', + transportFee: '運輸費', + contact: '聯絡人', + phone: '電話', + email: '郵箱', + validityDays: '有效期(天)', + awarded: '中標', + notAwarded: '未中標', + evaluating: '評標中', + quoteAmount: '報價金額', + quoteTime: '報價時間', + uploadAttachment: '上傳附件', + comparePrice: '比價', + lowestPrice: '製程最低價', + averagePrice: '平均價', + inquiryTitle: '詢價單名稱', + }, + }, + }, + }, +}; diff --git a/web/src/views/pisadmin/basicinfo/company/crud.tsx b/web/src/views/pisadmin/basicinfo/company/crud.tsx index cb084eb..0631f45 100644 --- a/web/src/views/pisadmin/basicinfo/company/crud.tsx +++ b/web/src/views/pisadmin/basicinfo/company/crud.tsx @@ -2,14 +2,11 @@ import { dict, CreateCrudOptionsProps, CreateCrudOptionsRet } from '@fast-crud/f import * as api from './api' import { useUserInfo } from '/@/stores/userInfo' import { ElMessage } from 'element-plus' - -const statusDict = [ - { value: 1, label: '可用' }, - { value: 0, label: '不可用' } -] +import { useI18n } from 'vue-i18n' export const createCrudOptions = function ({ crudExpose }: Partial): CreateCrudOptionsRet { void crudExpose + const { t } = useI18n() const userStore = useUserInfo() const currentUser = userStore.userInfos?.name || @@ -30,7 +27,7 @@ export const createCrudOptions = function ({ crudExpose }: Partial item.company_code === code) : null if (exists && (!currentId || exists.id !== currentId)) { - throw new Error('公司代码已存在,不可重复') + throw new Error(t('message.pages.basicinfo.company.companyCode') + t('message.pages.menu.validation.alreadyExists')) } } return { @@ -84,46 +81,46 @@ export const createCrudOptions = function ({ crudExpose }: Partial { if (!Array.isArray(value)) return '' return value.filter((v) => !!v).join('; ') } -const formatAttachments = (value: unknown) => { - if (!Array.isArray(value)) return '' - const names = value - .map((v: any) => v?.name || v?.file_name || v?.filename || v?.key || '') - .filter((v: any) => !!v) - if (names.length === 0) return value.length ? `${value.length} 个附件` : '' - return names.join('; ') -} - export const createCrudOptions = function ({ crudExpose }: Partial): CreateCrudOptionsRet { + const { t } = useI18n() + + const statusDict = [ + { value: 'pending', label: t('message.pages.basicinfo.emailnotice.statusPending') }, + { value: 'sending', label: t('message.pages.basicinfo.emailnotice.statusSending') }, + { value: 'success', label: t('message.pages.basicinfo.emailnotice.statusSuccess') }, + { value: 'failed', label: t('message.pages.basicinfo.emailnotice.statusFailed') } + ] + + const formatAttachments = (value: unknown) => { + if (!Array.isArray(value)) return '' + const names = value + .map((v: any) => v?.name || v?.file_name || v?.filename || v?.key || '') + .filter((v: any) => !!v) + if (names.length === 0) return value.length ? `${value.length} ${t('message.pages.basicinfo.emailnotice.attachments')}` : '' + return names.join('; ') + } + return { crudOptions: { request: { @@ -42,7 +45,7 @@ export const createCrudOptions = function ({ crudExpose }: Partial row.status !== 'sending', @@ -53,9 +56,9 @@ export const createCrudOptions = function ({ crudExpose }: Partial joinEmails(value) } }, cc_emails: { - title: '抄送', + title: t('message.pages.basicinfo.emailnotice.ccEmails'), type: 'text', column: { minWidth: 180, showOverflowTooltip: true, formatter: ({ value }) => joinEmails(value) } }, bcc_emails: { - title: '密送', + title: t('message.pages.basicinfo.emailnotice.bccEmails'), type: 'text', column: { minWidth: 180, showOverflowTooltip: true, formatter: ({ value }) => joinEmails(value) } }, status: { - title: '发送状态', + title: t('message.pages.basicinfo.emailnotice.status'), type: 'dict-select', dict: dict({ data: statusDict }), - search: { show: true, component: { props: { clearable: true, placeholder: '请选择状态' } } }, + search: { show: true, component: { props: { clearable: true, placeholder: t('message.pages.basicinfo.emailnotice.status') } } }, column: { width: 120 } }, sent_at: { - title: '发送时间', + title: t('message.pages.basicinfo.emailnotice.sentAt'), type: 'datetime', search: { show: true, @@ -121,35 +124,35 @@ export const createCrudOptions = function ({ crudExpose }: Partial formatAttachments(value) } }, last_error: { - title: '错误信息', + title: t('message.pages.basicinfo.emailnotice.lastError'), type: 'text', column: { minWidth: 240, showOverflowTooltip: true } }, message_id: { - title: '消息ID', + title: t('message.pages.basicinfo.emailnotice.messageId'), type: 'text', column: { minWidth: 180, showOverflowTooltip: true } }, retry_count: { - title: '重试次数', + title: t('message.pages.basicinfo.emailnotice.retryCount'), type: 'number', column: { width: 100 } }, create_datetime: { - title: '创建时间', + title: t('message.pages.system.user.createTime'), type: 'datetime', form: { show: false }, column: { width: 180 } diff --git a/web/src/views/pisadmin/basicinfo/supplier_user/crud.tsx b/web/src/views/pisadmin/basicinfo/supplier_user/crud.tsx index d985bb4..b78f098 100644 --- a/web/src/views/pisadmin/basicinfo/supplier_user/crud.tsx +++ b/web/src/views/pisadmin/basicinfo/supplier_user/crud.tsx @@ -2,13 +2,7 @@ import { dict, CreateCrudOptionsProps, CreateCrudOptionsRet } from '@fast-crud/f import * as api from './api' import { GetList as GetSupplierList } from '../supplier/api' import { ElMessage } from 'element-plus' - -const statusDict = [ - { value: 1, label: '有效' }, - { value: 0, label: '无效' } -] - -const supplierRoleDict = [{ value: 1, label: '报价' }] +import { useI18n } from 'vue-i18n' let supplierById: Record = {} @@ -66,6 +60,7 @@ void loadSupplierOptions() export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet { void crudExpose + const { t } = useI18n() const ensureUserEmailUnique = async (supplierId: string, userEmail: string, currentId?: number) => { if (!supplierId || !userEmail) return @@ -85,7 +80,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp ) : null if (exists && (!currentId || exists.id !== currentId)) { - throw new Error('同一供应商下该联络邮箱已存在') + throw new Error(t('message.pages.basicinfo.supplierUser.userEmail') + t('message.pages.menu.validation.alreadyExists')) } } @@ -101,7 +96,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp await ensureUserEmailUnique(form.supplier_id, form.user_email) const res = await api.AddObj(form) ElMessage.success( - '保存成功;已同步创建系统用户(登录账号为联络人邮箱,初始密码为系统默认密码,部门:供应商)' + '保存成功,已同步创建系统用户(登录账号为联络人邮箱,初始密码为系统默认密码,部门:供应商)' ) return res } catch (err: any) { @@ -133,7 +128,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp }, columns: { supplier_id: { - title: '供应商唯一ID', + title: t('message.pages.basicinfo.supplierUser.supplierId'), type: 'dict-select', dict: dict({ cache: false, @@ -147,9 +142,9 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp })) } }), - search: { show: true, component: { props: { placeholder: '请选择或搜索', filterable: true, clearable: true } } }, + search: { show: true, component: { props: { placeholder: t('message.pages.basicinfo.emailnotice.selectOrSearch'), filterable: true, clearable: true } } }, form: { - rules: [{ required: true, message: '请选择供应商' }], + rules: [{ required: true, message: t('message.pages.basicinfo.supplierUser.supplierId') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }], /** dict-select 需用 fast-crud 的 valueChange;component.on.change 往往不会触发 */ valueChange: async ({ value, form }: any) => { const v = value @@ -181,67 +176,67 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp column: { minWidth: 200, showOverflowTooltip: true } }, supplier_name: { - title: '供应商全称', + title: t('message.pages.basicinfo.supplierUser.supplierName'), type: 'input', - search: { show: true, component: { props: { placeholder: '请输入供应商全称', clearable: true } } }, + search: { show: true, component: { props: { placeholder: t('message.pages.basicinfo.supplierUser.supplierName'), clearable: true } } }, form: { rules: [{ required: true, message: '请先选择供应商唯一ID,将自动带出供应商全称' }], component: { props: { disabled: true, - placeholder: '选择供应商唯一ID后自动带出' + placeholder: t('message.pages.basicinfo.supplierUser.autoFillNote') } } }, column: { minWidth: 180, showOverflowTooltip: true } }, supplier_role: { - title: '供应商角色', + title: t('message.pages.basicinfo.supplierUser.supplierRole'), type: 'dict-select', - dict: dict({ data: supplierRoleDict }), + dict: dict({ data: [{ value: 1, label: t('message.pages.basicinfo.supplierUser.roleQuote') }] }), search: { show: true }, form: { - rules: [{ required: true, message: '请选择供应商角色' }], + rules: [{ required: true, message: t('message.pages.basicinfo.supplierUser.supplierRole') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }], value: 1 }, column: { minWidth: 120, showOverflowTooltip: true } }, user_email: { - title: '联络人邮箱', + title: t('message.pages.basicinfo.supplierUser.userEmail'), type: 'input', - search: { show: true, component: { props: { placeholder: '请输入邮箱', clearable: true } } }, - form: { rules: [{ required: true, message: '请输入联络人邮箱' }] }, + search: { show: true, component: { props: { placeholder: t('message.pages.basicinfo.supplierUser.userEmail'), clearable: true } } }, + form: { rules: [{ required: true, message: t('message.pages.basicinfo.supplierUser.userEmail') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, column: { minWidth: 200, showOverflowTooltip: true } }, user_name: { - title: '联络人', + title: t('message.pages.basicinfo.supplierUser.userName'), type: 'input', - search: { show: true, component: { props: { placeholder: '请输入联络人', clearable: true } } }, - form: { rules: [{ required: true, message: '请输入联络人' }] }, + search: { show: true, component: { props: { placeholder: t('message.pages.basicinfo.supplierUser.userName'), clearable: true } } }, + form: { rules: [{ required: true, message: t('message.pages.basicinfo.supplierUser.userName') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, column: { minWidth: 120, showOverflowTooltip: true } }, user_phone: { - title: '联络人电话', + title: t('message.pages.basicinfo.supplierUser.userPhone'), type: 'input', - search: { show: true, component: { props: { placeholder: '请输入电话', clearable: true } } }, - form: { rules: [{ required: true, message: '请输入联络人电话' }] }, + search: { show: true, component: { props: { placeholder: t('message.pages.basicinfo.supplierUser.userPhone'), clearable: true } } }, + form: { rules: [{ required: true, message: t('message.pages.basicinfo.supplierUser.userPhone') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, column: { minWidth: 140, showOverflowTooltip: true } }, status: { - title: '有效否', + title: t('message.pages.basicinfo.supplierUser.status'), type: 'dict-switch', - dict: dict({ data: statusDict }), + dict: dict({ data: [{ value: 1, label: t('message.pages.basicinfo.supplierUser.statusValid') }, { value: 0, label: t('message.pages.basicinfo.supplierUser.statusInvalid') }] }), form: { value: 1 }, column: { width: 120 } }, create_datetime: { - title: '创建时间', + title: t('message.pages.system.user.createTime'), type: 'datetime', form: { show: false }, column: { width: 180 } }, update_datetime: { - title: '更新时间', + title: t('message.pages.system.user.updateTime'), type: 'datetime', form: { show: false }, column: { width: 180 } diff --git a/web/src/views/pisadmin/basicinfo/systemno/crud.tsx b/web/src/views/pisadmin/basicinfo/systemno/crud.tsx index a5198bf..b4c1540 100644 --- a/web/src/views/pisadmin/basicinfo/systemno/crud.tsx +++ b/web/src/views/pisadmin/basicinfo/systemno/crud.tsx @@ -3,21 +3,7 @@ import * as api from './api' import { GetCompanies } from '../currency/api' import { useUserInfo } from '/@/stores/userInfo' import { ElMessage } from 'element-plus' - -const resetCycleDict = [ - { value: 'yy', label: '按年2(YY)' }, - { value: 'yyyy', label: '按年4(YYYY)' }, - { value: 'yymm', label: '按月4(YYMM)' }, - { value: 'yyyymm', label: '按月6(YYYYMM)' }, - { value: 'yymmdd', label: '按日6(YYMMDD)' }, - { value: 'yyyymmdd', label: '按日8(YYYYMMDD)' } -] - -/** 与 `SystemNoRule.RULE_CODE_CHOICES` 一致;表单/搜索下拉展示「代码 - 名称」,列表列仅显示代码(见 column.formatter) */ -const ruleCodeDict = [ - { value: 'miscQTS', label: 'miscQTS (杂采报价单)' }, - { value: 'miscRFS', label: 'miscRFS (杂采询价单)' } -] +import { useI18n } from 'vue-i18n' /** * 交易厂区「通用」:非公司主数据,仅存于编号规则下拉;与 unique(company_code, rule_code) 兼容。 @@ -55,6 +41,7 @@ const loadCompanyOptions = async () => { } export const createCrudOptions = function ({ crudExpose }: Partial): CreateCrudOptionsRet { + const { t } = useI18n() void crudExpose const userStore = useUserInfo() const currentUser = @@ -63,6 +50,21 @@ export const createCrudOptions = function ({ crudExpose }: Partial { if (!companyCode || !ruleCode) return const res = await api.GetList({ company_code: companyCode, rule_code: ruleCode, page: 1, page_size: 1, pageSize: 1 }) @@ -78,7 +80,7 @@ export const createCrudOptions = function ({ crudExpose }: Partial item.company_code === companyCode && item.rule_code === ruleCode) : null if (exists && (!currentId || exists.id !== currentId)) { - throw new Error('同一交易厂区下的生成单据标识号不可重复') + throw new Error(t('message.pages.basicinfo.systemno.companyCode') + t('message.pages.basicinfo.systemno.ruleCode') + t('message.pages.menu.validation.alreadyExists')) } } @@ -130,7 +132,7 @@ export const createCrudOptions = function ({ crudExpose }: Partial { }) } -const visibleTitles = (procurementCategory?: string, enableCostStructure?: boolean) => { - // 杂采(2) 不显示“管销研费用” +const visibleTitles = (t: any, procurementCategory?: string, enableCostStructure?: boolean) => { + // 杂采(2) 不显示”管销研费用” if (procurementCategory === '2') { return enableCostStructure - ? ['材料成本', '加工成本', '其它成本', '利润', '税金'] - : ['产品明细', '利润', '税金'] + ? [t('message.pages.miscprocurement.cost_template.materials'), t('message.pages.miscprocurement.cost_template.process'), t('message.pages.miscprocurement.cost_template.others'), t('message.pages.miscprocurement.cost_template.profit'), t('message.pages.miscprocurement.cost_template.tax')] + : [t('message.pages.miscprocurement.cost_template.productDetail'), t('message.pages.miscprocurement.cost_template.profit'), t('message.pages.miscprocurement.cost_template.tax')] } return enableCostStructure - ? ['材料成本', '加工成本', '其它成本', '管销研费用', '利润', '税金'] - : ['产品明细', '利润', '税金'] + ? [t('message.pages.miscprocurement.cost_template.materials'), t('message.pages.miscprocurement.cost_template.process'), t('message.pages.miscprocurement.cost_template.others'), t('message.pages.miscprocurement.cost_template.sgna'), t('message.pages.miscprocurement.cost_template.profit'), t('message.pages.miscprocurement.cost_template.tax')] + : [t('message.pages.miscprocurement.cost_template.productDetail'), t('message.pages.miscprocurement.cost_template.profit'), t('message.pages.miscprocurement.cost_template.tax')] } const ensureAllSections = (form: any, titlesForEnabled?: string[], procurementCategory?: string) => { @@ -349,8 +350,8 @@ const ensureAllSections = (form: any, titlesForEnabled?: string[], procurementCa return arr } -const refreshSectionsIfNeeded = (form: any, overrides: any = {}) => { - const titles = visibleTitles( +const refreshSectionsIfNeeded = (t: any, form: any, overrides: any = {}) => { + const titles = visibleTitles(t, overrides.procurement_category ?? form?.procurement_category, overrides.enable_cost_structure ?? (form?.is_bom || 'Y') === 'Y' ) @@ -615,6 +616,213 @@ const buildCostTemplateSubmitPayload = (form: any) => { } export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet { + const { t } = useI18n() + + // i18n-aware field factories + const makeMaterialsFieldsMisc = () => [ + createField(t('message.pages.miscprocurement.cost_template.material'), 'material', 'text'), + createField(t('message.pages.miscprocurement.cost_template.length'), 'length', 'number'), + createField(t('message.pages.miscprocurement.cost_template.width'), 'width', 'number'), + createField(t('message.pages.miscprocurement.cost_template.height'), 'height', 'number'), + createField(t('message.pages.miscprocurement.cost_template.specificgravity'), 'specificgravity', 'number', t('message.pages.miscprocurement.cost_template.autoByMaterial'), { supplierEditable: false }), + createField(t('message.pages.miscprocurement.cost_template.qty'), 'qty', 'number', '', { supplierRequired: true }), + createField(t('message.pages.miscprocurement.cost_template.weight'), 'weight', 'number', t('message.pages.miscprocurement.cost_template.lengthWidthHeightSpecificgravityQty'), { supplierEditable: false }), + createField(t('message.pages.miscprocurement.cost_template.unitPrice'), 'unitPrice', 'number'), + createField(t('message.pages.miscprocurement.cost_template.materialCost'), 'material_cost', 'number', t('message.pages.miscprocurement.cost_template.weightTimesUnitPrice'), { supplierEditable: false }) + ] + + const makeMaterialsFieldsStrategic = () => [ + createField(t('message.pages.miscprocurement.cost_template.material'), 'material', 'text'), + createField(t('message.pages.miscprocurement.cost_template.weightUsage'), 'weight', 'number'), + createField(t('message.pages.miscprocurement.cost_template.unitPrice'), 'unitPrice', 'number'), + createField(t('message.pages.miscprocurement.cost_template.unit'), 'unit', 'text'), + createField(t('message.pages.miscprocurement.cost_template.lossRate'), 'loss_rate', 'number'), + createField(t('message.pages.miscprocurement.cost_template.materialCost'), 'material_cost', 'number', t('message.pages.miscprocurement.cost_template.weightTimesUnitPrice'), { supplierEditable: false }), + createField(t('message.pages.miscprocurement.cost_template.remark'), 'remark', 'text') + ] + + const makeGetMaterialsFields = () => (procurementCategory?: string) => + procurementCategory === '1' ? makeMaterialsFieldsStrategic() : makeMaterialsFieldsMisc() + + const makeProcessFieldsMisc = () => [ + createField(t('message.pages.miscprocurement.cost_template.processStation'), 'process_station', 'select'), + createField(t('message.pages.miscprocurement.cost_template.unit'), 'unit', 'text', '', { supplierEditable: false }), + createField(t('message.pages.miscprocurement.cost_template.unitrate'), 'unitrate', 'number', t('message.pages.miscprocurement.cost_template.autoByStation'), { supplierEditable: false }), + createField(t('message.pages.miscprocurement.cost_template.processqty'), 'processqty', 'number'), + createField(t('message.pages.miscprocurement.cost_template.processprice'), 'processprice', 'number', t('message.pages.miscprocurement.cost_template.unitrateTimesProcessqty'), { supplierEditable: false }), + createField(t('message.pages.miscprocurement.cost_template.remark'), 'remark', 'text', '', { supplierEditable: false }) + ] + + const makeProcessFieldsStrategic = () => [ + createField(t('message.pages.miscprocurement.cost_template.processStation'), 'process_station', 'select'), + createField(t('message.pages.miscprocurement.cost_template.processTime'), 'process_time', 'number'), + createField(t('message.pages.miscprocurement.cost_template.unitPrice'), 'unit_price', 'number'), + createField(t('message.pages.miscprocurement.cost_template.unit'), 'unit', 'text', '', { supplierEditable: false }), + createField(t('message.pages.miscprocurement.cost_template.lossRate'), 'loss_rate', 'number', '', { supplierEditable: false }), + createField(t('message.pages.miscprocurement.cost_template.processCost'), 'process_cost', 'number', '', { supplierEditable: false }), + createField(t('message.pages.miscprocurement.cost_template.remark'), 'remark', 'text', '', { supplierEditable: false }) + ] + + const makeGetProcessFields = () => (procurementCategory?: string) => + procurementCategory === '1' ? makeProcessFieldsStrategic() : makeProcessFieldsMisc() + + const makeBaseSections = () => { + const getMaterialsFields = makeGetMaterialsFields() + const getProcessFields = makeGetProcessFields() + const sections = Object.values(baseSections).map((s) => deepCopy(s)) + sections.forEach((sec) => { + if (sec.id === 'productDetail') sec.title = t('message.pages.miscprocurement.cost_template.productDetail') + else if (sec.id === 'materials') sec.title = t('message.pages.miscprocurement.cost_template.materials') + else if (sec.id === 'process') sec.title = t('message.pages.miscprocurement.cost_template.process') + else if (sec.id === 'sgna') sec.title = t('message.pages.miscprocurement.cost_template.sgna') + else if (sec.id === 'others') sec.title = t('message.pages.miscprocurement.cost_template.others') + else if (sec.id === 'profit') sec.title = t('message.pages.miscprocurement.cost_template.profit') + else if (sec.id === 'tax') sec.title = t('message.pages.miscprocurement.cost_template.tax') + if (sec.id === 'materials') { + sec.fields = deepCopy(getMaterialsFields()) + } else if (sec.id === 'process') { + sec.fields = deepCopy(getProcessFields()) + } + }) + return sections + } + + const makeBuildDefaultSections = () => (procurementCategory?: string) => { + const sections = makeBaseSections() + return sections + } + + // i18n-aware visibleTitles + const doVisibleTitles = (procurementCategory?: string, enableCostStructure?: boolean) => { + if (procurementCategory === '2') { + return enableCostStructure + ? [t('message.pages.miscprocurement.cost_template.materials'), t('message.pages.miscprocurement.cost_template.process'), t('message.pages.miscprocurement.cost_template.others'), t('message.pages.miscprocurement.cost_template.profit'), t('message.pages.miscprocurement.cost_template.tax')] + : [t('message.pages.miscprocurement.cost_template.productDetail'), t('message.pages.miscprocurement.cost_template.profit'), t('message.pages.miscprocurement.cost_template.tax')] + } + return enableCostStructure + ? [t('message.pages.miscprocurement.cost_template.materials'), t('message.pages.miscprocurement.cost_template.process'), t('message.pages.miscprocurement.cost_template.others'), t('message.pages.miscprocurement.cost_template.sgna'), t('message.pages.miscprocurement.cost_template.profit'), t('message.pages.miscprocurement.cost_template.tax')] + : [t('message.pages.miscprocurement.cost_template.productDetail'), t('message.pages.miscprocurement.cost_template.profit'), t('message.pages.miscprocurement.cost_template.tax')] + } + + // i18n-aware validation + const doValidateDuplicateFieldKeys = (form: any): { ok: true } | { ok: false; message: string } => { + const allowTitles = doVisibleTitles(form.procurement_category, (form.is_bom || 'Y') === 'Y') + const scan = (sectionsRaw: any): string[] => { + const msgs: string[] = [] + for (const sec of normalizeSections(sectionsRaw)) { + if (!sec || sec.enabled === false) continue + const title = sec.title || sec.name || '' + if (allowTitles.length && !allowTitles.includes(title)) continue + const keys: string[] = [] + for (const f of sec.fields || []) { + const k = String(f?.key ?? '').trim() + if (!k) continue + keys.push(k) + } + const cnt = new Map() + for (const k of keys) cnt.set(k, (cnt.get(k) || 0) + 1) + const dups = [...cnt.entries()].filter(([, c]) => c > 1).map(([k]) => k) + if (dups.length) msgs.push(`${t('message.pages.miscprocurement.cost_template.duplicateFieldKey', { title })}:${dups.join('、')}`) + } + return msgs + } + const merged = new Set([...scan(latestSectionDraft), ...scan(form?.sections)]) + const parts = [...merged].filter(Boolean) + if (parts.length) { + return { ok: false, message: `${parts.join(';')},${t('message.pages.miscprocurement.cost_template.pleaseModifyAndSave')}` } + } + return { ok: true } + } + + const doValidateItemNamesCn = (form: any): { ok: true } | { ok: false; message: string } => { + const sections = normalizeSections(resolveSectionsForSubmit(form)) + const allowTitles = doVisibleTitles(form.procurement_category, (form.is_bom || 'Y') === 'Y') + const msgs: string[] = [] + for (const sec of sections) { + if (!sec || sec.enabled === false) continue + const title = sec.title || sec.name || '' + if (allowTitles.length && !allowTitles.includes(title)) continue + const badKeys: string[] = [] + for (const f of sec.fields || []) { + if (!fieldDisplayNameCn(f)) { + const k = String(f?.key ?? '').trim() + badKeys.push(k || `(${t('message.pages.miscprocurement.cost_template.keyNotFilled')})`) + } + } + if (badKeys.length) msgs.push(`${t('message.pages.miscprocurement.cost_template.fieldNameNotFilled', { title })}(${t('message.pages.miscprocurement.cost_template.fieldKey')}: ${badKeys.join('、')})`) + } + if (msgs.length) { + return { ok: false, message: `${msgs.join(';')},${t('message.pages.miscprocurement.cost_template.pleaseCompleteAndSave')}` } + } + return { ok: true } + } + + const doValidateCostTemplateBeforeSubmit = (form: any): { ok: true } | { ok: false; message: string } => { + const issues: string[] = [] + const dup = doValidateDuplicateFieldKeys(form) + if (!dup.ok) issues.push(dup.message.replace(new RegExp(`,${t('message.pages.miscprocurement.cost_template.pleaseModifyAndSave')}$`), '')) + const cn = doValidateItemNamesCn(form) + if (!cn.ok) issues.push(cn.message.replace(new RegExp(`,${t('message.pages.miscprocurement.cost_template.pleaseCompleteAndSave')}$`), '')) + if (issues.length) { + return { ok: false, message: `${issues.join(';')},${t('message.pages.miscprocurement.cost_template.pleaseModifyAndSave')}` } + } + return { ok: true } + } + + const doRefreshSectionsIfNeeded = (form: any, overrides: any = {}) => { + const titles = doVisibleTitles( + overrides.procurement_category ?? form?.procurement_category, + overrides.enable_cost_structure ?? (form?.is_bom || 'Y') === 'Y' + ) + const procurementCategory = overrides.procurement_category ?? form?.procurement_category + const sections = makeBaseSections() + // Ensure all sections exist + const existing = normalizeSections(form?.sections) + const map = new Map() + existing.forEach((s: any) => { + const key = normalizeTitleKey(s?.title || s?.name) + if (key) map.set(key, s) + }) + sections.forEach((base) => { + if (!map.has(base.title)) { + map.set(base.title, deepCopy(base)) + } + }) + const arr = Array.from(map.values()) + // Always replace built-in materials/process fields by procurement category + const materials = arr.find((s: any) => s?.title === t('message.pages.miscprocurement.cost_template.materials')) + if (materials) { + const getMaterialsFields = makeGetMaterialsFields() + replaceBuiltInFields(materials, deepCopy(getMaterialsFields(procurementCategory))) + } + const process = arr.find((s: any) => s?.title === t('message.pages.miscprocurement.cost_template.process')) + if (process) { + const getProcessFields = makeGetProcessFields() + replaceBuiltInFields(process, deepCopy(getProcessFields(procurementCategory))) + } + if (titles.length) { + applyEnabledFlags(arr, titles) + } + form.sections = arr + form.__visibleTitles = titles + if (Array.isArray(form.sections)) { + (form.sections as any).__visibleTitles = titles + } + latestSectionDraft = normalizeSections(form.sections) + logPT('refreshSections', { + procurement_category: overrides.procurement_category ?? form?.procurement_category, + enable_cost_structure: overrides.enable_cost_structure ?? (form?.is_bom || 'Y') === 'Y', + titles, + sectionsCount: Array.isArray(form.sections) ? form.sections.length : 0, + draftSectionsCount: latestSectionDraft.length + }) + } + + const procurementDictLocalized = [ + { value: '1', label: t('message.pages.miscprocurement.cost_template.procurementStrategic') }, + { value: '2', label: t('message.pages.miscprocurement.cost_template.procurementMisc') } + ] + return { crudOptions: { form: { @@ -628,15 +836,15 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp group: { type: 'tab', base: { - label: '基础信息', + label: t('message.pages.miscprocurement.cost_template.basicInfo'), columns: ['template_name', 'procurement_category', 'version', 'template_desc'] }, controls: { - label: '启用设置', + label: t('message.pages.miscprocurement.cost_template.controls'), columns: ['acti', 'is_bom'] }, sections: { - label: '成本结构', + label: t('message.pages.miscprocurement.cost_template.sections'), columns: ['sections'] } }, @@ -644,7 +852,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp if (ctx.mode === 'add') { // 版本变更:由 openAdd 预填完整 sections/items;勿 refreshSectionsIfNeeded(会再走 replaceBuiltInFields,且易与预填冲突) if (ctx.form?.__newVersionSourceId != null && ctx.form.__newVersionSourceId !== '') { - const vis = visibleTitles(ctx.form.procurement_category, (ctx.form.is_bom || 'Y') === 'Y') + const vis = doVisibleTitles(ctx.form.procurement_category, (ctx.form.is_bom || 'Y') === 'Y') ctx.form.__visibleTitles = vis if (Array.isArray(ctx.form.sections)) { ;(ctx.form.sections as any).__visibleTitles = vis @@ -658,7 +866,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp if (ctx.form.version == null || ctx.form.version === '') { ctx.form.version = 1 } - refreshSectionsIfNeeded(ctx.form) + doRefreshSectionsIfNeeded(ctx.form) latestSectionDraft = normalizeSections(ctx.form.sections) return } @@ -671,7 +879,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp Object.assign(ctx.form, detail) if (Array.isArray(detail.items)) { const secs = itemsToSections(detail.items, detail) - const vis = visibleTitles(detail.procurement_category, (detail.is_bom || 'Y') === 'Y') + const vis = doVisibleTitles(detail.procurement_category, (detail.is_bom || 'Y') === 'Y') ;(secs as any).__visibleTitles = vis ctx.form.sections = secs ctx.form.__visibleTitles = vis @@ -679,7 +887,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp } } } catch (e) { - console.warn('加载成本模板详情失败', e) + console.warn(t('message.pages.miscprocurement.cost_template.loadDetailFailed'), e) } } }, @@ -687,7 +895,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp request: { pageRequest: async (query) => api.GetList(query), addRequest: async ({ form }) => { - const pre = validateCostTemplateBeforeSubmit(form) + const pre = doValidateCostTemplateBeforeSubmit(form) if (!pre.ok) { ElMessage.error(pre.message) return Promise.reject(new Error(pre.message)) @@ -715,7 +923,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp }) }, editRequest: async ({ form, row }) => { - const pre = validateCostTemplateBeforeSubmit(form) + const pre = doValidateCostTemplateBeforeSubmit(form) if (!pre.ok) { ElMessage.error(pre.message) return Promise.reject(new Error(pre.message)) @@ -764,32 +972,32 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp show: false }, confirm: { - text: '确认', - title: '确认', + text: t('message.pages.miscprocurement.cost_template.confirm'), + title: t('message.pages.miscprocurement.cost_template.confirm'), type: 'success', order: 4, show: compute(({ row }) => templateStatusUnconfirmed(row)), async click({ row }: { row: any }) { try { - await ElMessageBox.confirm('确认将模板设为「已确认」状态?', '确认', { + await ElMessageBox.confirm(t('message.pages.miscprocurement.cost_template.confirmStatusTip'), t('message.pages.miscprocurement.cost_template.confirm'), { type: 'warning', - confirmButtonText: '确定', - cancelButtonText: '取消' + confirmButtonText: t('message.pages.miscprocurement.cost_template.confirmButtonText'), + cancelButtonText: t('message.pages.miscprocurement.cost_template.cancelButtonText') }) const cres: any = await api.ConfirmObj(row.id) - const okMsg = cres?.data?.msg || cres?.msg || '确认成功' + const okMsg = cres?.data?.msg || cres?.msg || t('message.pages.miscprocurement.cost_template.confirmSuccess') ElMessage.success(okMsg) crudExpose?.doRefresh?.() } catch (e: any) { if (e === 'cancel' || e === 'close') return - const msg = e?.response?.data?.msg || e?.message || '确认失败' + const msg = e?.response?.data?.msg || e?.message || t('message.pages.miscprocurement.cost_template.confirmFailed') ElMessage.error(msg) } } }, newVersion: { - text: '版本变更', - title: '版本变更', + text: t('message.pages.miscprocurement.cost_template.newVersion'), + title: t('message.pages.miscprocurement.cost_template.newVersion'), type: 'primary', order: 5, show: compute(({ row }) => templateStatusConfirmed(row)), @@ -798,7 +1006,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp const res: any = await api.GetObj(row.id) const detail = res?.data?.data || res?.data || res if (!detail || typeof detail !== 'object') { - ElMessage.error('加载模板详情失败') + ElMessage.error(t('message.pages.miscprocurement.cost_template.loadDetailFailed')) return } const nextV = Number(detail.version) + 1 @@ -812,7 +1020,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp // 必须用源模板版本过滤明细;勿把 version 设为 nextV,否则 itemsToSections 会筛掉全部旧版行 const headForSections = { ...detail, __itemsSourceVersion: sourceVer } const secs = itemsToSections(itemsStripped, headForSections) - const vis = visibleTitles(detail.procurement_category, (detail.is_bom || 'Y') === 'Y') + const vis = doVisibleTitles(detail.procurement_category, (detail.is_bom || 'Y') === 'Y') ;(secs as any).__visibleTitles = vis await crudExpose?.openAdd?.( { @@ -834,10 +1042,10 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp items: itemsStripped } }, - { title: '版本变更' } + { title: t('message.pages.miscprocurement.cost_template.newVersion') } ) } catch (e: any) { - const msg = e?.response?.data?.msg || e?.message || '版本变更失败' + const msg = e?.response?.data?.msg || e?.message || t('message.pages.miscprocurement.cost_template.newVersionFailed') ElMessage.error(msg) } } @@ -846,42 +1054,42 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp }, columns: { template_name: { - title: '模板名称', + title: t('message.pages.miscprocurement.cost_template.templateName'), type: 'input', search: { show: true, component: { - props: { placeholder: '请输入模板名称', clearable: true } + props: { placeholder: t('message.pages.miscprocurement.cost_template.inputTemplateName'), clearable: true } } }, form: { col: { span: 12 }, - rules: [{ required: true, message: '请输入模板名称' }] + rules: [{ required: true, message: t('message.pages.miscprocurement.cost_template.inputTemplateName') }] }, column: { minWidth: 160 } }, template_no: { - title: '模板编号', + title: t('message.pages.miscprocurement.cost_template.templateNo'), type: 'input', search: { show: true, - component: { props: { placeholder: '模板编号', clearable: true } } + component: { props: { placeholder: t('message.pages.miscprocurement.cost_template.templateNo'), clearable: true } } }, form: { show: false }, column: { width: 160, showOverflowTooltip: true } }, procurement_category: { - title: '采购类别', + title: t('message.pages.miscprocurement.cost_template.procurementCategory'), type: 'dict-select', - dict: dict({ data: procurementDict }), + dict: dict({ data: procurementDictLocalized }), column: { width: 120 }, search: { show: true }, form: { col: { span: 12 }, value: '2', - rules: [{ required: true, message: '请选择采购类别' }], + rules: [{ required: true, message: t('message.pages.miscprocurement.cost_template.selectProcurementCategory') }], valueChange({ form, value }) { - refreshSectionsIfNeeded(form, { procurement_category: value }) + doRefreshSectionsIfNeeded(form, { procurement_category: value }) logPT('onChange procurement_category', value, { visibleTitles: form.__visibleTitles }) logPT('sections titles now', Array.isArray(form.sections) ? form.sections.map((s: any) => s.title) : []) } @@ -891,36 +1099,36 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp } }, acti: { - title: '有效', + title: t('message.pages.miscprocurement.cost_template.acti'), type: 'dict-select', dict: dict({ data: [ - { value: 'Y', label: '是' }, - { value: 'N', label: '否' } + { value: 'Y', label: t('message.pages.miscprocurement.cost_template.actiYes') }, + { value: 'N', label: t('message.pages.miscprocurement.cost_template.actiNo') } ] }), column: { width: 90 }, search: { show: true }, form: { value: 'Y' } }, is_bom: { - title: '启用BOM', + title: t('message.pages.miscprocurement.cost_template.isBom'), type: 'dict-select', dict: dict({ data: [ - { value: 'Y', label: '是' }, - { value: 'N', label: '否' } + { value: 'Y', label: t('message.pages.miscprocurement.cost_template.bomYes') }, + { value: 'N', label: t('message.pages.miscprocurement.cost_template.bomNo') } ] }), column: { width: 100 }, search: { show: true }, form: { value: 'Y', valueChange({ form, value }) { - refreshSectionsIfNeeded(form, { enable_cost_structure: value === 'Y' }) + doRefreshSectionsIfNeeded(form, { enable_cost_structure: value === 'Y' }) logPT('onChange is_bom', value, { visibleTitles: form.__visibleTitles }) logPT('sections titles now', Array.isArray(form.sections) ? form.sections.map((s: any) => s.title) : []) } } }, template_desc: { - title: '备注', + title: t('message.pages.miscprocurement.cost_template.templateDesc'), type: 'textarea', column: { minWidth: 180, showOverflowTooltip: true }, form: { @@ -929,7 +1137,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp } }, version: { - title: '版本号', + title: t('message.pages.miscprocurement.cost_template.version'), type: 'number', column: { width: 100 }, form: { @@ -941,18 +1149,18 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp } }, status: { - title: '状态', + title: t('message.pages.miscprocurement.cost_template.status'), type: 'dict-select', dict: dict({ data: [ - { value: '0', label: '未确认' }, - { value: '1', label: '已确认' }, - { value: '2', label: '作废' } + { value: '0', label: t('message.pages.miscprocurement.cost_template.statusUnconfirmed') }, + { value: '1', label: t('message.pages.miscprocurement.cost_template.statusConfirmed') }, + { value: '2', label: t('message.pages.miscprocurement.cost_template.statusCancelled') } ] }), search: { show: true, - component: { props: { clearable: true, placeholder: '状态(默认不含作废)' } } + component: { props: { clearable: true, placeholder: t('message.pages.miscprocurement.cost_template.statusPlaceholder') } } }, form: { show: false }, column: { width: 100 } @@ -977,7 +1185,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp } }, value: () => { - const vis = visibleTitles('2', true) + const vis = doVisibleTitles('2', true) const defaults = ensureAllSections({ sections: buildDefaultSections('2') }, vis, '2') ;(defaults as any).__visibleTitles = vis return defaults @@ -991,7 +1199,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp // 否则会把数据库里的 is_computed 等真实值覆盖成前端预设默认值。 if (Array.isArray(form.items) && form.items.length) { const secs = itemsToSections(form.items, form) - const vis = visibleTitles(form.procurement_category, (form.is_bom || 'Y') === 'Y') + const vis = doVisibleTitles(form.procurement_category, (form.is_bom || 'Y') === 'Y') ;(secs as any).__visibleTitles = vis form.sections = secs form.__visibleTitles = vis @@ -999,7 +1207,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp logPT('valueBuilder(items)', { visibleTitles: form.__visibleTitles, sections: form.sections?.length, items: form.items.length }) return } - const vis = visibleTitles(form.procurement_category, (form.is_bom || 'Y') === 'Y') + const vis = doVisibleTitles(form.procurement_category, (form.is_bom || 'Y') === 'Y') const ensured = ensureAllSections(form, vis, form.procurement_category) ;(ensured as any).__visibleTitles = vis form.sections = ensured @@ -1019,7 +1227,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp // 初次回填时(尚未形成 sections),再从 items 转换 if (Array.isArray(form.items) && form.items.length) { const secs = itemsToSections(form.items, form) - const vis = visibleTitles(form.procurement_category, (form.is_bom || 'Y') === 'Y') + const vis = doVisibleTitles(form.procurement_category, (form.is_bom || 'Y') === 'Y') ;(secs as any).__visibleTitles = vis form.sections = secs form.__visibleTitles = vis @@ -1034,7 +1242,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp } }, update_time: { - title: '更新时间', + title: t('message.pages.miscprocurement.cost_template.updateTime'), type: 'datetime', form: { show: false }, column: { width: 180 } diff --git a/web/src/views/pisadmin/miscprocurement/misc_materials/crud.tsx b/web/src/views/pisadmin/miscprocurement/misc_materials/crud.tsx index a64e83c..ac72eab 100644 --- a/web/src/views/pisadmin/miscprocurement/misc_materials/crud.tsx +++ b/web/src/views/pisadmin/miscprocurement/misc_materials/crud.tsx @@ -1,12 +1,8 @@ import { dict, CreateCrudOptionsProps, CreateCrudOptionsRet } from '@fast-crud/fast-crud' +import { useI18n } from 'vue-i18n' import * as api from './api' import { GetCompanies } from '../../basicinfo/currency/api' -const statusDict = [ - { value: 1, label: '可用' }, - { value: 0, label: '不可用' } -] - const loadCompanyOptions = async () => { try { const res = await GetCompanies({ page: 1, page_size: 1000, pageSize: 1000 }) @@ -32,6 +28,13 @@ void loadCompanyOptions() export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet { void crudExpose + const { t } = useI18n() + + const statusDict = [ + { value: 1, label: t('message.pages.miscprocurement.misc_materials.statusEnabled') }, + { value: 0, label: t('message.pages.miscprocurement.misc_materials.statusDisabled') } + ] + return { crudOptions: { form: { @@ -56,7 +59,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp }, columns: { factory: { - title: '交易厂区', + title: t('message.pages.miscprocurement.misc_materials.companyCode'), type: 'dict-select', dict: dict({ cache: false, @@ -70,25 +73,28 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp column: { minWidth: 160, showOverflowTooltip: true } }, materialtype: { - title: '材质', + title: t('message.pages.miscprocurement.misc_materials.materialtype'), type: 'input', - search: { show: true, component: { props: { placeholder: '请输入材质', clearable: true } } }, + search: { + show: true, + component: { props: { placeholder: t('message.pages.miscprocurement.misc_materials.materialtype'), clearable: true } } + }, column: { minWidth: 160, showOverflowTooltip: true } }, density: { - title: '比重', + title: t('message.pages.miscprocurement.misc_materials.density'), type: 'input', - form: { rules: [{ required: true, message: '请输入比重' }] }, + form: { rules: [{ required: true, message: t('message.pages.miscprocurement.misc_materials.density') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, column: { width: 120, showOverflowTooltip: true } }, price: { - title: '单价', + title: t('message.pages.miscprocurement.misc_materials.price'), type: 'number', - form: { rules: [{ required: true, message: '请输入单价' }], component: { props: { precision: 2 } } }, + form: { rules: [{ required: true, message: t('message.pages.miscprocurement.misc_materials.price') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }], component: { props: { precision: 2 } } }, column: { width: 120 } }, status: { - title: '可用状态', + title: t('message.pages.miscprocurement.misc_materials.status'), type: 'dict-switch', dict: dict({ data: statusDict }), form: { value: 1 }, diff --git a/web/src/views/pisadmin/miscprocurement/misc_stations/crud.tsx b/web/src/views/pisadmin/miscprocurement/misc_stations/crud.tsx index f33d173..210d45b 100644 --- a/web/src/views/pisadmin/miscprocurement/misc_stations/crud.tsx +++ b/web/src/views/pisadmin/miscprocurement/misc_stations/crud.tsx @@ -3,16 +3,7 @@ import * as api from './api' import { GetCompanies } from '../../basicinfo/currency/api' import { GetList as GetUnits } from '../../basicinfo/unit/api' import { ElMessage } from 'element-plus' - -const statusDict = [ - { value: 1, label: '可用' }, - { value: 0, label: '不可用' } -] - -const stationTypeDict = [ - { value: 1, label: '模治具' }, - { value: 2, label: '石墨' } -] +import { useI18n } from 'vue-i18n' const loadCompanyOptions = async () => { try { @@ -59,6 +50,18 @@ const loadUnitOptions = async () => { void loadCompanyOptions() export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet { + const { t } = useI18n() + + const statusDict = [ + { value: 1, label: t('message.pages.miscprocurement.misc_stations.statusEnabled') }, + { value: 0, label: t('message.pages.miscprocurement.misc_stations.statusDisabled') } + ] + + const stationTypeDict = [ + { value: 1, label: t('message.pages.miscprocurement.misc_stations.typeTooling') }, + { value: 2, label: t('message.pages.miscprocurement.misc_stations.typeGraphite') } + ] + void crudExpose const ensureStationCodeUnique = async (companyCode: string, stationCode: string, currentId?: number) => { @@ -76,7 +79,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp ? list.find((item: any) => item.company_code === companyCode && item.stationcode === stationCode) : null if (exists && (!currentId || exists.id !== currentId)) { - throw new Error('同一交易厂区下工站代码已存在,不可重复') + throw new Error(t('message.pages.miscprocurement.misc_stations.companyCode') + t('message.pages.miscprocurement.misc_stations.stationcode') + t('message.pages.menu.validation.alreadyExists')) } } return { @@ -119,7 +122,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp }, columns: { company_code: { - title: '交易厂区', + title: t('message.pages.miscprocurement.misc_stations.companyCode'), type: 'dict-select', dict: dict({ cache: false, @@ -131,47 +134,47 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp column: { minWidth: 160, showOverflowTooltip: true } }, stationcode: { - title: '工站代码', + title: t('message.pages.miscprocurement.misc_stations.stationcode'), type: 'input', - search: { show: true, component: { props: { placeholder: '请输入工站代码', clearable: true } } }, - form: { rules: [{ required: true, message: '请输入工站代码' }] }, + search: { show: true, component: { props: { placeholder: t('message.pages.miscprocurement.misc_stations.stationcode'), clearable: true } } }, + form: { rules: [{ required: true, message: t('message.pages.miscprocurement.misc_stations.stationcode') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, editForm: { component: { props: { disabled: true } } }, column: { minWidth: 140, showOverflowTooltip: true } }, stationname: { - title: '工站名称', + title: t('message.pages.miscprocurement.misc_stations.stationname'), type: 'input', - search: { show: true, component: { props: { placeholder: '请输入工站名称', clearable: true } } }, - form: { rules: [{ required: true, message: '请输入工站名称' }] }, + search: { show: true, component: { props: { placeholder: t('message.pages.miscprocurement.misc_stations.stationname'), clearable: true } } }, + form: { rules: [{ required: true, message: t('message.pages.miscprocurement.misc_stations.stationname') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, column: { minWidth: 160, showOverflowTooltip: true } }, stationtype: { - title: '工站类型', + title: t('message.pages.miscprocurement.misc_stations.stationtype'), type: 'dict-select', dict: dict({ data: stationTypeDict }), - form: { rules: [{ required: true, message: '请选择工站类型' }] }, + form: { rules: [{ required: true, message: t('message.pages.miscprocurement.misc_stations.stationtype') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, column: { width: 140, showOverflowTooltip: true } }, unit: { - title: '计量单位', + title: t('message.pages.miscprocurement.misc_stations.unit'), type: 'dict-select', dict: dict({ cache: false, getData: async () => loadUnitOptions() }), - form: { rules: [{ required: true, message: '请选择计量单位' }] }, + form: { rules: [{ required: true, message: t('message.pages.miscprocurement.misc_stations.unit') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, column: { width: 140, showOverflowTooltip: true } }, rate: { - title: '费率', + title: t('message.pages.miscprocurement.misc_stations.rate'), type: 'number', - form: { rules: [{ required: true, message: '请输入费率' }], component: { props: { precision: 2 } } }, + form: { rules: [{ required: true, message: t('message.pages.miscprocurement.misc_stations.rate') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }], component: { props: { precision: 2 } } }, column: { width: 120 } }, status: { - title: '可用状态', + title: t('message.pages.miscprocurement.misc_stations.status'), type: 'dict-switch', dict: dict({ data: statusDict }), form: { value: 1 }, diff --git a/web/src/views/pisadmin/miscprocurement/rfqmiscellaneous/crud.tsx b/web/src/views/pisadmin/miscprocurement/rfqmiscellaneous/crud.tsx index 7f25b6d..dc459f1 100644 --- a/web/src/views/pisadmin/miscprocurement/rfqmiscellaneous/crud.tsx +++ b/web/src/views/pisadmin/miscprocurement/rfqmiscellaneous/crud.tsx @@ -1,37 +1,8 @@ import { compute, dict, CreateCrudOptionsProps, CreateCrudOptionsRet } from '@fast-crud/fast-crud' import { ElMessage, ElMessageBox } from 'element-plus' +import { useI18n } from 'vue-i18n' import * as api from './api' -const statusDict = [ - { value: 1, label: '开立' }, - { value: 2, label: '确认' }, - { value: 3, label: '发布' }, - { value: 4, label: '报价中' }, - { value: 5, label: '报价结束' }, - { value: 6, label: '比议价中' }, - { value: 7, label: '价格审核' }, - { value: 8, label: '核价通过(结束)' }, - { value: 9, label: '落标(结束)' }, - { value: 0, label: '作废' } -] - -const buyingMethodDict = [ - { value: 1, label: '询价' }, - { value: 2, label: '招标' } -] - -const paymentMethods = [ - { value: 1, label: '月结30天' }, - { value: 2, label: '月结60天' }, - { value: 3, label: '不到付款' }, - { value: 4, label: '预付30%' }, - { value: 5, label: '预付50%' }, - { value: 6, label: '余款至生产' }, - { value: 7, label: '价格审核' }, - { value: 8, label: '价格结算(运费)' }, - { value: 9, label: '新建(结束)' } -] - const formatQuoteDeadlineDisplay = (value: unknown) => { if (!value) return '' const text = String(value).trim() @@ -950,6 +921,38 @@ export const createCrudOptions = function ({ }: Partial & ExtraHooks): CreateCrudOptionsRet { void context + const { t } = useI18n() + + const statusDict = [ + { value: 1, label: t('message.pages.miscprocurement.rfqmiscellaneous.statusOpen') }, + { value: 2, label: t('message.pages.miscprocurement.rfqmiscellaneous.statusConfirmed') }, + { value: 3, label: t('message.pages.miscprocurement.rfqmiscellaneous.statusPublished') }, + { value: 4, label: t('message.pages.miscprocurement.rfqmiscellaneous.statusQuoting') }, + { value: 5, label: t('message.pages.miscprocurement.rfqmiscellaneous.statusQuotingEnd') }, + { value: 6, label: t('message.pages.miscprocurement.rfqmiscellaneous.statusBargaining') }, + { value: 7, label: t('message.pages.miscprocurement.rfqmiscellaneous.statusPriceAudit') }, + { value: 8, label: t('message.pages.miscprocurement.rfqmiscellaneous.statusPriceApproved') }, + { value: 9, label: t('message.pages.miscprocurement.rfqmiscellaneous.statusLost') }, + { value: 0, label: t('message.pages.miscprocurement.rfqmiscellaneous.statusCancelled') } + ] + + const buyingMethodDict = [ + { value: 1, label: t('message.pages.miscprocurement.rfqmiscellaneous.buyingMethodInquiry') }, + { value: 2, label: t('message.pages.miscprocurement.rfqmiscellaneous.buyingMethodBid') } + ] + + const paymentMethods = [ + { value: 1, label: t('message.pages.miscprocurement.rfqmiscellaneous.paymentMethod1') }, + { value: 2, label: t('message.pages.miscprocurement.rfqmiscellaneous.paymentMethod2') }, + { value: 3, label: t('message.pages.miscprocurement.rfqmiscellaneous.paymentMethod3') }, + { value: 4, label: t('message.pages.miscprocurement.rfqmiscellaneous.paymentMethod4') }, + { value: 5, label: t('message.pages.miscprocurement.rfqmiscellaneous.paymentMethod5') }, + { value: 6, label: t('message.pages.miscprocurement.rfqmiscellaneous.paymentMethod6') }, + { value: 7, label: t('message.pages.miscprocurement.rfqmiscellaneous.paymentMethod7') }, + { value: 8, label: t('message.pages.miscprocurement.rfqmiscellaneous.paymentMethod8') }, + { value: 9, label: t('message.pages.miscprocurement.rfqmiscellaneous.paymentMethod9') } + ] + const getSelectedRows = () => { if (typeof getTableSelection === 'function') { const rows = getTableSelection() @@ -976,11 +979,11 @@ export const createCrudOptions = function ({ const pickSelectedRow = (): any | null => { const rows = getSelectedRows() if (!rows.length) { - ElMessage.warning('请先选择询价单') + ElMessage.warning(t('message.pages.miscprocurement.rfqmiscellaneous.selectInquiryFirst')) return null } if (rows.length > 1) { - ElMessage.warning('仅支持单条操作') + ElMessage.warning(t('message.pages.miscprocurement.rfqmiscellaneous.onlySingleOperation')) return null } return rows[0] @@ -991,13 +994,13 @@ export const createCrudOptions = function ({ form: { labelWidth: '120px', col: { span: 12 }, - wrapper: { is: 'el-dialog', width: '960px', top: '6vh', title: '询价单' }, + wrapper: { is: 'el-dialog', width: '960px', top: '6vh', title: t('message.pages.miscprocurement.rfqmiscellaneous.title') }, group: { type: 'tab', - base: { label: '基础信息', columns: ['code', 'title', 'product_category', 'template', 'part_no', 'part_name', 'quote_deadline', 'purchase_qty', 'buyer', 'currency', 'plant', 'target_price', 'lead_time_days', 'payment_term', 'status', 'remark'] }, - cost: { label: '成本结构', columns: ['cost_items'] }, - vendors: { label: '供应商名单', columns: ['vendors'] }, - attachments: { label: '附件', columns: ['attachments'] } + base: { label: t('message.pages.miscprocurement.rfqmiscellaneous.basicInfo'), columns: ['code', 'title', 'product_category', 'template', 'part_no', 'part_name', 'quote_deadline', 'purchase_qty', 'buyer', 'currency', 'plant', 'target_price', 'lead_time_days', 'payment_term', 'status', 'remark'] }, + cost: { label: t('message.pages.miscprocurement.rfqmiscellaneous.costStructure'), columns: ['cost_items'] }, + vendors: { label: t('message.pages.miscprocurement.rfqmiscellaneous.supplierList'), columns: ['vendors'] }, + attachments: { label: t('message.pages.miscprocurement.rfqmiscellaneous.attachments'), columns: ['attachments'] } } }, request: { @@ -1009,7 +1012,7 @@ export const createCrudOptions = function ({ try { return await api.DelObj(row.id) } catch (err: any) { - ElMessage.error(getErrorMessage(err, '删除失败')) + ElMessage.error(getErrorMessage(err, t('message.pages.miscprocurement.rfqmiscellaneous.deleteFailed'))) throw err } } @@ -1024,28 +1027,28 @@ export const createCrudOptions = function ({ buttons: { add: { show: true, - text: '新建询价单', + text: t('message.pages.miscprocurement.rfqmiscellaneous.newInquiry'), click() { onAdd && onAdd() } }, startBargaining: { show: true, - text: '开启比价', + text: t('message.pages.miscprocurement.rfqmiscellaneous.startBargain'), order: 2, type: 'warning', async click() { const row = pickSelectedRow() if (!row) return if (!isQuotingOrEndedStatus(row)) { - ElMessage.warning('仅报价中或报价结束状态可开启比价') + ElMessage.warning(t('message.pages.miscprocurement.rfqmiscellaneous.onlyQuotingCanBargain')) return } try { - await ElMessageBox.confirm('确认将状态改为【比议价中】?', '提示', { + await ElMessageBox.confirm(t('message.pages.miscprocurement.rfqmiscellaneous.confirmBargainPrompt'), t('message.pages.miscprocurement.rfqmiscellaneous.prompt'), { type: 'warning', - confirmButtonText: '确定', - cancelButtonText: '取消' + confirmButtonText: t('message.pages.miscprocurement.rfqmiscellaneous.confirm'), + cancelButtonText: t('message.pages.miscprocurement.rfqmiscellaneous.cancel') }) await api.StartBargainingObj(row.id) await api.SaveNegotiationRecordsObj(row.id, { records: [] }) @@ -1054,7 +1057,7 @@ export const createCrudOptions = function ({ crudExpose?.doRefresh?.() } catch (err: any) { if (err === 'cancel' || err === 'close') return - ElMessage.error(getErrorMessage(err, '开启比价失败')) + ElMessage.error(getErrorMessage(err, t('message.pages.miscprocurement.rfqmiscellaneous.startBargainFailed'))) } } }, @@ -1067,7 +1070,7 @@ export const createCrudOptions = function ({ view: { show: false }, edit: { show: false }, remove: { - text: '删除', + text: t('message.pages.miscprocurement.rfqmiscellaneous.delete'), // 禁用时不沿用 danger 的淡红底,改为 info 灰底 + disabled type: compute(({ row }) => (isOpenStatus(row) ? 'danger' : 'info')), order: 1, @@ -1075,7 +1078,7 @@ export const createCrudOptions = function ({ disabled: compute(({ row }) => !isOpenStatus(row)) }, customView: { - text: '查看', + text: t('message.pages.miscprocurement.rfqmiscellaneous.view'), type: 'default', order: 0, show: true, @@ -1084,7 +1087,7 @@ export const createCrudOptions = function ({ } }, customEdit: { - text: '编辑', + text: t('message.pages.miscprocurement.rfqmiscellaneous.edit'), type: compute(({ row }) => (isOpenStatus(row) ? 'primary' : 'info')), order: 1.5, show: true, @@ -1095,7 +1098,7 @@ export const createCrudOptions = function ({ } }, confirm: { - text: '确认', + text: t('message.pages.miscprocurement.rfqmiscellaneous.confirm'), type: compute(({ row }) => (isOpenStatus(row) ? 'success' : 'info')), order: 2, show: true, @@ -1105,26 +1108,26 @@ export const createCrudOptions = function ({ try { const supplierOk = rowHasSuppliersList(row) if (supplierOk === false) { - ElMessage.warning('请先维护询价单供应商名单后再确认') + ElMessage.warning(t('message.pages.miscprocurement.rfqmiscellaneous.addSupplierFirst')) return } - await ElMessageBox.confirm('确认后,该询价单将锁定并不可再编辑。如需修改,后续需执行【还原】操作', '提示', { + await ElMessageBox.confirm(t('message.pages.miscprocurement.rfqmiscellaneous.confirmPrompt'), t('message.pages.miscprocurement.rfqmiscellaneous.prompt'), { type: 'warning', - confirmButtonText: '确定', - cancelButtonText: '取消' + confirmButtonText: t('message.pages.miscprocurement.rfqmiscellaneous.confirm'), + cancelButtonText: t('message.pages.miscprocurement.rfqmiscellaneous.cancel') }) const res = await api.ConfirmObj(row.id) crudExpose?.doRefresh?.() return res } catch (err: any) { if (err === 'cancel' || err === 'close') return - ElMessage.error(getErrorMessage(err, '确认失败')) + ElMessage.error(getErrorMessage(err, t('message.pages.miscprocurement.rfqmiscellaneous.confirmFailed'))) throw err } } }, restore: { - text: '还原', + text: t('message.pages.miscprocurement.rfqmiscellaneous.restore'), type: compute(({ row }) => (isConfirmedStatus(row) ? 'primary' : 'info')), order: 2.5, show: true, @@ -1132,23 +1135,23 @@ export const createCrudOptions = function ({ async click({ row }) { if (!isConfirmedStatus(row)) return try { - await ElMessageBox.confirm('确认将状态还原为【开立】?', '提示', { + await ElMessageBox.confirm(t('message.pages.miscprocurement.rfqmiscellaneous.restorePrompt'), t('message.pages.miscprocurement.rfqmiscellaneous.prompt'), { type: 'warning', - confirmButtonText: '确定', - cancelButtonText: '取消' + confirmButtonText: t('message.pages.miscprocurement.rfqmiscellaneous.confirm'), + cancelButtonText: t('message.pages.miscprocurement.rfqmiscellaneous.cancel') }) const res = await api.RestoreObj(row.id) crudExpose?.doRefresh?.() return res } catch (err: any) { if (err === 'cancel' || err === 'close') return - ElMessage.error(getErrorMessage(err, '还原失败')) + ElMessage.error(getErrorMessage(err, t('message.pages.miscprocurement.rfqmiscellaneous.restoreFailed'))) throw err } } }, publish: { - text: '发布', + text: t('message.pages.miscprocurement.rfqmiscellaneous.publish'), type: compute(({ row }) => (canPublishStatus(row) ? 'warning' : 'info')), order: 3, show: true, @@ -1156,23 +1159,23 @@ export const createCrudOptions = function ({ async click({ row }) { if (!canPublishStatus(row)) return try { - await ElMessageBox.confirm('确认将状态改为【发布】?', '提示', { + await ElMessageBox.confirm(t('message.pages.miscprocurement.rfqmiscellaneous.publishPrompt'), t('message.pages.miscprocurement.rfqmiscellaneous.prompt'), { type: 'warning', - confirmButtonText: '确定', - cancelButtonText: '取消' + confirmButtonText: t('message.pages.miscprocurement.rfqmiscellaneous.confirm'), + cancelButtonText: t('message.pages.miscprocurement.rfqmiscellaneous.cancel') }) const res = await api.PublishObj(row.id) crudExpose?.doRefresh?.() return res } catch (err: any) { if (err === 'cancel' || err === 'close') return - ElMessage.error(getErrorMessage(err, '发布失败')) + ElMessage.error(getErrorMessage(err, t('message.pages.miscprocurement.rfqmiscellaneous.publishFailed'))) throw err } } }, viewComparison: { - text: '比价', + text: t('message.pages.miscprocurement.rfqmiscellaneous.comparePrice'), type: compute(({ row }) => (canOpenComparison(row) ? 'primary' : 'info')), order: 0.25, show: true, @@ -1198,7 +1201,7 @@ export const createCrudOptions = function ({ } }, company_short_name: { - title: '交易厂区', + title: t('message.pages.miscprocurement.rfqmiscellaneous.companyShortName'), type: 'text', form: { show: false }, search: { show: false }, @@ -1212,12 +1215,12 @@ export const createCrudOptions = function ({ } }, buying_method: { - title: '采购方式', + title: t('message.pages.miscprocurement.rfqmiscellaneous.buyingMethod'), type: 'dict-select', dict: dict({ data: buyingMethodDict }), search: { show: true, - component: { props: { placeholder: '采购方式', clearable: true } } + component: { props: { placeholder: t('message.pages.miscprocurement.rfqmiscellaneous.buyingMethod'), clearable: true } } }, form: { show: false }, column: { @@ -1231,11 +1234,11 @@ export const createCrudOptions = function ({ } }, inquiry_no: { - title: '询价单号', + title: t('message.pages.miscprocurement.rfqmiscellaneous.inquiryNo'), type: 'input', search: { show: true, - component: { props: { placeholder: '请输入询价单号', clearable: true } } + component: { props: { placeholder: t('message.pages.miscprocurement.rfqmiscellaneous.inquiryNoPlaceholder'), clearable: true } } }, form: { show: false @@ -1243,17 +1246,17 @@ export const createCrudOptions = function ({ column: { minWidth: 120, showOverflowTooltip: true } }, title: { - title: '询价单名称', + title: t('message.pages.miscprocurement.rfqmiscellaneous.inquiryName'), type: 'input', search: { show: true, - component: { props: { placeholder: '请输入询价单名称', clearable: true } } + component: { props: { placeholder: t('message.pages.miscprocurement.rfqmiscellaneous.inquiryNamePlaceholder'), clearable: true } } }, - form: { rules: [{ required: true, message: '请输入询价单名称' }] }, + form: { rules: [{ required: true, message: t('message.pages.miscprocurement.rfqmiscellaneous.inquiryNameRequired') }] }, column: { minWidth: 160, showOverflowTooltip: true } }, template: { - title: '询价模版', + title: t('message.pages.miscprocurement.rfqmiscellaneous.inquiryTemplate'), type: 'input', column: { minWidth: 120, @@ -1268,7 +1271,7 @@ export const createCrudOptions = function ({ } }, quote_deadline: { - title: '报价截止时间', + title: t('message.pages.miscprocurement.rfqmiscellaneous.quoteDeadline'), type: 'datetime', column: { width: 150, @@ -1276,7 +1279,7 @@ export const createCrudOptions = function ({ } }, bid_start_time: { - title: '投标开始时间', + title: t('message.pages.miscprocurement.rfqmiscellaneous.bidStartTime'), type: 'datetime', column: { width: 150, @@ -1285,7 +1288,7 @@ export const createCrudOptions = function ({ } }, bid_end_time: { - title: '投标截止时间', + title: t('message.pages.miscprocurement.rfqmiscellaneous.bidEndTime'), type: 'datetime', column: { width: 150, @@ -1294,17 +1297,17 @@ export const createCrudOptions = function ({ } }, buyer: { - title: '采购负责人', + title: t('message.pages.miscprocurement.rfqmiscellaneous.buyer'), type: 'input', search: { show: true, - component: { props: { placeholder: '请输入采购负责人', clearable: true } } + component: { props: { placeholder: t('message.pages.miscprocurement.rfqmiscellaneous.buyerPlaceholder'), clearable: true } } }, - form: { rules: [{ required: true, message: '请输入采购负责人' }] }, + form: { rules: [{ required: true, message: t('message.pages.miscprocurement.rfqmiscellaneous.buyerRequired') }] }, column: { minWidth: 120 } }, currency: { - title: '币别', + title: t('message.pages.miscprocurement.rfqmiscellaneous.currency'), type: 'dict-select', dict: dict({ data: [ { value: 'CNY', label: 'CNY' }, @@ -1314,32 +1317,32 @@ export const createCrudOptions = function ({ form: { value: 'CNY' } }, lead_time_days: { - title: '交货周期(天)', + title: t('message.pages.miscprocurement.rfqmiscellaneous.leadTimeDays'), type: 'number', column: { width: 120 }, form: { component: { props: { precision: 0 } } } }, payment_method: { - title: '付款方式', + title: t('message.pages.miscprocurement.rfqmiscellaneous.paymentMethod'), type: 'dict-select', dict: dict({ data: paymentMethods }), column: { width: 140, showOverflowTooltip: true }, form: { show: false } }, status: { - title: '状态', + title: t('message.pages.miscprocurement.rfqmiscellaneous.status'), type: 'dict-select', dict: dict({ data: statusDict }), column: { width: 140 } }, remark: { - title: '备注', + title: t('message.pages.miscprocurement.rfqmiscellaneous.remark'), type: 'textarea', column: { minWidth: 180, showOverflowTooltip: true }, form: { component: { props: { rows: 3 } } } }, update_datetime: { - title: '更新时间', + title: t('message.pages.miscprocurement.rfqmiscellaneous.updateTime'), type: 'datetime', form: { show: false }, column: { width: 180 } diff --git a/web/src/views/pissupplier/quotation/crud.tsx b/web/src/views/pissupplier/quotation/crud.tsx index 0fc2e35..4ad2c99 100644 --- a/web/src/views/pissupplier/quotation/crud.tsx +++ b/web/src/views/pissupplier/quotation/crud.tsx @@ -1,5 +1,6 @@ import { computed, onMounted, reactive, ref } from 'vue' import { ElMessage } from 'element-plus' +import { useI18n } from 'vue-i18n' import * as api from './api' import * as inquiryApi from '../../pisadmin/miscprocurement/rfqmiscellaneous/api' import { GetList as GetCostTemplateList } from '../../pisadmin/miscprocurement/cost_template/api' @@ -142,15 +143,15 @@ export function isWithinSupplierBidWindow(row: any, nowMs: number = Date.now()) } /** 非招标或未超限返回 null;否则返回提示文案(列表按钮禁用、openQuote/submit 前置校验) */ -export function getSupplierBidWindowRejectReason(row: any, nowMs: number = Date.now()): string | null { +export function getSupplierBidWindowRejectReason(row: any, nowMs: number = Date.now(), t?: Function): string | null { if (!isBuyingMethodBidding(row)) return null const start = parseQuoteDeadlineToMs(row?.bidStartTime ?? row?.bid_start_time) const end = parseQuoteDeadlineToMs(row?.bidEndTime ?? row?.bid_end_time) if (!Number.isFinite(start) || !Number.isFinite(end)) { - return '招标项目缺少投标开始或截止时间,无法报价或提交' + return t ? t('message.pages.pissupplier.quotation.bidWindowMissing') : '招标项目缺少投标开始或截止时间,无法报价或提交' } // if (nowMs < start) return '投标尚未开始,请在投标开始后再报价或提交' - if (nowMs > end) return '已超过投标截止时间,无法报价或提交' + if (nowMs > end) return t ? t('message.pages.pissupplier.quotation.bidWindowExpired') : '已超过投标截止时间,无法报价或提交' return null } @@ -195,22 +196,23 @@ export type InquiryAttachmentRow = { } /** 与 `pis_proc_inquiry_attachment` / 询价单 `attachments` 嵌套结构一致(勿用报价单 `attachments`) */ -const INQUIRY_FILE_TYPE_LABELS: Record = { - 1: '产品图纸', - 2: '招标文件', - 3: '其它文件' -} +const getInquiryFileTypeLabels = (t: Function) => ({ + 1: t('message.pages.pissupplier.quotation.fileTypeDrawing'), + 2: t('message.pages.pissupplier.quotation.fileTypeBidDoc'), + 3: t('message.pages.pissupplier.quotation.fileTypeOther') +}) -export function mapInquiryAttachmentsFromInquiryApi(rows: any[] | null | undefined): InquiryAttachmentRow[] { +export function mapInquiryAttachmentsFromInquiryApi(rows: any[] | null | undefined, t?: Function): InquiryAttachmentRow[] { if (!Array.isArray(rows) || !rows.length) return [] + const labels = t ? getInquiryFileTypeLabels(t) : { 1: '产品图纸', 2: '招标文件', 3: '其它文件' } return rows.map((r) => { const ft = Number(r.file_type) - const t = ft === 1 || ft === 2 || ft === 3 ? ft : 3 + const tf = ft === 1 || ft === 2 || ft === 3 ? ft : 3 return { id: r.id, part_id: r.part_id, - file_type: t, - file_type_label: r.file_type_label || INQUIRY_FILE_TYPE_LABELS[t], + file_type: tf, + file_type_label: r.file_type_label || labels[tf], file_name: r.file_name, file_path: r.file_path, upload_time: r.upload_time, @@ -285,11 +287,11 @@ function normalizeQuotationAttachmentsForUpload(rows: any[] | null | undefined): })) } -const statusOptions = [ - { label: '待报价', value: 'pending' }, - { label: '报价中', value: 'quoted' }, - { label: '已报价', value: 'completed' }, - { label: '已过期', value: 'expired' } +const getStatusOptions = (t: Function) => [ + { label: t('message.pages.pissupplier.quotation.statusPending'), value: 'pending' }, + { label: t('message.pages.pissupplier.quotation.statusQuoting'), value: 'quoted' }, + { label: t('message.pages.pissupplier.quotation.statusCompleted'), value: 'completed' }, + { label: t('message.pages.pissupplier.quotation.statusExpired'), value: 'expired' } ] const statusMapBackendToFront: Record = { @@ -321,7 +323,7 @@ export function formatAwardBidStatus(row: { statusCode?: number | string status?: QuoteStatus inquiryStatusCode?: number | string | null -}): { mode: 'flag'; text: string } | { mode: 'text'; text: string } { +}, t?: Function): { mode: 'flag'; text: string } | { mode: 'text'; text: string } { const ia = Number(row.isAwarded ?? row.is_awarded ?? 0) === 1 ? 1 : 0 let sc: number if (row.statusCode !== undefined && row.statusCode !== null && row.statusCode !== '') { @@ -333,13 +335,13 @@ export function formatAwardBidStatus(row: { const inqNum = inqRaw === undefined || inqRaw === null || inqRaw === '' ? NaN : Number(inqRaw) if (sc === 4) return { mode: 'text', text: '' } - if (ia === 1) return { mode: 'flag', text: '中标' } - if (ia === 0 && sc === 1) return { mode: 'text', text: '待报价' } - if (ia === 0 && sc === 2) return { mode: 'text', text: '报价中' } + if (ia === 1) return { mode: 'flag', text: t ? t('message.pages.pissupplier.quotation.awarded') : '中标' } + if (ia === 0 && sc === 1) return { mode: 'text', text: t ? t('message.pages.pissupplier.quotation.statusPending') : '待报价' } + if (ia === 0 && sc === 2) return { mode: 'text', text: t ? t('message.pages.pissupplier.quotation.statusQuoting') : '报价中' } if (ia === 0 && sc === 3) { - if (!Number.isFinite(inqNum)) return { mode: 'text', text: '评标中' } - if (inqNum !== 9) return { mode: 'text', text: '评标中' } - return { mode: 'text', text: '未中标' } + if (!Number.isFinite(inqNum)) return { mode: 'text', text: t ? t('message.pages.pissupplier.quotation.statusEvaluating') : '评标中' } + if (inqNum !== 9) return { mode: 'text', text: t ? t('message.pages.pissupplier.quotation.statusEvaluating') : '评标中' } + return { mode: 'text', text: t ? t('message.pages.pissupplier.quotation.statusLost') : '未中标' } } return { mode: 'text', text: '—' } } @@ -396,17 +398,17 @@ const paymentMapBackendToFront: Record = { } /** 与报价基础信息 `paymentTerm` 选项一致,供详情页只读展示 */ -export const PAYMENT_TERM_LABELS: Record = { - tt_30_70: 'T/T 30%预付,70%出货前', - net30: '月结30天', - net45: '月结45天', - prepaid: '全额预付' -} +export const getPaymentTermLabels = (t: Function) => ({ + tt_30_70: t('message.pages.pissupplier.quotation.paymentTt30_70'), + net30: t('message.pages.pissupplier.quotation.paymentNet30'), + net45: t('message.pages.pissupplier.quotation.paymentNet45'), + prepaid: t('message.pages.pissupplier.quotation.paymentPrepaid') +}) -export function formatPaymentTermLabel(term: string | null | undefined) { +export function formatPaymentTermLabel(term: string | null | undefined, t?: Function) { if (term == null || String(term).trim() === '') return '—' const k = String(term).trim() - return PAYMENT_TERM_LABELS[k] ?? k + return t ? getPaymentTermLabels(t)[k] ?? k : k } const costEnabledSections = ['材料成本', '加工成本', '其它成本', '利润', '税金'] @@ -683,27 +685,27 @@ const buildCostItemsFromTemplateSections = (sections: any, enableCostStructure = .filter(Boolean) as CostItem[] } -const buildDefaultNonBomCostItems = (): CostItem[] => { +const buildDefaultNonBomCostItems = (t: Function): CostItem[] => { const productDetail: CostItem = { id: crypto.randomUUID(), section: '产品明细', attrs: [ - { key: 'partNo', label: '料号', value: '' }, - { key: 'desc', label: '规格描述', value: '' }, - { key: 'qty', label: '数量', value: '' }, - { key: 'price', label: '单价', value: '' }, - { key: 'amount', label: '合计价格', value: '' } + { key: 'partNo', label: t('message.pages.pissupplier.quotation.partNo'), value: '' }, + { key: 'desc', label: t('message.pages.pissupplier.quotation.specDesc'), value: '' }, + { key: 'qty', label: t('message.pages.pissupplier.quotation.qty'), value: '' }, + { key: 'price', label: t('message.pages.pissupplier.quotation.unitPrice'), value: '' }, + { key: 'amount', label: t('message.pages.pissupplier.quotation.totalPrice'), value: '' } ] } const profit: CostItem = { id: crypto.randomUUID(), section: '利润', - attrs: [{ key: 'profitRate', label: '利润率', value: '' }] + attrs: [{ key: 'profitRate', label: t('message.pages.pissupplier.quotation.profitRate'), value: '' }] } const tax: CostItem = { id: crypto.randomUUID(), section: '税金', - attrs: [{ key: 'taxRate', label: '税率', value: '' }] + attrs: [{ key: 'taxRate', label: t('message.pages.pissupplier.quotation.taxRate'), value: '' }] } return [productDetail, profit, tax] } @@ -747,23 +749,23 @@ export const hasQuotationNestedCosts = (item: any): boolean => (Array.isArray(item.profit_costs) && item.profit_costs.length > 0)) /** 将详情嵌套子表转为 CostItem[],供 costItemsToRows 渲染 */ -const costItemsFromQuotationApi = (item: any): CostItem[] => { +const costItemsFromQuotationApi = (item: any, t: Function): CostItem[] => { const out: CostItem[] = [] let mid = 0 for (const m of item.material_costs || []) { const opt = parseJsonLoose(m.option_json) const attrs: { key: string; label: string; value: any }[] = [ - { key: 'part_id', label: '料号', value: m.part_id ?? '' }, - { key: 'material', label: '材质', value: m.material_spec ?? '' }, - { key: 'len', label: '长', value: m.length ?? '' }, - { key: 'width', label: '宽', value: m.width ?? '' }, - { key: 'height', label: '高', value: m.height ?? '' }, - { key: 'specificgravity', label: '比重', value: m.specific_gravity ?? '' }, - { key: 'qty', label: '数量', value: m.qty ?? '' }, - { key: 'weight', label: '重量', value: m.weight ?? '' }, - { key: 'unitPrice', label: '单价', value: m.unit_price ?? '' }, - { key: 'material_fee', label: '材料费用', value: m.material_cost ?? '' }, - { key: 'remark', label: '备注', value: m.remark ?? '' } + { key: 'part_id', label: t('message.pages.pissupplier.quotation.partNo'), value: m.part_id ?? '' }, + { key: 'material', label: t('message.pages.pissupplier.quotation.material'), value: m.material_spec ?? '' }, + { key: 'len', label: t('message.pages.pissupplier.quotation.length'), value: m.length ?? '' }, + { key: 'width', label: t('message.pages.pissupplier.quotation.width'), value: m.width ?? '' }, + { key: 'height', label: t('message.pages.pissupplier.quotation.height'), value: m.height ?? '' }, + { key: 'specificgravity', label: t('message.pages.pissupplier.quotation.specificGravity'), value: m.specific_gravity ?? '' }, + { key: 'qty', label: t('message.pages.pissupplier.quotation.qty'), value: m.qty ?? '' }, + { key: 'weight', label: t('message.pages.pissupplier.quotation.weight'), value: m.weight ?? '' }, + { key: 'unitPrice', label: t('message.pages.pissupplier.quotation.unitPrice'), value: m.unit_price ?? '' }, + { key: 'material_fee', label: t('message.pages.pissupplier.quotation.materialFee'), value: m.material_cost ?? '' }, + { key: 'remark', label: t('message.pages.pissupplier.quotation.remark'), value: m.remark ?? '' } ] Object.entries(opt).forEach(([k, v]) => { if (!attrs.find((a) => a.key === k)) attrs.push({ key: k, label: k, value: v }) @@ -779,13 +781,13 @@ const costItemsFromQuotationApi = (item: any): CostItem[] => { for (const p of item.process_costs || []) { const opt = parseJsonLoose(p.option_json) const attrs: { key: string; label: string; value: any }[] = [ - { key: 'part_id', label: '料号', value: p.part_id ?? '' }, - { key: 'processStation', label: '加工工站', value: p.process_station ?? '' }, - { key: 'processUnit', label: '单位', value: p.unit ?? '' }, - { key: 'processRate', label: '费率', value: p.unit_rate ?? '' }, - { key: 'processMeasure', label: '加工计量', value: p.process_qty ?? '' }, - { key: 'processFee', label: '加工费', value: p.process_price ?? '' }, - { key: 'remark', label: '备注', value: p.remark ?? '' } + { key: 'part_id', label: t('message.pages.pissupplier.quotation.partNo'), value: p.part_id ?? '' }, + { key: 'processStation', label: t('message.pages.pissupplier.quotation.processStation'), value: p.process_station ?? '' }, + { key: 'processUnit', label: t('message.pages.pissupplier.quotation.processUnit'), value: p.unit ?? '' }, + { key: 'processRate', label: t('message.pages.pissupplier.quotation.processRate'), value: p.unit_rate ?? '' }, + { key: 'processMeasure', label: t('message.pages.pissupplier.quotation.processMeasure'), value: p.process_qty ?? '' }, + { key: 'processFee', label: t('message.pages.pissupplier.quotation.processFee'), value: p.process_price ?? '' }, + { key: 'remark', label: t('message.pages.pissupplier.quotation.remark'), value: p.remark ?? '' } ] Object.entries(opt).forEach(([k, v]) => { if (!attrs.find((a) => a.key === k)) attrs.push({ key: k, label: k, value: v }) @@ -803,30 +805,30 @@ const costItemsFromQuotationApi = (item: any): CostItem[] => { id: `oth-${o.autoid ?? oid++}`, section: '其它成本', attrs: [ - { key: 'part_id', label: '料号', value: o.part_id ?? '' }, - { key: 'packageFee', label: '包装费', value: o.packaging_cost ?? '' }, - { key: 'transportFee', label: '运输费', value: o.transportation_cost ?? '' } + { key: 'part_id', label: t('message.pages.pissupplier.quotation.partNo'), value: o.part_id ?? '' }, + { key: 'packageFee', label: t('message.pages.pissupplier.quotation.packageFee'), value: o.packaging_cost ?? '' }, + { key: 'transportFee', label: t('message.pages.pissupplier.quotation.transportFee'), value: o.transportation_cost ?? '' } ] }) } for (const pr of item.profit_costs || []) { - const pid = pr.part_id ?? '' + const prtid = pr.part_id ?? '' out.push({ - id: `profit-${pr.autoid ?? pid}-p`, + id: `profit-${pr.autoid ?? prtid}-p`, section: '利润', attrs: [ - { key: 'part_id', label: '料号', value: pid }, - { key: 'profitRate', label: '利润率(%)', value: pr.profit_rate ?? '' }, - { key: 'profitTotal', label: '利润金额', value: '' } + { key: 'part_id', label: t('message.pages.pissupplier.quotation.partNo'), value: prtid }, + { key: 'profitRate', label: t('message.pages.pissupplier.quotation.profitRatePct'), value: pr.profit_rate ?? '' }, + { key: 'profitTotal', label: t('message.pages.pissupplier.quotation.profitAmount'), value: '' } ] }) out.push({ - id: `profit-${pr.autoid ?? pid}-t`, + id: `profit-${pr.autoid ?? prtid}-t`, section: '税金', attrs: [ - { key: 'part_id', label: '料号', value: pid }, - { key: 'taxRate', label: '税率(%)', value: pr.tax_rate ?? '' }, - { key: 'taxTotal', label: '税金金额', value: '' } + { key: 'part_id', label: t('message.pages.pissupplier.quotation.partNo'), value: prtid }, + { key: 'taxRate', label: t('message.pages.pissupplier.quotation.taxRatePct'), value: pr.tax_rate ?? '' }, + { key: 'taxTotal', label: t('message.pages.pissupplier.quotation.taxAmount'), value: '' } ] }) } @@ -1056,6 +1058,7 @@ export function useQuoteCrud(options?: { /** 详情页保存成功后(例如返回列表) */ onSaveSuccess?: () => void }) { + const { t } = useI18n() const uiContext = options?.uiContext ?? 'list' const filters = reactive<{ inquiryPlant: string @@ -1201,10 +1204,10 @@ export function useQuoteCrud(options?: { // 兼容后端/历史数据直接返回中文文案的情况 const labelToStatus: Record = { - 待报价: 'pending', - 报价中: 'quoted', - 已报价: 'completed', - 已过期: 'expired' + [t('message.pages.pissupplier.quotation.statusPending')]: 'pending', + [t('message.pages.pissupplier.quotation.statusQuoting')]: 'quoted', + [t('message.pages.pissupplier.quotation.statusCompleted')]: 'completed', + [t('message.pages.pissupplier.quotation.statusExpired')]: 'expired' } return labelToStatus[str] || 'pending' } @@ -1383,13 +1386,14 @@ export function useQuoteCrud(options?: { paymentTerm: normalizePayment(item.payment_method) }, costItems: hasQuotationNestedCosts(item) - ? costItemsFromQuotationApi(item) + ? costItemsFromQuotationApi(item, t) : normalizeCostItems(item.cost_items || item.costItems).length ? normalizeCostItems(item.cost_items || item.costItems) : buildCostItems( item.template || item.template_code || 'default', item.templateSections || item.template_sections || item.sections, - (item.enable_cost_structure ?? item.is_bom ?? item.isBom ?? item.template?.enable_cost_structure) !== false + (item.enable_cost_structure ?? item.is_bom ?? item.isBom ?? item.template?.enable_cost_structure) !== false, + t ), rfqItems: Array.isArray(item.rfq_items) ? item.rfq_items : [], attachments: normalizeQuotationAttachmentsForUpload(item.attachments), @@ -1909,9 +1913,9 @@ export function useQuoteCrud(options?: { // 询价附件必须以询价单子表为准(`Inquiry.attachments`),勿用报价单 `attachments` 回显 if (inquiry?.attachments?.length) { - quoteData.inquiryAttachments = mapInquiryAttachmentsFromInquiryApi(inquiry.attachments) + quoteData.inquiryAttachments = mapInquiryAttachmentsFromInquiryApi(inquiry.attachments, t) } else if (rawDetail?.inquiry_attachments?.length) { - quoteData.inquiryAttachments = mapInquiryAttachmentsFromInquiryApi(rawDetail.inquiry_attachments) + quoteData.inquiryAttachments = mapInquiryAttachmentsFromInquiryApi(rawDetail.inquiry_attachments, t) } quoteData.inquiryStatus = formatMiscInquiryStatus(quoteData) @@ -1974,7 +1978,7 @@ export function useQuoteCrud(options?: { merged.inquiryCompanyCode = icc } if (inv.attachments?.length) { - merged.inquiryAttachments = mapInquiryAttachmentsFromInquiryApi(inv.attachments) + merged.inquiryAttachments = mapInquiryAttachmentsFromInquiryApi(inv.attachments, t) } } } @@ -2097,7 +2101,7 @@ export function useQuoteCrud(options?: { const addCostRow = (section: string) => { const cols = mergeQuotationSectionColumns(section, current.templateSections) if (!cols.length) { - ElMessage.warning('该段未在成本模板中配置字段,无法新增行') + ElMessage.warning(t('message.pages.pissupplier.quotation.cannotAddRowNoFields')) return } const values: Record = {} @@ -2116,14 +2120,14 @@ export function useQuoteCrud(options?: { function saveQuote() { if (dialog.quoteId && !isQuotationEditable(current)) { - ElMessage.warning('仅未报价/报价中状态可保存') + ElMessage.warning(t('message.pages.pissupplier.quotation.onlyPendingCanSave')) return } const c = (current.base.contact || '').trim() const p = (current.base.phone || '').trim() const e = (current.base.email || '').trim() if (!c || !p || !e) { - ElMessage.warning('请填写完整【报价基础信息】后再保存。') + ElMessage.warning(t('message.pages.pissupplier.quotation.fillBasicInfoFirst')) return } ;(async () => { @@ -2138,10 +2142,10 @@ export function useQuoteCrud(options?: { if (!name && !path) continue if (!path) { if (f?.raw) { - ElMessage.error(`附件上传失败:${name || '未命名文件'},请检查网络后重试`) + ElMessage.error(t('message.pages.pissupplier.quotation.attachmentUploadFailed', { name: name || t('message.pages.pissupplier.quotation.unnamedFile') })) return } - ElMessage.error(`附件「${name || '未命名'}」缺少存储路径,请删除后重新上传`) + ElMessage.error(t('message.pages.pissupplier.quotation.attachmentMissingPath', { name: name || t('message.pages.pissupplier.quotation.unnamed') })) return } } @@ -2164,11 +2168,11 @@ export function useQuoteCrud(options?: { } else { dialog.visible = false } - ElMessage.success('已保存') + ElMessage.success(t('message.pages.pissupplier.quotation.saved')) options?.onChange?.() } catch (err) { console.error('保存报价失败', err) - ElMessage.error('保存失败,请检查网络或必填项后重试') + ElMessage.error(t('message.pages.pissupplier.quotation.saveFailed')) } finally { loading.value = false } @@ -2177,7 +2181,7 @@ export function useQuoteCrud(options?: { function submitQuotationFromRow(row: Quote) { if (!isQuotedQuotation(row)) { - ElMessage.warning('仅报价中状态可提交报价') + ElMessage.warning(t('message.pages.pissupplier.quotation.onlyQuotingCanSubmit')) return } const bidReason = getSupplierBidWindowRejectReason(row) @@ -2189,11 +2193,11 @@ export function useQuoteCrud(options?: { const p = (row.base?.phone || '').trim() const e = (row.base?.email || '').trim() if (!c || !p || !e) { - ElMessage.warning('请先将报价单中的【报价基础信息】填写完整后再提交报价。') + ElMessage.warning(t('message.pages.pissupplier.quotation.fillBasicInfoBeforeSubmit')) return } if (!row.id) { - ElMessage.warning('无法提交:缺少报价单标识') + ElMessage.warning(t('message.pages.pissupplier.quotation.cannotSubmitNoId')) return } ;(async () => { @@ -2209,12 +2213,12 @@ export function useQuoteCrud(options?: { else quotes.value.unshift(updated) const tip = res?.data?.msg || - (inquiryClosed ? '报价已提交,询价单已进入报价结束' : '报价已提交') + (inquiryClosed ? t('message.pages.pissupplier.quotation.submittedInquiryClosed') : t('message.pages.pissupplier.quotation.submitted')) ElMessage.success(tip) options?.onChange?.() } catch (err) { console.error('提交报价失败', err) - ElMessage.error('提交失败,请稍后重试') + ElMessage.error(t('message.pages.pissupplier.quotation.submitFailed')) } finally { loading.value = false } @@ -2361,10 +2365,10 @@ export function useQuoteCrud(options?: { return legacy[key] || key } const statusLabel = (s: QuoteStatus) => ({ - pending: '待报价', - quoted: '报价中', - completed: '已报价', - expired: '已过期' + pending: t('message.pages.pissupplier.quotation.statusPending'), + quoted: t('message.pages.pissupplier.quotation.statusQuoting'), + completed: t('message.pages.pissupplier.quotation.statusCompleted'), + expired: t('message.pages.pissupplier.quotation.statusExpired') }[s] || s) const statusTagType = (s: QuoteStatus) => ({ @@ -2376,7 +2380,7 @@ export function useQuoteCrud(options?: { return { filters, - statusOptions, + statusOptions: getStatusOptions(), resetFilter, filteredQuotes, loading, @@ -2387,7 +2391,7 @@ export function useQuoteCrud(options?: { viewQuote, openQuote, dialog, - dialogTitle: computed(() => (dialog.mode === 'view' ? '查看报价' : dialog.quoteId ? '编辑报价' : '新增报价')), + dialogTitle: computed(() => (dialog.mode === 'view' ? t('message.pages.pissupplier.quotation.viewQuote') : dialog.quoteId ? t('message.pages.pissupplier.quotation.editQuote') : t('message.pages.pissupplier.quotation.newQuote'))), statusTagType, statusLabel, templateLabel, @@ -2430,9 +2434,9 @@ export function useQuoteCrud(options?: { } } -const buildCostItems = (_templateKey: string, templateSections?: any, enableCostStructure = true): CostItem[] => { +const buildCostItems = (_templateKey: string, templateSections?: any, enableCostStructure = true, t?: Function): CostItem[] => { const fromTplSections = buildCostItemsFromTemplateSections(templateSections, enableCostStructure) if (fromTplSections.length) return fromTplSections - if (!enableCostStructure) return buildDefaultNonBomCostItems() + if (!enableCostStructure) return t ? buildDefaultNonBomCostItems(t) : [] return [] } From c07929a7b2347e1dee419aa730806e474e06ecce Mon Sep 17 00:00:00 2001 From: Lewis_yan Date: Wed, 8 Apr 2026 22:20:54 +0800 Subject: [PATCH 06/24] feat(i18n): Fix misc_materials/stations i18n refs and add misc_parts i18n - misc_materials/crud.tsx: Change misc_materials.* refs to materialInfo.* - misc_stations/crud.tsx: Change misc_stations.* refs to stationInfo.* - misc_parts/crud.tsx: Add full i18n support (useI18n, statusDict, categoryDict, all columns) - Add missing keys to all 3 i18n files: - materialInfo: statusEnabled, statusDisabled, createTime, updateTime - stationInfo: statusEnabled, statusDisabled, typeTooling, typeGraphite, createTime, updateTime - misc_parts: new section with all field labels - rfqmiscellaneous: paymentMethod1-9, selectInquiryFirst, onlySingleOperation, confirmBargainPrompt, addSupplierFirst, confirmPrompt, prompt, confirmFailed, restorePrompt, restoreFailed, publishPrompt, publishFailed, startBargainFailed, deleteFailed, cancel, inquiryNameRequired, buyerRequired, inquiryNoPlaceholder, inquiryNamePlaceholder, buyerPlaceholder --- web/src/i18n/pages/miscprocurement/en.ts | 122 ++++++++++++++++++ web/src/i18n/pages/miscprocurement/zh-cn.ts | 122 ++++++++++++++++++ web/src/i18n/pages/miscprocurement/zh-tw.ts | 122 ++++++++++++++++++ .../miscprocurement/misc_materials/crud.tsx | 24 ++-- .../miscprocurement/misc_parts/crud.tsx | 57 ++++---- .../miscprocurement/misc_stations/crud.tsx | 42 +++--- 6 files changed, 428 insertions(+), 61 deletions(-) diff --git a/web/src/i18n/pages/miscprocurement/en.ts b/web/src/i18n/pages/miscprocurement/en.ts index 7a46679..1eb7242 100644 --- a/web/src/i18n/pages/miscprocurement/en.ts +++ b/web/src/i18n/pages/miscprocurement/en.ts @@ -12,6 +12,10 @@ export default { density: 'Density', price: 'Unit Price', status: 'Status', + statusEnabled: 'Enabled', + statusDisabled: 'Disabled', + createTime: 'Create Time', + updateTime: 'Update Time', }, stationInfo: { title: 'Misc Procurement Station Info', @@ -24,6 +28,33 @@ export default { unit: 'Unit', rate: 'Rate', status: 'Status', + statusEnabled: 'Enabled', + statusDisabled: 'Disabled', + typeTooling: 'Tooling', + typeGraphite: 'Graphite', + createTime: 'Create Time', + updateTime: 'Update Time', + }, + misc_parts: { + title: 'Misc Parts Info', + companyCode: 'Transaction Plant', + partid: 'Part ID', + partidName: 'Part Name', + specification: 'Specification', + unit: 'Unit', + partidCategory: 'Part Category', + categoryTooling: 'Tooling', + categoryGraphite: 'Graphite', + categoryOther: 'Other', + status: 'Status', + statusEnabled: 'Enabled', + statusDisabled: 'Disabled', + createTime: 'Create Time', + updateTime: 'Update Time', + validation: { + fieldNameRequired: 'Field is required', + alreadyExists: 'already exists', + } }, inquiry: { title: 'Inquiry', @@ -52,8 +83,71 @@ export default { templateNameEn: 'Template Name (English)', templateNameZhTw: 'Template Name (Traditional Chinese)', procurementCategory: 'Procurement Category', + procurementMisc: 'Misc', + procurementStrategic: 'Strategic', templateDesc: 'Template Description', status: 'Status', + statusPlaceholder: 'Select status', + statusConfirmed: 'Confirmed', + statusUnconfirmed: 'Unconfirmed', + statusCancelled: 'Cancelled', + selectProcurementCategory: 'Select procurement category', + inputTemplateName: 'Enter template name', + version: 'Version', + newVersion: 'New Version', + newVersionFailed: 'Failed to create new version', + basicInfo: 'Basic Info', + sections: 'Sections', + controls: 'Controls', + fieldKey: 'Field Key', + confirm: 'Confirm', + confirmButtonText: 'Confirm', + confirmSuccess: 'Confirmed successfully', + confirmFailed: 'Confirmation failed', + confirmStatusTip: 'Confirmation status', + cancelButtonText: 'Cancel', + pleaseCompleteAndSave: 'Please complete and save first', + pleaseModifyAndSave: 'Please modify and save first', + loadDetailFailed: 'Failed to load details', + keyNotFilled: 'Required field not filled', + isBom: 'Is BOM', + bomYes: 'Yes', + bomNo: 'No', + acti: 'Action', + actiYes: 'Yes', + actiNo: 'No', + productDetail: 'Product Detail', + materials: 'Materials', + material: 'Material', + length: 'Length', + width: 'Width', + height: 'Height', + specificgravity: 'Specific Gravity', + autoByMaterial: 'Auto calculated by material', + qty: 'Qty', + weight: 'Weight', + weightUsage: 'Material Weight', + unitPrice: 'Unit Price', + materialCost: 'Material Cost', + lengthWidthHeightSpecificgravityQty: 'L*W*H*SG*Qty', + weightTimesUnitPrice: 'Weight x Unit Price', + process: 'Process', + processStation: 'Process Station', + processTime: 'Process Time', + unit: 'Unit', + unitrate: 'Station Rate', + autoByStation: 'Auto calculated by station', + processqty: 'Process Qty', + processprice: 'Process Price', + processCost: 'Process Cost', + unitrateTimesProcessqty: 'Station Rate x Process Qty', + lossRate: 'Loss Rate', + sgna: 'SG&A', + others: 'Others', + profit: 'Profit', + tax: 'Tax', + remark: 'Remark', + updateTime: 'Update Time', }, rfqmiscellaneous: { title: 'Misc RFQ', @@ -70,6 +164,34 @@ export default { currency: 'Currency', leadTimeDays: 'Lead Time (Days)', paymentMethod: 'Payment Method', + paymentMethod1: 'T/T 30 Days', + paymentMethod2: 'T/T 60 Days', + paymentMethod3: 'T/T 90 Days', + paymentMethod4: 'T/T 120 Days', + paymentMethod5: 'L/C 30 Days', + paymentMethod6: 'L/C 60 Days', + paymentMethod7: 'L/C 90 Days', + paymentMethod8: 'L/C 120 Days', + paymentMethod9: 'Other', + inquiryNoPlaceholder: 'Enter RFQ number', + inquiryNamePlaceholder: 'Enter RFQ name', + buyerPlaceholder: 'Enter buyer name', + selectInquiryFirst: 'Please select an RFQ first', + onlySingleOperation: 'Only single item operation is supported', + confirmBargainPrompt: 'Confirm to change status to [Bargaining]?', + addSupplierFirst: 'Please maintain RFQ supplier list first before confirming', + confirmPrompt: 'After confirmation, the RFQ will be locked and cannot be edited. To modify, you need to [Restore] it.', + prompt: 'Prompt', + confirmFailed: 'Confirmation failed', + restorePrompt: 'Confirm to restore status to [Open]?', + restoreFailed: 'Restore failed', + publishPrompt: 'Confirm to change status to [Published]?', + publishFailed: 'Publish failed', + startBargainFailed: 'Failed to start price comparison', + deleteFailed: 'Delete failed', + cancel: 'Cancel', + inquiryNameRequired: 'Please enter RFQ name', + buyerRequired: 'Please enter buyer name', status: 'Status', statusOpen: 'Open', statusConfirmed: 'Confirmed', diff --git a/web/src/i18n/pages/miscprocurement/zh-cn.ts b/web/src/i18n/pages/miscprocurement/zh-cn.ts index 6bf2e64..fe60c96 100644 --- a/web/src/i18n/pages/miscprocurement/zh-cn.ts +++ b/web/src/i18n/pages/miscprocurement/zh-cn.ts @@ -12,6 +12,10 @@ export default { density: '比重', price: '单价', status: '状态', + statusEnabled: '启用', + statusDisabled: '禁用', + createTime: '创建时间', + updateTime: '更新时间', }, stationInfo: { title: '杂采工站信息', @@ -24,6 +28,33 @@ export default { unit: '计量单位', rate: '费率', status: '状态', + statusEnabled: '启用', + statusDisabled: '禁用', + typeTooling: '模治具', + typeGraphite: '石墨', + createTime: '创建时间', + updateTime: '更新时间', + }, + misc_parts: { + title: '杂采料号信息', + companyCode: '交易厂区', + partid: '料号', + partidName: '物料说明', + specification: '品名规格', + unit: '单位', + partidCategory: '物料分类', + categoryTooling: '模治具', + categoryGraphite: '石墨', + categoryOther: '其他', + status: '启用否', + statusEnabled: '启用', + statusDisabled: '禁用', + createTime: '创建时间', + updateTime: '更新时间', + validation: { + fieldNameRequired: '字段不能为空', + alreadyExists: '已存在', + } }, inquiry: { title: '询价单', @@ -52,8 +83,71 @@ export default { templateNameEn: '模板英文名', templateNameZhTw: '模板繁体名', procurementCategory: '采购类别', + procurementMisc: '杂采', + procurementStrategic: '策采', templateDesc: '模板描述', status: '状态', + statusPlaceholder: '请选择状态', + statusConfirmed: '已确认', + statusUnconfirmed: '未确认', + statusCancelled: '已作废', + selectProcurementCategory: '请选择采购类别', + inputTemplateName: '请输入模板名称', + version: '版本', + newVersion: '新建版本', + newVersionFailed: '新建版本失败', + basicInfo: '基础信息', + sections: '区段信息', + controls: '控件', + fieldKey: '字段标识', + confirm: '确认', + confirmButtonText: '确认', + confirmSuccess: '确认成功', + confirmFailed: '确认失败', + confirmStatusTip: '确认状态提示', + cancelButtonText: '取消', + pleaseCompleteAndSave: '请先完成并保存', + pleaseModifyAndSave: '请先修改并保存', + loadDetailFailed: '加载明细失败', + keyNotFilled: '关键字段未填写', + isBom: '是否BOM', + bomYes: '是', + bomNo: '否', + acti: '操作', + actiYes: '是', + actiNo: '否', + productDetail: '产品明细', + materials: '材料', + material: '材质', + length: '长', + width: '宽', + height: '高', + specificgravity: '比重', + autoByMaterial: '由材质自动计算', + qty: '数量', + weight: '重量', + weightUsage: '用料重量', + unitPrice: '单价', + materialCost: '材料费用', + lengthWidthHeightSpecificgravityQty: '长*宽*高*比重*数量', + weightTimesUnitPrice: '重量*单价', + process: '加工', + processStation: '加工工站', + processTime: '加工时间', + unit: '计量单位', + unitrate: '工站费率', + autoByStation: '由工站自动计算', + processqty: '加工数量', + processprice: '加工单价', + processCost: '加工费', + unitrateTimesProcessqty: '工站费率*加工数量', + lossRate: '损耗率', + sgna: '销管费', + others: '其他', + profit: '利润', + tax: '税金', + remark: '备注', + updateTime: '更新时间', }, rfqmiscellaneous: { title: '杂采询价单', @@ -70,6 +164,34 @@ export default { currency: '币别', leadTimeDays: '交货周期(天)', paymentMethod: '付款方式', + paymentMethod1: 'T/T 30天', + paymentMethod2: 'T/T 60天', + paymentMethod3: 'T/T 90天', + paymentMethod4: 'T/T 120天', + paymentMethod5: 'L/C 30天', + paymentMethod6: 'L/C 60天', + paymentMethod7: 'L/C 90天', + paymentMethod8: 'L/C 120天', + paymentMethod9: '其他', + inquiryNoPlaceholder: '请输入询价单号', + inquiryNamePlaceholder: '请输入询价单名称', + buyerPlaceholder: '请输入采购负责人', + selectInquiryFirst: '请先选择询价单', + onlySingleOperation: '仅支持单条操作', + confirmBargainPrompt: '确认将状态改为【比议价中】?', + addSupplierFirst: '请先维护询价单供应商名单后再确认', + confirmPrompt: '确认后,该询价单将锁定并不可再编辑。如需修改,后续需执行【还原】操作', + prompt: '提示', + confirmFailed: '确认失败', + restorePrompt: '确认将状态还原为【开立】?', + restoreFailed: '还原失败', + publishPrompt: '确认将状态改为【发布】?', + publishFailed: '发布失败', + startBargainFailed: '开启比议价失败', + deleteFailed: '删除失败', + cancel: '取消', + inquiryNameRequired: '请输入询价单名称', + buyerRequired: '请输入采购负责人', status: '状态', statusOpen: '开立', statusConfirmed: '确认', diff --git a/web/src/i18n/pages/miscprocurement/zh-tw.ts b/web/src/i18n/pages/miscprocurement/zh-tw.ts index e2930a1..9c40a98 100644 --- a/web/src/i18n/pages/miscprocurement/zh-tw.ts +++ b/web/src/i18n/pages/miscprocurement/zh-tw.ts @@ -12,6 +12,10 @@ export default { density: '比重', price: '單價', status: '狀態', + statusEnabled: '啟用', + statusDisabled: '禁用', + createTime: '創建時間', + updateTime: '更新時間', }, stationInfo: { title: '雜採工站資訊', @@ -24,6 +28,33 @@ export default { unit: '計量單位', rate: '費率', status: '狀態', + statusEnabled: '啟用', + statusDisabled: '禁用', + typeTooling: '模具', + typeGraphite: '石墨', + createTime: '創建時間', + updateTime: '更新時間', + }, + misc_parts: { + title: '雜採料號資訊', + companyCode: '交易廠區', + partid: '料號', + partidName: '物料說明', + specification: '品名規格', + unit: '單位', + partidCategory: '物料分類', + categoryTooling: '模具', + categoryGraphite: '石墨', + categoryOther: '其他', + status: '啟用否', + statusEnabled: '啟用', + statusDisabled: '禁用', + createTime: '創建時間', + updateTime: '更新時間', + validation: { + fieldNameRequired: '字段不能為空', + alreadyExists: '已存在', + } }, inquiry: { title: '詢價單', @@ -52,8 +83,71 @@ export default { templateNameEn: '模版英文名', templateNameZhTw: '模版繁體名', procurementCategory: '採購類別', + procurementMisc: '雜採', + procurementStrategic: '策採', templateDesc: '模版描述', status: '狀態', + statusPlaceholder: '請選擇狀態', + statusConfirmed: '已確認', + statusUnconfirmed: '未確認', + statusCancelled: '已作廢', + selectProcurementCategory: '請選擇採購類別', + inputTemplateName: '請輸入模版名稱', + version: '版本', + newVersion: '新建版本', + newVersionFailed: '新建版本失敗', + basicInfo: '基本信息', + sections: '區段資訊', + controls: '控件', + fieldKey: '字段識別', + confirm: '確認', + confirmButtonText: '確認', + confirmSuccess: '確認成功', + confirmFailed: '確認失敗', + confirmStatusTip: '確認狀態提示', + cancelButtonText: '取消', + pleaseCompleteAndSave: '請先完成並儲存', + pleaseModifyAndSave: '請先修改並儲存', + loadDetailFailed: '載入明細失敗', + keyNotFilled: '關鍵字段未填寫', + isBom: '是否BOM', + bomYes: '是', + bomNo: '否', + acti: '操作', + actiYes: '是', + actiNo: '否', + productDetail: '產品明細', + materials: '材料', + material: '材質', + length: '長', + width: '寬', + height: '高', + specificgravity: '比重', + autoByMaterial: '由材質自動計算', + qty: '數量', + weight: '重量', + weightUsage: '用料重量', + unitPrice: '單價', + materialCost: '材料費用', + lengthWidthHeightSpecificgravityQty: '長*寬*高*比重*數量', + weightTimesUnitPrice: '重量*單價', + process: '加工', + processStation: '加工工站', + processTime: '加工時間', + unit: '計量單位', + unitrate: '工站費率', + autoByStation: '由工站自動計算', + processqty: '加工數量', + processprice: '加工單價', + processCost: '加工費', + unitrateTimesProcessqty: '工站費率*加工數量', + lossRate: '損耗率', + sgna: '銷管費', + others: '其他', + profit: '利潤', + tax: '稅金', + remark: '備註', + updateTime: '更新時間', }, rfqmiscellaneous: { title: '雜採詢價單', @@ -70,6 +164,34 @@ export default { currency: '幣別', leadTimeDays: '交貨週期(天)', paymentMethod: '付款方式', + paymentMethod1: 'T/T 30天', + paymentMethod2: 'T/T 60天', + paymentMethod3: 'T/T 90天', + paymentMethod4: 'T/T 120天', + paymentMethod5: 'L/C 30天', + paymentMethod6: 'L/C 60天', + paymentMethod7: 'L/C 90天', + paymentMethod8: 'L/C 120天', + paymentMethod9: '其他', + inquiryNoPlaceholder: '請輸入詢價單號', + inquiryNamePlaceholder: '請輸入詢價單名稱', + buyerPlaceholder: '請輸入採購負責人', + selectInquiryFirst: '請先選擇詢價單', + onlySingleOperation: '僅支援單條操作', + confirmBargainPrompt: '確認將狀態改為【比議價中】?', + addSupplierFirst: '請先維護詢價單供應商名單後再確認', + confirmPrompt: '確認後,該詢價單將鎖定並不可再編輯。如需修改,後續需執行【還原】操作', + prompt: '提示', + confirmFailed: '確認失敗', + restorePrompt: '確認將狀態還原為【開立】?', + restoreFailed: '還原失敗', + publishPrompt: '確認將狀態改為【發布】?', + publishFailed: '發布失敗', + startBargainFailed: '開啟比議價失敗', + deleteFailed: '刪除失敗', + cancel: '取消', + inquiryNameRequired: '請輸入詢價單名稱', + buyerRequired: '請輸入採購負責人', status: '狀態', statusOpen: '開立', statusConfirmed: '確認', diff --git a/web/src/views/pisadmin/miscprocurement/misc_materials/crud.tsx b/web/src/views/pisadmin/miscprocurement/misc_materials/crud.tsx index ac72eab..abe2746 100644 --- a/web/src/views/pisadmin/miscprocurement/misc_materials/crud.tsx +++ b/web/src/views/pisadmin/miscprocurement/misc_materials/crud.tsx @@ -31,8 +31,8 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp const { t } = useI18n() const statusDict = [ - { value: 1, label: t('message.pages.miscprocurement.misc_materials.statusEnabled') }, - { value: 0, label: t('message.pages.miscprocurement.misc_materials.statusDisabled') } + { value: 1, label: t('message.pages.miscprocurement.materialInfo.statusEnabled') }, + { value: 0, label: t('message.pages.miscprocurement.materialInfo.statusDisabled') } ] return { @@ -59,7 +59,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp }, columns: { factory: { - title: t('message.pages.miscprocurement.misc_materials.companyCode'), + title: t('message.pages.miscprocurement.materialInfo.factory'), type: 'dict-select', dict: dict({ cache: false, @@ -73,41 +73,41 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp column: { minWidth: 160, showOverflowTooltip: true } }, materialtype: { - title: t('message.pages.miscprocurement.misc_materials.materialtype'), + title: t('message.pages.miscprocurement.materialInfo.materialtype'), type: 'input', search: { show: true, - component: { props: { placeholder: t('message.pages.miscprocurement.misc_materials.materialtype'), clearable: true } } + component: { props: { placeholder: t('message.pages.miscprocurement.materialInfo.materialtype'), clearable: true } } }, column: { minWidth: 160, showOverflowTooltip: true } }, density: { - title: t('message.pages.miscprocurement.misc_materials.density'), + title: t('message.pages.miscprocurement.materialInfo.density'), type: 'input', - form: { rules: [{ required: true, message: t('message.pages.miscprocurement.misc_materials.density') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, + form: { rules: [{ required: true, message: t('message.pages.miscprocurement.materialInfo.density') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, column: { width: 120, showOverflowTooltip: true } }, price: { - title: t('message.pages.miscprocurement.misc_materials.price'), + title: t('message.pages.miscprocurement.materialInfo.price'), type: 'number', - form: { rules: [{ required: true, message: t('message.pages.miscprocurement.misc_materials.price') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }], component: { props: { precision: 2 } } }, + form: { rules: [{ required: true, message: t('message.pages.miscprocurement.materialInfo.price') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }], component: { props: { precision: 2 } } }, column: { width: 120 } }, status: { - title: t('message.pages.miscprocurement.misc_materials.status'), + title: t('message.pages.miscprocurement.materialInfo.status'), type: 'dict-switch', dict: dict({ data: statusDict }), form: { value: 1 }, column: { width: 120 } }, create_datetime: { - title: '创建时间', + title: t('message.pages.miscprocurement.materialInfo.createTime'), type: 'datetime', form: { show: false }, column: { width: 180 } }, update_datetime: { - title: '更新时间', + title: t('message.pages.miscprocurement.materialInfo.updateTime'), type: 'datetime', form: { show: false }, column: { width: 180 } diff --git a/web/src/views/pisadmin/miscprocurement/misc_parts/crud.tsx b/web/src/views/pisadmin/miscprocurement/misc_parts/crud.tsx index bfef5b0..e2153c2 100644 --- a/web/src/views/pisadmin/miscprocurement/misc_parts/crud.tsx +++ b/web/src/views/pisadmin/miscprocurement/misc_parts/crud.tsx @@ -4,17 +4,6 @@ import { GetCompanies } from '../../basicinfo/currency/api' import { GetList as GetUnits } from '../../basicinfo/unit/api' import { ElMessage } from 'element-plus' -const statusDict = [ - { value: 1, label: '启用' }, - { value: 0, label: '禁用' } -] - -const categoryDict = [ - { value: 1, label: '模治具' }, - { value: 2, label: '石墨' }, - { value: 3, label: '其他' } -] - const loadCompanyOptions = async () => { try { const res = await GetCompanies({ page: 1, page_size: 1000, pageSize: 1000 }) @@ -62,8 +51,20 @@ const loadUnitOptions = async (companyCode?: string) => { void loadCompanyOptions() export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet { + const { t } = useI18n() void crudExpose + const statusDict = () => [ + { value: 1, label: t('message.pages.miscprocurement.misc_parts.statusEnabled') }, + { value: 0, label: t('message.pages.miscprocurement.misc_parts.statusDisabled') } + ] + + const categoryDict = () => [ + { value: 1, label: t('message.pages.miscprocurement.misc_parts.categoryTooling') }, + { value: 2, label: t('message.pages.miscprocurement.misc_parts.categoryGraphite') }, + { value: 3, label: t('message.pages.miscprocurement.misc_parts.categoryOther') } + ] + const ensurePartUnique = async (companyCode: string, partId: string, currentId?: number) => { if (!companyCode || !partId) return const res = await api.GetList({ company_code: companyCode, partid: partId, page: 1, page_size: 1, pageSize: 1 }) @@ -79,7 +80,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp ? list.find((item: any) => item.company_code === companyCode && item.partid === partId) : null if (exists && (!currentId || exists.id !== currentId)) { - throw new Error('同一交易厂区下料号已存在,不可重复') + throw new Error(t('message.pages.miscprocurement.misc_parts.companyCode') + t('message.pages.miscprocurement.misc_parts.partid') + t('message.pages.miscprocurement.misc_parts.validation.alreadyExists')) } } return { @@ -122,7 +123,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp }, columns: { company_code: { - title: '交易厂区', + title: t('message.pages.miscprocurement.misc_parts.companyCode'), type: 'dict-select', dict: dict({ cache: false, @@ -144,55 +145,55 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp column: { minWidth: 160, showOverflowTooltip: true } }, partid: { - title: '料号', + title: t('message.pages.miscprocurement.misc_parts.partid'), type: 'input', - search: { show: true, component: { props: { placeholder: '请输入料号', clearable: true } } }, - form: { rules: [{ required: true, message: '请输入料号' }] }, + search: { show: true, component: { props: { placeholder: t('message.pages.miscprocurement.misc_parts.partid'), clearable: true } } }, + form: { rules: [{ required: true, message: t('message.pages.miscprocurement.misc_parts.partid') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, column: { minWidth: 160, showOverflowTooltip: true } }, partid_name: { - title: '物料说明', + title: t('message.pages.miscprocurement.misc_parts.partidName'), type: 'input', - form: { rules: [{ required: true, message: '请输入物料说明' }] }, + form: { rules: [{ required: true, message: t('message.pages.miscprocurement.misc_parts.partidName') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, column: { minWidth: 160, showOverflowTooltip: true } }, specification: { - title: '品名规格', + title: t('message.pages.miscprocurement.misc_parts.specification'), type: 'input', - form: { rules: [{ required: true, message: '请输入品名规格' }] }, + form: { rules: [{ required: true, message: t('message.pages.miscprocurement.misc_parts.specification') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, column: { minWidth: 160, showOverflowTooltip: true } }, unit: { - title: '单位', + title: t('message.pages.miscprocurement.misc_parts.unit'), type: 'dict-select', dict: dict({ cache: false, getData: async ({ form }: any = {}) => loadUnitOptions(form?.company_code) }), - form: { rules: [{ required: true, message: '请选择单位' }], component: { props: { placeholder: '先选择厂区' } } }, + form: { rules: [{ required: true, message: t('message.pages.miscprocurement.misc_parts.unit') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }], component: { props: { placeholder: t('message.pages.miscprocurement.misc_parts.companyCode') } } }, column: { width: 140, showOverflowTooltip: true } }, partid_category_id: { - title: '物料分类', + title: t('message.pages.miscprocurement.misc_parts.partidCategory'), type: 'dict-select', - dict: dict({ data: categoryDict }), + dict: dict({ data: categoryDict() }), column: { width: 140, showOverflowTooltip: true } }, status: { - title: '启用否', + title: t('message.pages.miscprocurement.misc_parts.status'), type: 'dict-switch', - dict: dict({ data: statusDict }), + dict: dict({ data: statusDict() }), form: { value: 1 }, column: { width: 120 } }, create_datetime: { - title: '创建时间', + title: t('message.pages.miscprocurement.misc_parts.createTime'), type: 'datetime', form: { show: false }, column: { width: 180 } }, update_datetime: { - title: '更新时间', + title: t('message.pages.miscprocurement.misc_parts.updateTime'), type: 'datetime', form: { show: false }, column: { width: 180 } diff --git a/web/src/views/pisadmin/miscprocurement/misc_stations/crud.tsx b/web/src/views/pisadmin/miscprocurement/misc_stations/crud.tsx index 210d45b..b688d6f 100644 --- a/web/src/views/pisadmin/miscprocurement/misc_stations/crud.tsx +++ b/web/src/views/pisadmin/miscprocurement/misc_stations/crud.tsx @@ -53,13 +53,13 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp const { t } = useI18n() const statusDict = [ - { value: 1, label: t('message.pages.miscprocurement.misc_stations.statusEnabled') }, - { value: 0, label: t('message.pages.miscprocurement.misc_stations.statusDisabled') } + { value: 1, label: t('message.pages.miscprocurement.stationInfo.statusEnabled') }, + { value: 0, label: t('message.pages.miscprocurement.stationInfo.statusDisabled') } ] const stationTypeDict = [ - { value: 1, label: t('message.pages.miscprocurement.misc_stations.typeTooling') }, - { value: 2, label: t('message.pages.miscprocurement.misc_stations.typeGraphite') } + { value: 1, label: t('message.pages.miscprocurement.stationInfo.typeTooling') }, + { value: 2, label: t('message.pages.miscprocurement.stationInfo.typeGraphite') } ] void crudExpose @@ -79,7 +79,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp ? list.find((item: any) => item.company_code === companyCode && item.stationcode === stationCode) : null if (exists && (!currentId || exists.id !== currentId)) { - throw new Error(t('message.pages.miscprocurement.misc_stations.companyCode') + t('message.pages.miscprocurement.misc_stations.stationcode') + t('message.pages.menu.validation.alreadyExists')) + throw new Error(t('message.pages.miscprocurement.stationInfo.companyCode') + t('message.pages.miscprocurement.stationInfo.stationcode') + t('message.pages.menu.validation.alreadyExists')) } } return { @@ -122,7 +122,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp }, columns: { company_code: { - title: t('message.pages.miscprocurement.misc_stations.companyCode'), + title: t('message.pages.miscprocurement.stationInfo.companyCode'), type: 'dict-select', dict: dict({ cache: false, @@ -134,60 +134,60 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp column: { minWidth: 160, showOverflowTooltip: true } }, stationcode: { - title: t('message.pages.miscprocurement.misc_stations.stationcode'), + title: t('message.pages.miscprocurement.stationInfo.stationcode'), type: 'input', - search: { show: true, component: { props: { placeholder: t('message.pages.miscprocurement.misc_stations.stationcode'), clearable: true } } }, - form: { rules: [{ required: true, message: t('message.pages.miscprocurement.misc_stations.stationcode') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, + search: { show: true, component: { props: { placeholder: t('message.pages.miscprocurement.stationInfo.stationcode'), clearable: true } } }, + form: { rules: [{ required: true, message: t('message.pages.miscprocurement.stationInfo.stationcode') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, editForm: { component: { props: { disabled: true } } }, column: { minWidth: 140, showOverflowTooltip: true } }, stationname: { - title: t('message.pages.miscprocurement.misc_stations.stationname'), + title: t('message.pages.miscprocurement.stationInfo.stationname'), type: 'input', - search: { show: true, component: { props: { placeholder: t('message.pages.miscprocurement.misc_stations.stationname'), clearable: true } } }, - form: { rules: [{ required: true, message: t('message.pages.miscprocurement.misc_stations.stationname') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, + search: { show: true, component: { props: { placeholder: t('message.pages.miscprocurement.stationInfo.stationname'), clearable: true } } }, + form: { rules: [{ required: true, message: t('message.pages.miscprocurement.stationInfo.stationname') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, column: { minWidth: 160, showOverflowTooltip: true } }, stationtype: { - title: t('message.pages.miscprocurement.misc_stations.stationtype'), + title: t('message.pages.miscprocurement.stationInfo.stationtype'), type: 'dict-select', dict: dict({ data: stationTypeDict }), - form: { rules: [{ required: true, message: t('message.pages.miscprocurement.misc_stations.stationtype') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, + form: { rules: [{ required: true, message: t('message.pages.miscprocurement.stationInfo.stationtype') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, column: { width: 140, showOverflowTooltip: true } }, unit: { - title: t('message.pages.miscprocurement.misc_stations.unit'), + title: t('message.pages.miscprocurement.stationInfo.unit'), type: 'dict-select', dict: dict({ cache: false, getData: async () => loadUnitOptions() }), - form: { rules: [{ required: true, message: t('message.pages.miscprocurement.misc_stations.unit') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, + form: { rules: [{ required: true, message: t('message.pages.miscprocurement.stationInfo.unit') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }] }, column: { width: 140, showOverflowTooltip: true } }, rate: { - title: t('message.pages.miscprocurement.misc_stations.rate'), + title: t('message.pages.miscprocurement.stationInfo.rate'), type: 'number', - form: { rules: [{ required: true, message: t('message.pages.miscprocurement.misc_stations.rate') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }], component: { props: { precision: 2 } } }, + form: { rules: [{ required: true, message: t('message.pages.miscprocurement.stationInfo.rate') + ' ' + t('message.pages.menu.validation.fieldNameRequired') }], component: { props: { precision: 2 } } }, column: { width: 120 } }, status: { - title: t('message.pages.miscprocurement.misc_stations.status'), + title: t('message.pages.miscprocurement.stationInfo.status'), type: 'dict-switch', dict: dict({ data: statusDict }), form: { value: 1 }, column: { width: 120 } }, create_datetime: { - title: '创建时间', + title: t('message.pages.miscprocurement.stationInfo.createTime'), type: 'datetime', form: { show: false }, column: { width: 180 } }, update_datetime: { - title: '更新时间', + title: t('message.pages.miscprocurement.stationInfo.updateTime'), type: 'datetime', form: { show: false }, column: { width: 180 } From 6a73422e82345d6833c875445a4d4b02716962d6 Mon Sep 17 00:00:00 2001 From: Lewis_yan Date: Wed, 8 Apr 2026 22:25:10 +0800 Subject: [PATCH 07/24] fix(i18n): add missing useI18n import in misc_parts/crud.tsx --- web/src/views/pisadmin/miscprocurement/misc_parts/crud.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/web/src/views/pisadmin/miscprocurement/misc_parts/crud.tsx b/web/src/views/pisadmin/miscprocurement/misc_parts/crud.tsx index e2153c2..1d537ba 100644 --- a/web/src/views/pisadmin/miscprocurement/misc_parts/crud.tsx +++ b/web/src/views/pisadmin/miscprocurement/misc_parts/crud.tsx @@ -1,4 +1,5 @@ import { dict, CreateCrudOptionsProps, CreateCrudOptionsRet } from '@fast-crud/fast-crud' +import { useI18n } from 'vue-i18n' import * as api from './api' import { GetCompanies } from '../../basicinfo/currency/api' import { GetList as GetUnits } from '../../basicinfo/unit/api' From 40c376f205eb814bc8b38f6c1277246a039be104 Mon Sep 17 00:00:00 2001 From: Lewis_yan Date: Wed, 8 Apr 2026 22:30:38 +0800 Subject: [PATCH 08/24] feat(i18n): add missing inquiry status keys and paymentPrepaid to pissupplier quotation --- web/src/i18n/pages/pissupplier/en.ts | 58 ++++++++++++++++++++ web/src/i18n/pages/pissupplier/zh-cn.ts | 58 ++++++++++++++++++++ web/src/i18n/pages/pissupplier/zh-tw.ts | 58 ++++++++++++++++++++ web/src/views/pissupplier/quotation/crud.tsx | 10 ++-- 4 files changed, 179 insertions(+), 5 deletions(-) diff --git a/web/src/i18n/pages/pissupplier/en.ts b/web/src/i18n/pages/pissupplier/en.ts index a096b85..7ba8c2b 100644 --- a/web/src/i18n/pages/pissupplier/en.ts +++ b/web/src/i18n/pages/pissupplier/en.ts @@ -68,6 +68,64 @@ export default { lowestPrice: 'Lowest Price', averagePrice: 'Average Price', inquiryTitle: 'Inquiry Title', + fileTypeDrawing: 'Drawing', + fileTypeBidDoc: 'Bid Document', + fileTypeOther: 'Other', + paymentTt30_70: 'T/T 30% Prepay, 70% Before Shipment', + paymentNet30: 'Net 30 Days', + paymentNet45: 'Net 45 Days', + paymentPrepaid: 'Full Prepayment', + partNo: 'Part No', + specDesc: 'Spec Description', + processStation: 'Process Station', + processUnit: 'Process Unit', + processRate: 'Station Rate', + processMeasure: 'Process Qty', + specificGravity: 'Specific Gravity', + totalPrice: 'Total Amount', + taxAmount: 'Tax Amount', + taxRatePct: 'Tax Rate (%)', + profitAmount: 'Profit Amount', + profitRatePct: 'Profit Rate (%)', + saved: 'Saved', + submitted: 'Submitted', + submittedInquiryClosed: 'Submitted, Inquiry Closed', + saveFailed: 'Save Failed', + submitFailed: 'Submit Failed', + cannotAddRowNoFields: 'Please configure fields in the template before adding rows', + attachmentUploadFailed: 'Attachment upload failed: {{name}}', + attachmentMissingPath: 'Attachment path missing: {{name}}', + unnamed: 'Unnamed', + unnamedFile: 'Unnamed File', + statusEvaluating: 'Evaluating', + statusLost: 'Lost', + statusOpen: 'Open', + statusConfirmed: 'Confirmed', + statusPublished: 'Published', + statusQuotingEnd: 'Quote Ended', + statusBargaining: 'Bargaining', + statusPriceAudit: 'Price Audit', + statusPriceApproved: 'Price Approved', + statusCancelled: 'Cancelled', + length: 'Length', + width: 'Width', + height: 'Height', + qty: 'Qty', + material: 'Material', + }, + vendorType: { + stateOwned: 'State-owned', + collective: 'Collective', + private: 'Private', + joint: 'Joint Venture', + whollyOwned: 'Wholly Foreign-owned', + other: 'Other', + }, + paymentTerms: { + tt30_70: 'T/T 30% Prepay, 70% Before Shipment', + net30: 'Net 30 Days', + net45: 'Net 45 Days', + prepaid: 'Full Prepayment', }, }, }, diff --git a/web/src/i18n/pages/pissupplier/zh-cn.ts b/web/src/i18n/pages/pissupplier/zh-cn.ts index 3b91d2b..2f67cd1 100644 --- a/web/src/i18n/pages/pissupplier/zh-cn.ts +++ b/web/src/i18n/pages/pissupplier/zh-cn.ts @@ -68,6 +68,64 @@ export default { lowestPrice: '制程最低价', averagePrice: '平均价', inquiryTitle: '询价单名称', + fileTypeDrawing: '图纸', + fileTypeBidDoc: '招标文件', + fileTypeOther: '其他', + paymentTt30_70: 'T/T 30%预付,70%出货前', + paymentNet30: '月结30天', + paymentNet45: '月结45天', + paymentPrepaid: '全额预付', + partNo: '料号', + specDesc: '规格描述', + processStation: '加工工站', + processUnit: '加工单位', + processRate: '工站费率', + processMeasure: '加工数量', + specificGravity: '比重', + totalPrice: '合计金额', + taxAmount: '税额', + taxRatePct: '税率(%)', + profitAmount: '利润金额', + profitRatePct: '利润率(%)', + saved: '已保存', + submitted: '已提交', + submittedInquiryClosed: '已提交,询价单已关闭', + saveFailed: '保存失败', + submitFailed: '提交失败', + cannotAddRowNoFields: '请先在模板中配置要填写的字段后再新增行', + attachmentUploadFailed: '附件上传失败:{{name}}', + attachmentMissingPath: '附件路径缺失:{{name}}', + unnamed: '未命名', + unnamedFile: '未命名文件', + statusEvaluating: '评标中', + statusLost: '落标', + statusOpen: '开立', + statusConfirmed: '确认', + statusPublished: '发布', + statusQuotingEnd: '报价结束', + statusBargaining: '比议价中', + statusPriceAudit: '价格审核', + statusPriceApproved: '核价通过(结束)', + statusCancelled: '作废', + length: '长', + width: '宽', + height: '高', + qty: '数量', + material: '材质', + }, + vendorType: { + stateOwned: '国有', + collective: '集体', + private: '私营', + joint: '合资', + whollyOwned: '独资', + other: '其他', + }, + paymentTerms: { + tt30_70: 'T/T 30%预付,70%出货前', + net30: '月结30天', + net45: '月结45天', + prepaid: '全额预付', }, }, }, diff --git a/web/src/i18n/pages/pissupplier/zh-tw.ts b/web/src/i18n/pages/pissupplier/zh-tw.ts index a51da41..91046a2 100644 --- a/web/src/i18n/pages/pissupplier/zh-tw.ts +++ b/web/src/i18n/pages/pissupplier/zh-tw.ts @@ -68,6 +68,64 @@ export default { lowestPrice: '製程最低價', averagePrice: '平均價', inquiryTitle: '詢價單名稱', + fileTypeDrawing: '圖紙', + fileTypeBidDoc: '招標文件', + fileTypeOther: '其他', + paymentTt30_70: 'T/T 30%預付,70%出貨前', + paymentNet30: '月結30天', + paymentNet45: '月結45天', + paymentPrepaid: '全額預付', + partNo: '料號', + specDesc: '規格描述', + processStation: '加工工站', + processUnit: '加工單位', + processRate: '工站費率', + processMeasure: '加工數量', + specificGravity: '比重', + totalPrice: '合計金額', + taxAmount: '稅額', + taxRatePct: '稅率(%)', + profitAmount: '利潤金額', + profitRatePct: '利潤率(%)', + saved: '已儲存', + submitted: '已提交', + submittedInquiryClosed: '已提交,詢價單已關閉', + saveFailed: '儲存失敗', + submitFailed: '提交失敗', + cannotAddRowNoFields: '請先在模板中配置要填寫的欄位後再新增行', + attachmentUploadFailed: '附件上傳失敗:{{name}}', + attachmentMissingPath: '附件路徑缺失:{{name}}', + unnamed: '未命名', + unnamedFile: '未命名檔案', + statusEvaluating: '評標中', + statusLost: '落標', + statusOpen: '開立', + statusConfirmed: '確認', + statusPublished: '發布', + statusQuotingEnd: '報價結束', + statusBargaining: '比議價中', + statusPriceAudit: '價格審核', + statusPriceApproved: '核價通過(結束)', + statusCancelled: '作廢', + length: '長', + width: '寬', + height: '高', + qty: '數量', + material: '材質', + }, + vendorType: { + stateOwned: '國有', + collective: '集體', + private: '私營', + joint: '合資', + whollyOwned: '獨資', + other: '其他', + }, + paymentTerms: { + tt30_70: 'T/T 30%預付,70%出貨前', + net30: '月結30天', + net45: '月結45天', + prepaid: '全額預付', }, }, }, diff --git a/web/src/views/pissupplier/quotation/crud.tsx b/web/src/views/pissupplier/quotation/crud.tsx index 4ad2c99..3238ac4 100644 --- a/web/src/views/pissupplier/quotation/crud.tsx +++ b/web/src/views/pissupplier/quotation/crud.tsx @@ -83,9 +83,9 @@ type Quote = { type SummaryRow = { section: string; amount: number; isSubtotal?: boolean } /** 与杂采询价列表列展示一致 */ -export const buyingMethodDict = [ - { value: 1, label: '询价' }, - { value: 2, label: '招标' } +export const getBuyingMethodDict = (t: Function) => [ + { value: 1, label: t('message.pages.pissupplier.quotation.buyingMethodInquiry') }, + { value: 2, label: t('message.pages.pissupplier.quotation.buyingMethodBid') } ] export function formatQuoteDeadlineDisplay(value: unknown) { @@ -806,7 +806,7 @@ const costItemsFromQuotationApi = (item: any, t: Function): CostItem[] => { section: '其它成本', attrs: [ { key: 'part_id', label: t('message.pages.pissupplier.quotation.partNo'), value: o.part_id ?? '' }, - { key: 'packageFee', label: t('message.pages.pissupplier.quotation.packageFee'), value: o.packaging_cost ?? '' }, + { key: 'packageFee', label: t('message.pages.pissupplier.quotation.packagingFee'), value: o.packaging_cost ?? '' }, { key: 'transportFee', label: t('message.pages.pissupplier.quotation.transportFee'), value: o.transportation_cost ?? '' } ] }) @@ -2380,7 +2380,7 @@ export function useQuoteCrud(options?: { return { filters, - statusOptions: getStatusOptions(), + statusOptions: getStatusOptions(t), resetFilter, filteredQuotes, loading, From 7a3dc8376e4e4830b49579bfed0caef187058486 Mon Sep 17 00:00:00 2001 From: Lewis_yan Date: Wed, 8 Apr 2026 22:32:50 +0800 Subject: [PATCH 09/24] fix(i18n): revert buyingMethodDict rename - still used by index.vue import --- web/src/views/pissupplier/quotation/crud.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/src/views/pissupplier/quotation/crud.tsx b/web/src/views/pissupplier/quotation/crud.tsx index 3238ac4..73c4dcb 100644 --- a/web/src/views/pissupplier/quotation/crud.tsx +++ b/web/src/views/pissupplier/quotation/crud.tsx @@ -83,9 +83,9 @@ type Quote = { type SummaryRow = { section: string; amount: number; isSubtotal?: boolean } /** 与杂采询价列表列展示一致 */ -export const getBuyingMethodDict = (t: Function) => [ - { value: 1, label: t('message.pages.pissupplier.quotation.buyingMethodInquiry') }, - { value: 2, label: t('message.pages.pissupplier.quotation.buyingMethodBid') } +export const buyingMethodDict = [ + { value: 1, label: '询价' }, + { value: 2, label: '招标' } ] export function formatQuoteDeadlineDisplay(value: unknown) { From 89b16e6047da7b4aa0d08f87e178f4e55e5af117 Mon Sep 17 00:00:00 2001 From: Lewis_yan Date: Wed, 8 Apr 2026 22:37:15 +0800 Subject: [PATCH 10/24] feat(i18n): full i18n adaptation of pissupplier quotation index.vue and add missing i18n keys --- web/src/i18n/pages/pissupplier/en.ts | 10 ++++ web/src/i18n/pages/pissupplier/zh-cn.ts | 10 ++++ web/src/i18n/pages/pissupplier/zh-tw.ts | 10 ++++ web/src/views/pissupplier/quotation/index.vue | 49 ++++++++++--------- 4 files changed, 56 insertions(+), 23 deletions(-) diff --git a/web/src/i18n/pages/pissupplier/en.ts b/web/src/i18n/pages/pissupplier/en.ts index 7ba8c2b..800a96f 100644 --- a/web/src/i18n/pages/pissupplier/en.ts +++ b/web/src/i18n/pages/pissupplier/en.ts @@ -112,6 +112,16 @@ export default { height: 'Height', qty: 'Qty', material: 'Material', + companyShortName: 'Transaction Plant', + inquiryTemplate: 'Inquiry Template', + quoteTime: 'Quote Time', + currency: 'Currency', + quoteStatus: 'Quote Status', + createTime: 'Create Time', + quoteNow: 'Quote Now', + submitQuote: 'Submit', + view: 'View', + companyCodeOrName: 'Company code or name', }, vendorType: { stateOwned: 'State-owned', diff --git a/web/src/i18n/pages/pissupplier/zh-cn.ts b/web/src/i18n/pages/pissupplier/zh-cn.ts index 2f67cd1..3a19584 100644 --- a/web/src/i18n/pages/pissupplier/zh-cn.ts +++ b/web/src/i18n/pages/pissupplier/zh-cn.ts @@ -112,6 +112,16 @@ export default { height: '高', qty: '数量', material: '材质', + companyShortName: '交易厂区', + inquiryTemplate: '询价模板', + quoteTime: '报价时间', + currency: '币别', + quoteStatus: '报价状态', + createTime: '创建时间', + quoteNow: '报价', + submitQuote: '提交', + view: '查看', + companyCodeOrName: '公司代码或简称', }, vendorType: { stateOwned: '国有', diff --git a/web/src/i18n/pages/pissupplier/zh-tw.ts b/web/src/i18n/pages/pissupplier/zh-tw.ts index 91046a2..a7cc0f1 100644 --- a/web/src/i18n/pages/pissupplier/zh-tw.ts +++ b/web/src/i18n/pages/pissupplier/zh-tw.ts @@ -112,6 +112,16 @@ export default { height: '高', qty: '數量', material: '材質', + companyShortName: '交易廠區', + inquiryTemplate: '詢價模版', + quoteTime: '報價時間', + currency: '幣別', + quoteStatus: '報價狀態', + createTime: '創建時間', + quoteNow: '報價', + submitQuote: '提交', + view: '查看', + companyCodeOrName: '公司代碼或簡稱', }, vendorType: { stateOwned: '國有', diff --git a/web/src/views/pissupplier/quotation/index.vue b/web/src/views/pissupplier/quotation/index.vue index b72495f..b884088 100644 --- a/web/src/views/pissupplier/quotation/index.vue +++ b/web/src/views/pissupplier/quotation/index.vue @@ -22,6 +22,7 @@ From 26fde667e2e039cc5caa49546e07e897a2781995 Mon Sep 17 00:00:00 2001 From: Lewis_yan Date: Thu, 9 Apr 2026 11:23:41 +0800 Subject: [PATCH 24/24] feat(i18n): adapt buyer/supplier dashboards to use i18n keys - Add buyerDashboard and supplierDashboard i18n keys to home module (zh-cn / en / zh-tw) - Replace all hardcoded Chinese text in BuyerDashboard.vue and SupplierDashboard.vue with $t() calls - Update index.vue role switcher buttons to use i18n - quickNav items, chart legend, KPI labels all now support i18n --- web/src/i18n/pages/home/en.ts | 141 ++++++++++++++ web/src/i18n/pages/home/zh-cn.ts | 141 ++++++++++++++ web/src/i18n/pages/home/zh-tw.ts | 182 ++++++++++++++++++ .../pisadmin/dashboard/BuyerDashboard.vue | 91 ++++----- .../pisadmin/dashboard/SupplierDashboard.vue | 93 ++++----- web/src/views/pisadmin/dashboard/index.vue | 10 +- 6 files changed, 568 insertions(+), 90 deletions(-) diff --git a/web/src/i18n/pages/home/en.ts b/web/src/i18n/pages/home/en.ts index 0319c25..924dc48 100644 --- a/web/src/i18n/pages/home/en.ts +++ b/web/src/i18n/pages/home/en.ts @@ -35,6 +35,147 @@ export default { notifications: { defaultCreator: 'Unknown User', }, + buyerDashboard: { + roleSwitch: { + buyer: 'Buyer Dashboard', + supplier: 'Supplier Dashboard', + }, + kpi: { + totalInquiries: 'Total Completed Inquiries', + pendingInquiries: 'Pending Inquiries', + quoteTimelyRate: 'Quote Timely Rate', + trendUp: '+12% vs last month', + trendFlat: 'Flat', + }, + task: { + title: 'My Tasks', + empty: 'No pending tasks', + table: { + columns: { + inquiryNo: 'Inquiry No.', + method: 'Procurement Method', + name: 'Inquiry Name', + status: 'Status', + deadline: 'Deadline / Remaining', + action: 'Action', + }, + }, + status: { + bidCompare: 'Bid Comparison', + published: 'Published', + negotiation: 'Negotiation', + urgent: 'Urgent', + default: '', + }, + action: { + goBidCompare: 'Go to Compare', + goNegotiate: 'Go to Negotiate', + viewDetail: 'View Details', + }, + }, + deadline: { + bidTime: 'Bid Time:', + quoteDeadline: 'Quote Deadline:', + remaining: 'Remaining:', + bidInProgress: 'Bid in Progress', + ended: 'Ended', + started: 'Started', + expired: 'Expired', + }, + notification: { + title: 'System Notifications', + empty: 'No notifications', + defaultCreator: 'Unknown User', + }, + quickNav: { + title: 'Quick Navigation', + items: { + role: 'Role Management', + dept: 'Department Management', + config: 'System Config', + dictionary: 'Dictionary Management', + areas: 'Area Management', + message: 'Message Center', + }, + }, + chart: { + title: 'Last 30 Days Trend', + legend: { + publishInquiry: 'Inquiries Published', + negotiationComplete: 'Negotiations Complete', + }, + yAxisName: 'Count', + }, + viewAll: 'View All', + more: 'More', + method: { + inquiry: 'Inquiry', + tender: 'Tender', + }, + }, + supplierDashboard: { + kpi: { + totalQuotes: 'Total Quotes', + pendingQuotes: 'Pending Quotes', + wonQuotes: 'Won Quotes', + conversionRate: 'Win Rate', + trendUp: '+8% vs last month', + waiting: 'Awaiting Quote', + winSuccess: 'Won Successfully', + trendFlat: 'Flat', + }, + quoteList: { + title: 'Pending Quote List', + empty: 'No pending quotes', + columns: { + inquiryNo: 'Inquiry No.', + status: 'Status', + method: 'Procurement Method', + deadline: 'Deadline', + action: 'Action', + }, + productName: 'Product Name', + quantity: 'Quantity', + }, + quoteStatus: { + unquoted: 'Unquoted', + quoting: 'Quoting', + quoted: 'Quoted', + }, + quoteAction: { + goQuote: 'Go to Quote', + }, + notification: { + title: 'System Notifications', + empty: 'No notifications', + defaultCreator: 'Unknown User', + }, + quickNav: { + title: 'Quick Navigation', + items: { + role: 'Role Management', + dept: 'Department Management', + config: 'System Config', + dictionary: 'Dictionary Management', + areas: 'Area Management', + message: 'Message Center', + }, + }, + chart: { + title: 'Quote & Win Trend', + legend: { + quotes: 'Quotes', + won: 'Won', + }, + yAxisName: 'Count', + }, + viewAll: 'View All', + more: 'More', + method: { + inquiry: 'Inquiry', + tender: 'Tender', + }, + }, }, }, }, diff --git a/web/src/i18n/pages/home/zh-cn.ts b/web/src/i18n/pages/home/zh-cn.ts index 746adbd..8a53562 100644 --- a/web/src/i18n/pages/home/zh-cn.ts +++ b/web/src/i18n/pages/home/zh-cn.ts @@ -35,6 +35,147 @@ export default { notifications: { defaultCreator: '未知用户', }, + buyerDashboard: { + roleSwitch: { + buyer: '采购方仪表盘', + supplier: '供应商仪表盘', + }, + kpi: { + totalInquiries: '已完成询价单总数', + pendingInquiries: '进行中询价单', + quoteTimelyRate: '供应商报价及时率', + trendUp: '较上月 +12%', + trendFlat: '持平', + }, + task: { + title: '我的待办任务', + empty: '暂无待办任务', + table: { + columns: { + inquiryNo: '询价单号', + method: '采购方式', + name: '询价单名称', + status: '当前状态', + deadline: '截止时间 / 剩余时间', + action: '操作', + }, + }, + status: { + bidCompare: '比价', + published: '发布', + negotiation: '议价', + urgent: '紧急', + default: '', + }, + action: { + goBidCompare: '去比价', + goNegotiate: '去议价', + viewDetail: '查看详情', + }, + }, + deadline: { + bidTime: '投标时间:', + quoteDeadline: '报价截止时间:', + remaining: '剩余:', + bidInProgress: '投标进行中', + ended: '已结束', + started: '已开始', + expired: '已到期', + }, + notification: { + title: '系统通知', + empty: '暂无通知', + defaultCreator: '未知用户', + }, + quickNav: { + title: '快捷入口', + items: { + role: '角色管理', + dept: '部门管理', + config: '系统配置', + dictionary: '字典管理', + areas: '区域管理', + message: '消息中心', + }, + }, + chart: { + title: '近30天业务趋势', + legend: { + publishInquiry: '发布询价', + negotiationComplete: '议价完成', + }, + yAxisName: '单据数量', + }, + viewAll: '查看全部', + more: '更多', + method: { + inquiry: '询价', + tender: '招标', + }, + }, + supplierDashboard: { + kpi: { + totalQuotes: '报价单总数', + pendingQuotes: '待报价', + wonQuotes: '已中标', + conversionRate: '中标率', + trendUp: '较上月 +8%', + waiting: '等待报价', + winSuccess: '中标成功', + trendFlat: '持平', + }, + quoteList: { + title: '待报价清单', + empty: '暂无待报价清单', + columns: { + inquiryNo: '询价单号', + status: '状态', + method: '采购方式', + deadline: '截止时间', + action: '操作', + }, + productName: '产品名称', + quantity: '数量', + }, + quoteStatus: { + unquoted: '未报价', + quoting: '报价中', + quoted: '已报价', + }, + quoteAction: { + goQuote: '去报价', + }, + notification: { + title: '系统通知', + empty: '暂无通知', + defaultCreator: '未知用户', + }, + quickNav: { + title: '快捷入口', + items: { + role: '角色管理', + dept: '部门管理', + config: '系统配置', + dictionary: '字典管理', + areas: '区域管理', + message: '消息中心', + }, + }, + chart: { + title: '报价与中标趋势', + legend: { + quotes: '报价数', + won: '中标数', + }, + yAxisName: '单据数量', + }, + viewAll: '查看全部', + more: '更多', + method: { + inquiry: '询价', + tender: '招标', + }, + }, }, }, }, diff --git a/web/src/i18n/pages/home/zh-tw.ts b/web/src/i18n/pages/home/zh-tw.ts index e69de29..393d918 100644 --- a/web/src/i18n/pages/home/zh-tw.ts +++ b/web/src/i18n/pages/home/zh-tw.ts @@ -0,0 +1,182 @@ +// Define content +export default { + message: { + pages: { + home: { + statCards: { + orderStats: '訂單統計信息', + monthlyPlan: '月度計劃信息', + visitStats: '訪問統計信息', + }, + chart: { + // Line chart (政策补贴额度) + lineTitle: '政策補貼額度', + lineLegendPreOrder: '預購隊列', + lineLegendLatestPrice: '最新成交價', + lineYAxisName: '價格', + month: '月', + // Pie chart (房屋建筑工程) + pieTitle: '房屋建築工程', + pieCategory1: '房屋及結構物', + pieCategory2: '專用設備', + pieCategory3: '通用設備', + pieCategory4: '文物和陳列品', + pieCategory5: '圖書、檔案', + // Bar chart (地热开发利用) + barTitle: '地熱開發利用', + barLegendSupplyTemp: '供溫', + barLegendReturnTemp: '回溫', + barLegendPressure: '壓力值(Mpa)', + barYAxisSupplyReturn: '供回溫度(℃)', + }, + quickNav: { + quickNavTitle: '快捷導航工具', + }, + notifications: { + defaultCreator: '未知用戶', + }, + buyerDashboard: { + roleSwitch: { + buyer: '採購方儀表盤', + supplier: '供應商儀表盤', + }, + kpi: { + totalInquiries: '已完成詢價單總數', + pendingInquiries: '進行中詢價單', + quoteTimelyRate: '供應商報價及時率', + trendUp: '較上月 +12%', + trendFlat: '持平', + }, + task: { + title: '我的待辦任務', + empty: '暫無待辦任務', + table: { + columns: { + inquiryNo: '詢價單號', + method: '採購方式', + name: '詢價單名稱', + status: '當前狀態', + deadline: '截止時間 / 剩餘時間', + action: '操作', + }, + }, + status: { + bidCompare: '比價', + published: '發布', + negotiation: '議價', + urgent: '緊急', + default: '', + }, + action: { + goBidCompare: '去比價', + goNegotiate: '去議價', + viewDetail: '查看詳情', + }, + }, + deadline: { + bidTime: '投標時間:', + quoteDeadline: '報價截止時間:', + remaining: '剩餘:', + bidInProgress: '投標進行中', + ended: '已結束', + started: '已開始', + expired: '已到期', + }, + notification: { + title: '系統通知', + empty: '暫無通知', + defaultCreator: '未知用戶', + }, + quickNav: { + title: '快捷入口', + items: { + role: '角色管理', + dept: '部門管理', + config: '系統配置', + dictionary: '字典管理', + areas: '區域管理', + message: '消息中心', + }, + }, + chart: { + title: '近30天業務趨勢', + legend: { + publishInquiry: '發布詢價', + negotiationComplete: '議價完成', + }, + yAxisName: '單據數量', + }, + viewAll: '查看全部', + more: '更多', + method: { + inquiry: '詢價', + tender: '招標', + }, + }, + supplierDashboard: { + kpi: { + totalQuotes: '報價單總數', + pendingQuotes: '待報價', + wonQuotes: '已中標', + conversionRate: '中標率', + trendUp: '較上月 +8%', + waiting: '等待報價', + winSuccess: '中標成功', + trendFlat: '持平', + }, + quoteList: { + title: '待報價清單', + empty: '暫無待報價清單', + columns: { + inquiryNo: '詢價單號', + status: '狀態', + method: '採購方式', + deadline: '截止時間', + action: '操作', + }, + productName: '產品名稱', + quantity: '數量', + }, + quoteStatus: { + unquoted: '未報價', + quoting: '報價中', + quoted: '已報價', + }, + quoteAction: { + goQuote: '去報價', + }, + notification: { + title: '系統通知', + empty: '暫無通知', + defaultCreator: '未知用戶', + }, + quickNav: { + title: '快捷入口', + items: { + role: '角色管理', + dept: '部門管理', + config: '系統配置', + dictionary: '字典管理', + areas: '區域管理', + message: '消息中心', + }, + }, + chart: { + title: '報價與中標趨勢', + legend: { + quotes: '報價數', + won: '中標數', + }, + yAxisName: '單據數量', + }, + viewAll: '查看全部', + more: '更多', + method: { + inquiry: '詢價', + tender: '招標', + }, + }, + }, + }, + }, +}; diff --git a/web/src/views/pisadmin/dashboard/BuyerDashboard.vue b/web/src/views/pisadmin/dashboard/BuyerDashboard.vue index 10f44a6..5ab98fa 100644 --- a/web/src/views/pisadmin/dashboard/BuyerDashboard.vue +++ b/web/src/views/pisadmin/dashboard/BuyerDashboard.vue @@ -10,20 +10,20 @@
-
已完成询价单总数
+
{{ $t('message.pages.home.buyerDashboard.kpi.totalInquiries') }}
{{ kpi.total_inquiries.toLocaleString() }}
-
较上月 +12%
+
{{ $t('message.pages.home.buyerDashboard.kpi.trendUp') }}
-
进行中询价单
+
{{ $t('message.pages.home.buyerDashboard.kpi.pendingInquiries') }}
{{ kpi.pending_inquiries }}
-
供应商报价及时率
+
{{ $t('message.pages.home.buyerDashboard.kpi.quoteTimelyRate') }}
{{ kpi.quote_timely_rate }}%
-
持平
+
{{ $t('message.pages.home.buyerDashboard.kpi.trendFlat') }}
@@ -33,21 +33,21 @@
- 我的待办任务({{ tasks.length }} {{ $t('message.pages.home.buyerDashboard.task.title') }}({{ tasks.length }})
- 查看全部 + {{ $t('message.pages.home.buyerDashboard.viewAll') }}
- - - - - - + + + + + + @@ -72,7 +72,7 @@ @@ -86,7 +86,7 @@ - +
询价单号采购方式询价单名称当前状态截止时间 / 剩余时间操作{{ $t('message.pages.home.buyerDashboard.task.table.columns.inquiryNo') }}{{ $t('message.pages.home.buyerDashboard.task.table.columns.method') }}{{ $t('message.pages.home.buyerDashboard.task.table.columns.name') }}{{ $t('message.pages.home.buyerDashboard.task.table.columns.status') }}{{ $t('message.pages.home.buyerDashboard.task.table.columns.deadline') }}{{ $t('message.pages.home.buyerDashboard.task.table.columns.action') }}
- 剩余: + {{ $t('message.pages.home.buyerDashboard.deadline.remaining') }} {{ getDeadlineRemainingValue(task) }}
暂无待办任务{{ $t('message.pages.home.buyerDashboard.task.empty') }}
@@ -102,8 +102,8 @@
-
系统通知
- 更多 +
{{ $t('message.pages.home.buyerDashboard.notification.title') }}
+ {{ $t('message.pages.home.buyerDashboard.more') }}
@@ -117,14 +117,14 @@
{{ v.title }}
-
暂无通知
+
{{ $t('message.pages.home.buyerDashboard.notification.empty') }}
-
快捷入口
+
{{ $t('message.pages.home.buyerDashboard.quickNav.title') }}
@@ -141,10 +141,10 @@
-
近30天业务趋势
+
{{ $t('message.pages.home.buyerDashboard.chart.title') }}
- 发布询价 - 议价完成 + {{ $t('message.pages.home.buyerDashboard.chart.legend.publishInquiry') }} + {{ $t('message.pages.home.buyerDashboard.chart.legend.negotiationComplete') }}
@@ -156,6 +156,7 @@