3 次代碼提交 9a709923cd ... f5e69e07d0

作者 SHA1 備註 提交日期
  wxyshine f5e69e07d0 feat(server): 国际化替换: 新增构建后发布到ftp 3 月之前
  wxyshine ce3200b1db feat(server): 新增构建后发布到ftp 3 月之前
  wxyshine 8abd4d42b0 feat(server): 国际化替换:完善功能管理FTP列表功能,系统管理FTP列表功能 4 月之前
共有 28 個文件被更改,包括 983 次插入339 次删除
  1. 47 2
      modules/common/src/main/resources/i18n/messages_en_US.properties
  2. 51 6
      modules/common/src/main/resources/i18n/messages_zh_CN.properties
  3. 47 2
      modules/common/src/main/resources/i18n/messages_zh_HK.properties
  4. 47 2
      modules/common/src/main/resources/i18n/messages_zh_TW.properties
  5. 45 0
      modules/common/src/main/resources/i18n/words.json
  6. 4 5
      modules/common/src/test/resources/baidubce_translate.txt
  7. 4 0
      modules/server/src/main/java/org/dromara/jpom/build/BuildExtraModule.java
  8. 81 11
      modules/server/src/main/java/org/dromara/jpom/build/ReleaseManage.java
  9. 44 1
      modules/server/src/main/java/org/dromara/jpom/controller/build/BuildInfoController.java
  10. 31 49
      modules/server/src/main/java/org/dromara/jpom/func/assets/controller/BaseFtpFileController.java
  11. 21 24
      modules/server/src/main/java/org/dromara/jpom/func/assets/controller/MachineFtpController.java
  12. 2 1
      modules/server/src/main/java/org/dromara/jpom/func/assets/controller/MachineFtpFileController.java
  13. 1 1
      modules/server/src/main/java/org/dromara/jpom/func/assets/model/MachineFtpModel.java
  14. 76 7
      modules/server/src/main/java/org/dromara/jpom/func/assets/server/MachineFtpServer.java
  15. 1 1
      modules/server/src/main/java/org/dromara/jpom/model/data/FtpModel.java
  16. 1 0
      modules/server/src/main/java/org/dromara/jpom/model/enums/BuildReleaseMethod.java
  17. 3 3
      modules/server/src/main/java/org/dromara/jpom/permission/ClassFeature.java
  18. 83 67
      modules/server/src/main/java/org/dromara/jpom/service/node/ftp/FtpService.java
  19. 8 8
      modules/server/src/main/java/org/dromara/jpom/system/db/InitDb.java
  20. 2 1
      web-vue/src/api/build-info.ts
  21. 8 0
      web-vue/src/api/ftp.ts
  22. 29 0
      web-vue/src/i18n/locales/en_us.json
  23. 29 0
      web-vue/src/i18n/locales/zh_cn.json
  24. 29 0
      web-vue/src/i18n/locales/zh_hk.json
  25. 29 0
      web-vue/src/i18n/locales/zh_tw.json
  26. 136 2
      web-vue/src/pages/build/edit.vue
  27. 22 23
      web-vue/src/pages/ftp/ftp.vue
  28. 102 123
      web-vue/src/pages/system/assets/ftp/ftp-list.vue

+ 47 - 2
modules/common/src/main/resources/i18n/messages_en_US.properties

@@ -1,5 +1,5 @@
 #i18n en_US
-#Thu Jan 09 16:59:46 CST 2025
+#Thu Jun 12 16:41:19 CST 2025
 i18n.ssh_info_does_not_exist.5ed0=SSH information does not exist
 i18n.incompatible_program_versions.5291=The current program version {} The new version of the program is minimum compatible {} and cannot be upgraded directly
 i18n.no_projects_configured.e873=No items are configured
@@ -8,6 +8,7 @@ i18n.machine_ssh_info.8dbb=Machine SSH information
 i18n.machine_info_not_exist.3468=The corresponding machine information does not exist.
 i18n.unsupported_method.a1de=Unsupported way
 i18n.delete_local_image_failed.91fa=Failed to delete local image
+i18n.cluster_not_grouped.8f54=The current cluster has not bound packets and cannot monitor FTP asset information
 i18n.service_name_in_cluster_required.5446=Please fill in the service name in the cluster
 i18n.cluster_manager_node_not_found.1cd0=No cluster management node found
 i18n.distribute_id_already_exists.2168=The distribution id already exists
@@ -34,6 +35,7 @@ i18n.start_waiting_for_data_migration.e76f=Start waiting for data migration
 i18n.empty_file_or_folder_for_publish.cae8=The published file or folder is empty and cannot continue publishing
 i18n.demo_account_cannot_use_feature.a1a1=The demo account cannot use this function.
 i18n.repository_type_required.9414=Please select a warehouse type
+i18n.start_backup_database.e554=Start backing up the database
 i18n.async_resource_expired.2ddc=The asynchronous resource has expired and needs to be actively closed, {} {}
 i18n.mark_cannot_be_empty.1927=Tag cannot be empty
 i18n.get_success.fb55=Get success
@@ -50,9 +52,11 @@ i18n.upload_failed_no_matching_project.b219=Upload failed, no corresponding dist
 i18n.no_branches_or_tags_in_repository.76b6=The warehouse does not have any branches or labels.
 i18n.download_file_description.10cb=Download file {} {} {}
 i18n.delay_build.7d62=Start building after a delay of {} seconds
+i18n.ftp_not_exist.f9b3=There is no corresponding ftp.
 i18n.default_cluster.38cf=default cluster
 i18n.node_and_check_project_failed.ac4b=Node and check item failed
 i18n.load_oauth2_config.da42=Load oauth2 configuration :{} {}
+i18n.affected_rows.5781=Number of rows affected
 i18n.cluster_not_bound_to_group_for_node_monitoring.1586=The current cluster has not been bound to a group, so the asset information of the cluster nodes cannot be monitored
 i18n.cannot_execute_error.4c29=Cannot execute\: error
 i18n.no_environment_variable.c79f=No corresponding environment variables
@@ -114,6 +118,7 @@ i18n.no_ssh_entry_found.d0e1=No corresponding ssh entry found\: {}
 i18n.build_runs_on_image_interrupted.00fd=Building the runsOn image was interrupted
 i18n.incorrect_parameter_format.9efb=The format of the passed parameter is incorrect
 i18n.multiple_certificate_files_found.bee3=Found more than 2 certificate files
+i18n.file_not_exist_or_unable_to_download.b977=The file does not exist or cannot be downloaded.
 i18n.invalid_runs_on_image_name.4b96=runsOn image name is invalid
 i18n.dockerfile_path_required.69ac=Please fill in the path to the Dockerfile to be executed
 i18n.file_upload_mode_not_configured.b3b2=No profile upload mode
@@ -248,6 +253,7 @@ i18n.select_node_to_modify.6617=Please select the section to modify
 i18n.correct_dingtalk_address_required.2b4a=Please enter the correct DingTalk address
 i18n.query_folder_sftp_failed.9d35=Failed to query folder SFTP,
 i18n.name_field_required.e0c5=Line {} name field cannot be empty
+i18n.ftp_connection_failed_message.bd99=Connection to FTP failed\:
 i18n.plugin_end_log_connection_successful.9035=Connection successful\: plugin-side log
 i18n.start_building_with_number_and_path.c41c=Start building \#{} Build execution path\: {}
 i18n.start_executing_upload_pre_command.fb5c=Start executing the pre-upload command
@@ -292,6 +298,7 @@ i18n.login_name_cannot_contain_chinese_and_special_characters.48a8=Login name ca
 i18n.cannot_join_cluster_as_role.01d4=Cannot join cluster as {} role
 i18n.not_an_enumeration.8244=Not an enumeration
 i18n.script_not_exist.b180=The corresponding script no longer exists
+i18n.file_not_exist_or_unable_to_open.b045=The file does not exist or cannot be opened.
 i18n.already_offline.d3b5=It's offline.
 i18n.rebuild_success.5938=Rebuild successfully
 i18n.hours.2de0=hour
@@ -328,6 +335,7 @@ i18n.upload_progress_template.ac3f=Upload file progress \:{}/{} {}
 i18n.mark_already_exists.0ccc=tag already exists
 i18n.docker_not_found.2a2e=\ No docker found. Maybe the docker tag is filled in incorrectly, you need to configure the tag for docker.
 i18n.download_remote_file_failed.fcc3=Failed to download remote file\:
+i18n.no_matching_asset_ftp.d420=There is no corresponding asset FTP.
 i18n.no_file_found.6f1b=No {} file found
 i18n.distribute_result.a230=Distribution result\: {}
 i18n.multiple_ssh_addresses_found.b3f7=SSH address {} has multiple data, and configuration information using {} SSH will be automatically merged
@@ -335,6 +343,7 @@ i18n.no_management_permission.fd25=You do not have the corresponding administrat
 i18n.workspace_env_vars.f7e8=Workspace environment variables
 i18n.unsupported_mode.a3d3=Unsupported modes\:
 i18n.select_node_and_project.6021=Please select a node and project
+i18n.initialize_sql.6691=Execute the initialization SQL file
 i18n.operation_succeeded.3313=Operation successful
 i18n.url_length_exceeded.ca1c=The URL length cannot exceed 200.
 i18n.waiting_to_close_process.3634=Waiting to close the [Process] process\: {}
@@ -364,6 +373,7 @@ i18n.webhooks_invocation_error.9792=WebHooks call error
 i18n.missing_parent_id.4331=Missing Parent Task ID
 i18n.data_modification_time_format_incorrect.7ffe=The data modification time format is incorrect {} {}
 i18n.cannot_delete_recent_logs.ee19=Logs related to the past day cannot be deleted (file modification time)
+i18n.monitor_name.9aff=monitor
 i18n.agent_jar_not_exist.28ac=Agent JAR package does not exist
 i18n.parse_certificate_unknown_error.c43c=An unknown error occurred in parsing the certificate.
 i18n.node_info_incomplete.3b69=The corresponding node information is incomplete and cannot continue.
@@ -377,6 +387,7 @@ i18n.system_logs.84aa=system log
 i18n.machines_ssh_data_fixed.1387=Successfully repaired {} machine SSH data
 i18n.docker_label_required.b690=Please fill in the docker tag to execute
 i18n.no_matching_permission.09cf=Insufficient permissions not matched
+i18n.ftp_create_folder_exception.a4fe=FTP folder creation exception
 i18n.data_id_does_not_exist.a566=Data ID does not exist
 i18n.no_ssh_info.a8ec=No corresponding SSH information
 i18n.distribution_with_build_items_message.45f5=There are construction items in the current distribution and cannot be deleted directly (you need to unbind or delete the associated data in advance to delete it)
@@ -401,6 +412,7 @@ i18n.node_not_enabled.10ef={} Node is not enabled
 i18n.client_id_not_configured.ab8e=No clientId configured
 i18n.build_product_dir_not_empty.ba06=The bundle directory cannot be empty, length 1-200
 i18n.trigger_token_error_or_expired.8976=Triggered token error, or has expired
+i18n.ftp_connection_failed.1f2f=FTP connection failed
 i18n.auth_info_error.c184=Authorization information error
 i18n.download_file_error.5bcd=Abnormal download file\:
 i18n.rollback_ended.fb1d=End of execution rollback\: {}
@@ -416,6 +428,7 @@ i18n.id_already_exists.6208=ID already exists
 i18n.ssh_info.ebe6=SSH information
 i18n.current_status.81c0=\ Currently still available\:
 i18n.project_path_no_spaces.263c=The project path cannot contain spaces
+i18n.ftp_asset_management.c6a5=FTP Asset Management
 i18n.please_fill_in_address_of.9e02=Please fill in the address of% s
 i18n.rsa_private_key_file_invalid.5f12=The RSA private key file does not exist or is incorrect
 i18n.ssh_node_required.4566=Please select the ssh node
@@ -456,6 +469,7 @@ i18n.load_plugin.1f64=Load\: {} plugin
 i18n.host_field_required.5c36=Line {} The host field cannot be empty
 i18n.container_build_interrupted.a17b=Container build was interrupted\:
 i18n.upload_action.d5a7=upload
+i18n.ftp_connection_or_operation_exception.09af=FTP connection or operation is abnormal
 i18n.delete_file_failure.041f=Failed to delete file, please check
 i18n.no_cluster_info_found.fb40=The corresponding cluster information was not found.
 i18n.script_template_log.30cb=Script template log
@@ -509,6 +523,7 @@ i18n.invalid_zip_file.3092=The compressed package uploaded is not a Jpom [{}] pa
 i18n.publish_command_non_zero_exit_code.ea80=Execute the publish command Exit code is not 0, {}
 i18n.project_path_promotion_issue.2250=There is an issue with the promoted directory in the project path
 i18n.handle_node_deletion_script_failure_duplicate.821e=Failed to process {} node deletion script {}
+i18n.ftp_folder_query_failed.0011=Unable to query folder FTP,
 i18n.no_matching_process_type.b468=Did not match the appropriate processing type
 i18n.unsupported_type.7495=Unsupported types
 i18n.submit_task_queue_success.5f5b=Submit task queue successfully, current queue number\:
@@ -567,6 +582,7 @@ i18n.select_correct_pre_publish_script.d230=Please select the correct pre-releas
 i18n.greeting.5ecd=Hello, Jpom.
 i18n.ssh_connection_failed.4719=SSH connection failed
 i18n.oauth2_redirect_failed.6dcd=Failed to jump to oauth2, {} {}
+i18n.ftp_upload_failed.8298=FTP upload failed
 i18n.data_workspace_mismatch.ae1d=The data workspace and the operation workspace are inconsistent
 i18n.process_file_event_exception.e8e6=Handling file event exceptions
 i18n.current_docker_cluster_has_no_management_nodes_online.56cd=The current {} docker cluster has no management nodes online
@@ -578,6 +594,7 @@ i18n.restart_operation.5e3a=Perform a restart operation
 i18n.no_h2_data_info_for_migration.5799=No h2 data information does not need to be migrated
 i18n.publish_success.2fff=Published successfully
 i18n.system_cache.c4a8=system cache
+i18n.no_ftp_item.8e39=No corresponding ftp entry
 i18n.distribution_machine_required.5921=Please select the machine to distribute
 i18n.build_call_container_exception.6e04=build call container exception
 i18n.process_killed_successfully.a4c3=Successful kill
@@ -586,6 +603,7 @@ i18n.auto_clear_data_errors.112f=Automatically clear data errors {} {}
 i18n.publish_directory_is_empty.79c6=Publish directory is empty
 i18n.file_or_directory_not_found.f03e=File does not exist or is a directory\:
 i18n.clear_file_cache_failed.5cd1=Failed to clear file cache
+i18n.database_backup_complete_path.861b=The database backup is complete, and the save path is
 i18n.file_downloading_status.c995=File downloading\:
 i18n.system_IP_authorization.9c08=System configuration IP authorization
 i18n.node_failed.20d5=Node failed\:
@@ -613,6 +631,7 @@ i18n.delete_failure_with_colon_and_full_stop.bc42=Delete failed\:
 i18n.product_directory_cannot_skip_levels.3ad4=The product catalog cannot be upgraded\:
 i18n.fix_null_workspace_data.4d0b=Fix data {} {} with null workspace
 i18n.external_config_file_path.06ec=external profile path
+i18n.asset_ftp_info.3b75=Asset FTP information
 i18n.soft_link_project_department_exists.fa97=The project department of Soft Chain exists
 i18n.docker_info.00d2=Docker information
 i18n.log_file_does_not_exist.f6c6=Log file does not exist
@@ -621,6 +640,7 @@ i18n.no_file_info.db01=There is no corresponding file information.
 i18n.record_operation_log_exception.8012=Log operation log exception
 i18n.corresponding_file_required.57b3=Please select the corresponding file
 i18n.build_command_no_delete.df52=Build commands cannot contain delete commands
+i18n.ftp_info_table.b177=FTP information table
 i18n.file_merge_error.f32f=Abnormal after file merging, incomplete files may be damaged.
 i18n.script_info_not_found.bd8d=No corresponding script information found.
 i18n.cannot_modify_own_info.4036=You can't modify your information.
@@ -675,6 +695,7 @@ i18n.container_build_host_config_conversion_failure.27aa=Container build hostCon
 i18n.build_task_count_and_queue_count.f0b6=Number of tasks currently under construction\: {}, Number of tasks in queue\: {} {}
 i18n.node_cache.d68c=Node cache
 i18n.cluster_node_not_in_system.0645=The node corresponding to the current cluster cannot exit the cluster if it is not in this system.
+i18n.ftp_selection.c903=Please choose to distribute FTP items
 i18n.file_search_failed.231b=File search failed
 i18n.exported_ssh_data.ce88=Exported ssh data
 i18n.execution_ended_with_duration.a59b=Execute the end {} process, time consuming\: {}
@@ -703,6 +724,7 @@ i18n.ssh_batch_command_execution_exception.029a=SSH batch execution command exce
 i18n.content_type_not_supported.81a9=unsupported contentType
 i18n.cloud_server_network_issues.a865=Troubleshooting and positioning of network-related issues such as security group configuration of Cloud as a Service.
 i18n.start_building_image.eacd={} Start building the mirror {} {}
+i18n.ftp_already_exists.d66b=The corresponding FTP already exists
 i18n.configure_correct_redirect_url.058e=Please configure the correct redirect URL.
 i18n.no_cache_info_with_minus_one.52f2=No corresponding cache information\: -1
 i18n.no_node_entry_found.b1ef=No corresponding node item found\: {}
@@ -714,6 +736,7 @@ i18n.no_docker_info_found.6d38=No corresponding docker information was found.
 i18n.update_docker_machine_id_failed.063d=Updating DOCKER table machine id failed\:
 i18n.build_status_abnormal.8ca1=The build status is abnormal or cancelled
 i18n.node_connection_failure.896d=Node connection failed, please check if the node is online.
+i18n.database_load_success_url.5f64=The database loaded successfully and the URL is
 i18n.login_name_already_exists.2511=Login name already exists
 i18n.port_error.312e=port error
 i18n.account_disabled.9361=The account has been disabled and cannot be used.
@@ -763,9 +786,12 @@ i18n.error_sql.15ff=Error sql\: {}
 i18n.verification_method_not_configured.7358={} Authentication method not configured\: {}
 i18n.local_git_certificate_not_supported.b395=Local git-specified certificate pull code is temporarily not supported
 i18n.unsupported_method_with_colon.eae8=Unsupported methods\:
+i18n.exported_ftp_data.2b54=Exported ftp data
 i18n.current_docker_has_no_cluster_info.0b52=The current docker has no cluster information.
 i18n.cannot_delete_self.fec9=Can't delete yourself
 i18n.operation_monitoring_error.8036=execution action monitoring error
+i18n.ftp_read_file_failed.e738=FTP read file failed
+i18n.file_exists.145b=The folder or file already exists
 i18n.alias_or_token_error.d5c6=The alias or token is wrong, or has expired
 i18n.version_config_info.7b29=version configuration information
 i18n.delete_old_package.ca95=Delete the old package\: {}
@@ -778,6 +804,7 @@ i18n.node_service_stopped_failed_restart.4307=The [{}] project {} of the [{}] no
 i18n.associated_workspace.885b=Affiliated workspace
 i18n.auto_clear_machine_node_stats_logs.5279=Automatically clean up {} machine node statistical logs
 i18n.unsupported_mode.501d=Unsupported mode
+i18n.ftp_client_build_failure.aa55=Failed to build FTP client side [{}]\: {}
 i18n.missing_script_message.af89=No corresponding script found
 i18n.start_migrating.20d6=Start migration {} {}
 i18n.incompatible_database_version.8f7b=Database versions are not compatible, and cross-version upgrades need to be handled.
@@ -802,6 +829,7 @@ i18n.configure_user_notification.250d=Please configure user notifications
 i18n.operation_status_code.8231=operation status code
 i18n.agent_jar_damaged.74a8=Agent JAR damaged, please re-upload,
 i18n.read_error.7fa5=Read error
+i18n.import_success.ef46=Import successful\: {}
 i18n.network_resource_monitoring_error.4ede=Network interface card resource monitoring abnormality\:
 i18n.select_workspace_to_modify.ac87=Please select the workspace you want to modify
 i18n.decode_failure.822e=Decoding failed
@@ -832,6 +860,8 @@ i18n.project_id_not_found.b87e=No project id.
 i18n.operation_type.de9c=operation type
 i18n.project_has_logs_cannot_migrate.2e0e=The current project has log reading and cannot be migrated directly.
 i18n.delete_failure_with_colon.b429=Delete failed\:
+i18n.no_ftp_server_correspondence.1af7=There is no corresponding Ftp.
+i18n.ftp_import_template.8fa3=FTP import template
 i18n.tag_cannot_contain_colon.f9ae=Labels cannot contain\:
 i18n.distribute_id_already_exists_globally.6478=The distribution id already exists, and the distribution id needs to be globally unique.
 i18n.import_exception.04b6=Import the {} data exception\: {}
@@ -895,7 +925,9 @@ i18n.no_manager_node_found.5934=No management nodes were found in the current cl
 i18n.file_transfer_exception.bda6=Forwarded file exception
 i18n.select_node.f8a6=Please select a node
 i18n.upload_progress_with_units.44ad=Upload file progress \:{} {}/{} {}
+i18n.ftp_download_file_failed.2e42=FTP download file failed
 i18n.ssh_terminal_execution_log.58f1=SSH end point execution log
+i18n.ftp_file_manager.c52e=FTP file management
 i18n.project_monitor.d2ff=project monitoring
 i18n.push_image_interrupted.6377=Push image is interrupted\:
 i18n.default_value.1aa9={} [Default]
@@ -986,6 +1018,7 @@ i18n.certificate_already_exists.adf9=The current certificate already exists (in
 i18n.oshi_file_system_monitoring_exception.dc24=Oshi file system resource monitoring exception
 i18n.image_cannot_be_empty.1600=Mirror image cannot be empty
 i18n.no_corresponding_node_info.cd24=There is no corresponding node information.
+i18n.auto_backup_path.a16b=Automatically backup data files to the path
 i18n.node_plugin_version_required.2318=Node plugin version cannot be empty
 i18n.start_new_thread_for_h2_database_backup.9337=Start a new thread to perform an H2 database backup
 i18n.docker_exec_terminal_process_ended.c734=[{}] docker exec end point
@@ -1005,6 +1038,7 @@ i18n.protocol_not_supported.b906=Unsupported protocols
 i18n.force_unbind_succeeded.5bfd=Forced unbinding successful
 i18n.unexpected_exception.2b52=Abnormality occurs
 i18n.check_email_error.636c=Check email information error\: {}
+i18n.ftp_unauthorized_directory.df73=This ftp is not authorized to operate on this directory
 i18n.initialization_success.4725=Initialization successful
 i18n.running_status.d679=Running
 i18n.auto_clean_temp_dir.11d2=Automatic cleaning of temporary directories
@@ -1101,6 +1135,7 @@ i18n.batch_trigger_script_exception.8fb4=Server level script batch trigger excep
 i18n.upgrade_failure.4ae2=Upgrade failed
 i18n.no_branch_or_tag_message.8ae3=No {} branches/tags
 i18n.general_error_message.728a=Ah, something seems to be wrong, please try again later~
+i18n.ftp_connection_failure.0f31=Failed to close FTP connection
 i18n.service_info_incomplete_with_code2.e9ca=The service information is incomplete and cannot be operated\: -2
 i18n.ignored_operation.edee=Ignored operation\: {}
 i18n.monitor_name_cannot_be_empty.514a=Monitor name cannot be empty
@@ -1115,6 +1150,7 @@ i18n.select_related_data_id.7fba=Please select the associated data ID.
 i18n.node_name_required.5bdf=Please fill in the node name
 i18n.client_terminated_connection.6886=Client side terminates connection\: {}
 i18n.close_thread_pool.4cd9=Close the {} thread pool
+i18n.ftp_upload_file_exception.118c=Abnormal FTP upload file
 i18n.clear_ip_whitelist_config_success.8cf6=Clear IP whitelist Configuration successful
 i18n.no_corresponding_folder.621f=No corresponding folder
 i18n.no_online_manager_node_found.05d7=The current cluster does not find an online management node
@@ -1124,6 +1160,7 @@ i18n.execution_completed.24a1=Execution completed\:
 i18n.close_project_failure.a1d2=Failed to close the project\:
 i18n.select_folder_to_compress.915f=Please select a folder to compress
 i18n.config_file_not_found.fc87=No configuration file found
+i18n.ftp_item_not_found.60a7=FTP entry not found\: {}
 i18n.update_ssh_machine_id_failed.bd24=Updating SSH table machine id failed\:
 i18n.select_pull_code_protocol.fc24=Please select the protocol for pulling the code
 i18n.auth_directory_cannot_be_empty.21ba=The authorization directory cannot be empty
@@ -1291,6 +1328,7 @@ i18n.program_already_running.96e1=The current program is running and cannot be s
 i18n.password_change_success.8013=Password changed successfully\!
 i18n.build_resource_cleanup_failed.c4cf=Failed to clean up build resources
 i18n.incorrect_publish_method.e095=Incorrect publishing method
+i18n.ftp_directory.a790=Please enter the directory to publish to ftp
 i18n.import_low_version_data_to_new_version.247b=2. Import the exported lower version data (sql file) into the new version [Add --replace-import-h2-sql\=/xxxx.sql to the startup parameters (the path needs to be replaced with the sql file save path output by the console in the first step) ]
 i18n.incorrect_line_number.5877=Line number is incorrect
 i18n.file_deletion_event_with_details.7537=File deletion event\: {} {}
@@ -1299,6 +1337,7 @@ i18n.maven_plugin_version_required.71f1=Maven plugin version cannot be empty
 i18n.trigger_token_error_or_expired_with_code.393b=Triggered token error, or has expired\: -1
 i18n.invalid_webhooks_address.d836=WebHooks address is invalid
 i18n.project_path_auth_not_under_jpom.0e18=Project path authorization cannot be located in the Jpom directory
+i18n.ftp_rename_failed_exception.0fcc=FTP rename failed exception
 i18n.reconnect_failure.7c01=Reconnect failed
 i18n.project_operations.03d9=Project operation and maintenance
 i18n.image_not_exist.ee17=Mirror does not exist
@@ -1338,6 +1377,7 @@ i18n.refreshing_cache.c969=The cache is being refreshed, please do not refresh r
 i18n.start_executing_database_event.fc57=Start executing database events\: {}
 i18n.static_file_storage.35f6=static file storage
 i18n.project_log_is_existing_folder.a80a=The project log is an existing folder
+i18n.check_ftp_connection_failed.f7de=Detect FTP connection failure [{}] and prepare to rebuild\: {}
 i18n.project_data_workspace_id_inconsistency.7ed6=Project data workspace ID [{}] query out that the node ID is inconsistent, old data\: {}, new data\: {}
 i18n.query_workspace_error.6a0d=Failed to query the wrong workspace
 i18n.unknown_database_mode.f9e5=The current database schema is unknown
@@ -1375,8 +1415,8 @@ i18n.token_invalid_or_expired.cb96=Token error, or has expired\: -1
 i18n.list_and_query.c783=List, query
 i18n.migration_docker_cert_error.a5ea=There was an exception migrating the docker [{}] certificate
 i18n.file_downloading.7a8f=File downloading
-i18n.mark_must_contain_letters_numbers_underscores.667d=Markers can only contain letters, numbers, and underscores
 i18n.please_fill_in_runs_on.c2ff=Please fill in runsOn.
+i18n.mark_must_contain_letters_numbers_underscores.667d=Markers can only contain letters, numbers, and underscores
 i18n.create_build_task_exception.06f1=Create build task exception
 i18n.execution_interrupted.1bb6=Execution was interrupted
 i18n.event_loss_or_execution_error.7b14=Event missing or execution error\: {} {}
@@ -1401,6 +1441,7 @@ i18n.please_pass_parameter.3182=Please pass in parameters
 i18n.node_no_data_pulled.0dae=The {} node did not pull any {}, but deleted the data\: {}
 i18n.node_info_not_found.2c8c=No node information was found\:
 i18n.please_fill_in_repository_address.0cf8=Please fill in the warehouse address.
+i18n.no_ftp_correspondence.23c4=There is no corresponding FTP.
 i18n.table_without_primary_key.7392=Table has no primary key
 i18n.invalid_shard_id.46fd=Illegal sharding id
 i18n.execution_ended.b793=End of execution\: {}
@@ -1499,6 +1540,7 @@ i18n.config_file_database_config_not_parsed.47b2=Database configuration informat
 i18n.data_already_exists.0397=The imported data already exists
 i18n.please_check_in_time.3b4f=Please check in time.
 i18n.installation_success.811f=Installation successful
+i18n.timeout.e944=timeout
 i18n.cluster_management.74ea=cluster management
 i18n.type_field_value_error.14cf=Line {} Type field value error (Git/Svn)
 i18n.migrate_data.f556=migrate data
@@ -1514,6 +1556,7 @@ i18n.backup_data_trigger.a71a=backup data trigger
 i18n.file_signature_info_not_found.83bf=No file signature information
 i18n.associated_nodes_warning.64d8=The current machine is also associated with {} nodes and cannot be deleted directly (you need to unbind or delete the associated data in advance to delete it)
 i18n.build_unknown_error.dad6=An unknown error occurred in the build
+i18n.start_import_data.ea31=Start importing data\: {}
 i18n.new_version_exists_download_unavailable.4ba7=There is a new version, and the download address is not available.
 i18n.compare_backup_failure.303e=Comparison Empty project file backup failed
 i18n.upload_success_and_restart.7bc3=Upload successful and restart
@@ -1547,9 +1590,11 @@ i18n.download_exception.e616=Abnormal download file
 i18n.process_file_deletion_exception.1c6e=Handling file deletion exceptions
 i18n.trigger_auto_execute_command_template_exception.4e01=Trigger an autoexecute command template exception
 i18n.no_build.d163=No corresponding build
+i18n.ftp_management.cb91=FTP management
 i18n.start_executing_publishing_with_file_size.5039=To start publishing, the file size that needs to be published\: {}
 i18n.command_execution_exception.4ccd=Execution command exception
 i18n.operation_ip.cbd4=Operate IP
+i18n.exception.c195=abnormal
 i18n.auth_directory_cannot_contain_hierarchy.d6ca=Inclusion relationships cannot exist in the authorization directory.
 i18n.ip_authorization_interception_exception.8130=The IP authorization interception is abnormal, please check whether the configuration is correct.
 i18n.refresh_token_timeout.3291=Refresh token timeout

+ 51 - 6
modules/common/src/main/resources/i18n/messages_zh_CN.properties

@@ -1,5 +1,5 @@
 #i18n zh
-#Thu Jan 09 16:59:38 CST 2025
+#Thu Jun 12 16:41:03 CST 2025
 i18n.ssh_info_does_not_exist.5ed0=ssh 信息不存在啦
 i18n.incompatible_program_versions.5291=当前程序版本 {} 新版程序最低兼容 {} 不能直接升级
 i18n.no_projects_configured.e873=没有配置任何项目
@@ -8,6 +8,7 @@ i18n.machine_ssh_info.8dbb=机器SSH信息
 i18n.machine_info_not_exist.3468=对应的机器信息不存在
 i18n.unsupported_method.a1de=不支持的方式
 i18n.delete_local_image_failed.91fa=删除本地镜像失败
+i18n.cluster_not_grouped.8f54=当前集群还未绑定分组,不能监控 FTP 资产信息
 i18n.service_name_in_cluster_required.5446=请填写集群中的服务名
 i18n.cluster_manager_node_not_found.1cd0=没有找到集群管理节点
 i18n.distribute_id_already_exists.2168=分发id已经存在啦
@@ -34,6 +35,7 @@ i18n.start_waiting_for_data_migration.e76f=开始等待数据迁移
 i18n.empty_file_or_folder_for_publish.cae8=发布的文件或者文件夹为空,不能继续发布
 i18n.repository_type_required.9414=请选择仓库类型
 i18n.demo_account_cannot_use_feature.a1a1=演示账号不能使用该功能
+i18n.start_backup_database.e554=开始备份数据库
 i18n.async_resource_expired.2ddc=异步资源过期,需要主动关闭,{} {}
 i18n.mark_cannot_be_empty.1927=标记不能为空
 i18n.get_success.fb55=获取成功
@@ -50,9 +52,11 @@ i18n.upload_failed_no_matching_project.b219=上传失败,没有找到对应的
 i18n.no_branches_or_tags_in_repository.76b6=仓库没有任何分支或者标签
 i18n.download_file_description.10cb=下载文件 {} {} {}
 i18n.delay_build.7d62=延迟 {} 秒后开始构建
+i18n.ftp_not_exist.f9b3=不存在对应ftp
 i18n.default_cluster.38cf=默认集群
 i18n.node_and_check_project_failed.ac4b=节点与检查项目失败
 i18n.load_oauth2_config.da42=加载 oauth2 配置 :{} {}
+i18n.affected_rows.5781=影响行数
 i18n.cluster_not_bound_to_group_for_node_monitoring.1586=当前集群还未绑定分组,不能监控集群节点资产信息
 i18n.cannot_execute_error.4c29=不能执行:error
 i18n.no_environment_variable.c79f=没有对应的环境变量
@@ -114,6 +118,7 @@ i18n.no_ssh_entry_found.d0e1=没有找到对应的ssh项:{}
 i18n.build_runs_on_image_interrupted.00fd=构建 runsOn 镜像被中断
 i18n.incorrect_parameter_format.9efb=传入的参数格式不正确
 i18n.multiple_certificate_files_found.bee3=找到 2 个以上的证书文件
+i18n.file_not_exist_or_unable_to_download.b977=文件不存在或无法下载\:
 i18n.invalid_runs_on_image_name.4b96=runsOn 镜像名称不合法
 i18n.dockerfile_path_required.69ac=请填写要执行的 Dockerfile 路径
 i18n.file_upload_mode_not_configured.b3b2=没有配置文件上传模式
@@ -248,6 +253,7 @@ i18n.select_node_to_modify.6617=请选择要修改的节
 i18n.correct_dingtalk_address_required.2b4a=请输入正确钉钉地址
 i18n.query_folder_sftp_failed.9d35=查询文件夹 SFTP 失败,
 i18n.name_field_required.e0c5=第 {} 行 name 字段不能位空
+i18n.ftp_connection_failed_message.bd99=连接FTP失败:
 i18n.start_building_with_number_and_path.c41c=开始构建 \#{} 构建执行路径 \: {}
 i18n.plugin_end_log_connection_successful.9035=连接成功:插件端日志
 i18n.start_executing_upload_pre_command.fb5c=开始执行上传前命令
@@ -293,6 +299,7 @@ i18n.cannot_join_cluster_as_role.01d4=不能以 {} 角色加入集群
 i18n.not_an_enumeration.8244=不是枚举
 i18n.script_not_exist.b180=对应脚本已经不存在啦
 i18n.rebuild_success.5938=重建成功
+i18n.file_not_exist_or_unable_to_open.b045=文件不存在或无法打开\:
 i18n.already_offline.d3b5=已经离线啦
 i18n.hours.2de0=小时
 i18n.project_management.4363=项目管理
@@ -328,6 +335,7 @@ i18n.upload_progress_template.ac3f=上传文件进度\:{}/{} {}
 i18n.mark_already_exists.0ccc=标记已存在
 i18n.docker_not_found.2a2e=\ 没有找到任何 docker。可能docker tag 填写不正确,需要为 docker 配置标签
 i18n.download_remote_file_failed.fcc3=下载远程文件失败\:
+i18n.no_matching_asset_ftp.d420=不存在对应的资产FTP
 i18n.no_file_found.6f1b=没有找到 {} 文件
 i18n.distribute_result.a230=分发结果:{}
 i18n.multiple_ssh_addresses_found.b3f7=SSH 地址 {} 存在多个数据,将自动合并使用 {} SSH的配置信息
@@ -335,6 +343,7 @@ i18n.no_management_permission.fd25=您没有对应管理权限\:-2
 i18n.workspace_env_vars.f7e8=工作空间环境变量
 i18n.unsupported_mode.a3d3=暂不支持的模式:
 i18n.select_node_and_project.6021=请选择节点和项目
+i18n.initialize_sql.6691=执行初始化SQL文件
 i18n.operation_succeeded.3313=操作成功
 i18n.waiting_to_close_process.3634=等待关闭[Process]进程:{}
 i18n.url_length_exceeded.ca1c=url 长度不能超过 200
@@ -364,6 +373,7 @@ i18n.webhooks_invocation_error.9792=WebHooks 调用错误
 i18n.missing_parent_id.4331=父任务id缺失
 i18n.data_modification_time_format_incorrect.7ffe=数据修改时间格式不正确 {} {}
 i18n.cannot_delete_recent_logs.ee19=不能删除近一天相关的日志(文件修改时间)
+i18n.monitor_name.9aff=监控
 i18n.agent_jar_not_exist.28ac=Agent JAR包不存在
 i18n.parse_certificate_unknown_error.c43c=解析证书发生未知错误:
 i18n.node_info_incomplete.3b69=对应的节点信息不完整不能继续
@@ -377,12 +387,13 @@ i18n.system_logs.84aa=系统日志
 i18n.machines_ssh_data_fixed.1387=成功修复 {} 条机器 SSH 数据
 i18n.docker_label_required.b690=请填要执行 docker 标签
 i18n.no_matching_permission.09cf=未匹配到合适的权限不足
+i18n.ftp_create_folder_exception.a4fe=FTP创建文件夹异常
 i18n.data_id_does_not_exist.a566=数据id 不存在
 i18n.no_ssh_info.a8ec=没有对应 SSH 信息
 i18n.distribution_with_build_items_message.45f5=当前分发存在构建项,不能直接删除(需要提前解绑或者删除关联数据后才能删除)
 i18n.scanning_in_progress.7444=当前正在扫描中
-i18n.day_or_sky.249a=天
 i18n.please_pass_body_parameter.4e5c=请传入 body 参数
+i18n.day_or_sky.249a=天
 i18n.get_decrypt_distribution_failure.4feb=获取解密分发失败
 i18n.retention_days.3c7d=,保留天数:{}
 i18n.no_log_info.d551=还没有日志信息
@@ -401,6 +412,7 @@ i18n.node_not_enabled.10ef={} 节点未启用
 i18n.client_id_not_configured.ab8e=没有配置 clientId
 i18n.build_product_dir_not_empty.ba06=构建产物目录不能为空,长度1-200
 i18n.trigger_token_error_or_expired.8976=触发token错误,或者已经失效
+i18n.ftp_connection_failed.1f2f=连接FTP失败
 i18n.auth_info_error.c184=授权信息错误
 i18n.download_file_error.5bcd=下载文件异常\:
 i18n.rollback_ended.fb1d=执行回滚结束:{}
@@ -416,6 +428,7 @@ i18n.ssh_info.ebe6=SSH 信息
 i18n.id_already_exists.6208=id已经存在啦
 i18n.current_status.81c0=\ 当前还在:
 i18n.project_path_no_spaces.263c=项目路径不能包含空格
+i18n.ftp_asset_management.c6a5=FTP资产管理
 i18n.please_fill_in_address_of.9e02=请填写 %s 的 地址
 i18n.rsa_private_key_file_invalid.5f12=rsa 私钥文件不存在或者有误
 i18n.ssh_node_required.4566=请选择 ssh 节点
@@ -456,6 +469,7 @@ i18n.load_plugin.1f64=加载:{} 插件
 i18n.host_field_required.5c36=第 {} 行 host 字段不能位空
 i18n.container_build_interrupted.a17b=容器 build 被中断\:
 i18n.upload_action.d5a7=上传
+i18n.ftp_connection_or_operation_exception.09af=FTP 连接或操作异常
 i18n.delete_file_failure.041f=删除文件失败,请检查
 i18n.script_template_log.30cb=脚本模板日志
 i18n.no_cluster_info_found.fb40=没有找到对应的集群信息
@@ -509,6 +523,7 @@ i18n.invalid_zip_file.3092=上传的压缩包不是 Jpom [{}] 包
 i18n.publish_command_non_zero_exit_code.ea80=执行发布命令退出码非0,{}
 i18n.project_path_promotion_issue.2250=项目路径存在提升目录问题
 i18n.handle_node_deletion_script_failure_duplicate.821e=处理 {} 节点删除脚本失败{}
+i18n.ftp_folder_query_failed.0011=无法查询文件夹FTP,
 i18n.unsupported_type.7495=不支持的类型
 i18n.submit_task_queue_success.5f5b=提交任务队列成功,当前队列数:
 i18n.no_matching_process_type.b468=未匹配到合适的处理类型
@@ -567,6 +582,7 @@ i18n.select_correct_pre_publish_script.d230=请选择正确的发布前脚本
 i18n.greeting.5ecd=您好,Jpom
 i18n.ssh_connection_failed.4719=ssh连接失败
 i18n.oauth2_redirect_failed.6dcd=跳转 oauth2 失败,{} {}
+i18n.ftp_upload_failed.8298=FTP 上传失败
 i18n.data_workspace_mismatch.ae1d=数据工作空间和操作工作空间不一致
 i18n.process_file_event_exception.e8e6=处理文件事件异常
 i18n.current_docker_cluster_has_no_management_nodes_online.56cd=当前 {} docker 集群没有管理节点在线
@@ -578,6 +594,7 @@ i18n.cluster_status_code_exception.9d89=集群状态码异常:{} {}
 i18n.no_h2_data_info_for_migration.5799=没有 h2 数据信息不用迁移
 i18n.publish_success.2fff=发布成功
 i18n.system_cache.c4a8=系统缓存
+i18n.no_ftp_item.8e39=没有对应的ftp项
 i18n.distribution_machine_required.5921=请选择分发的机器
 i18n.build_call_container_exception.6e04=构建调用容器异常
 i18n.process_killed_successfully.a4c3=成功kill
@@ -586,6 +603,7 @@ i18n.auto_clear_data_errors.112f=自动清除数据错误 {} {}
 i18n.publish_directory_is_empty.79c6=发布目录为空
 i18n.file_or_directory_not_found.f03e=文件不存在或者是目录\:
 i18n.clear_file_cache_failed.5cd1=清空文件缓存失败
+i18n.database_backup_complete_path.861b=数据库备份完成,保存路径为
 i18n.file_downloading_status.c995=文件下载中:
 i18n.system_IP_authorization.9c08=系统配置IP授权
 i18n.node_failed.20d5=节点失败:
@@ -613,6 +631,7 @@ i18n.delete_failure_with_colon_and_full_stop.bc42=删除失败:
 i18n.product_directory_cannot_skip_levels.3ad4=产物目录不能越级:
 i18n.fix_null_workspace_data.4d0b=修复工作空间为 null 的数据 {} {}
 i18n.external_config_file_path.06ec=外部配置文件路径
+i18n.asset_ftp_info.3b75=资产FTP信息
 i18n.soft_link_project_department_exists.fa97=软链的项目部存在
 i18n.system_admin_not_found.6f6c=没有找到系统管理员
 i18n.docker_info.00d2=docker 信息
@@ -621,6 +640,7 @@ i18n.record_operation_log_exception.8012=记录操作日志异常
 i18n.no_file_info.db01=没有对应的文件信息
 i18n.corresponding_file_required.57b3=请选择对应到文件
 i18n.build_command_no_delete.df52=构建命令不能包含删除命令
+i18n.ftp_info_table.b177=ftp信息表
 i18n.file_merge_error.f32f=文件合并后异常,文件不完整可能被损坏
 i18n.script_info_not_found.bd8d=找不到对应的脚本信息
 i18n.cannot_modify_own_info.4036=不能修改自己的信息
@@ -637,11 +657,11 @@ i18n.check_docker_url_exception.4302=检查 docker url 异常 {}
 i18n.id_not_empty.bf1f=id不能为空
 i18n.execution_frequency.d014={} 秒执行一次
 i18n.parse_jar.a26e=解析jar
-i18n.jpom_verification_code.5b5b=Jpom 验证码
 i18n.please_fill_in_personal_token.970a=请填写个人令牌
+i18n.jpom_verification_code.5b5b=Jpom 验证码
 i18n.parent_table_info_config_error.2f52=父级表信息配置错误,
-i18n.error_message.44ce=可能是下载授权码错误或者对应授权码被禁用以及触发限流机制
 i18n.physical_node_pull_records.99df={} 物理节点拉取到 {} 个执行记录,更新 {} 个执行记录
+i18n.error_message.44ce=可能是下载授权码错误或者对应授权码被禁用以及触发限流机制
 i18n.login_success.71fa=登录成功
 i18n.clear_temp_file_failed_check_directory.7340=清除临时文件失败,请检查目录:
 i18n.request_failed_message.9c71=请求失败\: status\: %s body\: %s headers\: %s
@@ -675,6 +695,7 @@ i18n.container_build_host_config_conversion_failure.27aa=容器构建 hostConfig
 i18n.build_task_count_and_queue_count.f0b6=当前构建中任务数:{},队列中任务数:{} {}
 i18n.node_cache.d68c=节点缓存
 i18n.cluster_node_not_in_system.0645=当前集群对应的节点,不在本系统中无法退出集群
+i18n.ftp_selection.c903=请选择分发FTP项
 i18n.file_search_failed.231b=文件搜索失败
 i18n.exported_ssh_data.ce88=导出的 ssh 数据
 i18n.execution_ended_with_duration.a59b=执行结束 {}流程,耗时:{}
@@ -703,6 +724,7 @@ i18n.ssh_batch_command_execution_exception.029a=ssh 批量执行命令异常
 i18n.content_type_not_supported.81a9=不支持的 contentType
 i18n.cloud_server_network_issues.a865=云服务器的安全组配置等网络相关问题排查定位。
 i18n.start_building_image.eacd={} 开始构建镜像 {}{}
+i18n.ftp_already_exists.d66b=对应的FTP已经存在啦
 i18n.configure_correct_redirect_url.058e=请配置正确的重定向 url
 i18n.no_cache_info_with_minus_one.52f2=没有对应的缓存信息:-1
 i18n.no_node_entry_found.b1ef=没有找到对应的节点项:{}
@@ -714,6 +736,7 @@ i18n.no_docker_info_found.6d38=没有找到对应的 docker 信息
 i18n.update_docker_machine_id_failed.063d=更新 DOCKER 表机器id 失败:
 i18n.build_status_abnormal.8ca1=构建状态异常或者被取消
 i18n.node_connection_failure.896d=节点连接失败,请检查节点是否在线
+i18n.database_load_success_url.5f64=数据库加载成功,URL为
 i18n.login_name_already_exists.2511=登录名已经存在
 i18n.port_error.312e=端口错误
 i18n.account_disabled.9361=账号已经被禁用,不能使用
@@ -744,8 +767,8 @@ i18n.cron_expression_incorrect.b41a=cron 表达式不正确,
 i18n.script_template_id_required.f339=请填写脚本模板id
 i18n.start_rolling_back.f020=开始回滚:{}
 i18n.execution_exception.b0d5=执行异常
-i18n.corresponding_function.5bb5=对应功能【{}-{}】
 i18n.plugin_parameter_incorrect.a355=插件端使用参数不正确
+i18n.corresponding_function.5bb5=对应功能【{}-{}】
 i18n.operation_failed.3d94=操作失败 
 i18n.start_publishing.c0b9=开始发布中
 i18n.monitor_info.f299=监控信息
@@ -763,9 +786,12 @@ i18n.error_sql.15ff=错误 sql\:{}
 i18n.verification_method_not_configured.7358={}未配置验证方法:{}
 i18n.local_git_certificate_not_supported.b395=暂时不支持本地 git 指定证书拉取代码
 i18n.unsupported_method_with_colon.eae8=不支持的方式:
+i18n.exported_ftp_data.2b54=导出的 ftp 数据
 i18n.current_docker_has_no_cluster_info.0b52=当前 docker 没有集群信息
 i18n.cannot_delete_self.fec9=不能删除自己
 i18n.operation_monitoring_error.8036=执行操作监控错误
+i18n.ftp_read_file_failed.e738=FTP 读取文件失败
+i18n.file_exists.145b=文件夹或文件已经存在
 i18n.alias_or_token_error.d5c6=别名或者token错误,或者已经失效
 i18n.version_config_info.7b29=版本配置信息
 i18n.delete_old_package.ca95=删除旧程序包:{}
@@ -778,6 +804,7 @@ i18n.node_service_stopped_failed_restart.4307=【{}】节点的【{}】项目{}
 i18n.associated_workspace.885b=所属工作空间
 i18n.auto_clear_machine_node_stats_logs.5279=自动清理 {} 条机器节点统计日志
 i18n.unsupported_mode.501d=不支持的模式
+i18n.ftp_client_build_failure.aa55=构建 FTP 客户端失败 [{}]\: {}
 i18n.missing_script_message.af89=找不到对应的脚本
 i18n.start_migrating.20d6=开始迁移 {} {}
 i18n.incompatible_database_version.8f7b=数据库版本不兼容,需要处理跨版本升级。
@@ -802,6 +829,7 @@ i18n.configure_user_notification.250d=请配置用户通知
 i18n.operation_status_code.8231=操作状态码
 i18n.agent_jar_damaged.74a8=Agent JAR 损坏请重新上传,
 i18n.read_error.7fa5=读取错误
+i18n.import_success.ef46=导入成功:{}
 i18n.select_workspace_to_modify.ac87=请选择要修改的工作空间
 i18n.network_resource_monitoring_error.4ede=网卡资源监控异常:
 i18n.decode_failure.822e=解码失败
@@ -832,7 +860,9 @@ i18n.project_id_not_found.b87e=没有项目id
 i18n.operation_type.de9c=操作类型
 i18n.project_has_logs_cannot_migrate.2e0e=当前项目存在日志阅读,不能直接迁移
 i18n.delete_failure_with_colon.b429=删除失败\:
+i18n.no_ftp_server_correspondence.1af7=没有对应的Ftp
 i18n.tag_cannot_contain_colon.f9ae=标签不能包含 :
+i18n.ftp_import_template.8fa3=ftp导入模板
 i18n.distribute_id_already_exists_globally.6478=分发id已经存在啦,分发id需要全局唯一
 i18n.import_exception.04b6=导入第 {} 条数据异常\:{}
 i18n.script_template_log2.6b2c=脚本模版日志
@@ -895,7 +925,9 @@ i18n.no_manager_node_found.5934=当前集群未找到任何管理节点
 i18n.file_transfer_exception.bda6=转发文件异常
 i18n.upload_progress_with_units.44ad=上传文件进度\:{} {}/{} {} 
 i18n.select_node.f8a6=请选择节点
+i18n.ftp_download_file_failed.2e42=FTP 下载文件失败
 i18n.ssh_terminal_execution_log.58f1=ssh 终端执行日志
+i18n.ftp_file_manager.c52e=FTP文件管理
 i18n.push_image_interrupted.6377=push image 被中断\:
 i18n.project_monitor.d2ff=项目监控
 i18n.default_value.1aa9={} [默认]
@@ -986,6 +1018,7 @@ i18n.certificate_already_exists.adf9=当前证书已经存在啦(系统全局范
 i18n.oshi_file_system_monitoring_exception.dc24=oshi 文件系统资源监控异常
 i18n.image_cannot_be_empty.1600=镜像不能为空
 i18n.no_corresponding_node_info.cd24=没有对应到节点信息
+i18n.auto_backup_path.a16b=自动备份数据文件到路径
 i18n.start_new_thread_for_h2_database_backup.9337=启动一个新线程来执行 H2 数据库备份...启动
 i18n.node_plugin_version_required.2318=node 插件 version 不能为空
 i18n.docker_exec_terminal_process_ended.c734=[{}] docker exec 终端进程结束
@@ -1005,6 +1038,7 @@ i18n.protocol_not_supported.b906=不支持的 protocol
 i18n.force_unbind_succeeded.5bfd=强制解绑成功
 i18n.unexpected_exception.2b52=发生异常
 i18n.check_email_error.636c=检查邮箱信息错误:{}
+i18n.ftp_unauthorized_directory.df73=此ftp未授权操作此目录
 i18n.initialization_success.4725=初始化成功
 i18n.running_status.d679=运行中
 i18n.auto_clean_temp_dir.11d2=自动清理临时目录
@@ -1101,6 +1135,7 @@ i18n.upgrade_failure.4ae2=升级失败
 i18n.batch_trigger_script_exception.8fb4=服务端脚本批量触发异常
 i18n.no_branch_or_tag_message.8ae3=没有 {} 分支/标签
 i18n.general_error_message.728a=啊哦,好像哪里出错了,请稍候再试试吧~
+i18n.ftp_connection_failure.0f31=关闭 FTP 连接失败
 i18n.service_info_incomplete_with_code2.e9ca=服务信息不完整不能操作:-2
 i18n.ignored_operation.edee=忽略的操作:{}
 i18n.monitor_name_cannot_be_empty.514a=监控名称不能为空
@@ -1115,6 +1150,7 @@ i18n.select_related_data_id.7fba=请选择关联数据 ID
 i18n.node_name_required.5bdf=请填写节点名称
 i18n.client_terminated_connection.6886=客户端终止连接:{}
 i18n.close_thread_pool.4cd9=关闭 {} 线程池
+i18n.ftp_upload_file_exception.118c=FTP上传文件异常
 i18n.clear_ip_whitelist_config_success.8cf6=清除 IP 白名单配置成功
 i18n.no_corresponding_folder.621f=没有对应文件夹
 i18n.no_online_manager_node_found.05d7=当前集群未找到在线的管理节点
@@ -1125,6 +1161,7 @@ i18n.close_project_failure.a1d2=关闭项目失败:
 i18n.select_folder_to_compress.915f=请选择文件夹进行压缩
 i18n.config_file_not_found.fc87=均未找到配置文件
 i18n.update_ssh_machine_id_failed.bd24=更新 SSH 表机器id 失败:
+i18n.ftp_item_not_found.60a7=没有找到对应的ftp项:{}
 i18n.select_pull_code_protocol.fc24=请选择拉取代码的协议
 i18n.auth_directory_cannot_be_empty.21ba=授权目录不能为空
 i18n.status_not_in_progress.f410=当前状态不在进行中,
@@ -1291,6 +1328,7 @@ i18n.program_already_running.96e1=当前程序正在运行中,不能重复启
 i18n.password_change_success.8013=修改密码成功!
 i18n.build_resource_cleanup_failed.c4cf=清理构建资源失败
 i18n.incorrect_publish_method.e095=发布方法不正确
+i18n.ftp_directory.a790=请输入发布到ftp中的目录
 i18n.import_low_version_data_to_new_version.247b=2. 将导出的低版本数据( sql 文件) 导入到新版本中【启动程序参数里面添加 --replace-import-h2-sql\=/xxxx.sql (路径需要替换为第一步控制台输出的 sql 文件保存路径)】
 i18n.incorrect_line_number.5877=行号不正确
 i18n.file_deletion_event_with_details.7537=文件删除事件:{} {}
@@ -1299,6 +1337,7 @@ i18n.maven_plugin_version_required.71f1=maven 插件 version 不能为空
 i18n.trigger_token_error_or_expired_with_code.393b=触发token错误,或者已经失效\:-1
 i18n.invalid_webhooks_address.d836=WebHooks 地址不合法
 i18n.project_path_auth_not_under_jpom.0e18=项目路径授权不能位于Jpom目录下
+i18n.ftp_rename_failed_exception.0fcc=FTP重命名失败异常
 i18n.reconnect_failure.7c01=重连失败
 i18n.project_operations.03d9=项目运维
 i18n.image_not_exist.ee17=镜像不存在
@@ -1339,6 +1378,7 @@ i18n.start_executing_database_event.fc57=开始执行数据库事件:{}
 i18n.static_file_storage.35f6=静态文件存储
 i18n.project_log_is_existing_folder.a80a=项目log是一个已经存在的文件夹
 i18n.project_data_workspace_id_inconsistency.7ed6=项目数据工作空间ID[{}]查询出节点ID不一致, 旧数据\: {}, 新数据\: {}
+i18n.check_ftp_connection_failed.f7de=检测 FTP 连接失效 [{}],准备重建\: {}
 i18n.query_workspace_error.6a0d=查询错误的工作空间失败
 i18n.unknown_database_mode.f9e5=当前数据库模式未知
 i18n.secondary_directory_match.0aec={} 二级目录模糊匹配到 {} 个文件, 当前文件保留方式 {}
@@ -1375,8 +1415,8 @@ i18n.token_invalid_or_expired.cb96=token错误,或者已经失效\:-1
 i18n.list_and_query.c783=列表、查询
 i18n.migration_docker_cert_error.a5ea=迁移 docker[{}] 证书发生异常
 i18n.file_downloading.7a8f=文件下载中
-i18n.mark_must_contain_letters_numbers_underscores.667d=标记只能包含字母、数字、下划线
 i18n.please_fill_in_runs_on.c2ff=请填写runsOn。
+i18n.mark_must_contain_letters_numbers_underscores.667d=标记只能包含字母、数字、下划线
 i18n.create_build_task_exception.06f1=创建构建任务异常
 i18n.execution_interrupted.1bb6=执行被中断
 i18n.event_loss_or_execution_error.7b14=事件丢失或者执行错误:{} {}
@@ -1401,6 +1441,7 @@ i18n.please_pass_parameter.3182=请传入参数
 i18n.node_no_data_pulled.0dae={} 节点没有拉取到任何 {},但是删除了数据:{}
 i18n.node_info_not_found.2c8c=没有查询到节点信息:
 i18n.please_fill_in_repository_address.0cf8=请填写仓库地址
+i18n.no_ftp_correspondence.23c4=没有对应的FTP
 i18n.table_without_primary_key.7392=表没有主键
 i18n.invalid_shard_id.46fd=不合法的分片id
 i18n.execution_ended.b793=执行结束\:{}
@@ -1499,6 +1540,7 @@ i18n.config_file_database_config_not_parsed.47b2=未解析出配置文件中的
 i18n.data_already_exists.0397=导入的数据已经存在啦
 i18n.please_check_in_time.3b4f=请及时检查
 i18n.installation_success.811f=安装成功
+i18n.timeout.e944=超时
 i18n.cluster_management.74ea=集群管理
 i18n.type_field_value_error.14cf=第 {} 行 type 字段值错误(Git/Svn)
 i18n.migrate_data.f556=迁移数据
@@ -1514,6 +1556,7 @@ i18n.backup_data_trigger.a71a=备份数据触发器
 i18n.file_signature_info_not_found.83bf=没有文件签名信息
 i18n.associated_nodes_warning.64d8=当前机器还关联{}个节点,不能直接删除(需要提前解绑或者删除关联数据后才能删除)
 i18n.build_unknown_error.dad6=构建发生未知错误
+i18n.start_import_data.ea31=开始导入数据:{}
 i18n.new_version_exists_download_unavailable.4ba7=存在新版本,下载地址不可用
 i18n.compare_backup_failure.303e=对比清空项目文件备份失败
 i18n.upload_success_and_restart.7bc3=上传成功并重启
@@ -1547,9 +1590,11 @@ i18n.download_exception.e616=下载文件异常
 i18n.process_file_deletion_exception.1c6e=处理文件删除异常
 i18n.trigger_auto_execute_command_template_exception.4e01=触发自动执行命令模版异常
 i18n.no_build.d163=没有对应的构建
+i18n.ftp_management.cb91=FTP管理
 i18n.start_executing_publishing_with_file_size.5039=开始执行发布,需要发布的文件大小:{}
 i18n.command_execution_exception.4ccd=执行命令异常
 i18n.operation_ip.cbd4=操作IP
+i18n.exception.c195=异常
 i18n.auth_directory_cannot_contain_hierarchy.d6ca=授权目录中不能存在包含关系:
 i18n.ip_authorization_interception_exception.8130=IP授权拦截异常,请检查配置是否正确
 i18n.refresh_token_timeout.3291=刷新token超时

+ 47 - 2
modules/common/src/main/resources/i18n/messages_zh_HK.properties

@@ -1,5 +1,5 @@
 #i18n zh_HK
-#Thu Jan 09 16:59:42 CST 2025
+#Thu Jun 12 16:41:16 CST 2025
 i18n.ssh_info_does_not_exist.5ed0=ssh 信息不存在啦
 i18n.incompatible_program_versions.5291=當前程序版本 {} 新版程序最低兼容 {} 不能直接升級
 i18n.no_projects_configured.e873=沒有配置任何項目
@@ -8,6 +8,7 @@ i18n.machine_ssh_info.8dbb=機器SSH信息
 i18n.machine_info_not_exist.3468=對應的機器信息不存在
 i18n.unsupported_method.a1de=不支持的方式
 i18n.delete_local_image_failed.91fa=刪除本地鏡像失敗
+i18n.cluster_not_grouped.8f54=當前集羣還未綁定分組,不能監控 FTP 資產信息
 i18n.service_name_in_cluster_required.5446=請填寫集羣中的服務名
 i18n.cluster_manager_node_not_found.1cd0=沒有找到集羣管理節點
 i18n.distribute_id_already_exists.2168=分發id已經存在啦
@@ -34,6 +35,7 @@ i18n.start_waiting_for_data_migration.e76f=開始等待數據遷移
 i18n.empty_file_or_folder_for_publish.cae8=發佈的文件或者文件夾為空,不能繼續發佈
 i18n.demo_account_cannot_use_feature.a1a1=演示賬號不能使用該功能
 i18n.repository_type_required.9414=請選擇倉庫類型
+i18n.start_backup_database.e554=開始備份數據庫
 i18n.async_resource_expired.2ddc=異步資源過期,需要主動關閉,{} {}
 i18n.mark_cannot_be_empty.1927=標記不能為空
 i18n.get_success.fb55=獲取成功
@@ -50,9 +52,11 @@ i18n.upload_failed_no_matching_project.b219=上傳失敗,沒有找到對應的
 i18n.no_branches_or_tags_in_repository.76b6=倉庫沒有任何分支或者標籤
 i18n.download_file_description.10cb=下載文件 {} {} {}
 i18n.delay_build.7d62=延遲 {} 秒後開始構建
+i18n.ftp_not_exist.f9b3=不存在對應ftp
 i18n.default_cluster.38cf=默認集羣
 i18n.node_and_check_project_failed.ac4b=節點與檢查項目失敗
 i18n.load_oauth2_config.da42=加載 oauth2 配置 :{} {}
+i18n.affected_rows.5781=影響行數
 i18n.cluster_not_bound_to_group_for_node_monitoring.1586=當前集羣還未綁定分組,不能監控集羣節點資產信息
 i18n.cannot_execute_error.4c29=不能執行:error
 i18n.no_environment_variable.c79f=沒有對應的環境變量
@@ -114,6 +118,7 @@ i18n.no_ssh_entry_found.d0e1=沒有找到對應的ssh項:{}
 i18n.build_runs_on_image_interrupted.00fd=構建 runsOn 鏡像被中斷
 i18n.incorrect_parameter_format.9efb=傳入的參數格式不正確
 i18n.multiple_certificate_files_found.bee3=找到 2 個以上的證書文件
+i18n.file_not_exist_or_unable_to_download.b977=文件不存在或無法下載\:
 i18n.invalid_runs_on_image_name.4b96=runsOn 鏡像名稱不合法
 i18n.dockerfile_path_required.69ac=請填寫要執行的 Dockerfile 路徑
 i18n.file_upload_mode_not_configured.b3b2=沒有配置文件上傳模式
@@ -248,6 +253,7 @@ i18n.select_node_to_modify.6617=請選擇要修改的節
 i18n.correct_dingtalk_address_required.2b4a=請輸入正確釘釘地址
 i18n.query_folder_sftp_failed.9d35=查詢文件夾 SFTP 失敗,
 i18n.name_field_required.e0c5=第 {} 行 name 字段不能位空
+i18n.ftp_connection_failed_message.bd99=連接FTP失敗:
 i18n.plugin_end_log_connection_successful.9035=連接成功:插件端日誌
 i18n.start_building_with_number_and_path.c41c=開始構建 \#{} 構建執行路徑 \: {}
 i18n.start_executing_upload_pre_command.fb5c=開始執行上傳前命令
@@ -292,6 +298,7 @@ i18n.login_name_cannot_contain_chinese_and_special_characters.48a8=登錄名不
 i18n.cannot_join_cluster_as_role.01d4=不能以 {} 角色加入集羣
 i18n.not_an_enumeration.8244=不是枚舉
 i18n.script_not_exist.b180=對應腳本已經不存在啦
+i18n.file_not_exist_or_unable_to_open.b045=文件不存在或無法打開\:
 i18n.already_offline.d3b5=已經離線啦
 i18n.rebuild_success.5938=重建成功
 i18n.hours.2de0=小時
@@ -328,6 +335,7 @@ i18n.upload_progress_template.ac3f=上傳文件進度\:{}/{} {}
 i18n.mark_already_exists.0ccc=標記已存在
 i18n.docker_not_found.2a2e=\ 沒有找到任何 docker。可能docker tag 填寫不正確,需要為 docker 配置標籤
 i18n.download_remote_file_failed.fcc3=下載遠程文件失敗\:
+i18n.no_matching_asset_ftp.d420=不存在對應的資產FTP
 i18n.no_file_found.6f1b=沒有找到 {} 文件
 i18n.distribute_result.a230=分發結果:{}
 i18n.multiple_ssh_addresses_found.b3f7=SSH 地址 {} 存在多個數據,將自動合併使用 {} SSH的配置信息
@@ -335,6 +343,7 @@ i18n.no_management_permission.fd25=您沒有對應管理權限\:-2
 i18n.workspace_env_vars.f7e8=工作空間環境變量
 i18n.unsupported_mode.a3d3=暫不支持的模式:
 i18n.select_node_and_project.6021=請選擇節點和項目
+i18n.initialize_sql.6691=執行初始化SQL文件
 i18n.operation_succeeded.3313=操作成功
 i18n.url_length_exceeded.ca1c=url 長度不能超過 200
 i18n.waiting_to_close_process.3634=等待關閉[Process]進程:{}
@@ -364,6 +373,7 @@ i18n.webhooks_invocation_error.9792=WebHooks 調用錯誤
 i18n.missing_parent_id.4331=父任務id缺失
 i18n.data_modification_time_format_incorrect.7ffe=數據修改時間格式不正確 {} {}
 i18n.cannot_delete_recent_logs.ee19=不能刪除近一天相關的日誌(文件修改時間)
+i18n.monitor_name.9aff=監控
 i18n.agent_jar_not_exist.28ac=Agent JAR包不存在
 i18n.parse_certificate_unknown_error.c43c=解析證書發生未知錯誤:
 i18n.node_info_incomplete.3b69=對應的節點信息不完整不能繼續
@@ -377,6 +387,7 @@ i18n.system_logs.84aa=系統日誌
 i18n.machines_ssh_data_fixed.1387=成功修復 {} 條機器 SSH 數據
 i18n.docker_label_required.b690=請填要執行 docker 標籤
 i18n.no_matching_permission.09cf=未匹配到合適的權限不足
+i18n.ftp_create_folder_exception.a4fe=FTP創建文件夾異常
 i18n.data_id_does_not_exist.a566=數據id 不存在
 i18n.no_ssh_info.a8ec=沒有對應 SSH 信息
 i18n.distribution_with_build_items_message.45f5=當前分發存在構建項,不能直接刪除(需要提前解綁或者刪除關聯數據後才能刪除)
@@ -401,6 +412,7 @@ i18n.node_not_enabled.10ef={} 節點未啟用
 i18n.client_id_not_configured.ab8e=沒有配置 clientId
 i18n.build_product_dir_not_empty.ba06=構建產物目錄不能為空,長度1-200
 i18n.trigger_token_error_or_expired.8976=觸發token錯誤,或者已經失效
+i18n.ftp_connection_failed.1f2f=連接FTP失敗
 i18n.auth_info_error.c184=授權信息錯誤
 i18n.download_file_error.5bcd=下載文件異常\:
 i18n.rollback_ended.fb1d=執行回滾結束:{}
@@ -416,6 +428,7 @@ i18n.id_already_exists.6208=id已經存在啦
 i18n.ssh_info.ebe6=SSH 信息
 i18n.current_status.81c0=\ 當前還在:
 i18n.project_path_no_spaces.263c=項目路徑不能包含空格
+i18n.ftp_asset_management.c6a5=FTP資產管理
 i18n.please_fill_in_address_of.9e02=請填寫 %s 的 地址
 i18n.rsa_private_key_file_invalid.5f12=rsa 私鑰文件不存在或者有誤
 i18n.ssh_node_required.4566=請選擇 ssh 節點
@@ -456,6 +469,7 @@ i18n.load_plugin.1f64=加載:{} 插件
 i18n.host_field_required.5c36=第 {} 行 host 字段不能位空
 i18n.container_build_interrupted.a17b=容器 build 被中斷\:
 i18n.upload_action.d5a7=上傳
+i18n.ftp_connection_or_operation_exception.09af=FTP 連接或操作異常
 i18n.delete_file_failure.041f=刪除文件失敗,請檢查
 i18n.no_cluster_info_found.fb40=沒有找到對應的集羣信息
 i18n.script_template_log.30cb=腳本模板日誌
@@ -509,6 +523,7 @@ i18n.invalid_zip_file.3092=上傳的壓縮包不是 Jpom [{}] 包
 i18n.publish_command_non_zero_exit_code.ea80=執行發佈命令退出碼非0,{}
 i18n.project_path_promotion_issue.2250=項目路徑存在提升目錄問題
 i18n.handle_node_deletion_script_failure_duplicate.821e=處理 {} 節點刪除腳本失敗{}
+i18n.ftp_folder_query_failed.0011=無法查詢文件夾FTP,
 i18n.no_matching_process_type.b468=未匹配到合適的處理類型
 i18n.unsupported_type.7495=不支持的類型
 i18n.submit_task_queue_success.5f5b=提交任務隊列成功,當前隊列數:
@@ -567,6 +582,7 @@ i18n.select_correct_pre_publish_script.d230=請選擇正確的發佈前腳本
 i18n.greeting.5ecd=您好,Jpom
 i18n.ssh_connection_failed.4719=ssh連接失敗
 i18n.oauth2_redirect_failed.6dcd=跳轉 oauth2 失敗,{} {}
+i18n.ftp_upload_failed.8298=FTP 上傳失敗
 i18n.data_workspace_mismatch.ae1d=數據工作空間和操作工作空間不一致
 i18n.process_file_event_exception.e8e6=處理文件事件異常
 i18n.current_docker_cluster_has_no_management_nodes_online.56cd=當前 {} docker 集羣沒有管理節點在線
@@ -578,6 +594,7 @@ i18n.restart_operation.5e3a=執行重啟操作
 i18n.no_h2_data_info_for_migration.5799=沒有 h2 數據信息不用遷移
 i18n.publish_success.2fff=發佈成功
 i18n.system_cache.c4a8=系統緩存
+i18n.no_ftp_item.8e39=沒有對應的ftp項
 i18n.distribution_machine_required.5921=請選擇分發的機器
 i18n.build_call_container_exception.6e04=構建調用容器異常
 i18n.process_killed_successfully.a4c3=成功kill
@@ -586,6 +603,7 @@ i18n.auto_clear_data_errors.112f=自動清除數據錯誤 {} {}
 i18n.publish_directory_is_empty.79c6=發佈目錄為空
 i18n.file_or_directory_not_found.f03e=文件不存在或者是目錄\:
 i18n.clear_file_cache_failed.5cd1=清空文件緩存失敗
+i18n.database_backup_complete_path.861b=數據庫備份完成,保存路徑為
 i18n.file_downloading_status.c995=文件下載中:
 i18n.system_IP_authorization.9c08=系統配置IP授權
 i18n.node_failed.20d5=節點失敗:
@@ -613,6 +631,7 @@ i18n.delete_failure_with_colon_and_full_stop.bc42=刪除失敗:
 i18n.product_directory_cannot_skip_levels.3ad4=產物目錄不能越級:
 i18n.fix_null_workspace_data.4d0b=修復工作空間為 null 的數據 {} {}
 i18n.external_config_file_path.06ec=外部配置文件路徑
+i18n.asset_ftp_info.3b75=資產FTP信息
 i18n.soft_link_project_department_exists.fa97=軟鏈的項目部存在
 i18n.docker_info.00d2=docker 信息
 i18n.log_file_does_not_exist.f6c6=日誌文件不存在
@@ -621,6 +640,7 @@ i18n.no_file_info.db01=沒有對應的文件信息
 i18n.record_operation_log_exception.8012=記錄操作日誌異常
 i18n.corresponding_file_required.57b3=請選擇對應到文件
 i18n.build_command_no_delete.df52=構建命令不能包含刪除命令
+i18n.ftp_info_table.b177=ftp信息表
 i18n.file_merge_error.f32f=文件合併後異常,文件不完整可能被損壞
 i18n.script_info_not_found.bd8d=找不到對應的腳本信息
 i18n.cannot_modify_own_info.4036=不能修改自己的信息
@@ -675,6 +695,7 @@ i18n.container_build_host_config_conversion_failure.27aa=容器構建 hostConfig
 i18n.build_task_count_and_queue_count.f0b6=當前構建中任務數:{},隊列中任務數:{} {}
 i18n.node_cache.d68c=節點緩存
 i18n.cluster_node_not_in_system.0645=當前集羣對應的節點,不在本系統中無法退出集羣
+i18n.ftp_selection.c903=請選擇分發FTP項
 i18n.file_search_failed.231b=文件搜索失敗
 i18n.exported_ssh_data.ce88=導出的 ssh 數據
 i18n.execution_ended_with_duration.a59b=執行結束 {}流程,耗時:{}
@@ -703,6 +724,7 @@ i18n.ssh_batch_command_execution_exception.029a=ssh 批量執行命令異常
 i18n.content_type_not_supported.81a9=不支持的 contentType
 i18n.cloud_server_network_issues.a865=雲服務器的安全組配置等網絡相關問題排查定位。
 i18n.start_building_image.eacd={} 開始構建鏡像 {}{}
+i18n.ftp_already_exists.d66b=對應的FTP已經存在啦
 i18n.configure_correct_redirect_url.058e=請配置正確的重定向 url
 i18n.no_cache_info_with_minus_one.52f2=沒有對應的緩存信息:-1
 i18n.no_node_entry_found.b1ef=沒有找到對應的節點項:{}
@@ -714,6 +736,7 @@ i18n.no_docker_info_found.6d38=沒有找到對應的 docker 信息
 i18n.update_docker_machine_id_failed.063d=更新 DOCKER 表機器id 失敗:
 i18n.build_status_abnormal.8ca1=構建狀態異常或者被取消
 i18n.node_connection_failure.896d=節點連接失敗,請檢查節點是否在線
+i18n.database_load_success_url.5f64=數據庫加載成功,URL為
 i18n.login_name_already_exists.2511=登錄名已經存在
 i18n.port_error.312e=端口錯誤
 i18n.account_disabled.9361=賬號已經被禁用,不能使用
@@ -763,9 +786,12 @@ i18n.error_sql.15ff=錯誤 sql\:{}
 i18n.verification_method_not_configured.7358={}未配置驗證方法:{}
 i18n.local_git_certificate_not_supported.b395=暫時不支持本地 git 指定證書拉取代碼
 i18n.unsupported_method_with_colon.eae8=不支持的方式:
+i18n.exported_ftp_data.2b54=導出的 ftp 數據
 i18n.current_docker_has_no_cluster_info.0b52=當前 docker 沒有集羣信息
 i18n.cannot_delete_self.fec9=不能刪除自己
 i18n.operation_monitoring_error.8036=執行操作監控錯誤
+i18n.ftp_read_file_failed.e738=FTP 讀取文件失敗
+i18n.file_exists.145b=文件夾或文件已經存在
 i18n.alias_or_token_error.d5c6=別名或者token錯誤,或者已經失效
 i18n.version_config_info.7b29=版本配置信息
 i18n.delete_old_package.ca95=刪除舊程序包:{}
@@ -778,6 +804,7 @@ i18n.node_service_stopped_failed_restart.4307=【{}】節點的【{}】項目{}
 i18n.associated_workspace.885b=所屬工作空間
 i18n.auto_clear_machine_node_stats_logs.5279=自動清理 {} 條機器節點統計日誌
 i18n.unsupported_mode.501d=不支持的模式
+i18n.ftp_client_build_failure.aa55=構建 FTP 客户端失敗 [{}]\: {}
 i18n.missing_script_message.af89=找不到對應的腳本
 i18n.start_migrating.20d6=開始遷移 {} {}
 i18n.incompatible_database_version.8f7b=數據庫版本不兼容,需要處理跨版本升級。
@@ -802,6 +829,7 @@ i18n.configure_user_notification.250d=請配置用户通知
 i18n.operation_status_code.8231=操作狀態碼
 i18n.agent_jar_damaged.74a8=Agent JAR 損壞請重新上傳,
 i18n.read_error.7fa5=讀取錯誤
+i18n.import_success.ef46=導入成功:{}
 i18n.network_resource_monitoring_error.4ede=網卡資源監控異常:
 i18n.select_workspace_to_modify.ac87=請選擇要修改的工作空間
 i18n.decode_failure.822e=解碼失敗
@@ -832,6 +860,8 @@ i18n.project_id_not_found.b87e=沒有項目id
 i18n.operation_type.de9c=操作類型
 i18n.project_has_logs_cannot_migrate.2e0e=當前項目存在日誌閲讀,不能直接遷移
 i18n.delete_failure_with_colon.b429=刪除失敗\:
+i18n.no_ftp_server_correspondence.1af7=沒有對應的Ftp
+i18n.ftp_import_template.8fa3=ftp導入模板
 i18n.tag_cannot_contain_colon.f9ae=標籤不能包含 :
 i18n.distribute_id_already_exists_globally.6478=分發id已經存在啦,分發id需要全局唯一
 i18n.import_exception.04b6=導入第 {} 條數據異常\:{}
@@ -895,7 +925,9 @@ i18n.no_manager_node_found.5934=當前集羣未找到任何管理節點
 i18n.file_transfer_exception.bda6=轉發文件異常
 i18n.select_node.f8a6=請選擇節點
 i18n.upload_progress_with_units.44ad=上傳文件進度\:{} {}/{} {}
+i18n.ftp_download_file_failed.2e42=FTP 下載文件失敗
 i18n.ssh_terminal_execution_log.58f1=ssh 終端執行日誌
+i18n.ftp_file_manager.c52e=FTP文件管理
 i18n.project_monitor.d2ff=項目監控
 i18n.push_image_interrupted.6377=push image 被中斷\:
 i18n.default_value.1aa9={} [默認]
@@ -986,6 +1018,7 @@ i18n.certificate_already_exists.adf9=當前證書已經存在啦(系統全局範
 i18n.oshi_file_system_monitoring_exception.dc24=oshi 文件系統資源監控異常
 i18n.image_cannot_be_empty.1600=鏡像不能為空
 i18n.no_corresponding_node_info.cd24=沒有對應到節點信息
+i18n.auto_backup_path.a16b=自動備份數據文件到路徑
 i18n.node_plugin_version_required.2318=node 插件 version 不能為空
 i18n.start_new_thread_for_h2_database_backup.9337=啟動一個新線程來執行 H2 數據庫備份...啟動
 i18n.docker_exec_terminal_process_ended.c734=[{}] docker exec 終端進程結束
@@ -1005,6 +1038,7 @@ i18n.protocol_not_supported.b906=不支持的 protocol
 i18n.force_unbind_succeeded.5bfd=強制解綁成功
 i18n.unexpected_exception.2b52=發生異常
 i18n.check_email_error.636c=檢查郵箱信息錯誤:{}
+i18n.ftp_unauthorized_directory.df73=此ftp未授權操作此目錄
 i18n.initialization_success.4725=初始化成功
 i18n.running_status.d679=運行中
 i18n.auto_clean_temp_dir.11d2=自動清理臨時目錄
@@ -1101,6 +1135,7 @@ i18n.batch_trigger_script_exception.8fb4=服務端腳本批量觸發異常
 i18n.upgrade_failure.4ae2=升級失敗
 i18n.no_branch_or_tag_message.8ae3=沒有 {} 分支/標籤
 i18n.general_error_message.728a=啊哦,好像哪裏出錯了,請稍候再試試吧~
+i18n.ftp_connection_failure.0f31=關閉 FTP 連接失敗
 i18n.service_info_incomplete_with_code2.e9ca=服務信息不完整不能操作:-2
 i18n.ignored_operation.edee=忽略的操作:{}
 i18n.monitor_name_cannot_be_empty.514a=監控名稱不能為空
@@ -1115,6 +1150,7 @@ i18n.select_related_data_id.7fba=請選擇關聯數據 ID
 i18n.node_name_required.5bdf=請填寫節點名稱
 i18n.client_terminated_connection.6886=客户端終止連接:{}
 i18n.close_thread_pool.4cd9=關閉 {} 線程池
+i18n.ftp_upload_file_exception.118c=FTP上傳文件異常
 i18n.clear_ip_whitelist_config_success.8cf6=清除 IP 白名單配置成功
 i18n.no_corresponding_folder.621f=沒有對應文件夾
 i18n.no_online_manager_node_found.05d7=當前集羣未找到在線的管理節點
@@ -1124,6 +1160,7 @@ i18n.execution_completed.24a1=執行完畢\:
 i18n.close_project_failure.a1d2=關閉項目失敗:
 i18n.select_folder_to_compress.915f=請選擇文件夾進行壓縮
 i18n.config_file_not_found.fc87=均未找到配置文件
+i18n.ftp_item_not_found.60a7=沒有找到對應的ftp項:{}
 i18n.update_ssh_machine_id_failed.bd24=更新 SSH 表機器id 失敗:
 i18n.select_pull_code_protocol.fc24=請選擇拉取代碼的協議
 i18n.auth_directory_cannot_be_empty.21ba=授權目錄不能為空
@@ -1291,6 +1328,7 @@ i18n.program_already_running.96e1=當前程序正在運行中,不能重複啟
 i18n.password_change_success.8013=修改密碼成功!
 i18n.build_resource_cleanup_failed.c4cf=清理構建資源失敗
 i18n.incorrect_publish_method.e095=發佈方法不正確
+i18n.ftp_directory.a790=請輸入發佈到ftp中的目錄
 i18n.import_low_version_data_to_new_version.247b=2. 將導出的低版本數據( sql 文件) 導入到新版本中【啟動程序參數裏面添加 --replace-import-h2-sql\=/xxxx.sql (路徑需要替換為第一步控制枱輸出的 sql 文件保存路徑)】
 i18n.incorrect_line_number.5877=行號不正確
 i18n.file_deletion_event_with_details.7537=文件刪除事件:{} {}
@@ -1299,6 +1337,7 @@ i18n.maven_plugin_version_required.71f1=maven 插件 version 不能為空
 i18n.trigger_token_error_or_expired_with_code.393b=觸發token錯誤,或者已經失效\:-1
 i18n.invalid_webhooks_address.d836=WebHooks 地址不合法
 i18n.project_path_auth_not_under_jpom.0e18=項目路徑授權不能位於Jpom目錄下
+i18n.ftp_rename_failed_exception.0fcc=FTP重命名失敗異常
 i18n.reconnect_failure.7c01=重連失敗
 i18n.project_operations.03d9=項目運維
 i18n.image_not_exist.ee17=鏡像不存在
@@ -1338,6 +1377,7 @@ i18n.refreshing_cache.c969=正在刷新緩存中,請勿重複刷新
 i18n.start_executing_database_event.fc57=開始執行數據庫事件:{}
 i18n.static_file_storage.35f6=靜態文件存儲
 i18n.project_log_is_existing_folder.a80a=項目log是一個已經存在的文件夾
+i18n.check_ftp_connection_failed.f7de=檢測 FTP 連接失效 [{}],準備重建\: {}
 i18n.project_data_workspace_id_inconsistency.7ed6=項目數據工作空間ID[{}]查詢出節點ID不一致, 舊數據\: {}, 新數據\: {}
 i18n.query_workspace_error.6a0d=查詢錯誤的工作空間失敗
 i18n.unknown_database_mode.f9e5=當前數據庫模式未知
@@ -1375,8 +1415,8 @@ i18n.token_invalid_or_expired.cb96=token錯誤,或者已經失效\:-1
 i18n.list_and_query.c783=列表、查詢
 i18n.migration_docker_cert_error.a5ea=遷移 docker[{}] 證書發生異常
 i18n.file_downloading.7a8f=文件下載中
-i18n.mark_must_contain_letters_numbers_underscores.667d=標記只能包含字母、數字、下劃線
 i18n.please_fill_in_runs_on.c2ff=請填寫runsOn。
+i18n.mark_must_contain_letters_numbers_underscores.667d=標記只能包含字母、數字、下劃線
 i18n.create_build_task_exception.06f1=創建構建任務異常
 i18n.execution_interrupted.1bb6=執行被中斷
 i18n.event_loss_or_execution_error.7b14=事件丟失或者執行錯誤:{} {}
@@ -1401,6 +1441,7 @@ i18n.please_pass_parameter.3182=請傳入參數
 i18n.node_no_data_pulled.0dae={} 節點沒有拉取到任何 {},但是刪除了數據:{}
 i18n.node_info_not_found.2c8c=沒有查詢到節點信息:
 i18n.please_fill_in_repository_address.0cf8=請填寫倉庫地址
+i18n.no_ftp_correspondence.23c4=沒有對應的FTP
 i18n.table_without_primary_key.7392=表沒有主鍵
 i18n.invalid_shard_id.46fd=不合法的分片id
 i18n.execution_ended.b793=執行結束\:{}
@@ -1499,6 +1540,7 @@ i18n.config_file_database_config_not_parsed.47b2=未解析出配置文件中的
 i18n.data_already_exists.0397=導入的數據已經存在啦
 i18n.please_check_in_time.3b4f=請及時檢查
 i18n.installation_success.811f=安裝成功
+i18n.timeout.e944=超時
 i18n.cluster_management.74ea=集羣管理
 i18n.type_field_value_error.14cf=第 {} 行 type 字段值錯誤(Git/Svn)
 i18n.migrate_data.f556=遷移數據
@@ -1514,6 +1556,7 @@ i18n.backup_data_trigger.a71a=備份數據觸發器
 i18n.file_signature_info_not_found.83bf=沒有文件簽名信息
 i18n.associated_nodes_warning.64d8=當前機器還關聯{}個節點,不能直接刪除(需要提前解綁或者刪除關聯數據後才能刪除)
 i18n.build_unknown_error.dad6=構建發生未知錯誤
+i18n.start_import_data.ea31=開始導入數據:{}
 i18n.new_version_exists_download_unavailable.4ba7=存在新版本,下載地址不可用
 i18n.compare_backup_failure.303e=對比清空項目文件備份失敗
 i18n.upload_success_and_restart.7bc3=上傳成功並重啟
@@ -1547,9 +1590,11 @@ i18n.download_exception.e616=下載文件異常
 i18n.process_file_deletion_exception.1c6e=處理文件刪除異常
 i18n.trigger_auto_execute_command_template_exception.4e01=觸發自動執行命令模版異常
 i18n.no_build.d163=沒有對應的構建
+i18n.ftp_management.cb91=FTP管理
 i18n.start_executing_publishing_with_file_size.5039=開始執行發佈,需要發佈的文件大小:{}
 i18n.command_execution_exception.4ccd=執行命令異常
 i18n.operation_ip.cbd4=操作IP
+i18n.exception.c195=異常
 i18n.auth_directory_cannot_contain_hierarchy.d6ca=授權目錄中不能存在包含關係:
 i18n.ip_authorization_interception_exception.8130=IP授權攔截異常,請檢查配置是否正確
 i18n.refresh_token_timeout.3291=刷新token超時

+ 47 - 2
modules/common/src/main/resources/i18n/messages_zh_TW.properties

@@ -1,5 +1,5 @@
 #i18n zh_TW
-#Thu Jan 09 16:59:43 CST 2025
+#Thu Jun 12 16:41:17 CST 2025
 i18n.ssh_info_does_not_exist.5ed0=ssh 資訊不存在啦
 i18n.incompatible_program_versions.5291=當前程式版本 {} 新版程式最低相容 {} 不能直接升級
 i18n.no_projects_configured.e873=沒有配置任何專案
@@ -8,6 +8,7 @@ i18n.machine_ssh_info.8dbb=機器SSH資訊
 i18n.machine_info_not_exist.3468=對應的機器資訊不存在
 i18n.unsupported_method.a1de=不支援的方式
 i18n.delete_local_image_failed.91fa=刪除本地映象失敗
+i18n.cluster_not_grouped.8f54=當前叢集還未繫結分組,不能監控 FTP 資產資訊
 i18n.service_name_in_cluster_required.5446=請填寫叢集中的服務名
 i18n.cluster_manager_node_not_found.1cd0=沒有找到叢集管理節點
 i18n.distribute_id_already_exists.2168=分發id已經存在啦
@@ -34,6 +35,7 @@ i18n.start_waiting_for_data_migration.e76f=開始等待資料遷移
 i18n.empty_file_or_folder_for_publish.cae8=釋出的檔案或者資料夾為空,不能繼續釋出
 i18n.demo_account_cannot_use_feature.a1a1=演示賬號不能使用該功能
 i18n.repository_type_required.9414=請選擇倉庫型別
+i18n.start_backup_database.e554=開始備份資料庫
 i18n.async_resource_expired.2ddc=非同步資源過期,需要主動關閉,{} {}
 i18n.mark_cannot_be_empty.1927=標記不能為空
 i18n.get_success.fb55=獲取成功
@@ -50,9 +52,11 @@ i18n.upload_failed_no_matching_project.b219=上傳失敗,沒有找到對應的
 i18n.no_branches_or_tags_in_repository.76b6=倉庫沒有任何分支或者標籤
 i18n.download_file_description.10cb=下載檔案 {} {} {}
 i18n.delay_build.7d62=延遲 {} 秒後開始構建
+i18n.ftp_not_exist.f9b3=不存在對應ftp
 i18n.default_cluster.38cf=預設叢集
 i18n.node_and_check_project_failed.ac4b=節點與檢查專案失敗
 i18n.load_oauth2_config.da42=載入 oauth2 配置 :{} {}
+i18n.affected_rows.5781=影響行數
 i18n.cluster_not_bound_to_group_for_node_monitoring.1586=當前叢集還未繫結分組,不能監控叢集節點資產資訊
 i18n.cannot_execute_error.4c29=不能執行:error
 i18n.no_environment_variable.c79f=沒有對應的環境變數
@@ -114,6 +118,7 @@ i18n.no_ssh_entry_found.d0e1=沒有找到對應的ssh項:{}
 i18n.build_runs_on_image_interrupted.00fd=構建 runsOn 映象被中斷
 i18n.incorrect_parameter_format.9efb=傳入的引數格式不正確
 i18n.multiple_certificate_files_found.bee3=找到 2 個以上的證書檔案
+i18n.file_not_exist_or_unable_to_download.b977=檔案不存在或無法下載\:
 i18n.invalid_runs_on_image_name.4b96=runsOn 映象名稱不合法
 i18n.dockerfile_path_required.69ac=請填寫要執行的 Dockerfile 路徑
 i18n.file_upload_mode_not_configured.b3b2=沒有配置檔案上傳模式
@@ -248,6 +253,7 @@ i18n.select_node_to_modify.6617=請選擇要修改的節
 i18n.correct_dingtalk_address_required.2b4a=請輸入正確釘釘地址
 i18n.query_folder_sftp_failed.9d35=查詢資料夾 SFTP 失敗,
 i18n.name_field_required.e0c5=第 {} 行 name 欄位不能位空
+i18n.ftp_connection_failed_message.bd99=連線FTP失敗:
 i18n.plugin_end_log_connection_successful.9035=連線成功:外掛端日誌
 i18n.start_building_with_number_and_path.c41c=開始構建 \#{} 構建執行路徑 \: {}
 i18n.start_executing_upload_pre_command.fb5c=開始執行上傳前命令
@@ -292,6 +298,7 @@ i18n.login_name_cannot_contain_chinese_and_special_characters.48a8=登入名不
 i18n.cannot_join_cluster_as_role.01d4=不能以 {} 角色加入叢集
 i18n.not_an_enumeration.8244=不是列舉
 i18n.script_not_exist.b180=對應指令碼已經不存在啦
+i18n.file_not_exist_or_unable_to_open.b045=檔案不存在或無法開啟\:
 i18n.already_offline.d3b5=已經離線啦
 i18n.rebuild_success.5938=重建成功
 i18n.hours.2de0=小時
@@ -328,6 +335,7 @@ i18n.upload_progress_template.ac3f=上傳檔案進度\:{}/{} {}
 i18n.mark_already_exists.0ccc=標記已存在
 i18n.docker_not_found.2a2e=\ 沒有找到任何 docker。可能docker tag 填寫不正確,需要為 docker 配置標籤
 i18n.download_remote_file_failed.fcc3=下載遠端檔案失敗\:
+i18n.no_matching_asset_ftp.d420=不存在對應的資產FTP
 i18n.no_file_found.6f1b=沒有找到 {} 檔案
 i18n.distribute_result.a230=分發結果:{}
 i18n.multiple_ssh_addresses_found.b3f7=SSH 地址 {} 存在多個資料,將自動合併使用 {} SSH的配置資訊
@@ -335,6 +343,7 @@ i18n.no_management_permission.fd25=您沒有對應管理許可權\:-2
 i18n.workspace_env_vars.f7e8=工作空間環境變數
 i18n.unsupported_mode.a3d3=暫不支援的模式:
 i18n.select_node_and_project.6021=請選擇節點和專案
+i18n.initialize_sql.6691=執行初始化SQL檔案
 i18n.operation_succeeded.3313=操作成功
 i18n.url_length_exceeded.ca1c=url 長度不能超過 200
 i18n.waiting_to_close_process.3634=等待關閉[Process]程序:{}
@@ -364,6 +373,7 @@ i18n.webhooks_invocation_error.9792=WebHooks 呼叫錯誤
 i18n.missing_parent_id.4331=父任務id缺失
 i18n.data_modification_time_format_incorrect.7ffe=資料修改時間格式不正確 {} {}
 i18n.cannot_delete_recent_logs.ee19=不能刪除近一天相關的日誌(檔案修改時間)
+i18n.monitor_name.9aff=監控
 i18n.agent_jar_not_exist.28ac=Agent JAR包不存在
 i18n.parse_certificate_unknown_error.c43c=解析證書發生未知錯誤:
 i18n.node_info_incomplete.3b69=對應的節點資訊不完整不能繼續
@@ -377,6 +387,7 @@ i18n.system_logs.84aa=系統日誌
 i18n.machines_ssh_data_fixed.1387=成功修復 {} 條機器 SSH 資料
 i18n.docker_label_required.b690=請填要執行 docker 標籤
 i18n.no_matching_permission.09cf=未匹配到合適的許可權不足
+i18n.ftp_create_folder_exception.a4fe=FTP建立資料夾異常
 i18n.data_id_does_not_exist.a566=資料id 不存在
 i18n.no_ssh_info.a8ec=沒有對應 SSH 資訊
 i18n.distribution_with_build_items_message.45f5=當前分發存在構建項,不能直接刪除(需要提前解綁或者刪除關聯資料後才能刪除)
@@ -401,6 +412,7 @@ i18n.node_not_enabled.10ef={} 節點未啟用
 i18n.client_id_not_configured.ab8e=沒有配置 clientId
 i18n.build_product_dir_not_empty.ba06=構建產物目錄不能為空,長度1-200
 i18n.trigger_token_error_or_expired.8976=觸發token錯誤,或者已經失效
+i18n.ftp_connection_failed.1f2f=連線FTP失敗
 i18n.auth_info_error.c184=授權資訊錯誤
 i18n.download_file_error.5bcd=下載檔案異常\:
 i18n.rollback_ended.fb1d=執行回滾結束:{}
@@ -416,6 +428,7 @@ i18n.id_already_exists.6208=id已經存在啦
 i18n.ssh_info.ebe6=SSH 資訊
 i18n.current_status.81c0=\ 當前還在:
 i18n.project_path_no_spaces.263c=專案路徑不能包含空格
+i18n.ftp_asset_management.c6a5=FTP資產管理
 i18n.please_fill_in_address_of.9e02=請填寫 %s 的 地址
 i18n.rsa_private_key_file_invalid.5f12=rsa 私鑰檔案不存在或者有誤
 i18n.ssh_node_required.4566=請選擇 ssh 節點
@@ -456,6 +469,7 @@ i18n.load_plugin.1f64=載入:{} 外掛
 i18n.host_field_required.5c36=第 {} 行 host 欄位不能位空
 i18n.container_build_interrupted.a17b=容器 build 被中斷\:
 i18n.upload_action.d5a7=上傳
+i18n.ftp_connection_or_operation_exception.09af=FTP 連線或操作異常
 i18n.delete_file_failure.041f=刪除檔案失敗,請檢查
 i18n.no_cluster_info_found.fb40=沒有找到對應的叢集資訊
 i18n.script_template_log.30cb=指令碼模板日誌
@@ -509,6 +523,7 @@ i18n.invalid_zip_file.3092=上傳的壓縮包不是 Jpom [{}] 包
 i18n.publish_command_non_zero_exit_code.ea80=執行釋出命令退出碼非0,{}
 i18n.project_path_promotion_issue.2250=專案路徑存在提升目錄問題
 i18n.handle_node_deletion_script_failure_duplicate.821e=處理 {} 節點刪除指令碼失敗{}
+i18n.ftp_folder_query_failed.0011=無法查詢資料夾FTP,
 i18n.no_matching_process_type.b468=未匹配到合適的處理型別
 i18n.unsupported_type.7495=不支援的型別
 i18n.submit_task_queue_success.5f5b=提交任務佇列成功,當前佇列數:
@@ -567,6 +582,7 @@ i18n.select_correct_pre_publish_script.d230=請選擇正確的釋出前指令碼
 i18n.greeting.5ecd=您好,Jpom
 i18n.ssh_connection_failed.4719=ssh連線失敗
 i18n.oauth2_redirect_failed.6dcd=跳轉 oauth2 失敗,{} {}
+i18n.ftp_upload_failed.8298=FTP 上傳失敗
 i18n.data_workspace_mismatch.ae1d=資料工作空間和操作工作空間不一致
 i18n.process_file_event_exception.e8e6=處理檔案事件異常
 i18n.current_docker_cluster_has_no_management_nodes_online.56cd=當前 {} docker 叢集沒有管理節點線上
@@ -578,6 +594,7 @@ i18n.restart_operation.5e3a=執行重啟操作
 i18n.no_h2_data_info_for_migration.5799=沒有 h2 資料資訊不用遷移
 i18n.publish_success.2fff=釋出成功
 i18n.system_cache.c4a8=系統快取
+i18n.no_ftp_item.8e39=沒有對應的ftp項
 i18n.distribution_machine_required.5921=請選擇分發的機器
 i18n.build_call_container_exception.6e04=構建呼叫容器異常
 i18n.process_killed_successfully.a4c3=成功kill
@@ -586,6 +603,7 @@ i18n.auto_clear_data_errors.112f=自動清除資料錯誤 {} {}
 i18n.publish_directory_is_empty.79c6=釋出目錄為空
 i18n.file_or_directory_not_found.f03e=檔案不存在或者是目錄\:
 i18n.clear_file_cache_failed.5cd1=清空檔案快取失敗
+i18n.database_backup_complete_path.861b=資料庫備份完成,儲存路徑為
 i18n.file_downloading_status.c995=檔案下載中:
 i18n.system_IP_authorization.9c08=系統配置IP授權
 i18n.node_failed.20d5=節點失敗:
@@ -613,6 +631,7 @@ i18n.delete_failure_with_colon_and_full_stop.bc42=刪除失敗:
 i18n.product_directory_cannot_skip_levels.3ad4=產物目錄不能越級:
 i18n.fix_null_workspace_data.4d0b=修復工作空間為 null 的資料 {} {}
 i18n.external_config_file_path.06ec=外部配置檔案路徑
+i18n.asset_ftp_info.3b75=資產FTP資訊
 i18n.soft_link_project_department_exists.fa97=軟鏈的專案部存在
 i18n.docker_info.00d2=docker 資訊
 i18n.log_file_does_not_exist.f6c6=日誌檔案不存在
@@ -621,6 +640,7 @@ i18n.no_file_info.db01=沒有對應的檔案資訊
 i18n.record_operation_log_exception.8012=記錄操作日誌異常
 i18n.corresponding_file_required.57b3=請選擇對應到檔案
 i18n.build_command_no_delete.df52=構建命令不能包含刪除命令
+i18n.ftp_info_table.b177=ftp資訊表
 i18n.file_merge_error.f32f=檔案合併後異常,檔案不完整可能被損壞
 i18n.script_info_not_found.bd8d=找不到對應的指令碼資訊
 i18n.cannot_modify_own_info.4036=不能修改自己的資訊
@@ -675,6 +695,7 @@ i18n.container_build_host_config_conversion_failure.27aa=容器構建 hostConfig
 i18n.build_task_count_and_queue_count.f0b6=當前構建中任務數:{},佇列中任務數:{} {}
 i18n.node_cache.d68c=節點快取
 i18n.cluster_node_not_in_system.0645=當前叢集對應的節點,不在本系統中無法退出叢集
+i18n.ftp_selection.c903=請選擇分發FTP項
 i18n.file_search_failed.231b=檔案搜尋失敗
 i18n.exported_ssh_data.ce88=匯出的 ssh 資料
 i18n.execution_ended_with_duration.a59b=執行結束 {}流程,耗時:{}
@@ -703,6 +724,7 @@ i18n.ssh_batch_command_execution_exception.029a=ssh 批量執行命令異常
 i18n.content_type_not_supported.81a9=不支援的 contentType
 i18n.cloud_server_network_issues.a865=雲伺服器的安全組配置等網路相關問題排查定位。
 i18n.start_building_image.eacd={} 開始構建映象 {}{}
+i18n.ftp_already_exists.d66b=對應的FTP已經存在啦
 i18n.configure_correct_redirect_url.058e=請配置正確的重定向 url
 i18n.no_cache_info_with_minus_one.52f2=沒有對應的快取資訊:-1
 i18n.no_node_entry_found.b1ef=沒有找到對應的節點項:{}
@@ -714,6 +736,7 @@ i18n.no_docker_info_found.6d38=沒有找到對應的 docker 資訊
 i18n.update_docker_machine_id_failed.063d=更新 DOCKER 表機器id 失敗:
 i18n.build_status_abnormal.8ca1=構建狀態異常或者被取消
 i18n.node_connection_failure.896d=節點連線失敗,請檢查節點是否線上
+i18n.database_load_success_url.5f64=資料庫載入成功,URL為
 i18n.login_name_already_exists.2511=登入名已經存在
 i18n.port_error.312e=埠錯誤
 i18n.account_disabled.9361=賬號已經被禁用,不能使用
@@ -763,9 +786,12 @@ i18n.error_sql.15ff=錯誤 sql\:{}
 i18n.verification_method_not_configured.7358={}未配置驗證方法:{}
 i18n.local_git_certificate_not_supported.b395=暫時不支援本地 git 指定證書拉取程式碼
 i18n.unsupported_method_with_colon.eae8=不支援的方式:
+i18n.exported_ftp_data.2b54=匯出的 ftp 資料
 i18n.current_docker_has_no_cluster_info.0b52=當前 docker 沒有叢集資訊
 i18n.cannot_delete_self.fec9=不能刪除自己
 i18n.operation_monitoring_error.8036=執行操作監控錯誤
+i18n.ftp_read_file_failed.e738=FTP 讀取檔案失敗
+i18n.file_exists.145b=資料夾或檔案已經存在
 i18n.alias_or_token_error.d5c6=別名或者token錯誤,或者已經失效
 i18n.version_config_info.7b29=版本配置資訊
 i18n.delete_old_package.ca95=刪除舊程式包:{}
@@ -778,6 +804,7 @@ i18n.node_service_stopped_failed_restart.4307=【{}】節點的【{}】專案{}
 i18n.associated_workspace.885b=所屬工作空間
 i18n.auto_clear_machine_node_stats_logs.5279=自動清理 {} 條機器節點統計日誌
 i18n.unsupported_mode.501d=不支援的模式
+i18n.ftp_client_build_failure.aa55=構建 FTP 客戶端失敗 [{}]\: {}
 i18n.missing_script_message.af89=找不到對應的指令碼
 i18n.start_migrating.20d6=開始遷移 {} {}
 i18n.incompatible_database_version.8f7b=資料庫版本不相容,需要處理跨版本升級。
@@ -802,6 +829,7 @@ i18n.configure_user_notification.250d=請配置使用者通知
 i18n.operation_status_code.8231=操作狀態碼
 i18n.agent_jar_damaged.74a8=Agent JAR 損壞請重新上傳,
 i18n.read_error.7fa5=讀取錯誤
+i18n.import_success.ef46=匯入成功:{}
 i18n.network_resource_monitoring_error.4ede=網絡卡資源監控異常:
 i18n.select_workspace_to_modify.ac87=請選擇要修改的工作空間
 i18n.decode_failure.822e=解碼失敗
@@ -832,6 +860,8 @@ i18n.project_id_not_found.b87e=沒有專案id
 i18n.operation_type.de9c=操作型別
 i18n.project_has_logs_cannot_migrate.2e0e=當前專案存在日誌閱讀,不能直接遷移
 i18n.delete_failure_with_colon.b429=刪除失敗\:
+i18n.no_ftp_server_correspondence.1af7=沒有對應的Ftp
+i18n.ftp_import_template.8fa3=ftp匯入模板
 i18n.tag_cannot_contain_colon.f9ae=標籤不能包含 :
 i18n.distribute_id_already_exists_globally.6478=分發id已經存在啦,分發id需要全域性唯一
 i18n.import_exception.04b6=匯入第 {} 條資料異常\:{}
@@ -895,7 +925,9 @@ i18n.no_manager_node_found.5934=當前叢集未找到任何管理節點
 i18n.file_transfer_exception.bda6=轉發檔案異常
 i18n.select_node.f8a6=請選擇節點
 i18n.upload_progress_with_units.44ad=上傳檔案進度\:{} {}/{} {}
+i18n.ftp_download_file_failed.2e42=FTP 下載檔案失敗
 i18n.ssh_terminal_execution_log.58f1=ssh 終端執行日誌
+i18n.ftp_file_manager.c52e=FTP檔案管理
 i18n.project_monitor.d2ff=專案監控
 i18n.push_image_interrupted.6377=push image 被中斷\:
 i18n.default_value.1aa9={} [預設]
@@ -986,6 +1018,7 @@ i18n.certificate_already_exists.adf9=當前證書已經存在啦(系統全域性
 i18n.oshi_file_system_monitoring_exception.dc24=oshi 檔案系統資源監控異常
 i18n.image_cannot_be_empty.1600=映象不能為空
 i18n.no_corresponding_node_info.cd24=沒有對應到節點資訊
+i18n.auto_backup_path.a16b=自動備份資料檔案到路徑
 i18n.node_plugin_version_required.2318=node 外掛 version 不能為空
 i18n.start_new_thread_for_h2_database_backup.9337=啟動一個新執行緒來執行 H2 資料庫備份...啟動
 i18n.docker_exec_terminal_process_ended.c734=[{}] docker exec 終端程序結束
@@ -1005,6 +1038,7 @@ i18n.protocol_not_supported.b906=不支援的 protocol
 i18n.force_unbind_succeeded.5bfd=強制解綁成功
 i18n.unexpected_exception.2b52=發生異常
 i18n.check_email_error.636c=檢查郵箱資訊錯誤:{}
+i18n.ftp_unauthorized_directory.df73=此ftp未授權操作此目錄
 i18n.initialization_success.4725=初始化成功
 i18n.running_status.d679=執行中
 i18n.auto_clean_temp_dir.11d2=自動清理臨時目錄
@@ -1101,6 +1135,7 @@ i18n.batch_trigger_script_exception.8fb4=服務端指令碼批量觸發異常
 i18n.upgrade_failure.4ae2=升級失敗
 i18n.no_branch_or_tag_message.8ae3=沒有 {} 分支/標籤
 i18n.general_error_message.728a=啊哦,好像哪裡出錯了,請稍候再試試吧~
+i18n.ftp_connection_failure.0f31=關閉 FTP 連線失敗
 i18n.service_info_incomplete_with_code2.e9ca=服務資訊不完整不能操作:-2
 i18n.ignored_operation.edee=忽略的操作:{}
 i18n.monitor_name_cannot_be_empty.514a=監控名稱不能為空
@@ -1115,6 +1150,7 @@ i18n.select_related_data_id.7fba=請選擇關聯資料 ID
 i18n.node_name_required.5bdf=請填寫節點名稱
 i18n.client_terminated_connection.6886=客戶端終止連線:{}
 i18n.close_thread_pool.4cd9=關閉 {} 執行緒池
+i18n.ftp_upload_file_exception.118c=FTP上傳檔案異常
 i18n.clear_ip_whitelist_config_success.8cf6=清除 IP 白名單配置成功
 i18n.no_corresponding_folder.621f=沒有對應資料夾
 i18n.no_online_manager_node_found.05d7=當前叢集未找到線上的管理節點
@@ -1124,6 +1160,7 @@ i18n.execution_completed.24a1=執行完畢\:
 i18n.close_project_failure.a1d2=關閉專案失敗:
 i18n.select_folder_to_compress.915f=請選擇資料夾進行壓縮
 i18n.config_file_not_found.fc87=均未找到配置檔案
+i18n.ftp_item_not_found.60a7=沒有找到對應的ftp項:{}
 i18n.update_ssh_machine_id_failed.bd24=更新 SSH 表機器id 失敗:
 i18n.select_pull_code_protocol.fc24=請選擇拉取程式碼的協議
 i18n.auth_directory_cannot_be_empty.21ba=授權目錄不能為空
@@ -1291,6 +1328,7 @@ i18n.program_already_running.96e1=當前程式正在執行中,不能重複啟
 i18n.password_change_success.8013=修改密碼成功!
 i18n.build_resource_cleanup_failed.c4cf=清理構建資源失敗
 i18n.incorrect_publish_method.e095=釋出方法不正確
+i18n.ftp_directory.a790=請輸入釋出到ftp中的目錄
 i18n.import_low_version_data_to_new_version.247b=2. 將匯出的低版本資料( sql 檔案) 匯入到新版本中【啟動程式引數裡面新增 --replace-import-h2-sql\=/xxxx.sql (路徑需要替換為第一步控制檯輸出的 sql 檔案儲存路徑)】
 i18n.incorrect_line_number.5877=行號不正確
 i18n.file_deletion_event_with_details.7537=檔案刪除事件:{} {}
@@ -1299,6 +1337,7 @@ i18n.maven_plugin_version_required.71f1=maven 外掛 version 不能為空
 i18n.trigger_token_error_or_expired_with_code.393b=觸發token錯誤,或者已經失效\:-1
 i18n.invalid_webhooks_address.d836=WebHooks 地址不合法
 i18n.project_path_auth_not_under_jpom.0e18=專案路徑授權不能位於Jpom目錄下
+i18n.ftp_rename_failed_exception.0fcc=FTP重新命名失敗異常
 i18n.reconnect_failure.7c01=重連失敗
 i18n.project_operations.03d9=專案運維
 i18n.image_not_exist.ee17=映象不存在
@@ -1338,6 +1377,7 @@ i18n.refreshing_cache.c969=正在重新整理快取中,請勿重複重新整理
 i18n.start_executing_database_event.fc57=開始執行資料庫事件:{}
 i18n.static_file_storage.35f6=靜態檔案儲存
 i18n.project_log_is_existing_folder.a80a=專案log是一個已經存在的資料夾
+i18n.check_ftp_connection_failed.f7de=檢測 FTP 連線失效 [{}],準備重建\: {}
 i18n.project_data_workspace_id_inconsistency.7ed6=專案資料工作空間ID[{}]查詢出節點ID不一致, 舊資料\: {}, 新資料\: {}
 i18n.query_workspace_error.6a0d=查詢錯誤的工作空間失敗
 i18n.unknown_database_mode.f9e5=當前資料庫模式未知
@@ -1375,8 +1415,8 @@ i18n.token_invalid_or_expired.cb96=token錯誤,或者已經失效\:-1
 i18n.list_and_query.c783=列表、查詢
 i18n.migration_docker_cert_error.a5ea=遷移 docker[{}] 證書發生異常
 i18n.file_downloading.7a8f=檔案下載中
-i18n.mark_must_contain_letters_numbers_underscores.667d=標記只能包含字母、數字、下劃線
 i18n.please_fill_in_runs_on.c2ff=請填寫runsOn。
+i18n.mark_must_contain_letters_numbers_underscores.667d=標記只能包含字母、數字、下劃線
 i18n.create_build_task_exception.06f1=建立構建任務異常
 i18n.execution_interrupted.1bb6=執行被中斷
 i18n.event_loss_or_execution_error.7b14=事件丟失或者執行錯誤:{} {}
@@ -1401,6 +1441,7 @@ i18n.please_pass_parameter.3182=請傳入引數
 i18n.node_no_data_pulled.0dae={} 節點沒有拉取到任何 {},但是刪除了資料:{}
 i18n.node_info_not_found.2c8c=沒有查詢到節點資訊:
 i18n.please_fill_in_repository_address.0cf8=請填寫倉庫地址
+i18n.no_ftp_correspondence.23c4=沒有對應的FTP
 i18n.table_without_primary_key.7392=表沒有主鍵
 i18n.invalid_shard_id.46fd=不合法的分片id
 i18n.execution_ended.b793=執行結束\:{}
@@ -1499,6 +1540,7 @@ i18n.config_file_database_config_not_parsed.47b2=未解析出配置檔案中的
 i18n.data_already_exists.0397=匯入的資料已經存在啦
 i18n.please_check_in_time.3b4f=請及時檢查
 i18n.installation_success.811f=安裝成功
+i18n.timeout.e944=超時
 i18n.cluster_management.74ea=叢集管理
 i18n.type_field_value_error.14cf=第 {} 行 type 欄位值錯誤(Git/Svn)
 i18n.migrate_data.f556=遷移資料
@@ -1514,6 +1556,7 @@ i18n.backup_data_trigger.a71a=備份資料觸發器
 i18n.file_signature_info_not_found.83bf=沒有檔案簽名資訊
 i18n.associated_nodes_warning.64d8=當前機器還關聯{}個節點,不能直接刪除(需要提前解綁或者刪除關聯資料後才能刪除)
 i18n.build_unknown_error.dad6=構建發生未知錯誤
+i18n.start_import_data.ea31=開始匯入資料:{}
 i18n.new_version_exists_download_unavailable.4ba7=存在新版本,下載地址不可用
 i18n.compare_backup_failure.303e=對比清空專案檔案備份失敗
 i18n.upload_success_and_restart.7bc3=上傳成功並重啟
@@ -1547,9 +1590,11 @@ i18n.download_exception.e616=下載檔案異常
 i18n.process_file_deletion_exception.1c6e=處理檔案刪除異常
 i18n.trigger_auto_execute_command_template_exception.4e01=觸發自動執行命令模版異常
 i18n.no_build.d163=沒有對應的構建
+i18n.ftp_management.cb91=FTP管理
 i18n.start_executing_publishing_with_file_size.5039=開始執行釋出,需要釋出的檔案大小:{}
 i18n.command_execution_exception.4ccd=執行命令異常
 i18n.operation_ip.cbd4=操作IP
+i18n.exception.c195=異常
 i18n.auth_directory_cannot_contain_hierarchy.d6ca=授權目錄中不能存在包含關係:
 i18n.ip_authorization_interception_exception.8130=IP授權攔截異常,請檢查配置是否正確
 i18n.refresh_token_timeout.3291=重新整理token超時

+ 45 - 0
modules/common/src/main/resources/i18n/words.json

@@ -15,6 +15,7 @@
 	"i18n.address_not_configured.f2eb":"未配置地址",
 	"i18n.admin_account_required.31e0":"系统中的系统管理员账号数量必须存在一个以上",
 	"i18n.admin_email_not_configured.ecb8":"管理员还没有配置系统邮箱,请联系管理配置发件信息",
+	"i18n.affected_rows.5781":"影响行数",
 	"i18n.agent_jar_damaged.74a8":"Agent JAR 损坏请重新上传,",
 	"i18n.agent_jar_not_exist.28ac":"Agent JAR包不存在",
 	"i18n.agent_response_empty.cc8e":"agent 端响应内容为空",
@@ -27,6 +28,7 @@
 	"i18n.alias_or_token_error.d5c6":"别名或者token错误,或者已经失效",
 	"i18n.already_offline.d3b5":"已经离线啦",
 	"i18n.asset_cluster_and_node_mismatch.8964":"资产集群和节点不匹配",
+	"i18n.asset_ftp_info.3b75":"资产FTP信息",
 	"i18n.asset_machine_node_statistics.4a03":"资产机器节点统计",
 	"i18n.asset_monitoring_thread_pool_rejected_task.222e":"资产监控线程池拒绝了任务:{}",
 	"i18n.asset_ssh_not_exist.cd43":"不存在对应的资产SSH",
@@ -54,6 +56,7 @@
 	"i18n.authorization_exception.acc0":"{} 授权异常 {}",
 	"i18n.authorized_cannot_be_reloaded.6ece":"authorized 不能重复加载",
 	"i18n.auto_backup_h2_database.2ed0":"自动备份 h2 数据库文件,备份文件位于:{}",
+	"i18n.auto_backup_path.a16b":"自动备份数据文件到路径",
 	"i18n.auto_clean_temp_dir.11d2":"自动清理临时目录",
 	"i18n.auto_clear_data_errors.112f":"自动清除数据错误 {} {}",
 	"i18n.auto_clear_machine_node_stats_logs.5279":"自动清理 {} 条机器节点统计日志",
@@ -157,6 +160,7 @@
 	"i18n.check_docker_exception.a6d1":"检查 docker 异常",
 	"i18n.check_docker_url_exception.4302":"检查 docker url 异常 {}",
 	"i18n.check_email_error.636c":"检查邮箱信息错误:{}",
+	"i18n.check_ftp_connection_failed.f7de":"检测 FTP 连接失效 [{}],准备重建: {}",
 	"i18n.check_git_client_exception.42a3":"检查 git 客户端异常",
 	"i18n.check_passed.dce8":"检查通过",
 	"i18n.checkout_version.a586":"把版本:%s check out ",
@@ -209,6 +213,7 @@
 	"i18n.cluster_not_bound_to_group_for_node_monitoring.1586":"当前集群还未绑定分组,不能监控集群节点资产信息",
 	"i18n.cluster_not_bound_to_group_for_ssh_monitoring.c894":"当前集群还未绑定分组,不能监控 SSH 资产信息",
 	"i18n.cluster_not_exist.4098":"对应的集群不存在",
+	"i18n.cluster_not_grouped.8f54":"当前集群还未绑定分组,不能监控 FTP 资产信息",
 	"i18n.cluster_response_incorrect.c08a":"集群响应信息不正确,请确认集群地址是正确的服务端地址",
 	"i18n.cluster_status_code_exception.9d89":"集群状态码异常:{} {}",
 	"i18n.code_pull_conflict.6e8e":"拉取代码发生冲突,可以尝试清除构建或者解决仓库里面的冲突后重新操作。:",
@@ -346,12 +351,14 @@
 	"i18n.data_type_not_supported.fd03":"不支持的数据类型:",
 	"i18n.data_workspace_mismatch.ae1d":"数据工作空间和操作工作空间不一致",
 	"i18n.database_auto_backup_support.7b8f":"当前数据库不支持自动备份",
+	"i18n.database_backup_complete_path.861b":"数据库备份完成,保存路径为",
 	"i18n.database_backup_label.62d8":"数据库备份",
 	"i18n.database_connection_not_configured.c80e":"没有配置数据库连接",
 	"i18n.database_corrupted.944e":"数据库异常,可能数据库文件已经损坏(可能丢失部分数据),需要重新初始化。可以尝试在启动参数里面添加 --recover:h2db 来自动恢复,:",
 	"i18n.database_event_execution_ended.690b":"数据库 {} 事件执行结束,:{}",
 	"i18n.database_exception.4894":"数据库异常",
 	"i18n.database_exception_due_to_resources.dbf1":"数据库异常,可能因为服务器资源不足(内存、硬盘)等原因造成数据异常关闭。需要手动重启服务端来恢复,:",
+	"i18n.database_load_success_url.5f64":"数据库加载成功,URL为",
 	"i18n.database_mode_config_missing.ae5d":"数据库Mode配置缺失",
 	"i18n.database_not_initialized.e5e7":"还没有初始化数据库",
 	"i18n.database_username_not_configured.a048":"未配置(未解析到)数据库用户名",
@@ -487,6 +494,7 @@
 	"i18n.event_script_does_not_exist.e726":"事件脚本不存在:{} {}",
 	"i18n.event_script_interrupted.8c79":"事件脚本中断:",
 	"i18n.event_type_not_supported.e9c3":"不支持的事件类型:{}",
+	"i18n.exception.c195":"异常",
 	"i18n.exclusion_success.7d46":"剔除成功",
 	"i18n.execute.1a6a":"执行",
 	"i18n.execute_dsl_script_exception.0882":"执行 DSL 脚本异常:{}",
@@ -514,6 +522,7 @@
 	"i18n.exit_successful.8150":"退出成功",
 	"i18n.export_image_exception.cb1c":"导出镜像异常",
 	"i18n.export_low_version_data.f1aa":"1. 导出低版本数据 【启动程序参数里面添加 --backup-h2】",
+	"i18n.exported_ftp_data.2b54":"导出的 ftp 数据",
 	"i18n.exported_project_data.fd1f":"导出的项目数据 ",
 	"i18n.exported_repo_data.bac5":"导出的 仓库信息 数据 ",
 	"i18n.exported_ssh_data.ce88":"导出的 ssh 数据",
@@ -532,6 +541,7 @@
 	"i18n.file_download_failed.7983":"文件下载失败:",
 	"i18n.file_downloading.7a8f":"文件下载中",
 	"i18n.file_downloading_status.c995":"文件下载中:",
+	"i18n.file_exists.145b":"文件夹或文件已经存在",
 	"i18n.file_format_not_supported.eac4":"不支持的文件格式",
 	"i18n.file_full_path.16cc":"文件全路径:{}",
 	"i18n.file_id_missing.0e39":"文件 ID 缺失",
@@ -547,6 +557,8 @@
 	"i18n.file_name_not_found.b0ed":"没有文件名",
 	"i18n.file_not_exist.5091":"对应的文件不存在",
 	"i18n.file_not_exist.ea6a":"不存在对应的文件",
+	"i18n.file_not_exist_or_unable_to_download.b977":"文件不存在或无法下载:",
+	"i18n.file_not_exist_or_unable_to_open.b045":"文件不存在或无法打开:",
 	"i18n.file_not_found.d952":"文件不存在",
 	"i18n.file_or_directory_not_found.f03e":"文件不存在或者是目录:",
 	"i18n.file_publish_task_record.edc4":"文件发布任务记录",
@@ -581,6 +593,29 @@
 	"i18n.forbidden_operation_time_range.92bf":"【禁止操作】当前时段禁止执行 {} 至 {}",
 	"i18n.force_unbind_succeeded.5bfd":"强制解绑成功",
 	"i18n.free_script.7760":"自由脚本",
+	"i18n.ftp_already_exists.d66b":"对应的FTP已经存在啦",
+	"i18n.ftp_asset_management.c6a5":"FTP资产管理",
+	"i18n.ftp_client_build_failure.aa55":"构建 FTP 客户端失败 [{}]: {}",
+	"i18n.ftp_connection_failed.1f2f":"连接FTP失败",
+	"i18n.ftp_connection_failed_message.bd99":"连接FTP失败:",
+	"i18n.ftp_connection_failure.0f31":"关闭 FTP 连接失败",
+	"i18n.ftp_connection_or_operation_exception.09af":"FTP 连接或操作异常",
+	"i18n.ftp_create_folder_exception.a4fe":"FTP创建文件夹异常",
+	"i18n.ftp_directory.a790":"请输入发布到ftp中的目录",
+	"i18n.ftp_download_file_failed.2e42":"FTP 下载文件失败",
+	"i18n.ftp_file_manager.c52e":"FTP文件管理",
+	"i18n.ftp_folder_query_failed.0011":"无法查询文件夹FTP,",
+	"i18n.ftp_import_template.8fa3":"ftp导入模板",
+	"i18n.ftp_info_table.b177":"ftp信息表",
+	"i18n.ftp_item_not_found.60a7":"没有找到对应的ftp项:{}",
+	"i18n.ftp_management.cb91":"FTP管理",
+	"i18n.ftp_not_exist.f9b3":"不存在对应ftp",
+	"i18n.ftp_read_file_failed.e738":"FTP 读取文件失败",
+	"i18n.ftp_rename_failed_exception.0fcc":"FTP重命名失败异常",
+	"i18n.ftp_selection.c903":"请选择分发FTP项",
+	"i18n.ftp_unauthorized_directory.df73":"此ftp未授权操作此目录",
+	"i18n.ftp_upload_failed.8298":"FTP 上传失败",
+	"i18n.ftp_upload_file_exception.118c":"FTP上传文件异常",
 	"i18n.fuzzy_match_files.139d":"{} 模糊匹配到 {} 个文件",
 	"i18n.general_error_message.728a":"啊哦,好像哪里出错了,请稍候再试试吧~",
 	"i18n.general_execution_exception.62e9":"执行异常:",
@@ -647,6 +682,7 @@
 	"i18n.import_save_failure.001a":"导入第 {} 条数据保存失败:{}",
 	"i18n.import_save_project_exception.cdbe":"导入保存项目异常",
 	"i18n.import_success.b6d1":"导入成功",
+	"i18n.import_success.ef46":"导入成功:{}",
 	"i18n.import_success_message.2df3":"导入成功(编码格式:{}),更新 {} 条数据,因为节点分发/项目副本忽略 {} 条数据",
 	"i18n.import_success_with_count.22b9":"导入成功,添加 {} 条数据,修改 {} 条数据",
 	"i18n.import_success_with_details.a4a0":"导入成功(编码格式:{}),添加 {} 条数据,修改 {} 条数据",
@@ -677,6 +713,7 @@
 	"i18n.initialization_failure.19e9":"初始化失败:",
 	"i18n.initialization_success.4725":"初始化成功",
 	"i18n.initialize_database_failure.2ef9":"初始化数据库失败 {}",
+	"i18n.initialize_sql.6691":"执行初始化SQL文件",
 	"i18n.initialize_user_failure.fe27":"初始化用户失败",
 	"i18n.initialize_workspace.bc97":"初始化{}工作空间",
 	"i18n.install_id_does_not_exist.6aee":"数据错误,安装 ID 不存在",
@@ -803,6 +840,7 @@
 	"i18n.monitor_docker_exception_detail.e334":"监控 docker[{}] 异常 {}",
 	"i18n.monitor_docker_timeout.b03b":"监控 docker[{}] 超时 {}",
 	"i18n.monitor_info.f299":"监控信息",
+	"i18n.monitor_name.9aff":"监控",
 	"i18n.monitor_name_cannot_be_empty.514a":"监控名称不能为空",
 	"i18n.monitor_node_exception.6ff1":"监控 {} 节点异常 {}",
 	"i18n.monitor_ssh_exception.e9ce":"监控 ssh[{}] 异常",
@@ -904,6 +942,9 @@
 	"i18n.no_file_info.db01":"没有对应的文件信息",
 	"i18n.no_files_in_project_directory.108e":"项目目录没有任何文件,请先到项目文件管理中上传文件",
 	"i18n.no_files_in_zip.1af6":"压缩包里没有任何文件",
+	"i18n.no_ftp_correspondence.23c4":"没有对应的FTP",
+	"i18n.no_ftp_item.8e39":"没有对应的ftp项",
+	"i18n.no_ftp_server_correspondence.1af7":"没有对应的Ftp",
 	"i18n.no_get_id_method.2a65":"没有  getId 方法",
 	"i18n.no_h2_data_info_for_migration.5799":"没有 h2 数据信息不用迁移",
 	"i18n.no_implemented_feature.af80":"没有实现该功能",
@@ -919,6 +960,7 @@
 	"i18n.no_management_permission.fd25":"您没有对应管理权限:-2",
 	"i18n.no_management_permission2.35d4":"您没有对应管理权限:-3",
 	"i18n.no_manager_node_found.5934":"当前集群未找到任何管理节点",
+	"i18n.no_matching_asset_ftp.d420":"不存在对应的资产FTP",
 	"i18n.no_matching_data_found.fe9d":"未找到匹配的数据",
 	"i18n.no_matching_files.b7a6":"{} 没有匹配到任何文件",
 	"i18n.no_matching_permission.09cf":"未匹配到合适的权限不足",
@@ -1452,6 +1494,7 @@
 	"i18n.ssh_with_build_items_message.0f6d":"当前ssh存在构建项,不能直接删除(需要提前解绑或者删除关联数据后才能删除)",
 	"i18n.ssl_connection_failed.e26c":"SSL 无法连接(请检查证书信任的地址和配置的 docker host 是否一致):",
 	"i18n.start_async_download.78cc":"开始异步下载",
+	"i18n.start_backup_database.e554":"开始备份数据库",
 	"i18n.start_building.1039":"开始构建中",
 	"i18n.start_building_image.eacd":"{} 开始构建镜像 {}{}",
 	"i18n.start_building_with_number_and_path.c41c":"开始构建 #{} 构建执行路径 : {}",
@@ -1474,6 +1517,7 @@
 	"i18n.start_executing_upload_post_command.1c1b":"开始执行上传后命令",
 	"i18n.start_executing_upload_pre_command.fb5c":"开始执行上传前命令",
 	"i18n.start_execution.00d7":"开始执行",
+	"i18n.start_import_data.ea31":"开始导入数据:{}",
 	"i18n.start_loading_database.b040":"开始加载 {} 数据库",
 	"i18n.start_migrating.20d6":"开始迁移 {} {}",
 	"i18n.start_migrating_h2_data_to.f478":"开始迁移 h2 数据到 {}",
@@ -1549,6 +1593,7 @@
 	"i18n.temp_folder_file_count.8e31":"临时文件夹累计文件数:{},处理成功数:{}",
 	"i18n.temporary_result_file_does_not_exist.1c7e":"临时结果文件不存在: {}",
 	"i18n.test_result.8441":"测试结果:{} {}",
+	"i18n.timeout.e944":"超时",
 	"i18n.token_invalid_or_expired.cb96":"token错误,或者已经失效:-1",
 	"i18n.token_parse_failed.cadf":"token 解析失败:",
 	"i18n.too_many_attempts.d88d":"尝试次数太多,请稍后再来",

+ 4 - 5
modules/common/src/test/resources/baidubce_translate.txt

@@ -1,19 +1,18 @@
 You are the service that converts a user request JSON into a new (user-expected) JSON object based on the following JavaScript-defined JSON object:
 
-```
 // 将下面json中的 根据`值`的含义将 `key` 转为语义化且简短的首字母为小写的小驼峰英文变量名替换无意义字符串
 // 此处进行替换,禁止出现 k1 k2 k3
-const template = {
+```json
+{
  "key1": "string1",
  "key2": "string2",
 }
 ```
 
 The following is a user request:
-```
-const template = {REQUEST_STR}
+```json
+{REQUEST_STR}
 ```
 
 // 要求输出的请求和结果分开,不要输出到一个代码片段并且是 json 代码片段
-// 输出的变量请使用 var 语法
 // 输出的 json 结果中不要声明注释

+ 4 - 0
modules/server/src/main/java/org/dromara/jpom/build/BuildExtraModule.java

@@ -73,6 +73,10 @@ public class BuildExtraModule extends BaseModel {
      * 发布到ssh中的目录
      */
     private String releasePath;
+    /**
+     * 发布到ftp中的目录
+     */
+    private String releaseFtpPath;
     /**
      * 工作空间 ID
      */

+ 81 - 11
modules/server/src/main/java/org/dromara/jpom/build/ReleaseManage.java

@@ -7,6 +7,7 @@
  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
  * See the Mulan PSL v2 for more details.
  */
+
 package org.dromara.jpom.build;
 
 import cn.hutool.core.collection.CollUtil;
@@ -22,6 +23,7 @@ import cn.hutool.core.util.NumberUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.crypto.SecureUtil;
+import cn.hutool.extra.ftp.Ftp;
 import cn.hutool.extra.spring.SpringUtil;
 import cn.hutool.extra.ssh.JschUtil;
 import cn.keepbx.jpom.model.JsonMessage;
@@ -30,6 +32,21 @@ import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
 import com.jcraft.jsch.ChannelSftp;
 import com.jcraft.jsch.Session;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
 import lombok.Builder;
 import lombok.Lombok;
 import lombok.extern.slf4j.Slf4j;
@@ -39,14 +56,17 @@ import org.dromara.jpom.common.forward.NodeForward;
 import org.dromara.jpom.common.forward.NodeUrl;
 import org.dromara.jpom.common.i18n.I18nMessageUtil;
 import org.dromara.jpom.configuration.BuildExtConfig;
+import org.dromara.jpom.func.assets.model.MachineFtpModel;
 import org.dromara.jpom.func.assets.model.MachineSshModel;
 import org.dromara.jpom.func.assets.server.MachineDockerServer;
+import org.dromara.jpom.func.assets.server.MachineFtpServer;
 import org.dromara.jpom.func.assets.server.ScriptLibraryServer;
 import org.dromara.jpom.func.files.service.FileStorageService;
 import org.dromara.jpom.model.AfterOpt;
 import org.dromara.jpom.model.BaseEnum;
 import org.dromara.jpom.model.EnvironmentMapBuilder;
 import org.dromara.jpom.model.data.BuildInfoModel;
+import org.dromara.jpom.model.data.FtpModel;
 import org.dromara.jpom.model.data.NodeModel;
 import org.dromara.jpom.model.data.SshModel;
 import org.dromara.jpom.model.docker.DockerInfoModel;
@@ -60,6 +80,7 @@ import org.dromara.jpom.plugins.JschUtils;
 import org.dromara.jpom.service.docker.DockerInfoService;
 import org.dromara.jpom.service.docker.DockerSwarmInfoService;
 import org.dromara.jpom.service.node.NodeService;
+import org.dromara.jpom.service.node.ftp.FtpService;
 import org.dromara.jpom.service.node.ssh.SshService;
 import org.dromara.jpom.system.ExtConfigBean;
 import org.dromara.jpom.system.JpomRuntimeException;
@@ -69,17 +90,6 @@ import org.dromara.jpom.util.MySftp;
 import org.dromara.jpom.util.StringUtil;
 import org.springframework.util.Assert;
 
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.Charset;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.function.Consumer;
-import java.util.stream.Collectors;
-
 /**
  * 发布管理
  *
@@ -110,6 +120,8 @@ public class ReleaseManage {
     private static BuildExtConfig buildExtConfig;
     private static FileStorageService fileStorageService;
     private static ScriptLibraryServer scriptLibraryServer;
+    private static MachineFtpServer machineFtpServer;
+
 
     private void loadService() {
         buildExecuteService = ObjectUtil.defaultIfNull(buildExecuteService, () -> SpringUtil.getBean(BuildExecuteService.class));
@@ -118,6 +130,7 @@ public class ReleaseManage {
         buildExtConfig = ObjectUtil.defaultIfNull(buildExtConfig, () -> SpringUtil.getBean(BuildExtConfig.class));
         fileStorageService = ObjectUtil.defaultIfNull(fileStorageService, () -> SpringUtil.getBean(FileStorageService.class));
         scriptLibraryServer = ObjectUtil.defaultIfNull(scriptLibraryServer, () -> SpringUtil.getBean(ScriptLibraryServer.class));
+        machineFtpServer = ObjectUtil.defaultIfNull(machineFtpServer, () -> SpringUtil.getBean(MachineFtpServer.class));
     }
 
     private Integer getRealBuildNumberId() {
@@ -198,6 +211,8 @@ public class ReleaseManage {
             return this.localCommand();
         } else if (releaseMethod == BuildReleaseMethod.DockerImage.getCode()) {
             return this.doDockerImage();
+        } else if (releaseMethod == BuildReleaseMethod.Ftp.getCode()) {
+            this.doFtp();
         } else if (releaseMethod == BuildReleaseMethod.No.getCode()) {
             return null;
         } else {
@@ -503,6 +518,61 @@ public class ReleaseManage {
         }
     }
 
+
+    /**
+     * ftp发布
+     *
+     * @throws IOException
+     */
+    private void doFtp() {
+        String releaseMethodDataId = this.buildExtraModule.getReleaseMethodDataId();
+        FtpService ftpService = SpringUtil.getBean(FtpService.class);
+        List<String> strings = StrUtil.splitTrim(releaseMethodDataId, StrUtil.COMMA);
+        for (String releaseMethodDataIdItem : strings) {
+            FtpModel item = ftpService.getByKey(releaseMethodDataIdItem, false);
+            if (item == null) {
+                logRecorder.systemError(I18nMessageUtil.get("i18n.ftp_item_not_found.60a7"), releaseMethodDataIdItem);
+                continue;
+            }
+
+            String releasePath = this.buildExtraModule.getReleaseFtpPath();
+
+            if (StrUtil.isEmpty(releasePath)) {
+                logRecorder.systemWarning(I18nMessageUtil.get("i18n.publish_directory_is_empty.79c6"));
+            } else {
+                logRecorder.system(I18nMessageUtil.get("i18n.start_upload_ftp_file.20be"), DateUtil.now(), item.getName(), System.lineSeparator());
+
+                MachineFtpModel machineFtpModel = ftpService.getMachineFtpModel(item);
+                try (Ftp ftp = machineFtpServer.getFtpClient(machineFtpModel)) {
+
+
+                    String prefix = "";
+                    if (!StrUtil.startWith(releasePath, StrUtil.SLASH)) {
+                        prefix = ftp.pwd();
+                    }
+                    String normalizePath = FileUtil.normalize(prefix + StrUtil.SLASH + releasePath);
+                    if (this.buildExtraModule.isClearOld()) {
+                        try {
+                            if (ftp.exist(normalizePath)) {
+                                ftp.delDir(normalizePath);
+                            }
+                        } catch (Exception e) {
+                            if (!StrUtil.startWithIgnoreCase(e.getMessage(), "No such file")) {
+                                logRecorder.error(I18nMessageUtil.get("i18n.clear_build_product_failed.edd4"), e);
+                            }
+                        }
+                    }
+                    ftpService.uploadWithProgress(ftp, this.resultFile, normalizePath, logRecorder, 5);
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+                logRecorder.system(I18nMessageUtil.get("i18n.start_upload_ftp_file.20be"), DateUtil.now(), item.getName(), System.lineSeparator());
+
+                logRecorder.system("{} {} ftp upload done", DateUtil.now(), item.getName());
+            }
+        }
+    }
+
     /**
      * 差异上传发布
      *

+ 44 - 1
modules/server/src/main/java/org/dromara/jpom/controller/build/BuildInfoController.java

@@ -39,6 +39,7 @@ import org.dromara.jpom.model.AfterOpt;
 import org.dromara.jpom.model.BaseEnum;
 import org.dromara.jpom.model.PageResultDto;
 import org.dromara.jpom.model.data.BuildInfoModel;
+import org.dromara.jpom.model.data.FtpModel;
 import org.dromara.jpom.model.data.RepositoryModel;
 import org.dromara.jpom.model.data.SshModel;
 import org.dromara.jpom.model.enums.BuildReleaseMethod;
@@ -51,6 +52,7 @@ import org.dromara.jpom.service.dblog.BuildInfoService;
 import org.dromara.jpom.service.dblog.DbBuildHistoryLogService;
 import org.dromara.jpom.service.dblog.RepositoryService;
 import org.dromara.jpom.service.docker.DockerInfoService;
+import org.dromara.jpom.service.node.ftp.FtpService;
 import org.dromara.jpom.service.node.ssh.SshService;
 import org.dromara.jpom.service.script.ScriptServer;
 import org.dromara.jpom.util.CommandUtil;
@@ -78,6 +80,7 @@ public class BuildInfoController extends BaseServerController {
 
     private final DbBuildHistoryLogService dbBuildHistoryLogService;
     private final SshService sshService;
+    private final FtpService ftpService;
     private final BuildInfoService buildInfoService;
     private final RepositoryService repositoryService;
     private final BuildExecuteService buildExecuteService;
@@ -87,7 +90,7 @@ public class BuildInfoController extends BaseServerController {
     protected final MachineDockerServer machineDockerServer;
 
     public BuildInfoController(DbBuildHistoryLogService dbBuildHistoryLogService,
-                               SshService sshService,
+                               SshService sshService, FtpService ftpService,
                                BuildInfoService buildInfoService,
                                RepositoryService repositoryService,
                                BuildExecuteService buildExecuteService,
@@ -97,6 +100,7 @@ public class BuildInfoController extends BaseServerController {
                                MachineDockerServer machineDockerServer) {
         this.dbBuildHistoryLogService = dbBuildHistoryLogService;
         this.sshService = sshService;
+        this.ftpService = ftpService;
         this.buildInfoService = buildInfoService;
         this.repositoryService = repositoryService;
         this.buildExecuteService = buildExecuteService;
@@ -262,6 +266,8 @@ public class BuildInfoController extends BaseServerController {
             // dockerSwarmId default
             String dockerSwarmId = this.formatDocker(jsonObject, request);
             jsonObject.put("releaseMethodDataId", dockerSwarmId);
+        } else if (releaseMethod1 == BuildReleaseMethod.Ftp){
+            this.formatFtp(jsonObject, request);
         }
         // 检查关联数据ID
         buildInfoModel.setReleaseMethodDataId(jsonObject.getString("releaseMethodDataId"));
@@ -355,6 +361,43 @@ public class BuildInfoController extends BaseServerController {
         jsonObject.put("releaseMethodDataId", releaseMethodDataId);
     }
 
+    /**
+     * 验证构建信息
+     * 当发布方式为【FTP】的时候
+     *
+     * @param jsonObject 配置信息
+     */
+    private void formatFtp(JSONObject jsonObject, HttpServletRequest request) {
+        // 发布方式
+        String releaseMethodDataId = jsonObject.getString("releaseMethodDataId_6");
+        Assert.hasText(releaseMethodDataId, I18nMessageUtil.get("i18n.ftp_selection.c903"));
+
+        String releasePath = jsonObject.getString("releasePath");
+        Assert.hasText(releasePath, I18nMessageUtil.get("i18n.ftp_directory.a790"));
+        releasePath = FileUtil.normalize(releasePath);
+        List<String> strings = StrUtil.splitTrim(releaseMethodDataId, StrUtil.COMMA);
+        for (String releaseMethodDataIdItem : strings) {
+            FtpModel ftpServiceItem = ftpService.getByKey(releaseMethodDataIdItem, request);
+            Assert.notNull(ftpServiceItem, I18nMessageUtil.get("i18n.no_ftp_item.8e39"));
+            //
+            if (releasePath.startsWith(StrUtil.SLASH)) {
+                // 以根路径开始
+                List<String> fileDirs = ftpServiceItem.fileDirs();
+                Assert.notEmpty(fileDirs, ftpServiceItem.getName() + I18nMessageUtil.get("i18n.ftp_unauthorized_directory.df73"));
+
+                boolean find = false;
+                for (String fileDir : fileDirs) {
+                    if (FileUtil.isSub(new File(fileDir), new File(releasePath))) {
+                        find = true;
+                    }
+                }
+                Assert.state(find, ftpServiceItem.getName() + I18nMessageUtil.get("i18n.ftp_unauthorized_directory.df73"));
+            }
+
+        }
+        jsonObject.put("releaseMethodDataId", releaseMethodDataId);
+    }
+
     private String formatDocker(JSONObject jsonObject, HttpServletRequest request) {
         // 发布命令
         String dockerfile = jsonObject.getString("dockerfile");

+ 31 - 49
modules/server/src/main/java/org/dromara/jpom/func/assets/controller/BaseFtpFileController.java

@@ -17,14 +17,12 @@ import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.io.IoUtil;
 import cn.hutool.core.lang.Assert;
 import cn.hutool.core.util.CharsetUtil;
-import cn.hutool.core.util.EnumUtil;
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.URLUtil;
 import cn.hutool.crypto.SecureUtil;
 import cn.hutool.extra.ftp.Ftp;
-import cn.hutool.extra.ftp.FtpMode;
 import cn.hutool.extra.servlet.ServletUtil;
 import cn.keepbx.jpom.IJsonMessage;
 import cn.keepbx.jpom.model.JsonMessage;
@@ -220,13 +218,12 @@ public abstract class BaseFtpFileController extends BaseServerController {
     private String readFile(MachineFtpModel machineFtpModel, String allowPathParent, String nextPath, String name, Charset charset) {
         String normalize = FileUtil.normalize(allowPathParent + StrUtil.SLASH + nextPath + StrUtil.SLASH + name);
 
-        try (Ftp ftp = new Ftp(machineFtpServer.toFtpConfig(machineFtpModel),
-            EnumUtil.fromString(FtpMode.class, machineFtpModel.getMode(), FtpMode.Active));
+        try (Ftp ftp = machineFtpServer.getFtpClient(machineFtpModel);
              InputStream inputStream = ftp.getClient().retrieveFileStream(normalize);
              ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
 
             if (inputStream == null) {
-                throw new RuntimeException("文件不存在或无法打开: " + normalize);
+                throw new RuntimeException(I18nMessageUtil.get("i18n.file_not_exist_or_unable_to_open.b045") + normalize);
             }
 
             IoUtil.copy(inputStream, outputStream);
@@ -235,7 +232,7 @@ public abstract class BaseFtpFileController extends BaseServerController {
             return outputStream.toString(charset.name());
 
         } catch (IOException e) {
-            throw new RuntimeException("FTP 读取文件失败", e);
+            throw new RuntimeException(I18nMessageUtil.get("i18n.ftp_read_file_failed.e738"), e);
         }
     }
 
@@ -255,17 +252,14 @@ public abstract class BaseFtpFileController extends BaseServerController {
                           File file) {
         String normalizeDir = FileUtil.normalize(allowPathParent + StrUtil.SLASH + nextPath);
 
-        // 通过 EnumUtil.fromString 获取枚举,默认 FtpMode.Active
-        FtpMode ftpMode = EnumUtil.fromString(FtpMode.class, machineFtpModel.getMode(), FtpMode.Active);
-
-        try (Ftp ftp = new Ftp(machineFtpServer.toFtpConfig(machineFtpModel), ftpMode)) {
+        try (Ftp ftp = machineFtpServer.getFtpClient(machineFtpModel)) {
             // 直接upload到原来目录 会覆盖更新文件
             boolean success = ftp.upload(normalizeDir, file);
             if (!success) {
-                throw new RuntimeException("FTP 上传失败");
+                throw new RuntimeException(I18nMessageUtil.get("i18n.ftp_upload_failed.8298"));
             }
-        } catch (IOException e) {
-            throw new RuntimeException("FTP 连接或操作异常", e);
+        } catch (Exception e) {
+            throw new RuntimeException(I18nMessageUtil.get("i18n.ftp_connection_or_operation_exception.09af"), e);
         }
     }
 
@@ -288,19 +282,21 @@ public abstract class BaseFtpFileController extends BaseServerController {
 
         String normalize = FileUtil.normalize(allowPathParent + StrUtil.SLASH + nextPath + StrUtil.SLASH + name);
 
-        try (Ftp ftp = new Ftp(machineFtpServer.toFtpConfig(machineFtpModel),
-            EnumUtil.fromString(FtpMode.class, machineFtpModel.getMode(), FtpMode.Active));
-             InputStream inputStream = ftp.getClient().retrieveFileStream(normalize)) {
+        InputStream inputStream = null;
+        try (Ftp ftp = machineFtpServer.getFtpClient(machineFtpModel)) {
+            inputStream = ftp.getClient().retrieveFileStream(normalize);
 
             if (inputStream == null) {
-                throw new RuntimeException("文件不存在或无法下载: " + normalize);
+                throw new RuntimeException(I18nMessageUtil.get("i18n.file_not_exist_or_unable_to_download.b977") + normalize);
             }
 
             IoUtil.copy(inputStream, response.getOutputStream());
             ftp.getClient().completePendingCommand(); // 关键!
 
         } catch (IOException e) {
-            throw new RuntimeException("FTP 下载文件失败", e);
+            throw new RuntimeException(I18nMessageUtil.get("i18n.ftp_download_file_failed.2e42"), e);
+        } finally {
+            IoUtil.close(inputStream);
         }
     }
 
@@ -317,9 +313,7 @@ public abstract class BaseFtpFileController extends BaseServerController {
     private JSONArray listDir(MachineFtpModel ftpModel, String allowPathParent, String nextPath, ItemConfig itemConfig) throws SftpException {
 
         List<String> allowEditSuffix = itemConfig.allowEditSuffix();
-        try (Ftp ftp = new Ftp(machineFtpServer.toFtpConfig(ftpModel),
-            EnumUtil.fromString(FtpMode.class, ftpModel.getMode(), FtpMode.Active))) {
-
+        try (Ftp ftp = machineFtpServer.getFtpClient(ftpModel)) {
             String children2 = StrUtil.emptyToDefault(nextPath, StrUtil.SLASH);
             String allPath = StrUtil.format("{}/{}", allowPathParent, children2);
             allPath = FileUtil.normalize(allPath);
@@ -331,7 +325,7 @@ public abstract class BaseFtpFileController extends BaseServerController {
                 log.warn(I18nMessageUtil.get("i18n.get_folder_failure.0fda"), e);
                 Throwable causedBy = ExceptionUtil.getCausedBy(e, SftpException.class);
                 if (causedBy != null) {
-                    throw new IllegalStateException("无法查询文件夹FTP," + causedBy.getMessage());
+                    throw new IllegalStateException(I18nMessageUtil.get("i18n.ftp_folder_query_failed.0011") + causedBy.getMessage());
                 }
                 throw new IllegalStateException(I18nMessageUtil.get("i18n.query_folder_failed.3f0e") + e.getMessage());
             }
@@ -359,7 +353,7 @@ public abstract class BaseFtpFileController extends BaseServerController {
                 jsonArray.add(jsonObject);
             }
             return jsonArray;
-        } catch (IOException e) {
+        } catch (Exception e) {
             throw new RuntimeException(e);
         }
     }
@@ -377,8 +371,7 @@ public abstract class BaseFtpFileController extends BaseServerController {
             return jsonArray;
         }
 
-        try (Ftp ftp = new Ftp(machineFtpServer.toFtpConfig(ftpModel),
-            EnumUtil.fromString(FtpMode.class, ftpModel.getMode(), FtpMode.Active))) {
+        try (Ftp ftp = machineFtpServer.getFtpClient(ftpModel)) {
             for (String allowPathParent : list) {
                 JSONObject jsonObject = new JSONObject();
                 jsonObject.put("id", SecureUtil.sha1(allowPathParent));
@@ -387,7 +380,7 @@ public abstract class BaseFtpFileController extends BaseServerController {
                 jsonArray.add(jsonObject);
             }
         } catch (Exception e) {
-            log.error("连接FTP失败", e);
+            log.error(I18nMessageUtil.get("i18n.ftp_connection_failed.1f2f"), e);
         }
         return jsonArray;
     }
@@ -404,8 +397,7 @@ public abstract class BaseFtpFileController extends BaseServerController {
         Assert.state(!StrUtil.equals(name2, StrUtil.SLASH), I18nMessageUtil.get("i18n.cannot_delete_root_dir.fcdc"));
         return this.checkConfigPathChildren(id, allowPathParent, nextPath, (machineFtpModel, itemConfig) -> {
 
-            try (Ftp ftp = new Ftp(machineFtpServer.toFtpConfig(machineFtpModel),
-                EnumUtil.fromString(FtpMode.class, machineFtpModel.getMode(), FtpMode.Active))) {
+            try (Ftp ftp = machineFtpServer.getFtpClient(machineFtpModel)) {
                 String normalize = FileUtil.normalize(allowPathParent + StrUtil.SLASH + nextPath + StrUtil.SLASH + name2);
                 Assert.state(!StrUtil.equals(normalize, StrUtil.SLASH), I18nMessageUtil.get("i18n.cannot_delete_root_dir.fcdc"));
                 // 尝试删除
@@ -432,14 +424,13 @@ public abstract class BaseFtpFileController extends BaseServerController {
 
         return this.checkConfigPathChildren(id, allowPathParent, nextPath, (machineFtpModel, itemConfig) -> {
 
-            try (Ftp ftp = new Ftp(machineFtpServer.toFtpConfig(machineFtpModel),
-                EnumUtil.fromString(FtpMode.class, machineFtpModel.getMode(), FtpMode.Active))) {
+            try (Ftp ftp = machineFtpServer.getFtpClient(machineFtpModel)) {
                 String oldPath = FileUtil.normalize(allowPathParent + StrUtil.SLASH + nextPath + StrUtil.SLASH + name);
                 String newPath = FileUtil.normalize(allowPathParent + StrUtil.SLASH + nextPath + StrUtil.SLASH + newname);
                 ftp.getClient().rename(oldPath, newPath);
             } catch (Exception e) {
-                log.error("FTP重命名失败异常", e);
-                return new JsonMessage<>(400, "FTP重命名失败异常" + e.getMessage());
+                log.error(I18nMessageUtil.get("i18n.ftp_rename_failed_exception.0fcc"), e);
+                return new JsonMessage<>(400, I18nMessageUtil.get("i18n.ftp_rename_failed_exception.0fcc") + e.getMessage());
             }
             return JsonMessage.success(I18nMessageUtil.get("i18n.operation_succeeded.3313"));
         });
@@ -523,9 +514,7 @@ public abstract class BaseFtpFileController extends BaseServerController {
             String remotePath = FileUtil.normalize(allowPathParent + StrUtil.SLASH + nextPath);
             File filePath = null;
             File tempUnzipPath = null;
-            try (Ftp ftp = new Ftp(machineFtpServer.toFtpConfig(machineFtpModel),
-                EnumUtil.fromString(FtpMode.class, machineFtpModel.getMode(), FtpMode.Active))) {
-
+            try (Ftp ftp = machineFtpServer.getFtpClient(machineFtpModel)) {
                 // 保存路径
                 File tempPath = serverConfig.getUserTempPath();
                 File savePath = FileUtil.file(tempPath, "ftp", machineFtpModel.getId());
@@ -548,8 +537,8 @@ public abstract class BaseFtpFileController extends BaseServerController {
                     ftp.uploadFileOrDirectory(remotePath, filePath);
                 }
             } catch (Exception e) {
-                log.error("FTP上传文件异常", e);
-                return new JsonMessage<>(400, "FTP上传文件异常" + e.getMessage());
+                log.error(I18nMessageUtil.get("i18n.ftp_upload_file_exception.118c"), e);
+                return new JsonMessage<>(400, I18nMessageUtil.get("i18n.ftp_upload_file_exception.118c") + e.getMessage());
             } finally {
                 CommandUtil.systemFastDel(filePath);
                 CommandUtil.systemFastDel(tempUnzipPath);
@@ -578,14 +567,13 @@ public abstract class BaseFtpFileController extends BaseServerController {
         Assert.state(!StrUtil.contains(name, StrUtil.SLASH), I18nMessageUtil.get("i18n.file_name_error_message.7a25"));
         return this.checkConfigPathChildren(id, allowPathParent, nextPath, (machineFtpModel, itemConfig) -> {
 
-            try (Ftp ftp = new Ftp(machineFtpServer.toFtpConfig(machineFtpModel),
-                EnumUtil.fromString(FtpMode.class, machineFtpModel.getMode(), FtpMode.Active))) {
+            try (Ftp ftp = machineFtpServer.getFtpClient(machineFtpModel)) {
                 String remotePath = FileUtil.normalize(allowPathParent + StrUtil.SLASH + nextPath + StrUtil.SLASH + name);
 
                 File filePath = null;
                 try {
                     if (ftp.exist(remotePath)) {
-                        return new JsonMessage<>(400, "文件夹或文件已经存在");
+                        return new JsonMessage<>(400, I18nMessageUtil.get("i18n.file_exists.145b"));
                     }
                     if (Convert.toBool(unFolder, false)) {
                         // 创建空文件到临时保存路径
@@ -606,8 +594,8 @@ public abstract class BaseFtpFileController extends BaseServerController {
                                 return JsonMessage.success(I18nMessageUtil.get("i18n.operation_succeeded.3313"));
                             }
                         } catch (Exception e) {
-                            log.error("FTP创建文件夹异常", e);
-                            return new JsonMessage<>(500, "FTP创建文件夹异常" + e.getMessage());
+                            log.error(I18nMessageUtil.get("i18n.ftp_create_folder_exception.a4fe"), e);
+                            return new JsonMessage<>(500, I18nMessageUtil.get("i18n.ftp_create_folder_exception.a4fe") + e.getMessage());
                         }
                     }
                     List<String> result = new ArrayList<>();
@@ -618,7 +606,7 @@ public abstract class BaseFtpFileController extends BaseServerController {
                     // 删除临时文件
                     CommandUtil.systemFastDel(filePath);
                 }
-            } catch (IOException e) {
+            } catch (Exception e) {
                 throw new RuntimeException(e);
             }
         });
@@ -626,12 +614,6 @@ public abstract class BaseFtpFileController extends BaseServerController {
 
 
     public String getPermissionString(FTPFile file) {
-        // 如果权限信息无效,说明是 Windows FTP,返回占位符或空字符串
-        if (!file.hasPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION)
-            && !file.hasPermission(FTPFile.GROUP_ACCESS, FTPFile.READ_PERMISSION)
-            && !file.hasPermission(FTPFile.WORLD_ACCESS, FTPFile.READ_PERMISSION)) {
-            return "---------"; // 或返回 "N/A"、空串 ""
-        }
 
         // 否则按照 Unix 风格格式化
         StringBuilder sb = new StringBuilder();

+ 21 - 24
modules/server/src/main/java/org/dromara/jpom/func/assets/controller/MachineFtpController.java

@@ -28,12 +28,15 @@ import cn.keepbx.jpom.model.JsonMessage;
 import java.io.File;
 import java.io.IOException;
 import java.io.Reader;
+import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.function.Function;
+import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.jpom.common.i18n.I18nMessageUtil;
@@ -44,12 +47,10 @@ import org.dromara.jpom.configuration.AssetsConfig;
 import org.dromara.jpom.dialect.DialectUtil;
 import org.dromara.jpom.func.BaseGroupNameController;
 import org.dromara.jpom.func.assets.model.MachineFtpModel;
-import org.dromara.jpom.func.assets.model.MachineSshModel;
 import org.dromara.jpom.func.assets.server.MachineFtpServer;
 import org.dromara.jpom.model.PageResultDto;
 import org.dromara.jpom.model.data.AgentWhitelist;
 import org.dromara.jpom.model.data.FtpModel;
-import org.dromara.jpom.model.data.SshModel;
 import org.dromara.jpom.model.data.WorkspaceModel;
 import org.dromara.jpom.model.user.UserModel;
 import org.dromara.jpom.permission.ClassFeature;
@@ -65,10 +66,6 @@ import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
-
-import javax.servlet.http.HttpServletRequest;
-import java.nio.charset.Charset;
-import java.util.List;
 import org.springframework.web.multipart.MultipartFile;
 
 /**
@@ -88,6 +85,7 @@ public class MachineFtpController extends BaseGroupNameController {
     private final FtpService ftpService;
     private final ServerConfig serverConfig;
 
+
     public MachineFtpController(MachineFtpServer machineFtpServer, AssetsConfig assetsConfig, WorkspaceService workspaceService, FtpService ftpService, ServerConfig serverConfig) {
         super(machineFtpServer);
         this.machineFtpServer = machineFtpServer;
@@ -95,6 +93,7 @@ public class MachineFtpController extends BaseGroupNameController {
         this.workspaceService = workspaceService;
         this.ftpService = ftpService;
         this.serverConfig = serverConfig;
+
     }
 
     @PostMapping(value = "list-data", produces = MediaType.APPLICATION_JSON_VALUE)
@@ -154,7 +153,7 @@ public class MachineFtpController extends BaseGroupNameController {
             Assert.hasText(password, I18nMessageUtil.get("i18n.login_password_required.9605"));
         } else {
             boolean exists = machineFtpServer.exists(new MachineFtpModel(id));
-            Assert.state(exists, "不存在对应ftp");
+            Assert.state(exists, I18nMessageUtil.get("i18n.ftp_not_exist.f9b3"));
         }
 
         MachineFtpModel model = new MachineFtpModel();
@@ -166,6 +165,7 @@ public class MachineFtpController extends BaseGroupNameController {
         model.setSystemKey(systemKey);
         // 如果密码传递不为空就设置值 因为上面已经判断了只有修改的情况下 password 才可能为空
         Opt.ofBlankAble(password).ifPresent(model::setPassword);
+
         // 获取允许编辑的后缀
         List<String> allowEditSuffixList = AgentWhitelist.parseToList(allowEditSuffix, I18nMessageUtil.get("i18n.suffix_cannot_be_empty.ec72"));
         model.allowEditSuffix(allowEditSuffixList);
@@ -186,17 +186,21 @@ public class MachineFtpController extends BaseGroupNameController {
         entity.set(DialectUtil.wrapField("user"), model.getUser());
         Opt.ofBlankAble(id).ifPresent(s -> entity.set("id", StrUtil.format(" <> {}", s)));
         boolean exists = machineFtpServer.exists(entity);
-        Assert.state(!exists, "对应的FTP已经存在啦");
+        Assert.state(!exists, I18nMessageUtil.get("i18n.ftp_already_exists.d66b"));
+
+
+        MachineFtpModel byKey = machineFtpServer.getByKey(id,false);
+        Optional.ofNullable(byKey).ifPresent(item -> {
+            model.setPassword(StrUtil.emptyToDefault(model.getPassword(), item.getPassword()));
+        });
 
         // 测试连接
         try (Ftp ftp = new Ftp(machineFtpServer.toFtpConfig(model),
-            EnumUtil.fromString(FtpMode.class, mode, FtpMode.Active))) {
+            EnumUtil.fromString(FtpMode.class, mode, FtpMode.Active)))  {
             ftp.pwd();
-            List<String> ls = ftp.ls(".");
-            System.out.println(ls);
         } catch (Exception e) {
-            log.error("连接FTP失败", e);
-            return new JsonMessage<>(500, "连接FTP失败:" + e.getMessage());
+            log.error(I18nMessageUtil.get("i18n.ftp_connection_failed.1f2f"), e);
+            return new JsonMessage<>(500, I18nMessageUtil.get("i18n.ftp_connection_failed_message.bd99") + e.getMessage());
         }
 
         model.setStatus(1);
@@ -232,7 +236,7 @@ public class MachineFtpController extends BaseGroupNameController {
         List<String> list = StrUtil.splitTrim(ids, StrUtil.COMMA);
         for (String id : list) {
             MachineFtpModel machineFtpModel = machineFtpServer.getByKey(id);
-            Assert.notNull(machineFtpModel, "没有对应的FTP");
+            Assert.notNull(machineFtpModel, I18nMessageUtil.get("i18n.no_ftp_correspondence.23c4"));
             boolean exists = workspaceService.exists(new WorkspaceModel(workspaceId));
             Assert.state(exists, I18nMessageUtil.get("i18n.workspace_not_exist.a6fd"));
             if (!ftpService.existsFtp2(workspaceId, id)) {
@@ -263,12 +267,6 @@ public class MachineFtpController extends BaseGroupNameController {
             ftpModel.fileDirs(null);
         } else {
             List<String> list = StrSplitter.splitTrim(fileDirs, StrUtil.LF, true);
-            /*for (String s : list) {
-                String normalize = FileUtil.normalize(s + StrUtil.SLASH);
-                int count = StrUtil.count(normalize, StrUtil.SLASH);
-                Assert.state(count >= 2, I18nMessageUtil.get("i18n.ssh_authorization_directory_cannot_be_root.8125"));
-            }*/
-            //
             UserModel userModel = getUser();
             Assert.state(!userModel.isDemoUser(), PermissionInterceptor.DEMO_TIP);
             ftpModel.fileDirs(list);
@@ -302,7 +300,8 @@ public class MachineFtpController extends BaseGroupNameController {
     @GetMapping(value = "import-template", produces = MediaType.APPLICATION_JSON_VALUE)
     @Feature(method = MethodFeature.LIST)
     public void importTemplate(HttpServletResponse response) throws IOException {
-        String fileName = "ftp导入模板.csv";
+        String prefix = I18nMessageUtil.get("i18n.ftp_import_template.8fa3");
+        String fileName = prefix + ".csv";
         this.setApplicationHeader(response, fileName);
         //
         CsvWriter writer = CsvUtil.getWriter(response.getWriter());
@@ -316,7 +315,7 @@ public class MachineFtpController extends BaseGroupNameController {
     @GetMapping(value = "export-data", produces = MediaType.APPLICATION_JSON_VALUE)
     @Feature(method = MethodFeature.DOWNLOAD)
     public void exportData(HttpServletResponse response, HttpServletRequest request) throws IOException {
-        String prefix = "导出的 ftp 数据";
+        String prefix = I18nMessageUtil.get("i18n.exported_ftp_data.2b54");
         String fileName = prefix + DateTime.now().toString(DatePattern.NORM_DATE_FORMAT) + ".csv";
         this.setApplicationHeader(response, fileName);
         //
@@ -360,8 +359,6 @@ public class MachineFtpController extends BaseGroupNameController {
      *
      * @return json
      */
-//            writer.writeLine("name", "groupName", "host", "port", "user", "password", "serverLanguageCode", "systemKey", "charset", "mode", "timeout");
-
     @PostMapping(value = "import-data", produces = MediaType.APPLICATION_JSON_VALUE)
     @Feature(method = MethodFeature.UPLOAD)
     public IJsonMessage<String> importData(MultipartFile file) throws IOException {

+ 2 - 1
modules/server/src/main/java/org/dromara/jpom/func/assets/controller/MachineFtpFileController.java

@@ -16,6 +16,7 @@ import cn.hutool.core.util.StrUtil;
 import java.util.List;
 import java.util.function.BiFunction;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.jpom.common.i18n.I18nMessageUtil;
 import org.dromara.jpom.func.assets.model.MachineFtpModel;
 import org.dromara.jpom.permission.ClassFeature;
 import org.dromara.jpom.permission.Feature;
@@ -39,7 +40,7 @@ public class MachineFtpFileController extends BaseFtpFileController {
     @Override
     protected <T> T checkConfigPath(String id, BiFunction<MachineFtpModel, ItemConfig, T> function) {
         MachineFtpModel machineFtpModel = machineFtpServer.getByKey(id, false);
-        Assert.notNull(machineFtpModel, "没有对应的Ftp");
+        Assert.notNull(machineFtpModel, I18nMessageUtil.get("i18n.no_ftp_server_correspondence.1af7"));
         return function.apply(machineFtpModel, new ItemConfig() {
             @Override
             public List<String> allowEditSuffix() {

+ 1 - 1
modules/server/src/main/java/org/dromara/jpom/func/assets/model/MachineFtpModel.java

@@ -28,7 +28,7 @@ import java.util.List;
  */
 @EqualsAndHashCode(callSuper = true)
 @TableName(value = "MACHINE_FTP_INFO",
-    nameKey = "资产FTP信息")
+    nameKey = "i18n.asset_ftp_info.3b75")
 @Data
 @NoArgsConstructor
 public class MachineFtpModel extends BaseGroupNameModel {

+ 76 - 7
modules/server/src/main/java/org/dromara/jpom/func/assets/server/MachineFtpServer.java

@@ -1,6 +1,7 @@
 package org.dromara.jpom.func.assets.server;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.io.IoUtil;
 import cn.hutool.core.lang.Opt;
 import cn.hutool.core.util.EnumUtil;
 import cn.hutool.core.util.ObjectUtil;
@@ -9,10 +10,17 @@ import cn.hutool.cron.task.Task;
 import cn.hutool.db.Entity;
 import cn.hutool.extra.ftp.Ftp;
 import cn.hutool.extra.ftp.FtpConfig;
+import cn.hutool.extra.ftp.FtpException;
 import cn.hutool.extra.ftp.FtpMode;
 import cn.keepbx.jpom.event.IAsyncLoad;
+import java.time.Duration;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import javax.annotation.PreDestroy;
 import lombok.Lombok;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.net.ftp.FTPClient;
 import org.dromara.jpom.common.Const;
 import org.dromara.jpom.common.ServerConst;
 import org.dromara.jpom.common.i18n.I18nMessageUtil;
@@ -42,6 +50,9 @@ public class MachineFtpServer extends BaseDbService<MachineFtpModel> implements
     private final AssetsConfig.FtpConfig ftpConfig;
     private final AssetsExecutorPoolService assetsExecutorPoolService;
 
+    private final Map<String, Ftp> ftpConnectionPool = new ConcurrentHashMap<>();
+
+
     public MachineFtpServer(ClusterInfoService clusterInfoService,
                             AssetsConfig assetsConfig,
                             AssetsExecutorPoolService assetsExecutorPoolService) {
@@ -99,7 +110,7 @@ public class MachineFtpServer extends BaseDbService<MachineFtpModel> implements
             String linkGroup = clusterInfoService.getCurrent().getLinkGroup();
             List<String> linkGroups = StrUtil.splitTrim(linkGroup, StrUtil.COMMA);
             if (CollUtil.isEmpty(linkGroups)) {
-                log.warn("当前集群还未绑定分组,不能监控 FTP 资产信息");
+                log.warn(I18nMessageUtil.get("i18n.cluster_not_grouped.8f54"));
                 return;
             }
             entity.set("groupName", linkGroups);
@@ -132,20 +143,19 @@ public class MachineFtpServer extends BaseDbService<MachineFtpModel> implements
             this.updateStatus(machineFtpModel.getId(), 2, I18nMessageUtil.get("i18n.disable_monitoring.4615"));
             return;
         }
-
-        try (Ftp ftp = new Ftp(this.toFtpConfig(machineFtpModel),
-            EnumUtil.fromString(FtpMode.class, machineFtpModel.getMode(), FtpMode.Active))) {
+        log.warn("machineFtpModel:{}",machineFtpModel);
+        try (Ftp ftp = getFtpClient(machineFtpModel)) {
             ftp.pwd();
             //
             this.updateStatus(machineFtpModel.getId(), 1, "");
         } catch (Exception e) {
             String message = e.getMessage();
-            String s = "监控";
+            String s = I18nMessageUtil.get("i18n.monitor_name.9aff");
             if (StrUtil.containsIgnoreCase(message, "timeout")) {
-                String s1 = "超时";
+                String s1 = I18nMessageUtil.get("i18n.timeout.e944");
                 log.error("{} ftp[{}] {} {}", s, machineFtpModel.getName(), s1, message);
             } else {
-                String s1 = "异常";
+                String s1 = I18nMessageUtil.get("i18n.exception.c195");
                 log.error("{} ftp[{}] {}", s, machineFtpModel.getName(), s1, e);
             }
             this.updateStatus(machineFtpModel.getId(), 0, message);
@@ -173,4 +183,63 @@ public class MachineFtpServer extends BaseDbService<MachineFtpModel> implements
         String cron = Opt.ofBlankAble(monitorCron).orElse("0 0/1 * * * ?");
         CronUtils.add(CRON_ID, cron, () -> MachineFtpServer.this);
     }
+
+
+    /**
+     * 获取或创建 Ftp 连接,自动重连失效连接
+     *
+     * @param machineFtpModel 模型
+     * @return Ftp 实例
+     */
+    public synchronized Ftp getFtpClient(MachineFtpModel machineFtpModel) {
+        MachineFtpModel model = this.getByKey(machineFtpModel.getId(), false);
+        Optional.ofNullable(model).ifPresent(machineSshModel -> {
+            machineFtpModel.setPassword(StrUtil.emptyToDefault(machineFtpModel.getPassword(), machineFtpModel.getPassword()));
+        });
+        String id = machineFtpModel.getId();
+        Ftp ftp = ftpConnectionPool.get(id);
+        try {
+            if (ftp != null) {
+                ftp.pwd();
+                return ftp;
+            }
+        } catch (Exception e) {
+            System.out.println(machineFtpModel);
+            log.warn(I18nMessageUtil.get("i18n.check_ftp_connection_failed.f7de"), id, e.getMessage());
+            IoUtil.close(ftp);
+        }
+
+        try {
+            FtpConfig config = toFtpConfig(machineFtpModel);
+            Ftp tmpFtp = new Ftp(config, EnumUtil.fromString(FtpMode.class, machineFtpModel.getMode(), FtpMode.Active));
+
+            tmpFtp.pwd();
+
+            ftpConnectionPool.put(id, tmpFtp);
+            return tmpFtp;
+        } catch (FtpException e) {
+            log.error(I18nMessageUtil.get("i18n.ftp_client_build_failure.aa55"), id, e.getMessage());
+            throw Lombok.sneakyThrow(e);
+        }
+//        return ftp;
+    }
+
+    /**
+     * 销毁所有连接(服务销毁时调用)
+     */
+/*    @PreDestroy
+    public void destroy() {
+        synchronized (ftpConnectionPool) {
+            for (Ftp ftp : ftpConnectionPool.values()) {
+                try {
+                    if (ftp != null && ftp.getClient().isAvailable()) {
+                        ftp.close();
+                    }
+                } catch (Exception e) {
+                    log.warn(I18nMessageUtil.get("i18n.ftp_connection_failure.0f31"), e);
+                }
+            }
+            ftpConnectionPool.clear();
+        }
+    }*/
 }

+ 1 - 1
modules/server/src/main/java/org/dromara/jpom/model/data/FtpModel.java

@@ -34,7 +34,7 @@ import org.dromara.jpom.util.StringUtil;
  * @since 2025/05/29
  */
 @TableName(value = "FTP_INFO",
-    nameKey = "ftp信息表")
+    nameKey = "i18n.ftp_info_table.b177")
 @Data
 @EqualsAndHashCode(callSuper = true)
 @NoArgsConstructor

+ 1 - 0
modules/server/src/main/java/org/dromara/jpom/model/enums/BuildReleaseMethod.java

@@ -25,6 +25,7 @@ public enum BuildReleaseMethod implements BaseEnum {
 	Ssh(3, "SSH"),
 	LocalCommand(4, "本地命令行"),
 	DockerImage(5, "Docker镜像"),
+	Ftp(6, "FTP"),
 	;
 	private final int code;
 	private final String desc;

+ 3 - 3
modules/server/src/main/java/org/dromara/jpom/permission/ClassFeature.java

@@ -75,8 +75,8 @@ public enum ClassFeature {
     SSH_TERMINAL_LOG(() -> I18nMessageUtil.get("i18n.ssh_terminal_log.775f"), SshTerminalExecuteLogService.class),
     SSH_COMMAND(() -> I18nMessageUtil.get("i18n.ssh_command_management.c40a"), SshCommandService.class),
     SSH_COMMAND_LOG(() -> I18nMessageUtil.get("i18n.ssh_command_log.7fd1"), CommandExecLogService.class),
-    FTP(() -> "FTP管理", SshService.class),
-    FTP_FILE(() -> "FTP文件管理", FtpService.class),
+    FTP(() -> I18nMessageUtil.get("i18n.ftp_management.cb91"), FtpService.class),
+    FTP_FILE(() -> I18nMessageUtil.get("i18n.ftp_file_manager.c52e"), FtpService.class),
     OUTGIVING(() -> I18nMessageUtil.get("i18n.distribute_management.3a2d"), OutGivingServer.class),
     LOG_READ(() -> I18nMessageUtil.get("i18n.log_reading.a4c8"), LogReadServer.class),
     OUTGIVING_LOG(() -> I18nMessageUtil.get("i18n.distribute_log.c612"), DbOutGivingLogService.class),
@@ -109,7 +109,7 @@ public enum ClassFeature {
     SYSTEM_UPGRADE(() -> I18nMessageUtil.get("i18n.online_upgrade.da8c")),
     SYSTEM_ASSETS_MACHINE(() -> I18nMessageUtil.get("i18n.machine_asset_management.36ea"), MachineNodeServer.class),
     SYSTEM_ASSETS_MACHINE_SSH(() -> I18nMessageUtil.get("i18n.ssh_asset_management.3b6c"), MachineSshServer.class),
-    SYSTEM_ASSETS_MACHINE_FTP(() -> "FTP资产管理", MachineFtpServer.class),
+    SYSTEM_ASSETS_MACHINE_FTP(() -> I18nMessageUtil.get("i18n.ftp_asset_management.c6a5"), MachineFtpServer.class),
     SYSTEM_ASSETS_MACHINE_DOCKER(() -> I18nMessageUtil.get("i18n.docker_asset_management.96d9"), MachineDockerServer.class),
     SYSTEM_ASSETS_GLOBAL_SCRIPT(() -> I18nMessageUtil.get("i18n.script_library.aed1"), ScriptLibraryServer.class),
     SYSTEM_CONFIG(() -> I18nMessageUtil.get("i18n.server_system_config.3181")),

+ 83 - 67
modules/server/src/main/java/org/dromara/jpom/service/node/ftp/FtpService.java

@@ -13,11 +13,16 @@ package org.dromara.jpom.service.node.ftp;
 import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.util.NumberUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.ftp.Ftp;
 import com.jcraft.jsch.JSch;
-import com.jcraft.jsch.SftpException;
+import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Consumer;
 import javax.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.jpom.common.ServerConst;
@@ -79,62 +84,13 @@ public class FtpService extends BaseWorkspaceService<FtpModel> {
      * @param ftpModel ftpModel
      * @return session
      */
-    public MachineFtpModel getMachineSshModel(FtpModel ftpModel) {
+    public MachineFtpModel getMachineFtpModel(FtpModel ftpModel) {
         MachineFtpModel ftpModel1 = machineFtpServer.getByKey(ftpModel.getMachineFtpId(), false);
-        Assert.notNull(ftpModel1, I18nMessageUtil.get("i18n.asset_ssh_not_exist.cd43"));
+        Assert.notNull(ftpModel1, I18nMessageUtil.get("i18n.no_matching_asset_ftp.d420"));
         return ftpModel1;
     }
 
 
-    /**
-     * 上传文件
-     *
-     * @param machineSshModel ssh
-     * @param remotePath      远程路径
-     * @param desc            文件夹或者文件
-     */
-/*    public void uploadDir(MachineSshModel machineSshModel, String remotePath, File desc) {
-        Session session = null;
-        ChannelSftp channel = null;
-        // MachineSshModel machineSshModel = this.getMachineSshModel(sshModel);
-        try {
-            session = this.getSessionByModel(machineSshModel);
-            channel = (ChannelSftp) JschUtil.openChannel(session, ChannelType.SFTP);
-            try (Sftp sftp = new Sftp(channel, machineSshModel.charset(), machineSshModel.timeout())) {
-                sftp.syncUpload(desc, remotePath);
-            }
-            //uploadDir(channel, remotePath, desc, sshModel.getCharsetT());
-        } finally {
-            JschUtil.close(channel);
-            JschUtil.close(session);
-        }
-    }*/
-
-    /**
-     * 下载文件
-     *
-     * @param ftpModel   实体
-     * @param remoteFile 远程文件
-     * @param save       文件对象
-     * @throws IOException   io
-     * @throws SftpException sftp
-     */
-  /*  public void download(FtpModel ftpModel, String remoteFile, File save) throws IOException, SftpException {
-        Session session = null;
-        ChannelSftp channel = null;
-        OutputStream output = null;
-        try (Ftp ftp = new Ftp(machineFtpServer.toFtpConfig(machineFtpModel), ftpMode)) {
-            session = this.getSessionByModel(ftpModel);
-            channel = (ChannelSftp) JschUtil.openChannel(session, ChannelType.SFTP);
-            output = Files.newOutputStream(save.toPath());
-            channel.get(remoteFile, output);
-        } finally {
-            IoUtil.close(output);
-            JschUtil.close(channel);
-            JschUtil.close(session);
-        }
-    }*/
-
     /**
      * 将ssh信息同步到其他工作空间
      *
@@ -169,20 +125,6 @@ public class FtpService extends BaseWorkspaceService<FtpModel> {
             });
     }
 
-    public long countByMachine(String machineSshId) {
-        FtpModel ftpModel = new FtpModel();
-        ftpModel.setMachineFtpId(machineSshId);
-        return this.count(ftpModel);
-    }
-
-    public void existsSsh(String workspaceId, String machineFtpId) {
-        //
-        FtpModel where = new FtpModel();
-        where.setWorkspaceId(workspaceId);
-        where.setMachineFtpId(machineFtpId);
-        FtpModel data = this.queryByBean(where);
-        Assert.isNull(data, () -> I18nMessageUtil.get("i18n.ssh_already_exists_in_workspace.569e") + data.getName());
-    }
 
     public boolean existsFtp2(String workspaceId, String machineFtpId) {
         //
@@ -231,9 +173,83 @@ public class FtpService extends BaseWorkspaceService<FtpModel> {
         };
     }
 
-    public FtpModel getByMachineSshId(String id) {
+    public FtpModel getByMachineFtpId(String id) {
         FtpModel model = new FtpModel();
         model.setMachineFtpId(id);
         return queryByBean(model);
     }
+
+    /**
+     * FTP 上传文件(带进度)
+     *
+     * @param ftp              hutool 的 ftp 对象
+     * @param localFile        本地文件
+     * @param remotePath       远程文件完整路径
+     * @param logRecorder      日志记录器
+     * @param progressRatio    进度输出频率,例如 5 表示每 5% 输出一次
+     */
+    public void uploadWithProgress(Ftp ftp, File localFile, String remotePath,
+                                          LogRecorder logRecorder, int progressRatio) throws IOException {
+        long total = localFile.length();
+        Set<Integer> progressRangeList = ConcurrentHashMap.newKeySet((int) (100f / progressRatio));
+
+        try (InputStream in = Files.newInputStream(localFile.toPath())) {
+            ProgressInputStream progressInputStream = new ProgressInputStream(in, total, now -> {
+                double percent = Math.floor((double) now / total * 100);
+                int range = (int) (percent / progressRatio);
+                if (progressRangeList.add(range)) {
+                    logRecorder.system(I18nMessageUtil.get("i18n.upload_progress_with_units.44ad"),
+                        localFile.getName(),
+                        FileUtil.readableFileSize(now),
+                        FileUtil.readableFileSize(total),
+                        String.format("%.0f%%", percent)
+                    );
+                }
+            });
+
+             remotePath = remotePath + StrUtil.SLASH + localFile.getName();
+            ftp.getClient().storeFile(remotePath, progressInputStream);
+        }
+    }
+
+    /**
+     * 包装带进度的 InputStream
+     */
+    private static class ProgressInputStream extends InputStream {
+        private final InputStream in;
+        private final long totalSize;
+        private long readSize = 0;
+        private final Consumer<Long> onProgress;
+
+        public ProgressInputStream(InputStream in, long totalSize, Consumer<Long> onProgress) {
+            this.in = in;
+            this.totalSize = totalSize;
+            this.onProgress = onProgress;
+        }
+
+        @Override
+        public int read() throws IOException {
+            int b = in.read();
+            if (b != -1) {
+                readSize++;
+                onProgress.accept(readSize);
+            }
+            return b;
+        }
+
+        @Override
+        public int read(byte[] b, int off, int len) throws IOException {
+            int count = in.read(b, off, len);
+            if (count > 0) {
+                readSize += count;
+                onProgress.accept(readSize);
+            }
+            return count;
+        }
+
+        @Override
+        public void close() throws IOException {
+            in.close();
+        }
+    }
 }

+ 8 - 8
modules/server/src/main/java/org/dromara/jpom/system/db/InitDb.java

@@ -165,7 +165,7 @@ public class InitDb implements DisposableBean, ILoadEvent {
             JpomApplicationEvent.asyncExit(2);
             throw Lombok.sneakyThrow(e);
         }
-        String s = "数据库加载成功,URL为";
+        String s = I18nMessageUtil.get("i18n.database_load_success_url.5f64");
         log.info("{} {}:[{}]", storageService.mode(), s, storageService.dbUrl());
     }
 
@@ -230,8 +230,8 @@ public class InitDb implements DisposableBean, ILoadEvent {
                         }
                     })
                     .sum();
-                String s = "执行初始化SQL文件";
-                String s1 = "影响行数";
+                String s = I18nMessageUtil.get("i18n.initialize_sql.6691");
+                String s1 = I18nMessageUtil.get("i18n.affected_rows.5781");
                 log.info("{}:{},{}:{}", s, name, s1, rows);
             });
         } catch (SQLException e) {
@@ -266,11 +266,11 @@ public class InitDb implements DisposableBean, ILoadEvent {
         Opt.ofNullable(environment.getProperty("backup-h2")).ifPresent(s -> {
             // 备份数据库
             this.addCallback(I18nMessageUtil.get("i18n.backup_database.9524"), () -> {
-                log.info("开始备份数据库");
+                log.info(I18nMessageUtil.get("i18n.start_backup_database.e554"));
                 Future<BackupInfoModel> backupInfoModelFuture = backupInfoService.autoBackup();
                 try {
                     BackupInfoModel backupInfoModel = backupInfoModelFuture.get();
-                    String s1 = "数据库备份完成,保存路径为";
+                    String s1 = I18nMessageUtil.get("i18n.database_backup_complete_path.861b");
                     log.info("{}:{}", s1, backupInfoModel.getFilePath());
                 } catch (Exception e) {
                     throw new JpomRuntimeException(StrUtil.format("Backup database failed:{}", e.getMessage()), e);
@@ -286,7 +286,7 @@ public class InitDb implements DisposableBean, ILoadEvent {
                 try {
                     String dbFiles = StorageServiceFactory.get().deleteDbFiles();
                     if (dbFiles != null) {
-                        String s1 = "自动备份数据文件到路径";
+                        String s1 = I18nMessageUtil.get("i18n.auto_backup_path.a16b");
                         log.info("{}:{}", s1, dbFiles);
                     }
                 } catch (Exception e) {
@@ -337,12 +337,12 @@ public class InitDb implements DisposableBean, ILoadEvent {
             //
             Opt.ofNullable(environment.getProperty("transform-sql")).ifPresent(s -> StorageServiceFactory.get().transformSql(file));
             //
-            log.info("开始导入数据:{}", sqlPath);
+            log.info(I18nMessageUtil.get("i18n.start_import_data.ea31"), sqlPath);
             boolean flag = backupInfoService.restoreWithSql(sqlPath);
             if (!flag) {
                 throw new JpomRuntimeException(StrUtil.format("Failed to import according to sql,{}", sqlPath));
             }
-            log.info("导入成功:{}", sqlPath);
+            log.info(I18nMessageUtil.get("i18n.import_success.ef46"), sqlPath);
             return true;
         });
     }

+ 2 - 1
web-vue/src/api/build-info.ts

@@ -336,7 +336,8 @@ export const releaseMethodMap = {
   2: t('i18n_31ecc0e65b'),
   3: 'SSH',
   4: t('i18n_b71a7e6aab'),
-  5: t('i18n_9136e1859a')
+  5: t('i18n_9136e1859a'),
+  6: 'FTP'
 }
 
 export const triggerBuildTypeMap = {

+ 8 - 0
web-vue/src/api/ftp.ts

@@ -27,6 +27,14 @@ export function getFtpGroupAll() {
   })
 }
 
+// 根据 nodeId 查询列表
+export function getFtpListAll() {
+  return axios({
+    url: '/node/ftp/list_data_all.json',
+    method: 'get'
+  })
+}
+
 /**
  * 编辑 FTP
  * @param {*} params

+ 29 - 0
web-vue/src/i18n/locales/en_us.json

@@ -30,6 +30,7 @@
 	"i18n_02e35447d4":"Download the bundle. If the button is not available, it means that the product file does not exist. Generally, the corresponding file is not generated by the build or the file related to the build history is deleted.",
 	"i18n_0306ea1908":"Delete Mirror",
 	"i18n_031020489f":"Current workspace The build record you triggered",
+	"i18n_03113c0f1a":"Do you really want to delete FTP?",
 	"i18n_03580275cb":"Please select the item you want to restart",
 	"i18n_0360fffb40":"And turn on this switch",
 	"i18n_036c0dc2aa":"System Cancel Distribution",
@@ -83,6 +84,7 @@
 	"i18n_080b914139":"Upload package",
 	"i18n_0836332bf6":"upgrade protocol",
 	"i18n_083b8a2ec9":"A physical node bound to multiple server levels can also generate lonely data",
+	"i18n_087c992cc0":"passive mode",
 	"i18n_08902526f1":"Skin:",
 	"i18n_0895c740a6":"swap memory usage",
 	"i18n_089a88ecee":"System time:",
@@ -136,6 +138,7 @@
 	"i18n_0ce54ecc25":"paid community",
 	"i18n_0cf4f0ba82":"Do you really want to save the current configuration? If the configuration is wrong, the service may not be started. You need to manually restore Austria!!! Please pay attention to the restart status in time after successful saving!!",
 	"i18n_0cf81d77bb":"Please fill in the warehouse address.",
+	"i18n_0d1ee51203":"system keywords",
 	"i18n_0d44f4903a":"Do you really want to release (delete) the current project?",
 	"i18n_0d467f7889":"#Whether to enable the log backup function",
 	"i18n_0d48f8e881":"Please enter the service address",
@@ -213,6 +216,7 @@
 	"i18n_143bfbc3a1":"Click to resynchronize the current workspace logical node project information",
 	"i18n_143d8d3de5":"Otherwise, all data that meets the conditions will be deleted",
 	"i18n_148484b985":"You need to configure the docker container to be managed at the server level and assigned to the current workspace",
+	"i18n_148d37218a":"FTP name",
 	"i18n_1498557b2d":"Only one menu can be expanded at a time",
 	"i18n_14a25beebb":"Every 10 seconds",
 	"i18n_14d342362f":"label",
@@ -281,6 +285,7 @@
 	"i18n_1a8f90122f":"prompt message ",
 	"i18n_1abf39bdb6":"#Cache this directory globally (multiple builds can share this cache directory)",
 	"i18n_1ad696efdc":"Build execution commands (non-blocking commands), such as: mvn clean package, npm run build. Supported variables: {'${BUILD_ID BUILD_NAME BUILD_SOURCE_FILE }'}、{'${ BUILD_NUMBER_ID}'}, .env in the warehouse directory, workspace variables",
+	"i18n_1add83f77b":"FTP name",
 	"i18n_1ae2955867":"Specify the pom file package mvn -f xxx/pom.xml clean package",
 	"i18n_1afdb4a364":"Hide scroll bar. Longitudinal scroll mode Reminder: scroll wheel, horizontal scroll mode: Shift + scroll wheel",
 	"i18n_1b03b0c1ff":"The Docker or cluster that has been assigned to the workspace is not directly deleted. You need to delete the assets Docker or cluster one by one after the assigned workspaces are deleted.",
@@ -460,6 +465,7 @@
 	"i18n_29b48a76be":"Please choose a publishing method",
 	"i18n_29efa328e5":"undistributed",
 	"i18n_2a049f4f5b":"Distribution failed",
+	"i18n_2a04f7b9be":"If the button is not available, please go to the association of the asset management ftp list to add the authorization folder allowed to be managed in the current workspace",
 	"i18n_2a0bea27c4":"execution domain",
 	"i18n_2a0c4740f1":"file",
 	"i18n_2a1d1da97a":"Package testing environment package mvn clean package -Dmaven.test.skip = true -Ptest",
@@ -572,6 +578,7 @@
 	"i18n_32d0576d85":"token",
 	"i18n_32dcc6f36e":"Restart strategy: no, always, less-stopped, on-failure",
 	"i18n_32e05f01f4":"cluster information",
+	"i18n_32e3c8b702":"Published FTP",
 	"i18n_32f882ae24":"Matches zero or more characters",
 	"i18n_330363dfc5":"success",
 	"i18n_3306c2a7c7":"read default",
@@ -659,6 +666,7 @@
 	"i18n_3b94c70734":"project status",
 	"i18n_3ba621d736":"Processing successful",
 	"i18n_3baa9f3d72":"Batch build parameters also support specified parameters, delay (delayed execution of builds, in seconds) branchName (branch name), branchTagName (tag), script (build script), resultDirFile (bundle), webhook (notification webhook)",
+	"i18n_3bc3bdc031":"Please go to [System Management] - > [Asset Management] - > [FTP Management] to add FTP, or associate and assign the newly added FTP authorization to this workspace",
 	"i18n_3bc5e602b2":"email",
 	"i18n_3bcc1c7a20":"Last Modifier",
 	"i18n_3bdab2c607":"10 Minutes",
@@ -673,6 +681,7 @@
 	"i18n_3c6fa6f667":"Cron expression",
 	"i18n_3c8eada338":"Please select an encoding method",
 	"i18n_3c91490844":"publish action",
+	"i18n_3c943b89c6":"This editor can only edit the name information of the current FTP in this workspace",
 	"i18n_3c99ea4ec2":"For example, in 2, 3, 6/3, since \"/\" has a high priority, it is equivalent to 2, 3, (6/3), and the result is equivalent to 2, 3, 6",
 	"i18n_3c9eeee356":"Do you really want to delete log files?",
 	"i18n_3cc09369ad":"Really want to delete [",
@@ -849,6 +858,7 @@
 	"i18n_4b96762a7e":"Last modification time",
 	"i18n_4b9c3271dc":"reset",
 	"i18n_4ba304e77a":"DingTalk account login",
+	"i18n_4bb37cc406":"server language",
 	"i18n_4bbc09fc55":"Search on file lines 3 - 20",
 	"i18n_4c096c51a3":"Port number:",
 	"i18n_4c0eead6ff":"new parameter",
@@ -867,6 +877,7 @@
 	"i18n_4d18dcbd15":"Do you really want to restore backup information?",
 	"i18n_4d351f3c91":"IP ban",
 	"i18n_4d49b2a15f":"Automatic execution: docker",
+	"i18n_4d4ab2f8f5":"For the authorization directory (file directory, file suffix) of the current FTP, please go to [System Management] - > [Asset Management] - > [FTP Management] - > Operation Bar - > Associated Button - > Corresponding Workspace - > Operation Bar - > Configuration Button",
 	"i18n_4d775d4cd7":"show",
 	"i18n_4d7dc6c5f8":"write",
 	"i18n_4d85ac1250":"System Management",
@@ -1126,6 +1137,7 @@
 	"i18n_649d90ab3c":"Close right",
 	"i18n_649f8046f3":"Please select an SSH node",
 	"i18n_64c083c0a9":"result description",
+	"i18n_64c8791ba1":"Configuration method: FTP management - > operation bar - > associated button - > corresponding workspace - > operation bar - > configuration button",
 	"i18n_64eee9aafa":"boot time",
 	"i18n_652273694e":"host",
 	"i18n_65571516e2":"Build Notes:",
@@ -1144,6 +1156,7 @@
 	"i18n_66ab5e9f24":"new",
 	"i18n_66b71b06c6":"Upload compressed files (automatic decompression)",
 	"i18n_66c15f2815":"Match lines containing numbers",
+	"i18n_66e623e6f8":"Configure FTP",
 	"i18n_66e9ea5488":"log name",
 	"i18n_6707667676":"hostname",
 	"i18n_6709f4548f":"random generation",
@@ -1329,6 +1342,7 @@
 	"i18n_77373db7d8":"Receive alarm message, optional, GET request",
 	"i18n_7737f088de":"batch restart",
 	"i18n_773b1a5ef6":"Please select a language mode",
+	"i18n_774aecfd99":"If you want to configure FTP, please go to [System Management] - > [Asset Management] - > [FTP Management] to configure.",
 	"i18n_775fde44cf":"Process port cache:",
 	"i18n_7760785daf":"free script",
 	"i18n_7764df7ccc":"Enabling differential releases but not empty releases is equivalent to only incremental and change updates",
@@ -1406,6 +1420,7 @@
 	"i18n_7e930b95ef":"publish file",
 	"i18n_7e951d56d9":"operating time",
 	"i18n_7e9f0d2606":"Project refers to a certain project in the node, and the project needs to be created in the node in advance",
+	"i18n_7eef73a0eb":"Edit FTP",
 	"i18n_7ef30cfd31":"Additional environment variables refer to reading the environment variables file specified by the warehouse to add to the execution build runtime",
 	"i18n_7f0abcf48d":"You need to go to the editor to bind an ssh information for a node to enable this function.",
 	"i18n_7f3809d36b":"end of build",
@@ -1424,6 +1439,7 @@
 	"i18n_8086beecb3":"Tag name:",
 	"i18n_808c18d2bb":"A value of true indicates that the project is currently running",
 	"i18n_809b12d6a0":"Please be patient, there is no need to refresh the page for the time being.",
+	"i18n_80b7af89ee":"There is no FTP in the current workspace.",
 	"i18n_80cfc33cbe":"Confirm reset",
 	"i18n_81301b6813":"Open end point",
 	"i18n_81485b76d8":"Please enter the host address",
@@ -1449,6 +1465,7 @@
 	"i18n_8306971039":"user",
 	"i18n_8309cec640":"Please select the node project. It may be that there is no project in the node, and you need to go to the node to create a project.",
 	"i18n_833249fb92":"Current file time",
+	"i18n_8339e5e8e9":"If you multi-select ftp, the directory below only displays the first item in the options, but the authorization directory needs to ensure that each item is configured with the corresponding directory",
 	"i18n_8347a927c0":"modify",
 	"i18n_835050418f":"Are you sure you want to upload the latest plugin package?",
 	"i18n_8351876236":"Alias",
@@ -1635,6 +1652,7 @@
 	"i18n_917381e4a5":"Current download source:",
 	"i18n_91985e3574":"automatic detection",
 	"i18n_91a10b8776":" script library ",
+	"i18n_91a828d055":"Do you really want to clear FTP hidden field information? (password)",
 	"i18n_920f05031b":"state description",
 	"i18n_922b76febd":"Run mode Required",
 	"i18n_923f8d2688":"Post-issue command",
@@ -1867,6 +1885,7 @@
 	"i18n_a436c94494":"Feishu scan code",
 	"i18n_a472019766":"Node Id",
 	"i18n_a497562c8e":"executor",
+	"i18n_a49f609d09":"Active Mode",
 	"i18n_a4f5cae8d2":"on state",
 	"i18n_a4f629041c":"The path needs to be configured with an absolute path.",
 	"i18n_a50fbc5a52":"Support specifying the network interface card name to bind:",
@@ -2345,6 +2364,7 @@
 	"i18n_cd998f12fa":"When a node already exists in the target workspace, the node authorization information and agent configuration information will be automatically synchronized",
 	"i18n_cda84be2f6":"operation log",
 	"i18n_cdc478d90c":"system name",
+	"i18n_cdf2e36c2a":"FTP name",
 	"i18n_ce043fac7d":"The current workspace does not have SSH yet.",
 	"i18n_ce07501354":"Click on a number to see a running task",
 	"i18n_ce1c5765e4":"View Release Template",
@@ -2358,6 +2378,7 @@
 	"i18n_ceee1db95a":"container port",
 	"i18n_ceffe5d643":"two-step verification app",
 	"i18n_cf38e8f9fd":"The authorization path configuration currently distributed for the node",
+	"i18n_cf93cd2cde":"Please select FTP.",
 	"i18n_cfa72dd73a":"Please enter the cron expression to check",
 	"i18n_cfb00269fd":"Execute script",
 	"i18n_cfbb3341d5":"The currently logged in account is:",
@@ -2411,6 +2432,7 @@
 	"i18n_d4aea8d7e6":"execution times",
 	"i18n_d4e03f60a9":"Check the project status when the plug-in side starts, and try to execute the startup project if the project status is not running.",
 	"i18n_d5269713c7":"Indicates that when bundled as a folder, it will be packaged as",
+	"i18n_d55b5f6ce4":"transmission mode",
 	"i18n_d57796d6ac":" : Range: 0~ 59",
 	"i18n_d584e1493b":"Search ssh name",
 	"i18n_d58a55bcee":"close",
@@ -2433,6 +2455,7 @@
 	"i18n_d731dc9325":"Timestamp:",
 	"i18n_d7471c0261":"Please select an execution node",
 	"i18n_d75c02d050":"Stop project",
+	"i18n_d769de863b":"Associated workspace ftp",
 	"i18n_d7ac764d3a":"The distribution interval time (sequential restart, full sequential restart) method will only take effect",
 	"i18n_d7ba18c360":"The distribution node refers to a script that automatically synchronizes the content of the script node after editing the script",
 	"i18n_d7bebd0e5e":"Please go to the console to control the status operation.",
@@ -2536,6 +2559,7 @@
 	"i18n_df9d1fedc5":"Node distribution refers to the deployment of a project in multiple nodes using node distribution to complete project publishing operations in multiple nodes in one step",
 	"i18n_dfb8d511c7":"user name",
 	"i18n_dfcc9e3c45":"post-distribution operation",
+	"i18n_e020a4df74":"Server system keywords",
 	"i18n_e039ffccc8":"Restore this file to the project directory?",
 	"i18n_e049546ff3":"Modified in [System Configuration Catalog]",
 	"i18n_e06497b0fb":"View currently available containers",
@@ -2645,9 +2669,11 @@
 	"i18n_ea8a79546f":"Please enter the published file id.",
 	"i18n_ea9f824647":"Pull warehouse timeout in seconds",
 	"i18n_eaa5d7cb9b":"expiration date",
+	"i18n_eaa85849f3":"If ftp does not configure the authorization directory, it cannot be selected.",
 	"i18n_eadd05ba6a":"medium",
 	"i18n_eaf987eea0":"Weight (relative weight).",
 	"i18n_eb164b696d":"exclude publishing",
+	"i18n_eb3a60fbc0":"Edit FTP",
 	"i18n_eb5bab1c31":"optional",
 	"i18n_eb79cea638":"Friday",
 	"i18n_eb7f9ceb71":"Script library:",
@@ -2706,6 +2732,7 @@
 	"i18n_f038f48ce5":"Edit script",
 	"i18n_f04a289502":"Svn ssh required Login user",
 	"i18n_f05e3ec44d":"Forbidden access, current IP restricts access",
+	"i18n_f06a391743":"The FTP that has been assigned to the workspace cannot be deleted directly. You need to delete the asset FTP one by one in each allocated workspace.",
 	"i18n_f06f95f8e6":"Lonely Data",
 	"i18n_f087eb347c":"Build command example",
 	"i18n_f08afd1f82":"Selected",
@@ -2807,6 +2834,7 @@
 	"i18n_fad1b9fb87":"The new script template needs to be added to the node management.",
 	"i18n_fb1f3b5125":"Current Workspace Linked Data Statistics",
 	"i18n_fb3a2241bb":"Status description:",
+	"i18n_fb5037a644":"This configuration is only valid for server level administration, the ftp configuration of the workspace needs to be configured separately",
 	"i18n_fb5bc565f3":"Failed to parse file:",
 	"i18n_fb61d4d708":"Do you really want to roll back the build history?",
 	"i18n_fb7b9876a6":"Please enter a script name",
@@ -2831,6 +2859,7 @@
 	"i18n_fcbf0d0a55":"You need to install the dependent yarn & & yarn run build first.",
 	"i18n_fcca8452fe":"The cluster address is mainly used to switch the workspace and automatically jump to the corresponding cluster.",
 	"i18n_fcef976c7a":"private key content",
+	"i18n_fcfbc11bb9":"The password field will not be returned when editing. Please click me if you need to reset or empty it.",
 	"i18n_fd6e80f1e0":"normal",
 	"i18n_fd7b461411":"Do not empty",
 	"i18n_fd7e0c997d":"Select file",

+ 29 - 0
web-vue/src/i18n/locales/zh_cn.json

@@ -30,6 +30,7 @@
   "i18n_02e35447d4": "下载构建产物,如果按钮不可用表示产物文件不存在,一般是构建没有产生对应的文件或者构建历史相关文件被删除",
   "i18n_0306ea1908": "删除镜像",
   "i18n_031020489f": "当前工作空间您触发的构建记录",
+  "i18n_03113c0f1a": "真的要删除 FTP 么?",
   "i18n_03580275cb": "请选中要重启的项目",
   "i18n_0360fffb40": "并开启此开关",
   "i18n_036c0dc2aa": "系统取消分发",
@@ -83,6 +84,7 @@
   "i18n_080b914139": "上传包",
   "i18n_0836332bf6": "升级协议",
   "i18n_083b8a2ec9": "一个物理节点被多个服务端绑定也会产生孤独数据奥",
+  "i18n_087c992cc0": "被动模式",
   "i18n_08902526f1": "皮肤:",
   "i18n_0895c740a6": "交换内存占用",
   "i18n_089a88ecee": "系统时间:",
@@ -136,6 +138,7 @@
   "i18n_0ce54ecc25": "付费社群",
   "i18n_0cf4f0ba82": "真的要保存当前配置吗?如果配置有误,可能无法启动服务需要手动还原奥!!! 保存成功后请及时关注重启状态!!",
   "i18n_0cf81d77bb": "请填写仓库地址",
+  "i18n_0d1ee51203": "系统关键词",
   "i18n_0d44f4903a": "真的要释放(删除)当前项目么?",
   "i18n_0d467f7889": "# 是否开启日志备份功能",
   "i18n_0d48f8e881": "请输入服务地址",
@@ -213,6 +216,7 @@
   "i18n_143bfbc3a1": "点击重新同步当前工作空间逻辑节点项目信息",
   "i18n_143d8d3de5": "否则将删除满足条件的所有数据",
   "i18n_148484b985": "实现您需要配置 docker 容器到服务端中来管理,并且分配到当前工作空间中",
+  "i18n_148d37218a": "FTP 名称",
   "i18n_1498557b2d": "同时只能展开一个菜单",
   "i18n_14a25beebb": "10秒一次",
   "i18n_14d342362f": "标签",
@@ -281,6 +285,7 @@
   "i18n_1a8f90122f": "提示信息 ",
   "i18n_1abf39bdb6": "# 将此目录缓存到全局(多个构建可以共享此缓存目录)",
   "i18n_1ad696efdc": "构建执行的命令(非阻塞命令),如:mvn clean package、npm run build。支持变量:{'${BUILD_ID}'}、{'${BUILD_NAME}'}、{'${BUILD_SOURCE_FILE}'}、{'${BUILD_NUMBER_ID}'}、仓库目录下 .env、工作空间变量",
+  "i18n_1add83f77b": "ftp名称",
   "i18n_1ae2955867": "指定 pom 文件打包 mvn -f xxx/pom.xml clean package",
   "i18n_1afdb4a364": "隐藏滚动条。纵向滚动方式提醒:滚轮,横行滚动方式:Shift+滚轮",
   "i18n_1b03b0c1ff": "已经分配到工作空间的 Docker 或者集群无法直接删除,需要到分配到的各个工作空间逐一删除后才能删除资产 Docker 或者集群",
@@ -460,6 +465,7 @@
   "i18n_29b48a76be": "请选择发布方式",
   "i18n_29efa328e5": "未分发",
   "i18n_2a049f4f5b": "分发失败",
+  "i18n_2a04f7b9be": "如果按钮不可用,请去资产管理 ftp 列表的关联中新增当前工作空间允许管理的授权文件夹",
   "i18n_2a0bea27c4": "执行域",
   "i18n_2a0c4740f1": "文件",
   "i18n_2a1d1da97a": "打包测试环境包 mvn clean package -Dmaven.test.skip=true -Ptest",
@@ -572,6 +578,7 @@
   "i18n_32d0576d85": "的令牌",
   "i18n_32dcc6f36e": "重启策略:no、always、unless-stopped、on-failure",
   "i18n_32e05f01f4": "集群信息",
+  "i18n_32e3c8b702": "发布的FTP",
   "i18n_32f882ae24": "匹配零个或多个字符",
   "i18n_330363dfc5": "成功",
   "i18n_3306c2a7c7": "读取默认",
@@ -659,6 +666,7 @@
   "i18n_3b94c70734": "项目状态",
   "i18n_3ba621d736": "处理成功",
   "i18n_3baa9f3d72": "批量构建参数还支持指定参数,delay(延迟执行构建,单位秒)branchName(分支名)、branchTagName(标签)、script(构建脚本)、resultDirFile(构建产物)、webhook(通知webhook)",
+  "i18n_3bc3bdc031": "请到【系统管理】-> 【资产管理】-> 【FTP管理】新增FTP,或者将已新增的FTP授权关联、分配到此工作空间",
   "i18n_3bc5e602b2": "邮箱",
   "i18n_3bcc1c7a20": "最后修改人",
   "i18n_3bdab2c607": "10分钟",
@@ -673,6 +681,7 @@
   "i18n_3c6fa6f667": "cron表达式",
   "i18n_3c8eada338": "请选择编码方式",
   "i18n_3c91490844": "发布操作",
+  "i18n_3c943b89c6": "此编辑仅能编辑当前 FTP 在此工作空间的名称信息",
   "i18n_3c99ea4ec2": "例如 2,3,6/3中,由于“/”优先级高,因此相当于2,3,(6/3),结果与 2,3,6等价",
   "i18n_3c9eeee356": "真的要删除日志文件么?",
   "i18n_3cc09369ad": "真的要删除【",
@@ -849,6 +858,7 @@
   "i18n_4b96762a7e": "最后修改时间",
   "i18n_4b9c3271dc": "重置",
   "i18n_4ba304e77a": "钉钉账号登录",
+  "i18n_4bb37cc406": "服务器语言",
   "i18n_4bbc09fc55": "在文件第 3 - 20 行中搜索",
   "i18n_4c096c51a3": "端口号:",
   "i18n_4c0eead6ff": "新增参数",
@@ -867,6 +877,7 @@
   "i18n_4d18dcbd15": "真的要还原备份信息么?",
   "i18n_4d351f3c91": "禁止 IP",
   "i18n_4d49b2a15f": "自动执行:docker",
+  "i18n_4d4ab2f8f5": "当前 FTP 的授权目录(文件目录、文件后缀)需要请到 【系统管理】-> 【资产管理】-> 【FTP 管理】-> 操作栏中->关联按钮->对应工作空间->操作栏中->配置按钮",
   "i18n_4d775d4cd7": "显示",
   "i18n_4d7dc6c5f8": "写",
   "i18n_4d85ac1250": "系统管理",
@@ -1126,6 +1137,7 @@
   "i18n_649d90ab3c": "关闭右侧",
   "i18n_649f8046f3": "请选择SSH节点",
   "i18n_64c083c0a9": "结果描述",
+  "i18n_64c8791ba1": "配置方式:FTP管理->操作栏中->关联按钮->对应工作空间->操作栏中->配置按钮",
   "i18n_64eee9aafa": "开机时间",
   "i18n_652273694e": "主机",
   "i18n_65571516e2": "构建备注:",
@@ -1144,6 +1156,7 @@
   "i18n_66ab5e9f24": "新增",
   "i18n_66b71b06c6": "上传压缩文件(自动解压)",
   "i18n_66c15f2815": "匹配包含数字的行",
+  "i18n_66e623e6f8": "配置ftp",
   "i18n_66e9ea5488": "日志名称",
   "i18n_6707667676": "主机名",
   "i18n_6709f4548f": "随机生成",
@@ -1329,6 +1342,7 @@
   "i18n_77373db7d8": "接收报警消息,非必填,GET请求",
   "i18n_7737f088de": "批量重新启动",
   "i18n_773b1a5ef6": "请选择语言模式",
+  "i18n_774aecfd99": "如果要配置 FTP 请到【系统管理】-> 【资产管理】-> 【FTP 管理】中去配置。",
   "i18n_775fde44cf": "进程端口缓存:",
   "i18n_7760785daf": "自由脚本",
   "i18n_7764df7ccc": "开启差异发布但不开启清空发布时相当于只做增量和变动更新",
@@ -1406,6 +1420,7 @@
   "i18n_7e930b95ef": "发布文件",
   "i18n_7e951d56d9": "操作时间",
   "i18n_7e9f0d2606": "项目是指,节点中的某一个项目,需要提前在节点中创建项目",
+  "i18n_7eef73a0eb": "编辑FTP",
   "i18n_7ef30cfd31": "附加环境变量是指读取仓库指定环境变量文件来新增到执行构建运行时",
   "i18n_7f0abcf48d": "需要到编辑中去为一个节点绑定一个 ssh信息才能启用该功能",
   "i18n_7f3809d36b": "构建结束",
@@ -1424,6 +1439,7 @@
   "i18n_8086beecb3": "标签名称:",
   "i18n_808c18d2bb": "值为 true 表示项目当前为运行中",
   "i18n_809b12d6a0": "请耐心等待暂时不用刷新页面",
+  "i18n_80b7af89ee": "当前工作空间还没有FTP",
   "i18n_80cfc33cbe": "确认重置",
   "i18n_81301b6813": "打开终端",
   "i18n_81485b76d8": "请输入主机地址",
@@ -1449,6 +1465,7 @@
   "i18n_8306971039": "所属用户",
   "i18n_8309cec640": "请选择节点项目,可能是节点中不存在任何项目,需要去节点中创建项目",
   "i18n_833249fb92": "当前文件用时",
+  "i18n_8339e5e8e9": "如果多选 ftp 下面目录只显示选项中的第一项,但是授权目录需要保证每项都配置对应目录",
   "i18n_8347a927c0": "修改",
   "i18n_835050418f": "确认要上传最新的插件包吗?",
   "i18n_8351876236": "别名 ",
@@ -1635,6 +1652,7 @@
   "i18n_917381e4a5": "当前下载源:",
   "i18n_91985e3574": "自动探测",
   "i18n_91a10b8776": " 脚本库 ",
+  "i18n_91a828d055": "真的要清除 FTP 隐藏字段信息么?(密码)",
   "i18n_920f05031b": "状态描述",
   "i18n_922b76febd": "运行模式必填",
   "i18n_923f8d2688": "发布后命令",
@@ -1867,6 +1885,7 @@
   "i18n_a436c94494": "飞书扫码",
   "i18n_a472019766": "节点Id",
   "i18n_a497562c8e": "执行人",
+  "i18n_a49f609d09": "主动模式",
   "i18n_a4f5cae8d2": "开启状态",
   "i18n_a4f629041c": "路径需要配置绝对路径",
   "i18n_a50fbc5a52": "支持指定网卡名称来绑定:",
@@ -2345,6 +2364,7 @@
   "i18n_cd998f12fa": "当目标工作空间已经存在节点时候将自动同步节点授权信息、代理配置信息",
   "i18n_cda84be2f6": "操作日志",
   "i18n_cdc478d90c": "系统名",
+  "i18n_cdf2e36c2a": "FTP名称",
   "i18n_ce043fac7d": "当前工作空间还没有SSH",
   "i18n_ce07501354": "点击数字查看运行中的任务",
   "i18n_ce1c5765e4": "查看发布模板",
@@ -2358,6 +2378,7 @@
   "i18n_ceee1db95a": "容器端口",
   "i18n_ceffe5d643": "两步验证应用",
   "i18n_cf38e8f9fd": "当前为节点分发的授权路径配置",
+  "i18n_cf93cd2cde": "请选择FTP",
   "i18n_cfa72dd73a": "请输入要检查的 cron 表达式",
   "i18n_cfb00269fd": "执行脚本",
   "i18n_cfbb3341d5": "当前登录的账号是:",
@@ -2411,6 +2432,7 @@
   "i18n_d4aea8d7e6": "执行次数",
   "i18n_d4e03f60a9": "插件端启动的时候检查项目状态,如果项目状态是未运行则尝试执行启动项目",
   "i18n_d5269713c7": "表示构建产物为文件夹时将打包为",
+  "i18n_d55b5f6ce4": "传输模式",
   "i18n_d57796d6ac": " :范围:0~59",
   "i18n_d584e1493b": "搜索ssh名称",
   "i18n_d58a55bcee": "关",
@@ -2433,6 +2455,7 @@
   "i18n_d731dc9325": "时间戳:",
   "i18n_d7471c0261": "请选择执行节点",
   "i18n_d75c02d050": "停止项目",
+  "i18n_d769de863b": "关联工作空间ftp",
   "i18n_d7ac764d3a": "分发间隔时间 (顺序重启、完整顺序重启)方式才生效",
   "i18n_d7ba18c360": "分发节点是指在编辑完脚本后自动将脚本内容同步节点的脚本中",
   "i18n_d7bebd0e5e": "状态操作请到控制台中控制",
@@ -2536,6 +2559,7 @@
   "i18n_df9d1fedc5": "节点分发是指,一个项目部署在多个节点中使用节点分发一步完成多个节点中的项目发布操作",
   "i18n_dfb8d511c7": "用户名称",
   "i18n_dfcc9e3c45": "分发后操作",
+  "i18n_e020a4df74": "服务器系统关键词",
   "i18n_e039ffccc8": "】此文件还原到项目目录?",
   "i18n_e049546ff3": "【系统配置目录】中修改",
   "i18n_e06497b0fb": "查看当前可用容器",
@@ -2645,9 +2669,11 @@
   "i18n_ea8a79546f": "请输入发布的文件id",
   "i18n_ea9f824647": "拉取仓库超时时间,单位秒",
   "i18n_eaa5d7cb9b": "过期天数",
+  "i18n_eaa85849f3": "如果 ftp 没有配置授权目录是不能选择的哟",
   "i18n_eadd05ba6a": "中等",
   "i18n_eaf987eea0": "权重(相对权重)。",
   "i18n_eb164b696d": "排除发布",
+  "i18n_eb3a60fbc0": "编辑 FTP",
   "i18n_eb5bab1c31": "非必填",
   "i18n_eb79cea638": "周五",
   "i18n_eb7f9ceb71": "脚本库:",
@@ -2706,6 +2732,7 @@
   "i18n_f038f48ce5": "编辑脚本",
   "i18n_f04a289502": "svn ssh 必填登录用户",
   "i18n_f05e3ec44d": "禁止访问,当前IP限制访问",
+  "i18n_f06a391743": "已经分配到工作空间的 FTP 无法直接删除,需要到分配到的各个工作空间逐一删除后才能删除资产 FTP",
   "i18n_f06f95f8e6": "孤独数据",
   "i18n_f087eb347c": "构建命令示例",
   "i18n_f08afd1f82": "已选择",
@@ -2807,6 +2834,7 @@
   "i18n_fad1b9fb87": "新增脚本模版需要到节点管理中去新增",
   "i18n_fb1f3b5125": "当前工作空间关联数据统计",
   "i18n_fb3a2241bb": "状态描述:",
+  "i18n_fb5037a644": "此配置仅对服务端管理生效, 工作空间的 ftp 配置需要单独配置",
   "i18n_fb5bc565f3": "解析文件失败:",
   "i18n_fb61d4d708": "真的要回滚该构建历史记录么?",
   "i18n_fb7b9876a6": "请输入脚本名称",
@@ -2831,6 +2859,7 @@
   "i18n_fcbf0d0a55": "需要先安装依赖 yarn && yarn run build",
   "i18n_fcca8452fe": "集群地址主要用于切换工作空间自动跳转到对应的集群",
   "i18n_fcef976c7a": "私钥内容",
+  "i18n_fcfbc11bb9": "密码字段在编辑的时候不会返回,如果需要重置或者清空就请点我",
   "i18n_fd6e80f1e0": "正常",
   "i18n_fd7b461411": "不清空",
   "i18n_fd7e0c997d": "选择文件",

+ 29 - 0
web-vue/src/i18n/locales/zh_hk.json

@@ -30,6 +30,7 @@
 	"i18n_02e35447d4":"下載構建產物,如果按鈕不可用表示產物文件不存在,一般是構建沒有產生對應的文件或者構建歷史相關文件被刪除",
 	"i18n_0306ea1908":"刪除鏡像",
 	"i18n_031020489f":"當前工作空間您觸發的構建記錄",
+	"i18n_03113c0f1a":"真的要刪除 FTP 麼?",
 	"i18n_03580275cb":"請選中要重啟的項目",
 	"i18n_0360fffb40":"並開啟此開關",
 	"i18n_036c0dc2aa":"系統取消分發",
@@ -83,6 +84,7 @@
 	"i18n_080b914139":"上傳包",
 	"i18n_0836332bf6":"升級協議",
 	"i18n_083b8a2ec9":"一個物理節點被多個服務端綁定也會產生孤獨數據奧",
+	"i18n_087c992cc0":"被動模式",
 	"i18n_08902526f1":"皮膚:",
 	"i18n_0895c740a6":"交換內存佔用",
 	"i18n_089a88ecee":"系統時間:",
@@ -136,6 +138,7 @@
 	"i18n_0ce54ecc25":"付費社羣",
 	"i18n_0cf4f0ba82":"真的要保存當前配置嗎?如果配置有誤,可能無法啟動服務需要手動還原奧!!! 保存成功後請及時關注重啟狀態!!",
 	"i18n_0cf81d77bb":"請填寫倉庫地址",
+	"i18n_0d1ee51203":"系統關鍵詞",
 	"i18n_0d44f4903a":"真的要釋放(刪除)當前項目麼?",
 	"i18n_0d467f7889":"# 是否開啟日誌備份功能",
 	"i18n_0d48f8e881":"請輸入服務地址",
@@ -213,6 +216,7 @@
 	"i18n_143bfbc3a1":"點擊重新同步當前工作空間邏輯節點項目信息",
 	"i18n_143d8d3de5":"否則將刪除滿足條件的所有數據",
 	"i18n_148484b985":"實現您需要配置 docker 容器到服務端中來管理,並且分配到當前工作空間中",
+	"i18n_148d37218a":"FTP 名稱",
 	"i18n_1498557b2d":"同時只能展開一個菜單",
 	"i18n_14a25beebb":"10秒一次",
 	"i18n_14d342362f":"標籤",
@@ -281,6 +285,7 @@
 	"i18n_1a8f90122f":"提示信息 ",
 	"i18n_1abf39bdb6":"# 將此目錄緩存到全局(多個構建可以共享此緩存目錄)",
 	"i18n_1ad696efdc":"構建執行的命令(非阻塞命令),如:mvn clean package、npm run build。支持變量:{'${BUILD_ID}'}、{'${BUILD_NAME}'}、{'${BUILD_SOURCE_FILE}'}、{'${BUILD_NUMBER_ID}'}、倉庫目錄下 .env、工作空間變量",
+	"i18n_1add83f77b":"ftp名稱",
 	"i18n_1ae2955867":"指定 pom 文件打包 mvn -f xxx/pom.xml clean package",
 	"i18n_1afdb4a364":"隱藏滾動條。縱向滾動方式提醒:滾輪,橫行滾動方式:Shift+滾輪",
 	"i18n_1b03b0c1ff":"已經分配到工作空間的 Docker 或者集羣無法直接刪除,需要到分配到的各個工作空間逐一刪除後才能刪除資產 Docker 或者集羣",
@@ -460,6 +465,7 @@
 	"i18n_29b48a76be":"請選擇發佈方式",
 	"i18n_29efa328e5":"未分發",
 	"i18n_2a049f4f5b":"分發失敗",
+	"i18n_2a04f7b9be":"如果按鈕不可用,請去資產管理 ftp 列表的關聯中新增當前工作空間允許管理的授權文件夾",
 	"i18n_2a0bea27c4":"執行域",
 	"i18n_2a0c4740f1":"文件",
 	"i18n_2a1d1da97a":"打包測試環境包 mvn clean package -Dmaven.test.skip=true -Ptest",
@@ -572,6 +578,7 @@
 	"i18n_32d0576d85":"的令牌",
 	"i18n_32dcc6f36e":"重啟策略:no、always、unless-stopped、on-failure",
 	"i18n_32e05f01f4":"集羣信息",
+	"i18n_32e3c8b702":"發佈的FTP",
 	"i18n_32f882ae24":"匹配零個或多個字符",
 	"i18n_330363dfc5":"成功",
 	"i18n_3306c2a7c7":"讀取默認",
@@ -659,6 +666,7 @@
 	"i18n_3b94c70734":"項目狀態",
 	"i18n_3ba621d736":"處理成功",
 	"i18n_3baa9f3d72":"批量構建參數還支持指定參數,delay(延遲執行構建,單位秒)branchName(分支名)、branchTagName(標籤)、script(構建腳本)、resultDirFile(構建產物)、webhook(通知webhook)",
+	"i18n_3bc3bdc031":"請到【系統管理】-> 【資產管理】-> 【FTP管理】新增FTP,或者將已新增的FTP授權關聯、分配到此工作空間",
 	"i18n_3bc5e602b2":"郵箱",
 	"i18n_3bcc1c7a20":"最後修改人",
 	"i18n_3bdab2c607":"10分鐘",
@@ -673,6 +681,7 @@
 	"i18n_3c6fa6f667":"cron表達式",
 	"i18n_3c8eada338":"請選擇編碼方式",
 	"i18n_3c91490844":"發佈操作",
+	"i18n_3c943b89c6":"此編輯僅能編輯當前 FTP 在此工作空間的名稱信息",
 	"i18n_3c99ea4ec2":"例如 2,3,6/3中,由於“/”優先級高,因此相當於2,3,(6/3),結果與 2,3,6等價",
 	"i18n_3c9eeee356":"真的要刪除日誌文件麼?",
 	"i18n_3cc09369ad":"真的要刪除【",
@@ -849,6 +858,7 @@
 	"i18n_4b96762a7e":"最後修改時間",
 	"i18n_4b9c3271dc":"重置",
 	"i18n_4ba304e77a":"釘釘賬號登錄",
+	"i18n_4bb37cc406":"服務器語言",
 	"i18n_4bbc09fc55":"在文件第 3 - 20 行中搜索",
 	"i18n_4c096c51a3":"端口號:",
 	"i18n_4c0eead6ff":"新增參數",
@@ -867,6 +877,7 @@
 	"i18n_4d18dcbd15":"真的要還原備份信息麼?",
 	"i18n_4d351f3c91":"禁止 IP",
 	"i18n_4d49b2a15f":"自動執行:docker",
+	"i18n_4d4ab2f8f5":"當前 FTP 的授權目錄(文件目錄、文件後綴)需要請到 【系統管理】-> 【資產管理】-> 【FTP 管理】-> 操作欄中->關聯按鈕->對應工作空間->操作欄中->配置按鈕",
 	"i18n_4d775d4cd7":"顯示",
 	"i18n_4d7dc6c5f8":"寫",
 	"i18n_4d85ac1250":"系統管理",
@@ -1126,6 +1137,7 @@
 	"i18n_649d90ab3c":"關閉右側",
 	"i18n_649f8046f3":"請選擇SSH節點",
 	"i18n_64c083c0a9":"結果描述",
+	"i18n_64c8791ba1":"配置方式:FTP管理->操作欄中->關聯按鈕->對應工作空間->操作欄中->配置按鈕",
 	"i18n_64eee9aafa":"開機時間",
 	"i18n_652273694e":"主機",
 	"i18n_65571516e2":"構建備註:",
@@ -1144,6 +1156,7 @@
 	"i18n_66ab5e9f24":"新增",
 	"i18n_66b71b06c6":"上傳壓縮文件(自動解壓)",
 	"i18n_66c15f2815":"匹配包含數字的行",
+	"i18n_66e623e6f8":"配置ftp",
 	"i18n_66e9ea5488":"日誌名稱",
 	"i18n_6707667676":"主機名",
 	"i18n_6709f4548f":"隨機生成",
@@ -1329,6 +1342,7 @@
 	"i18n_77373db7d8":"接收報警消息,非必填,GET請求",
 	"i18n_7737f088de":"批量重新啟動",
 	"i18n_773b1a5ef6":"請選擇語言模式",
+	"i18n_774aecfd99":"如果要配置 FTP 請到【系統管理】-> 【資產管理】-> 【FTP 管理】中去配置。",
 	"i18n_775fde44cf":"進程端口緩存:",
 	"i18n_7760785daf":"自由腳本",
 	"i18n_7764df7ccc":"開啟差異發佈但不開啟清空發佈時相當於只做增量和變動更新",
@@ -1406,6 +1420,7 @@
 	"i18n_7e930b95ef":"發佈文件",
 	"i18n_7e951d56d9":"操作時間",
 	"i18n_7e9f0d2606":"項目是指,節點中的某一個項目,需要提前在節點中創建項目",
+	"i18n_7eef73a0eb":"編輯FTP",
 	"i18n_7ef30cfd31":"附加環境變量是指讀取倉庫指定環境變量文件來新增到執行構建運行時",
 	"i18n_7f0abcf48d":"需要到編輯中去為一個節點綁定一個 ssh信息才能啟用該功能",
 	"i18n_7f3809d36b":"構建結束",
@@ -1424,6 +1439,7 @@
 	"i18n_8086beecb3":"標籤名稱:",
 	"i18n_808c18d2bb":"值為 true 表示項目當前為運行中",
 	"i18n_809b12d6a0":"請耐心等待暫時不用刷新頁面",
+	"i18n_80b7af89ee":"當前工作空間還沒有FTP",
 	"i18n_80cfc33cbe":"確認重置",
 	"i18n_81301b6813":"打開終端",
 	"i18n_81485b76d8":"請輸入主機地址",
@@ -1449,6 +1465,7 @@
 	"i18n_8306971039":"所屬用户",
 	"i18n_8309cec640":"請選擇節點項目,可能是節點中不存在任何項目,需要去節點中創建項目",
 	"i18n_833249fb92":"當前文件用時",
+	"i18n_8339e5e8e9":"如果多選 ftp 下面目錄只顯示選項中的第一項,但是授權目錄需要保證每項都配置對應目錄",
 	"i18n_8347a927c0":"修改",
 	"i18n_835050418f":"確認要上傳最新的插件包嗎?",
 	"i18n_8351876236":"別名 ",
@@ -1635,6 +1652,7 @@
 	"i18n_917381e4a5":"當前下載源:",
 	"i18n_91985e3574":"自動探測",
 	"i18n_91a10b8776":" 腳本庫 ",
+	"i18n_91a828d055":"真的要清除 FTP 隱藏字段信息麼?(密碼)",
 	"i18n_920f05031b":"狀態描述",
 	"i18n_922b76febd":"運行模式必填",
 	"i18n_923f8d2688":"發佈後命令",
@@ -1867,6 +1885,7 @@
 	"i18n_a436c94494":"飛書掃碼",
 	"i18n_a472019766":"節點Id",
 	"i18n_a497562c8e":"執行人",
+	"i18n_a49f609d09":"主動模式",
 	"i18n_a4f5cae8d2":"開啟狀態",
 	"i18n_a4f629041c":"路徑需要配置絕對路徑",
 	"i18n_a50fbc5a52":"支持指定網卡名稱來綁定:",
@@ -2345,6 +2364,7 @@
 	"i18n_cd998f12fa":"當目標工作空間已經存在節點時候將自動同步節點授權信息、代理配置信息",
 	"i18n_cda84be2f6":"操作日誌",
 	"i18n_cdc478d90c":"系統名",
+	"i18n_cdf2e36c2a":"FTP名稱",
 	"i18n_ce043fac7d":"當前工作空間還沒有SSH",
 	"i18n_ce07501354":"點擊數字查看運行中的任務",
 	"i18n_ce1c5765e4":"查看發佈模板",
@@ -2358,6 +2378,7 @@
 	"i18n_ceee1db95a":"容器端口",
 	"i18n_ceffe5d643":"兩步驗證應用",
 	"i18n_cf38e8f9fd":"當前為節點分發的授權路徑配置",
+	"i18n_cf93cd2cde":"請選擇FTP",
 	"i18n_cfa72dd73a":"請輸入要檢查的 cron 表達式",
 	"i18n_cfb00269fd":"執行腳本",
 	"i18n_cfbb3341d5":"當前登錄的賬號是:",
@@ -2411,6 +2432,7 @@
 	"i18n_d4aea8d7e6":"執行次數",
 	"i18n_d4e03f60a9":"插件端啟動的時候檢查項目狀態,如果項目狀態是未運行則嘗試執行啟動項目",
 	"i18n_d5269713c7":"表示構建產物為文件夾時將打包為",
+	"i18n_d55b5f6ce4":"傳輸模式",
 	"i18n_d57796d6ac":" :範圍:0~59",
 	"i18n_d584e1493b":"搜索ssh名稱",
 	"i18n_d58a55bcee":"關",
@@ -2433,6 +2455,7 @@
 	"i18n_d731dc9325":"時間戳:",
 	"i18n_d7471c0261":"請選擇執行節點",
 	"i18n_d75c02d050":"停止項目",
+	"i18n_d769de863b":"關聯工作空間ftp",
 	"i18n_d7ac764d3a":"分發間隔時間 (順序重啟、完整順序重啟)方式才生效",
 	"i18n_d7ba18c360":"分發節點是指在編輯完腳本後自動將腳本內容同步節點的腳本中",
 	"i18n_d7bebd0e5e":"狀態操作請到控制枱中控制",
@@ -2536,6 +2559,7 @@
 	"i18n_df9d1fedc5":"節點分發是指,一個項目部署在多個節點中使用節點分發一步完成多個節點中的項目發佈操作",
 	"i18n_dfb8d511c7":"用户名稱",
 	"i18n_dfcc9e3c45":"分發後操作",
+	"i18n_e020a4df74":"服務器系統關鍵詞",
 	"i18n_e039ffccc8":"】此文件還原到項目目錄?",
 	"i18n_e049546ff3":"【系統配置目錄】中修改",
 	"i18n_e06497b0fb":"查看當前可用容器",
@@ -2645,9 +2669,11 @@
 	"i18n_ea8a79546f":"請輸入發佈的文件id",
 	"i18n_ea9f824647":"拉取倉庫超時時間,單位秒",
 	"i18n_eaa5d7cb9b":"過期天數",
+	"i18n_eaa85849f3":"如果 ftp 沒有配置授權目錄是不能選擇的喲",
 	"i18n_eadd05ba6a":"中等",
 	"i18n_eaf987eea0":"權重(相對權重)。",
 	"i18n_eb164b696d":"排除發佈",
+	"i18n_eb3a60fbc0":"編輯 FTP",
 	"i18n_eb5bab1c31":"非必填",
 	"i18n_eb79cea638":"週五",
 	"i18n_eb7f9ceb71":"腳本庫:",
@@ -2706,6 +2732,7 @@
 	"i18n_f038f48ce5":"編輯腳本",
 	"i18n_f04a289502":"svn ssh 必填登錄用户",
 	"i18n_f05e3ec44d":"禁止訪問,當前IP限制訪問",
+	"i18n_f06a391743":"已經分配到工作空間的 FTP 無法直接刪除,需要到分配到的各個工作空間逐一刪除後才能刪除資產 FTP",
 	"i18n_f06f95f8e6":"孤獨數據",
 	"i18n_f087eb347c":"構建命令示例",
 	"i18n_f08afd1f82":"已選擇",
@@ -2807,6 +2834,7 @@
 	"i18n_fad1b9fb87":"新增腳本模版需要到節點管理中去新增",
 	"i18n_fb1f3b5125":"當前工作空間關聯數據統計",
 	"i18n_fb3a2241bb":"狀態描述:",
+	"i18n_fb5037a644":"此配置僅對服務端管理生效, 工作空間的 ftp 配置需要單獨配置",
 	"i18n_fb5bc565f3":"解析文件失敗:",
 	"i18n_fb61d4d708":"真的要回滾該構建歷史記錄麼?",
 	"i18n_fb7b9876a6":"請輸入腳本名稱",
@@ -2831,6 +2859,7 @@
 	"i18n_fcbf0d0a55":"需要先安裝依賴 yarn && yarn run build",
 	"i18n_fcca8452fe":"集羣地址主要用於切換工作空間自動跳轉到對應的集羣",
 	"i18n_fcef976c7a":"私鑰內容",
+	"i18n_fcfbc11bb9":"密碼字段在編輯的時候不會返回,如果需要重置或者清空就請點我",
 	"i18n_fd6e80f1e0":"正常",
 	"i18n_fd7b461411":"不清空",
 	"i18n_fd7e0c997d":"選擇文件",

+ 29 - 0
web-vue/src/i18n/locales/zh_tw.json

@@ -30,6 +30,7 @@
 	"i18n_02e35447d4":"下載構建產物,如果按鈕不可用表示產物檔案不存在,一般是構建沒有產生對應的檔案或者構建歷史相關檔案被刪除",
 	"i18n_0306ea1908":"刪除映象",
 	"i18n_031020489f":"當前工作空間您觸發的構建記錄",
+	"i18n_03113c0f1a":"真的要刪除 FTP 麼?",
 	"i18n_03580275cb":"請選中要重啟的專案",
 	"i18n_0360fffb40":"並開啟此開關",
 	"i18n_036c0dc2aa":"系統取消分發",
@@ -83,6 +84,7 @@
 	"i18n_080b914139":"上傳包",
 	"i18n_0836332bf6":"升級協議",
 	"i18n_083b8a2ec9":"一個物理節點被多個服務端繫結也會產生孤獨資料奧",
+	"i18n_087c992cc0":"被動模式",
 	"i18n_08902526f1":"面板:",
 	"i18n_0895c740a6":"交換記憶體佔用",
 	"i18n_089a88ecee":"系統時間:",
@@ -136,6 +138,7 @@
 	"i18n_0ce54ecc25":"付費社群",
 	"i18n_0cf4f0ba82":"真的要儲存當前配置嗎?如果配置有誤,可能無法啟動服務需要手動還原奧!!! 儲存成功後請及時關注重啟狀態!!",
 	"i18n_0cf81d77bb":"請填寫倉庫地址",
+	"i18n_0d1ee51203":"系統關鍵詞",
 	"i18n_0d44f4903a":"真的要釋放(刪除)當前專案麼?",
 	"i18n_0d467f7889":"# 是否開啟日誌備份功能",
 	"i18n_0d48f8e881":"請輸入服務地址",
@@ -213,6 +216,7 @@
 	"i18n_143bfbc3a1":"點選重新同步當前工作空間邏輯節點專案資訊",
 	"i18n_143d8d3de5":"否則將刪除滿足條件的所有資料",
 	"i18n_148484b985":"實現您需要配置 docker 容器到服務端中來管理,並且分配到當前工作空間中",
+	"i18n_148d37218a":"FTP 名稱",
 	"i18n_1498557b2d":"同時只能展開一個選單",
 	"i18n_14a25beebb":"10秒一次",
 	"i18n_14d342362f":"標籤",
@@ -281,6 +285,7 @@
 	"i18n_1a8f90122f":"提示資訊 ",
 	"i18n_1abf39bdb6":"# 將此目錄快取到全域性(多個構建可以共享此快取目錄)",
 	"i18n_1ad696efdc":"構建執行的命令(非阻塞命令),如:mvn clean package、npm run build。支援變數:{'${BUILD_ID}'}、{'${BUILD_NAME}'}、{'${BUILD_SOURCE_FILE}'}、{'${BUILD_NUMBER_ID}'}、倉庫目錄下 .env、工作空間變數",
+	"i18n_1add83f77b":"ftp名稱",
 	"i18n_1ae2955867":"指定 pom 檔案打包 mvn -f xxx/pom.xml clean package",
 	"i18n_1afdb4a364":"隱藏滾動條。縱向滾動方式提醒:滾輪,橫行滾動方式:Shift+滾輪",
 	"i18n_1b03b0c1ff":"已經分配到工作空間的 Docker 或者叢集無法直接刪除,需要到分配到的各個工作空間逐一刪除後才能刪除資產 Docker 或者叢集",
@@ -460,6 +465,7 @@
 	"i18n_29b48a76be":"請選擇釋出方式",
 	"i18n_29efa328e5":"未分發",
 	"i18n_2a049f4f5b":"分發失敗",
+	"i18n_2a04f7b9be":"如果按鈕不可用,請去資產管理 ftp 列表的關聯中新增當前工作空間允許管理的授權資料夾",
 	"i18n_2a0bea27c4":"執行域",
 	"i18n_2a0c4740f1":"檔案",
 	"i18n_2a1d1da97a":"打包測試環境包 mvn clean package -Dmaven.test.skip=true -Ptest",
@@ -572,6 +578,7 @@
 	"i18n_32d0576d85":"的令牌",
 	"i18n_32dcc6f36e":"重啟策略:no、always、unless-stopped、on-failure",
 	"i18n_32e05f01f4":"叢集資訊",
+	"i18n_32e3c8b702":"釋出的FTP",
 	"i18n_32f882ae24":"匹配零個或多個字元",
 	"i18n_330363dfc5":"成功",
 	"i18n_3306c2a7c7":"讀取預設",
@@ -659,6 +666,7 @@
 	"i18n_3b94c70734":"專案狀態",
 	"i18n_3ba621d736":"處理成功",
 	"i18n_3baa9f3d72":"批量構建引數還支援指定引數,delay(延遲執行構建,單位秒)branchName(分支名)、branchTagName(標籤)、script(構建指令碼)、resultDirFile(構建產物)、webhook(通知webhook)",
+	"i18n_3bc3bdc031":"請到【系統管理】-> 【資產管理】-> 【FTP管理】新增FTP,或者將已新增的FTP授權關聯、分配到此工作空間",
 	"i18n_3bc5e602b2":"郵箱",
 	"i18n_3bcc1c7a20":"最後修改人",
 	"i18n_3bdab2c607":"10分鐘",
@@ -673,6 +681,7 @@
 	"i18n_3c6fa6f667":"cron表示式",
 	"i18n_3c8eada338":"請選擇編碼方式",
 	"i18n_3c91490844":"釋出操作",
+	"i18n_3c943b89c6":"此編輯僅能編輯當前 FTP 在此工作空間的名稱資訊",
 	"i18n_3c99ea4ec2":"例如 2,3,6/3中,由於“/”優先順序高,因此相當於2,3,(6/3),結果與 2,3,6等價",
 	"i18n_3c9eeee356":"真的要刪除日誌檔案麼?",
 	"i18n_3cc09369ad":"真的要刪除【",
@@ -849,6 +858,7 @@
 	"i18n_4b96762a7e":"最後修改時間",
 	"i18n_4b9c3271dc":"重置",
 	"i18n_4ba304e77a":"釘釘賬號登入",
+	"i18n_4bb37cc406":"伺服器語言",
 	"i18n_4bbc09fc55":"在檔案第 3 - 20 行中搜尋",
 	"i18n_4c096c51a3":"埠號:",
 	"i18n_4c0eead6ff":"新增引數",
@@ -867,6 +877,7 @@
 	"i18n_4d18dcbd15":"真的要還原備份資訊麼?",
 	"i18n_4d351f3c91":"禁止 IP",
 	"i18n_4d49b2a15f":"自動執行:docker",
+	"i18n_4d4ab2f8f5":"當前 FTP 的授權目錄(檔案目錄、檔案字尾)需要請到 【系統管理】-> 【資產管理】-> 【FTP 管理】-> 操作欄中->關聯按鈕->對應工作空間->操作欄中->配置按鈕",
 	"i18n_4d775d4cd7":"顯示",
 	"i18n_4d7dc6c5f8":"寫",
 	"i18n_4d85ac1250":"系統管理",
@@ -1126,6 +1137,7 @@
 	"i18n_649d90ab3c":"關閉右側",
 	"i18n_649f8046f3":"請選擇SSH節點",
 	"i18n_64c083c0a9":"結果描述",
+	"i18n_64c8791ba1":"配置方式:FTP管理->操作欄中->關聯按鈕->對應工作空間->操作欄中->配置按鈕",
 	"i18n_64eee9aafa":"開機時間",
 	"i18n_652273694e":"主機",
 	"i18n_65571516e2":"構建備註:",
@@ -1144,6 +1156,7 @@
 	"i18n_66ab5e9f24":"新增",
 	"i18n_66b71b06c6":"上傳壓縮檔案(自動解壓)",
 	"i18n_66c15f2815":"匹配包含數字的行",
+	"i18n_66e623e6f8":"配置ftp",
 	"i18n_66e9ea5488":"日誌名稱",
 	"i18n_6707667676":"主機名",
 	"i18n_6709f4548f":"隨機生成",
@@ -1329,6 +1342,7 @@
 	"i18n_77373db7d8":"接收報警訊息,非必填,GET請求",
 	"i18n_7737f088de":"批量重新啟動",
 	"i18n_773b1a5ef6":"請選擇語言模式",
+	"i18n_774aecfd99":"如果要配置 FTP 請到【系統管理】-> 【資產管理】-> 【FTP 管理】中去配置。",
 	"i18n_775fde44cf":"程序埠快取:",
 	"i18n_7760785daf":"自由指令碼",
 	"i18n_7764df7ccc":"開啟差異釋出但不開啟清空釋出時相當於只做增量和變動更新",
@@ -1406,6 +1420,7 @@
 	"i18n_7e930b95ef":"釋出檔案",
 	"i18n_7e951d56d9":"操作時間",
 	"i18n_7e9f0d2606":"專案是指,節點中的某一個專案,需要提前在節點中建立專案",
+	"i18n_7eef73a0eb":"編輯FTP",
 	"i18n_7ef30cfd31":"附加環境變數是指讀取倉庫指定環境變數檔案來新增到執行構建執行時",
 	"i18n_7f0abcf48d":"需要到編輯中去為一個節點繫結一個 ssh資訊才能啟用該功能",
 	"i18n_7f3809d36b":"構建結束",
@@ -1424,6 +1439,7 @@
 	"i18n_8086beecb3":"標籤名稱:",
 	"i18n_808c18d2bb":"值為 true 表示專案當前為執行中",
 	"i18n_809b12d6a0":"請耐心等待暫時不用重新整理頁面",
+	"i18n_80b7af89ee":"當前工作空間還沒有FTP",
 	"i18n_80cfc33cbe":"確認重置",
 	"i18n_81301b6813":"開啟終端",
 	"i18n_81485b76d8":"請輸入主機地址",
@@ -1449,6 +1465,7 @@
 	"i18n_8306971039":"所屬使用者",
 	"i18n_8309cec640":"請選擇節點專案,可能是節點中不存在任何專案,需要去節點中建立專案",
 	"i18n_833249fb92":"當前檔案用時",
+	"i18n_8339e5e8e9":"如果多選 ftp 下面目錄只顯示選項中的第一項,但是授權目錄需要保證每項都配置對應目錄",
 	"i18n_8347a927c0":"修改",
 	"i18n_835050418f":"確認要上傳最新的外掛包嗎?",
 	"i18n_8351876236":"別名 ",
@@ -1635,6 +1652,7 @@
 	"i18n_917381e4a5":"當前下載源:",
 	"i18n_91985e3574":"自動探測",
 	"i18n_91a10b8776":" 指令碼庫 ",
+	"i18n_91a828d055":"真的要清除 FTP 隱藏欄位資訊麼?(密碼)",
 	"i18n_920f05031b":"狀態描述",
 	"i18n_922b76febd":"執行模式必填",
 	"i18n_923f8d2688":"釋出後命令",
@@ -1867,6 +1885,7 @@
 	"i18n_a436c94494":"飛書掃碼",
 	"i18n_a472019766":"節點Id",
 	"i18n_a497562c8e":"執行人",
+	"i18n_a49f609d09":"主動模式",
 	"i18n_a4f5cae8d2":"開啟狀態",
 	"i18n_a4f629041c":"路徑需要配置絕對路徑",
 	"i18n_a50fbc5a52":"支援指定網絡卡名稱來繫結:",
@@ -2345,6 +2364,7 @@
 	"i18n_cd998f12fa":"當目標工作空間已經存在節點時候將自動同步節點授權資訊、代理配置資訊",
 	"i18n_cda84be2f6":"操作日誌",
 	"i18n_cdc478d90c":"系統名",
+	"i18n_cdf2e36c2a":"FTP名稱",
 	"i18n_ce043fac7d":"當前工作空間還沒有SSH",
 	"i18n_ce07501354":"點選數字檢視執行中的任務",
 	"i18n_ce1c5765e4":"檢視釋出模板",
@@ -2358,6 +2378,7 @@
 	"i18n_ceee1db95a":"容器埠",
 	"i18n_ceffe5d643":"兩步驗證應用",
 	"i18n_cf38e8f9fd":"當前為節點分發的授權路徑配置",
+	"i18n_cf93cd2cde":"請選擇FTP",
 	"i18n_cfa72dd73a":"請輸入要檢查的 cron 表示式",
 	"i18n_cfb00269fd":"執行指令碼",
 	"i18n_cfbb3341d5":"當前登入的賬號是:",
@@ -2411,6 +2432,7 @@
 	"i18n_d4aea8d7e6":"執行次數",
 	"i18n_d4e03f60a9":"外掛端啟動的時候檢查專案狀態,如果專案狀態是未執行則嘗試執行啟動專案",
 	"i18n_d5269713c7":"表示構建產物為資料夾時將打包為",
+	"i18n_d55b5f6ce4":"傳輸模式",
 	"i18n_d57796d6ac":" :範圍:0~59",
 	"i18n_d584e1493b":"搜尋ssh名稱",
 	"i18n_d58a55bcee":"關",
@@ -2433,6 +2455,7 @@
 	"i18n_d731dc9325":"時間戳:",
 	"i18n_d7471c0261":"請選擇執行節點",
 	"i18n_d75c02d050":"停止專案",
+	"i18n_d769de863b":"關聯工作空間ftp",
 	"i18n_d7ac764d3a":"分發間隔時間 (順序重啟、完整順序重啟)方式才生效",
 	"i18n_d7ba18c360":"分發節點是指在編輯完指令碼後自動將指令碼內容同步節點的指令碼中",
 	"i18n_d7bebd0e5e":"狀態操作請到控制檯中控制",
@@ -2536,6 +2559,7 @@
 	"i18n_df9d1fedc5":"節點分發是指,一個專案部署在多個節點中使用節點分發一步完成多個節點中的專案釋出操作",
 	"i18n_dfb8d511c7":"使用者名稱稱",
 	"i18n_dfcc9e3c45":"分發後操作",
+	"i18n_e020a4df74":"伺服器系統關鍵詞",
 	"i18n_e039ffccc8":"】此檔案還原到專案目錄?",
 	"i18n_e049546ff3":"【系統配置目錄】中修改",
 	"i18n_e06497b0fb":"檢視當前可用容器",
@@ -2645,9 +2669,11 @@
 	"i18n_ea8a79546f":"請輸入釋出的檔案id",
 	"i18n_ea9f824647":"拉取倉庫超時時間,單位秒",
 	"i18n_eaa5d7cb9b":"過期天數",
+	"i18n_eaa85849f3":"如果 ftp 沒有配置授權目錄是不能選擇的喲",
 	"i18n_eadd05ba6a":"中等",
 	"i18n_eaf987eea0":"權重(相對權重)。",
 	"i18n_eb164b696d":"排除釋出",
+	"i18n_eb3a60fbc0":"編輯 FTP",
 	"i18n_eb5bab1c31":"非必填",
 	"i18n_eb79cea638":"週五",
 	"i18n_eb7f9ceb71":"指令碼庫:",
@@ -2706,6 +2732,7 @@
 	"i18n_f038f48ce5":"編輯指令碼",
 	"i18n_f04a289502":"svn ssh 必填登入使用者",
 	"i18n_f05e3ec44d":"禁止訪問,當前IP限制訪問",
+	"i18n_f06a391743":"已經分配到工作空間的 FTP 無法直接刪除,需要到分配到的各個工作空間逐一刪除後才能刪除資產 FTP",
 	"i18n_f06f95f8e6":"孤獨資料",
 	"i18n_f087eb347c":"構建命令示例",
 	"i18n_f08afd1f82":"已選擇",
@@ -2807,6 +2834,7 @@
 	"i18n_fad1b9fb87":"新增指令碼模版需要到節點管理中去新增",
 	"i18n_fb1f3b5125":"當前工作空間關聯資料統計",
 	"i18n_fb3a2241bb":"狀態描述:",
+	"i18n_fb5037a644":"此配置僅對服務端管理生效, 工作空間的 ftp 配置需要單獨配置",
 	"i18n_fb5bc565f3":"解析檔案失敗:",
 	"i18n_fb61d4d708":"真的要回滾該構建歷史記錄麼?",
 	"i18n_fb7b9876a6":"請輸入指令碼名稱",
@@ -2831,6 +2859,7 @@
 	"i18n_fcbf0d0a55":"需要先安裝依賴 yarn && yarn run build",
 	"i18n_fcca8452fe":"叢集地址主要用於切換工作空間自動跳轉到對應的叢集",
 	"i18n_fcef976c7a":"私鑰內容",
+	"i18n_fcfbc11bb9":"密碼欄位在編輯的時候不會返回,如果需要重置或者清空就請點我",
 	"i18n_fd6e80f1e0":"正常",
 	"i18n_fd7b461411":"不清空",
 	"i18n_fd7e0c997d":"選擇檔案",

+ 136 - 2
web-vue/src/pages/build/edit.vue

@@ -886,6 +886,73 @@
                   </a-form-item-rest>
                 </a-form-item>
               </template>
+
+              <!-- FTP -->
+              <template v-if="temp.releaseMethod === 6">
+                <a-form-item name="releaseMethodDataId" :help="$t('i18n_eaa85849f3')">
+                  <template #label>
+                    <a-tooltip
+                      >{{ $t('i18n_32e3c8b702') }}<template #title>{{ $t('i18n_eaa85849f3') }}</template>
+                      <QuestionCircleOutlined v-if="!temp.id" />
+                    </a-tooltip>
+                  </template>
+                  <a-row>
+                    <a-col :span="22">
+                      <a-select
+                        v-model:value="tempExtraData.releaseMethodDataId_6"
+                        show-search
+                        :filter-option="
+                          (input, option) => {
+                            const children = option.children && option.children()
+                            return (
+                              children &&
+                              children[0].children &&
+                              children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                            )
+                          }
+                        "
+                        mode="multiple"
+                        :placeholder="$t('i18n_cf93cd2cde')"
+                      >
+                        <a-select-option v-for="ftp in ftpList" :key="ftp.id" :disabled="!ftp.fileDirs">
+                          <a-tooltip :title="ftp.name"> {{ ftp.name }}</a-tooltip>
+                        </a-select-option>
+                      </a-select>
+                    </a-col>
+                    <a-col :span="1" style="margin-left: 10px">
+                      <ReloadOutlined @click="loadFtpList" />
+                    </a-col>
+                  </a-row>
+                </a-form-item>
+                <a-form-item name="releaseMethodDataId" :help="$t('i18n_8339e5e8e9')">
+                  <template #label>
+                    <a-tooltip :title="$t('i18n_8339e5e8e9')">
+                      {{ $t('i18n_dbb2df00cf') }}
+                      <QuestionCircleOutlined v-if="!temp.id" />
+                    </a-tooltip>
+                  </template>
+                  <a-input-group compact>
+                    <a-select
+                      v-model:value="tempExtraData.releaseFtpDir"
+                      show-search
+                      allow-clear
+                      style="width: 30%"
+                      :placeholder="$t('i18n_cf93cd2cde')"
+                    >
+                      <a-select-option v-for="item in selectFtpDirs" :key="item">
+                        <a-tooltip :title="item">{{ item }}</a-tooltip>
+                      </a-select-option>
+                    </a-select>
+                    <a-form-item-rest>
+                      <a-input
+                        v-model:value="tempExtraData.releasePath3"
+                        style="width: 70%"
+                        :placeholder="$t('i18n_a75a5a9525')"
+                      />
+                    </a-form-item-rest>
+                  </a-input-group>
+                </a-form-item>
+              </template>
             </template>
           </div>
 
@@ -1266,8 +1333,8 @@
           chooseScriptVisible === 1
             ? tempExtraData.noticeScriptId
             : temp.script?.indexOf('$ref.script.') != -1
-              ? temp.script.replace('$ref.script.', '')
-              : ''
+            ? temp.script.replace('$ref.script.', '')
+            : ''
         "
         mode="choose"
         @confirm="
@@ -1384,6 +1451,7 @@ import {
   getBuildGet
 } from '@/api/build-info'
 import { getSshListAll } from '@/api/ssh'
+import { getFtpListAll } from '@/api/ftp'
 import { getRepositoryInfo } from '@/api/repository'
 import { getNodeListAll, getProjectListAll } from '@/api/node'
 // import { getScriptListAll } from "@/api/server-script";
@@ -1497,6 +1565,7 @@ export default {
       dispatchList: [],
       cascaderList: [],
       sshList: [],
+      ftpList: [],
       dockerSwarmList: [],
       //集群下 服务下拉数据
       swarmServiceListOptions: [],
@@ -1658,6 +1727,27 @@ export default {
       }
       return []
     },
+    selectFtpDirs() {
+      if (!this.ftpList || this.ftpList.length <= 0) {
+        return []
+      }
+      const findArray = this.ftpList.filter((item) => {
+        if (Array.isArray(this.tempExtraData.releaseMethodDataId_6)) {
+          return item.id === this.tempExtraData.releaseMethodDataId_6[0]
+        }
+        return item.id === this.tempExtraData.releaseMethodDataId_6
+      })
+      if (findArray.length) {
+        const fileDirs = findArray[0].fileDirs
+        if (!fileDirs) {
+          return []
+        }
+        return JSON.parse(fileDirs).map((item) => {
+          return (item + '/').replace(new RegExp('//', 'gm'), '/')
+        })
+      }
+      return []
+    },
     buildModeArray() {
       return Object.keys(this.buildModeMap).map((item) => {
         return {
@@ -1714,6 +1804,7 @@ export default {
       this.loadDispatchList()
       this.loadNodeProjectList()
       this.loadSshList()
+      this.loadFtpList()
       this.loadDockerSwarmListAll()
       // this.loadScriptListList();
 
@@ -1766,6 +1857,9 @@ export default {
         if (record.releaseMethod === 3) {
           this.tempExtraData.releaseMethodDataId_3 = this.tempExtraData.releaseMethodDataId.split(',')
         }
+        if (record.releaseMethod === 6) {
+          this.tempExtraData.releaseMethodDataId_6 = this.tempExtraData.releaseMethodDataId.split(',')
+        }
       }
       this.tempExtraData = { ...this.tempExtraData }
       this.changeRepositpry(true)
@@ -1792,6 +1886,25 @@ export default {
           }
         }
       })
+
+      this.loadFtpList().then(() => {
+        if (this.tempExtraData.releaseMethodDataId_6) {
+          //
+          const findDirs = this.selectFtpDirs
+            .filter((item) => {
+              return this.tempExtraData.releaseFtpPath && this.tempExtraData.releaseFtpPath.indexOf(item) > -1
+            })
+            .sort((item1, item2) => {
+              return item2.length - item1.length
+            })
+          const releaseFtpDir = findDirs[0] || ''
+          this.tempExtraData = {
+            ...this.tempExtraData,
+            releaseFtpDir: releaseFtpDir,
+            releasePath3: (this.tempExtraData.releaseFtpPath || '').slice(releaseFtpDir.length)
+          }
+        }
+      })
       // 默认打开构建流程
       // this.stepsCurrent = this.editSteps
     },
@@ -1884,6 +1997,7 @@ export default {
             tempExtraData.releaseMethodDataId_2_node = this.temp.releaseMethodDataIdList[0]
             tempExtraData.releaseMethodDataId_2_project = this.temp.releaseMethodDataIdList[1]
           } else if (this.temp.releaseMethod === 3) {
+            // ssh
             //  (this. tempExtraData.releasePath || '').slice(releaseSshDir.length);
             tempExtraData.releasePath = (
               (tempExtraData.releaseSshDir || '') +
@@ -1891,6 +2005,14 @@ export default {
               (tempExtraData.releasePath2 || '')
             ).replace(new RegExp('//', 'gm'), '/')
             tempExtraData.releaseMethodDataId_3 = (tempExtraData.releaseMethodDataId_3 || []).join(',')
+          } else if (this.temp.releaseMethod === 6) {
+            // ftp
+            tempExtraData.releaseFtpPath = (
+              (tempExtraData.releaseFtpDir || '') +
+              '/' +
+              (tempExtraData.releasePath3 || '')
+            ).replace(new RegExp('//', 'gm'), '/')
+            tempExtraData.releaseMethodDataId_6 = (tempExtraData.releaseMethodDataId_6 || []).join(',')
           }
 
           this.temp = {
@@ -1975,6 +2097,18 @@ export default {
         })
       })
     },
+    // 加载 FTP 列表
+    loadFtpList() {
+      return new Promise((resolve) => {
+        this.ftpList = []
+        getFtpListAll().then((res) => {
+          if (res.code === 200) {
+            this.ftpList = res.data
+            resolve()
+          }
+        })
+      })
+    },
     //
     loadDockerSwarmListAll() {
       dockerSwarmListAll().then((res) => {

+ 22 - 23
web-vue/src/pages/ftp/ftp.vue

@@ -1,7 +1,7 @@
 <template>
   <div>
     <template v-if="useSuggestions">
-      <a-result title="当前工作空间还没有FTP" sub-title="请到【系统管理】-> 【资产管理】-> 【FTP管理】新增FTP,或者将已新增的FTP授权关联、分配到此工作空间">
+      <a-result :title="$t('i18n_80b7af89ee')" :sub-title="$t('i18n_3bc3bdc031')">
         <template #extra>
           <router-link to="/system/assets/ftp-list">
             <a-button key="console" type="primary">{{ $t('i18n_6dcf6175d8') }}</a-button></router-link
@@ -36,7 +36,7 @@
           <a-input
             v-model:value="listQuery['%name%']"
             class="search-input-item"
-            placeholder="ftp名称"
+            :placeholder="$t('i18n_1add83f77b')"
             @press-enter="loadData"
           />
           <a-select
@@ -71,7 +71,7 @@
         </a-space>
       </template>
 
-<!--      <template #tableHelp>
+      <!--      <template #tableHelp>
         <a-tooltip>
           <template #title>
             <div>
@@ -116,7 +116,7 @@
 
         <template v-else-if="column.dataIndex === 'operation'">
           <a-space>
-<!--            <a-dropdown>
+            <!--            <a-dropdown>
               <a-button size="small" type="primary" @click="handleTerminal(record, false)"
                 >{{ $t('i18n_4722bc0c56') }}<DownOutlined
               /></a-button>
@@ -147,23 +147,21 @@
               <a-button size="small" type="primary" @click="handleFile(record)">{{ $t('i18n_2a0c4740f1') }}</a-button>
             </template>
             <template v-else>
-              <a-tooltip placement="topLeft" title="如果按钮不可用,请去资产管理 ftp 列表的关联中新增当前工作空间允许管理的授权文件夹">
+              <a-tooltip placement="topLeft" :title="$t('i18n_2a04f7b9be')">
                 <a-button size="small" type="primary" :disabled="true">{{ $t('i18n_2a0c4740f1') }}</a-button>
               </a-tooltip>
             </template>
 
-            <a-tooltip placement="topLeft" title="如果按钮不可用,请去资产管理 ftp 列表的关联中新增当前工作空间允许管理的授权文件夹">
-              <a-button size="small" type="primary" @click="handleEdit(record)">{{
-                  $t('i18n_95b351c862')
-                }}</a-button>
+            <a-tooltip placement="topLeft" :title="$t('i18n_2a04f7b9be')">
+              <a-button size="small" type="primary" @click="handleEdit(record)">{{ $t('i18n_95b351c862') }}</a-button>
             </a-tooltip>
-            <a-tooltip placement="topLeft" title="如果按钮不可用,请去资产管理 ftp 列表的关联中新增当前工作空间允许管理的授权文件夹">
+            <a-tooltip placement="topLeft" :title="$t('i18n_2a04f7b9be')">
               <a-button size="small" type="primary" danger @click="handleDelete(record)">{{
-                  $t('i18n_2f4aaddde3')
-                }}</a-button>
+                $t('i18n_2f4aaddde3')
+              }}</a-button>
             </a-tooltip>
 
-<!--            <a-dropdown>
+            <!--            <a-dropdown>
               <a @click="(e) => e.preventDefault()">
                 {{ $t('i18n_0ec9eaf9c3') }}
                 <DownOutlined />
@@ -188,7 +186,6 @@
                 </a-menu>
               </template>
             </a-dropdown>-->
-
           </a-space>
         </template>
       </template>
@@ -199,7 +196,7 @@
       v-model:open="editFtpVisible"
       destroy-on-close
       width="600px"
-      title="编辑 FTP"
+      :title="$t('i18n_eb3a60fbc0')"
       :mask-closable="false"
       :confirm-loading="confirmLoading"
       @ok="handleEditSshOk"
@@ -209,15 +206,17 @@
           <a-alert type="info" show-icon style="width: 100%; margin-bottom: 10px">
             <template #message>
               <ul>
-                <li>{{ "此编辑仅能编辑当前 FTP 在此工作空间的名称信" }}</li>
-                <li>{{ "如果要配置 FTP 请到【系统管理】-> 【资产管理】-> 【FTP 管理】中去配置。" }}</li>
-                <li>{{ "当前 FTP 的授权目录(文件目录、文件后缀)需要请到 【系统管理】-> 【资产管理】-> 【FTP 管理】-> 操作栏中->关联按钮->对应工作空间->操作栏中->配置按钮" }}</li>
+                <li>{{ $t('i18n_3c943b89c6') }}</li>
+                <li>{{ $t('i18n_774aecfd99') }}</li>
+                <li>
+                  {{ $t('i18n_4d4ab2f8f5') }}
+                </li>
               </ul>
             </template>
           </a-alert>
         </template>
-        <a-form-item label="FTP 名称" name="name">
-          <a-input v-model:value="temp.name" :max-length="50" placeholder="FTP 名称" />
+        <a-form-item :label="$t('i18n_148d37218a')" name="name">
+          <a-input v-model:value="temp.name" :max-length="50" :placeholder="$t('i18n_148d37218a')" />
         </a-form-item>
         <a-form-item :label="$t('i18n_1014b33d22')" name="group">
           <custom-select
@@ -315,7 +314,7 @@ import {
   PAGE_DEFAULT_LIST_QUERY,
   parseTime,
   renderSize,
-  formatDuration,
+  formatDuration
 } from '@/utils/const'
 import { getWorkSpaceListAll } from '@/api/workspace'
 
@@ -373,7 +372,7 @@ export default {
         },
 
         {
-          title: "端口",
+          title: this.$t('i18n_c76cfefe72'),
           dataIndex: ['machineFtp', 'port'],
           width: 80,
           ellipsis: true
@@ -533,7 +532,7 @@ export default {
       $confirm({
         title: this.$t('i18n_c4535759ee'),
         zIndex: 1009,
-        content: "真的要删除 FTP 么?",
+        content: this.$t('i18n_03113c0f1a'),
         okText: this.$t('i18n_e83a256e4f'),
         cancelText: this.$t('i18n_625fb26b4b'),
         onOk: () => {

+ 102 - 123
web-vue/src/pages/system/assets/ftp/ftp-list.vue

@@ -11,12 +11,11 @@
       :columns="columns"
       size="middle"
       :pagination="pagination"
-
       row-key="id"
       :row-selection="rowSelection"
       :scroll="{
-            x: 'max-content'
-          }"
+        x: 'max-content'
+      }"
       @change="changePage"
       @refresh="loadData"
     >
@@ -25,7 +24,7 @@
           <a-input
             v-model:value="listQuery['%name%']"
             class="search-input-item"
-            placeholder="ftp名称"
+            :placeholder="$t('i18n_1add83f77b')"
             @press-enter="loadData"
           />
           <a-input
@@ -38,15 +37,15 @@
             v-model:value="listQuery.groupName"
             show-search
             :filter-option="
-                  (input, option) => {
-                    const children = option.children && option.children()
-                    return (
-                      children &&
-                      children[0].children &&
-                      children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
-                    )
-                  }
-                "
+              (input, option) => {
+                const children = option.children && option.children()
+                return (
+                  children &&
+                  children[0].children &&
+                  children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                )
+              }
+            "
             allow-clear
             :placeholder="$t('i18n_829abe5a8d')"
             class="search-input-item"
@@ -61,14 +60,11 @@
           <a-button type="primary" @click="handleAdd">{{ $t('i18n_66ab5e9f24') }}</a-button>
           <a-button :disabled="!tableSelections.length" type="primary" @click="syncToWorkspaceShow()">
             {{ $t('i18n_82d2c66f47') }}
-          </a-button
-          >
-          <a-button type="primary" @click="handlerExportData()"
-          >
-            <DownloadOutlined/>
+          </a-button>
+          <a-button type="primary" @click="handlerExportData()">
+            <DownloadOutlined />
             {{ $t('i18n_55405ea6ff') }}
-          </a-button
-          >
+          </a-button>
           <a-dropdown>
             <template #overlay>
               <a-menu>
@@ -87,9 +83,9 @@
               :before-upload="beforeUpload"
             >
               <a-button type="primary">
-                <UploadOutlined/>
+                <UploadOutlined />
                 {{ $t('i18n_8d9a071ee2') }}
-                <DownOutlined/>
+                <DownOutlined />
               </a-button>
             </a-upload>
           </a-dropdown>
@@ -106,7 +102,7 @@
               </ul>
             </div>
           </template>
-          <QuestionCircleOutlined/>
+          <QuestionCircleOutlined />
         </a-tooltip>
       </template>
       <template #tableBodyCell="{ column, text, record }">
@@ -122,12 +118,10 @@
           <a-tooltip :title="`${text}:${record.port}`"> {{ text }}:{{ record.port }}</a-tooltip>
         </template>
 
-
         <template v-else-if="column.dataIndex === 'status'">
           <a-tooltip :title="`${record.statusMsg || $t('i18n_77e100e462')}`">
-            <a-tag :color="statusMap[record.status] && statusMap[record.status].color">{{
-                (statusMap[record.status] && statusMap[record.status].desc) || $t('i18n_1622dc9b6b')
-              }}
+            <a-tag :color="statusMap[record.status] && statusMap[record.status].color"
+              >{{ (statusMap[record.status] && statusMap[record.status].desc) || $t('i18n_1622dc9b6b') }}
             </a-tag>
           </a-tooltip>
         </template>
@@ -138,33 +132,29 @@
         </template>
         <template v-else-if="column.dataIndex === 'operation'">
           <a-space>
-            <a-button size="small" type="primary" @click="syncToWorkspaceShow(record)">{{
-                $t('i18n_e39de3376e')
-              }}
+            <a-button size="small" type="primary" @click="syncToWorkspaceShow(record)"
+              >{{ $t('i18n_e39de3376e') }}
             </a-button>
             <a-button size="small" type="primary" @click="handleFile(record)">{{ $t('i18n_2a0c4740f1') }}</a-button>
-            <a-button size="small" type="primary" @click="handleViewWorkspaceFtp(record)">{{
-                $t('i18n_1c3cf7f5f0')
-              }}
+            <a-button size="small" type="primary" @click="handleViewWorkspaceFtp(record)"
+              >{{ $t('i18n_1c3cf7f5f0') }}
             </a-button>
 
             <a-dropdown>
               <a @click="(e) => e.preventDefault()">
                 {{ $t('i18n_0ec9eaf9c3') }}
-                <DownOutlined/>
+                <DownOutlined />
               </a>
               <template #overlay>
                 <a-menu>
                   <a-menu-item>
-                    <a-button size="small" type="primary" @click="handleEdit(record)">{{
-                        $t('i18n_95b351c862')
-                      }}
+                    <a-button size="small" type="primary" @click="handleEdit(record)"
+                      >{{ $t('i18n_95b351c862') }}
                     </a-button>
                   </a-menu-item>
                   <a-menu-item>
-                    <a-button size="small" type="primary" danger @click="handleDelete(record)">{{
-                        $t('i18n_2f4aaddde3')
-                      }}
+                    <a-button size="small" type="primary" danger @click="handleDelete(record)"
+                      >{{ $t('i18n_2f4aaddde3') }}
                     </a-button>
                   </a-menu-item>
                   <!--                      <a-menu-item>
@@ -187,13 +177,13 @@
       destroy-on-close
       :confirm-loading="confirmLoading"
       width="600px"
-      title="编辑FTP"
+      :title="$t('i18n_7eef73a0eb')"
       :mask-closable="false"
       @ok="handleEditFtpOk"
     >
       <a-form ref="editFtpForm" :rules="rules" :model="temp" :label-col="{ span: 4 }" :wrapper-col="{ span: 18 }">
-        <a-form-item label="FTP名称" name="name">
-          <a-input v-model:value="temp.name" :max-length="50" placeholder="FTP名称"/>
+        <a-form-item :label="$t('i18n_cdf2e36c2a')" name="name">
+          <a-input v-model:value="temp.name" :max-length="50" :placeholder="$t('i18n_cdf2e36c2a')" />
         </a-form-item>
         <a-form-item :label="$t('i18n_1014b33d22')" name="group">
           <custom-select
@@ -212,14 +202,14 @@
                     {{ $t('i18n_f92d505ff5') }}
                   </div>
                 </template>
-                <QuestionCircleOutlined/>
+                <QuestionCircleOutlined />
               </a-tooltip>
             </template>
           </custom-select>
         </a-form-item>
         <a-form-item label="Host" name="host">
           <a-input-group compact name="host">
-            <a-input v-model:value="temp.host" style="width: 70%" :placeholder="$t('i18n_3d83a07747')"/>
+            <a-input v-model:value="temp.host" style="width: 70%" :placeholder="$t('i18n_3d83a07747')" />
             <a-form-item-rest>
               <a-input-number
                 v-model:value="temp.port"
@@ -230,8 +220,8 @@
             </a-form-item-rest>
           </a-input-group>
         </a-form-item>
-        <a-form-item label="传输模式" name="mode">
-          <a-radio-group v-model:value="temp.mode" :options="options"/>
+        <a-form-item :label="$t('i18n_d55b5f6ce4')" name="mode">
+          <a-radio-group v-model:value="temp.mode" :options="options" />
         </a-form-item>
         <a-form-item name="user">
           <template #label>
@@ -239,17 +229,15 @@
               {{ $t('i18n_819767ada1') }}
               <template #title>
                 {{ $t('i18n_f0a1428f65') }}<b>$ref.wEnv.xxxx</b> xxxx {{ $t('i18n_c1b72e7ded') }}
-              </template
-              >
-              <QuestionCircleOutlined v-if="!temp.id"/>
+              </template>
+              <QuestionCircleOutlined v-if="!temp.id" />
             </a-tooltip>
           </template>
           <a-input v-model:value="temp.user" :placeholder="$t('i18n_1fd02a90c3')">
             <template #suffix>
-              <a-tooltip v-if="temp.id" title="密码字段在编辑的时候不会返回,如果需要重置或者清空就请点我">
-                <a-button size="small" type="primary" danger @click="handerRestHideField(temp)">{{
-                    $t('i18n_4403fca0c0')
-                  }}
+              <a-tooltip v-if="temp.id" :title="$t('i18n_fcfbc11bb9')">
+                <a-button size="small" type="primary" danger @click="handerRestHideField(temp)"
+                  >{{ $t('i18n_4403fca0c0') }}
                 </a-button>
               </a-tooltip>
             </template>
@@ -261,17 +249,14 @@
         <!--					<a-input-password v-model="temp.password" placeholder="密码"/>-->
         <!--				</a-form-item>-->
         <!-- 修改时可以不填写 -->
-        <a-form-item
-          :name="`${temp.type === 'add' ? 'password' : 'password-update'}`"
-        >
+        <a-form-item :name="`${temp.type === 'add' ? 'password' : 'password-update'}`">
           <template #label>
             <a-tooltip>
               {{ $t('i18n_a810520460') }}
               <template #title>
                 {{ $t('i18n_63dd96a28a') }}<b>$ref.wEnv.xxxx</b> xxxx {{ $t('i18n_c1b72e7ded') }}
-              </template
-              >
-              <QuestionCircleOutlined v-if="!temp.id"/>
+              </template>
+              <QuestionCircleOutlined v-if="!temp.id" />
             </a-tooltip>
           </template>
           <!-- <a-input-password v-model="temp.password" :placeholder="`${temp.type === 'add' ? '密码' : '密码若没修改可以不用填写'}`" /> -->
@@ -280,21 +265,21 @@
             :env-list="envVarList"
             :placeholder="`${temp.type === 'add' ? $t('i18n_a810520460') : $t('i18n_6c08692a3a')}`"
             @change="
-                  (v) => {
-                    temp = { ...temp, password: v }
-                  }
-                "
+              (v) => {
+                temp = { ...temp, password: v }
+              }
+            "
           >
           </custom-input>
         </a-form-item>
-        <a-form-item label="服务器语言" name="serverLanguageCode">
-          <a-input v-model:value="temp.serverLanguageCode" placeholder="服务器语言"/>
+        <a-form-item :label="$t('i18n_4bb37cc406')" name="serverLanguageCode">
+          <a-input v-model:value="temp.serverLanguageCode" :placeholder="$t('i18n_4bb37cc406')" />
         </a-form-item>
-        <a-form-item label="系统关键词" name="systemKey">
-          <a-input v-model:value="temp.systemKey" placeholder="服务器系统关键词"/>
+        <a-form-item :label="$t('i18n_0d1ee51203')" name="systemKey">
+          <a-input v-model:value="temp.systemKey" :placeholder="$t('i18n_e020a4df74')" />
         </a-form-item>
         <a-form-item :label="$t('i18n_6143a714d0')" name="charset">
-          <a-input v-model:value="temp.charset" :placeholder="$t('i18n_6143a714d0')"/>
+          <a-input v-model:value="temp.charset" :placeholder="$t('i18n_6143a714d0')" />
         </a-form-item>
         <a-form-item :label="$t('i18n_67425c29a5')" name="timeout">
           <a-input-number
@@ -305,8 +290,8 @@
           />
         </a-form-item>
         <a-form-item :label="$t('i18n_649231bdee')" name="suffix">
-          <template #help>
-            {{ "此配置仅对服务端管理生效, 工作空间的 ftp 配置需要单独配置" }}<span style="color: red">{{ "配置方式:FTP管理->操作栏中->关联按钮->对应工作空间->操作栏中->配置按钮" }}</span>
+          <template #help
+            >{{ $t('i18n_fb5037a644') }}<span style="color: red">{{ $t('i18n_64c8791ba1') }}</span>
           </template>
           <a-textarea
             v-model:value="temp.allowEditSuffix"
@@ -327,12 +312,12 @@
       width="90vw"
       :open="drawerVisible"
       @close="
-            () => {
-              drawerVisible = false
-            }
-          "
+        () => {
+          drawerVisible = false
+        }
+      "
     >
-      <ftp-file v-if="drawerVisible" :machine-ftp-id="temp.id"/>
+      <ftp-file v-if="drawerVisible" :machine-ftp-id="temp.id" />
     </CustomDrawer>
 
     <!-- 查看 ftp 关联工作空间的信息 -->
@@ -341,14 +326,14 @@
       v-model:open="viewWorkspaceFtp"
       destroy-on-close
       width="50%"
-      title="关联工作空间ftp"
+      :title="$t('i18n_d769de863b')"
       :footer="null"
       :mask-closable="false"
     >
       <a-space direction="vertical" style="width: 100%">
         <a-alert
           v-if="workspaceFtpList && workspaceFtpList.length"
-          message="已经分配到工作空间的 FTP 无法直接删除,需要到分配到的各个工作空间逐一删除后才能删除资产 FTP"
+          :message="$t('i18n_f06a391743')"
           type="info"
           show-icon
         />
@@ -360,10 +345,10 @@
                 <a-col :span="10">{{ $t('i18n_2358e1ef49') }}{{ item.workspace && item.workspace.name }}</a-col>
                 <a-col :span="4">
                   <a-button v-if="item.workspace" size="small" type="primary" @click="configWorkspaceFtp(item)"
-                  >{{ $t('i18n_224e2ccda8') }}
+                    >{{ $t('i18n_224e2ccda8') }}
                   </a-button>
                   <a-button v-else size="small" type="primary" danger @click="handleDeleteWorkspaceItem(item)"
-                  >{{ $t('i18n_2f4aaddde3') }}
+                    >{{ $t('i18n_2f4aaddde3') }}
                   </a-button>
                 </a-col>
               </a-row>
@@ -378,7 +363,7 @@
       destroy-on-close
       :confirm-loading="confirmLoading"
       width="50%"
-      title="配置ftp"
+      :title="$t('i18n_66e623e6f8')"
       :mask-closable="false"
       @ok="handleConfigWorkspaceFtpOk"
     >
@@ -390,15 +375,10 @@
         :wrapper-col="{ span: 18 }"
       >
         <a-form-item label="" :label-col="{ span: 0 }" :wrapper-col="{ span: 24 }">
-          <a-alert :message="$t('i18n_ce7e6e0ea9')" banner/>
+          <a-alert :message="$t('i18n_ce7e6e0ea9')" banner />
         </a-form-item>
-        <a-form-item label="FTP 名称">
-          <a-input
-            v-model:value="temp.name"
-            :disabled="true"
-            :max-length="50"
-            placeholder="FTP 名称"
-          />
+        <a-form-item :label="$t('i18n_148d37218a')">
+          <a-input v-model:value="temp.name" :disabled="true" :max-length="50" :placeholder="$t('i18n_148d37218a')" />
         </a-form-item>
         <a-form-item :label="$t('i18n_6a588459d0')">
           <a-input
@@ -414,7 +394,7 @@
             <a-tooltip>
               {{ $t('i18n_7a3c815b1e') }}
               <template #title> {{ $t('i18n_d0874922f0') }}</template>
-              <QuestionCircleOutlined/>
+              <QuestionCircleOutlined />
             </a-tooltip>
           </template>
           <a-textarea
@@ -474,15 +454,15 @@
               v-model:value="temp.workspaceId"
               show-search
               :filter-option="
-                    (input, option) => {
-                      const children = option.children && option.children()
-                      return (
-                        children &&
-                        children[0].children &&
-                        children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
-                      )
-                    }
-                  "
+                (input, option) => {
+                  const children = option.children && option.children()
+                  return (
+                    children &&
+                    children[0].children &&
+                    children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  )
+                }
+              "
               :placeholder="$t('i18n_b3bda9bf9e')"
             >
               <a-select-option v-for="item in workspaceList" :key="item.id">{{ item.name }}</a-select-option>
@@ -491,7 +471,6 @@
         </a-form>
       </a-space>
     </CustomModal>
-
   </div>
 </template>
 <script>
@@ -507,7 +486,7 @@ import {
   importTemplate,
   exportData,
   importData,
-  statusMap,
+  statusMap
 } from '@/api/system/assets-ftp'
 import {
   COMPUTED_PAGINATION,
@@ -523,8 +502,8 @@ import fastInstall from '@/pages/node/fast-install.vue'
 import CustomSelect from '@/components/customSelect'
 import CustomInput from '@/components/customInput'
 import FtpFile from '@/pages/ftp/ftp-file'
-import {deleteForeFtp} from '@/api/ftp'
-import {getWorkspaceEnvAll, getWorkSpaceListAll} from '@/api/workspace'
+import { deleteForeFtp } from '@/api/ftp'
+import { getWorkspaceEnvAll, getWorkSpaceListAll } from '@/api/workspace'
 
 export default {
   components: {
@@ -544,8 +523,8 @@ export default {
       statusMap,
       // 传输模式: '',
       options: [
-        {label: "主动模式", value: 'Active'},
-        {label: "被动模式", value: 'Passive'}
+        { label: this.$t('i18n_a49f609d09'), value: 'Active' },
+        { label: this.$t('i18n_087c992cc0'), value: 'Passive' }
       ],
 
       columns: [
@@ -573,25 +552,25 @@ export default {
           tooltip: true
         },
         {
-          title: "服务器语言",
+          title: this.$t('i18n_4bb37cc406'),
           dataIndex: 'serverLanguageCode',
           width: 120,
           sorter: true,
           ellipsis: true
         },
         {
-          title: '服务器系统关键词',
+          title: this.$t('i18n_e020a4df74'),
           dataIndex: 'systemKey',
           sorter: true,
           width: '100px',
           ellipsis: true
         },
         {
-          title: "编码格式",
-          dataIndex: "charset",
+          title: this.$t('i18n_6143a714d0'),
+          dataIndex: 'charset',
           sorter: true,
           width: 120,
-          ellipsis: true,
+          ellipsis: true
         },
         {
           title: this.$t('i18n_7912615699'),
@@ -605,7 +584,7 @@ export default {
           dataIndex: 'createTimeMillis',
           ellipsis: true,
           sorter: true,
-          customRender: ({text}) => parseTime(text),
+          customRender: ({ text }) => parseTime(text),
           width: '170px'
         },
         {
@@ -613,7 +592,7 @@ export default {
           dataIndex: 'modifyTimeMillis',
           sorter: true,
           ellipsis: true,
-          customRender: ({text}) => parseTime(text),
+          customRender: ({ text }) => parseTime(text),
           width: '170px'
         },
         {
@@ -629,9 +608,9 @@ export default {
 
       // 表单校验规则
       rules: {
-        name: [{required: true, message: this.$t('i18n_06e2f88f42'), trigger: 'blur'}],
-        host: [{required: true, message: this.$t('i18n_81485b76d8'), trigger: 'blur'}],
-        port: [{required: true, message: this.$t('i18n_8d0fa2ee2d'), trigger: 'blur'}],
+        name: [{ required: true, message: this.$t('i18n_06e2f88f42'), trigger: 'blur' }],
+        host: [{ required: true, message: this.$t('i18n_81485b76d8'), trigger: 'blur' }],
+        port: [{ required: true, message: this.$t('i18n_8d0fa2ee2d'), trigger: 'blur' }],
         connectType: [
           {
             required: true,
@@ -640,9 +619,9 @@ export default {
           }
         ],
 
-        mode: [{required: true, message: this.$t('i18n_3103effdfd'), trigger: 'blur'}],
-        user: [{required: true, message: this.$t('i18n_3103effdfd'), trigger: 'blur'}],
-        password: [{required: true, message: this.$t('i18n_209f2b8e91'), trigger: 'blur'}]
+        mode: [{ required: true, message: this.$t('i18n_3103effdfd'), trigger: 'blur' }],
+        user: [{ required: true, message: this.$t('i18n_3103effdfd'), trigger: 'blur' }],
+        password: [{ required: true, message: this.$t('i18n_209f2b8e91'), trigger: 'blur' }]
       },
       nodeVisible: false,
 
@@ -768,7 +747,7 @@ export default {
     },
     // 分页、排序、筛选变化时触发
     changePage(pagination, filters, sorter) {
-      this.listQuery = CHANGE_PAGE(this.listQuery, {pagination, sorter})
+      this.listQuery = CHANGE_PAGE(this.listQuery, { pagination, sorter })
       this.loadData()
     },
     // 安装节点
@@ -862,7 +841,7 @@ export default {
         okText: this.$t('i18n_e83a256e4f'),
         cancelText: this.$t('i18n_625fb26b4b'),
         onOk: async () => {
-          const {code, msg} = await deleteForeFtp(record.id)
+          const { code, msg } = await deleteForeFtp(record.id)
           if (code === 200) {
             $notification.success({
               message: msg
@@ -909,7 +888,7 @@ export default {
         return false
       }
       if (!this.temp.ids) {
-        this.temp = {...this.temp, ids: this.tableSelections.join(',')}
+        this.temp = { ...this.temp, ids: this.tableSelections.join(',') }
         this.tableSelections = []
       }
       this.confirmLoading = true
@@ -934,7 +913,7 @@ export default {
       $confirm({
         title: this.$t('i18n_c4535759ee'),
         zIndex: 1009,
-        content: "真的要清除 FTP 隐藏字段信息么?(密码)",
+        content: this.$t('i18n_91a828d055'),
         okText: this.$t('i18n_e83a256e4f'),
         cancelText: this.$t('i18n_625fb26b4b'),
         onOk: () => {
@@ -954,7 +933,7 @@ export default {
       window.open(importTemplate(), '_blank')
     },
     handlerExportData() {
-      window.open(exportData({...this.listQuery}), '_blank')
+      window.open(exportData({ ...this.listQuery }), '_blank')
     },
     beforeUpload(file) {
       const formData = new FormData()