opt:1.Param中@NotBlank和@NotNull国际化。2.音量设置接口。

This commit is contained in:
2026-03-05 09:37:16 +08:00
parent 65c6d41e4b
commit b8b2a8d682
34 changed files with 241 additions and 184 deletions

View File

@@ -3,6 +3,7 @@ package org.nl.api.schedule.setting.api;
import cn.hutool.http.HttpResponse;
import org.nl.api.schedule.setting.core.ScheduleAPISettingChargeParam;
import org.nl.api.schedule.setting.core.ScheduleAPISettingSpeedParam;
import org.nl.response.WebResponse;
/**
* @author dsh
@@ -23,4 +24,12 @@ public interface ScheduleSettingAPI {
* @return HttpResponse
*/
HttpResponse settingCharge(ScheduleAPISettingChargeParam scheduleAPISettingChargeParam);
/**
* 设置音量
* @param volume
* @param agvId
* @return
*/
WebResponse settingVolume(Integer volume, String agvId);
}

View File

@@ -13,6 +13,6 @@ public class ScheduleAPISettingSpeedParam {
/**
* 速度单位m/s
*/
@NotBlank(message = "速度不能为空")
@NotBlank(message = "{validation_speed_empty}")
private double customSpeed;
}

View File

@@ -13,18 +13,18 @@ public class ScheduleAPICreateOneClickTaskParam {
/**
* 任务号
*/
@NotBlank(message = "调度任务号不能为空")
@NotBlank(message = "{validation_schedule_task_code_empty}")
private String task_code;
/**
* 一键任务类型
*/
@NotBlank(message = "调度一键任务类型不能为空")
@NotBlank(message = "{validation_schedule_one_click_type_empty}")
private String type;
/**
* 车号
*/
@NotBlank(message = "车号不能为空")
@NotBlank(message = "{validation_vehicle_number_empty}")
private String vehicle_number;
}

View File

@@ -59,4 +59,11 @@ public interface TaskAPI {
* @return
*/
WebResponse taskOperationConfirm(String taskCode);
/**
* 根据目标点查询是否有任务
* @param destination
* @return
*/
boolean queryTaskInfoByDestination(String destination);
}

View File

@@ -13,13 +13,13 @@ public class TaskRequestParam {
/**
* 目标点
*/
@NotBlank(message = "目标点不能为空")
@NotBlank(message = "{validation_destinations_empty}")
private String destinations;
/**
* 任务类型
*/
@NotBlank(message = "任务类型不能为空")
@NotBlank(message = "{validation_task_type_empty}")
private String type;
/**

View File

@@ -14,13 +14,13 @@ public class CreateTaskParam {
/**
* 目的地
*/
@NotBlank(message = "目的地不能为空")
@NotBlank(message = "{validation_destinations_empty}")
private String destinations;
/**
* 任务类型
*/
@NotBlank(message = "任务类型不能为空")
@NotBlank(message = "{validation_task_type_empty}")
private String type;
/**

View File

@@ -1,7 +1,9 @@
package org.nl.schedule.modular.setting.controller;
import jakarta.annotation.Resource;
import org.nl.logging.annotation.Log;
import org.nl.schedule.modular.setting.param.NetworkParam;
import org.nl.schedule.modular.setting.param.VolumeParam;
import org.nl.schedule.modular.setting.service.ScheduleSettingService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -15,14 +17,21 @@ import org.springframework.web.bind.annotation.RestController;
* 2026/3/2
*/
@RestController
@RequestMapping("/schedule/setting")
@RequestMapping("/schedule/setting/")
public class ScheduleSettingController {
@Resource
private ScheduleSettingService scheduleSettingService;
@Log("调度网络操作")
@PostMapping("/networkOperation")
public ResponseEntity<Object> networkOperation(@RequestBody NetworkParam param){
return new ResponseEntity<>(scheduleSettingService.networkOperation(param), HttpStatus.OK);
}
@Log("设置车辆音量")
@PostMapping("/settingVolume")
public ResponseEntity<Object> settingVolume(@RequestBody VolumeParam param){
return new ResponseEntity<>(scheduleSettingService.settingVolume(param), HttpStatus.OK);
}
}

View File

@@ -0,0 +1,22 @@
package org.nl.schedule.modular.setting.param;
import lombok.Data;
/**
* @author dsh
* 2026/3/4
*/
@Data
public class VolumeParam {
/**
* 音量
*/
private Integer volume;
/**
* 车号
*/
private String agvId;
}

View File

@@ -4,12 +4,16 @@ import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSONObject;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.nl.api.schedule.setting.api.ScheduleSettingAPI;
import org.nl.api.schedule.setting.core.ScheduleAPISettingChargeParam;
import org.nl.api.schedule.setting.core.ScheduleAPISettingSpeedParam;
import org.nl.config.language.LangProcess;
import org.nl.exception.BadRequestException;
import org.nl.response.WebResponse;
import org.nl.schedule.modular.setting.param.VolumeParam;
import org.nl.schedule.modular.setting.service.ScheduleSettingService;
import org.nl.util.URLConstant;
import org.springframework.stereotype.Service;
@@ -21,6 +25,9 @@ import org.springframework.stereotype.Service;
@Service
public class ScheduleSettingAPIProvider implements ScheduleSettingAPI {
@Resource
private ScheduleSettingService scheduleSettingService;
@Override
public HttpResponse settingSpeed(ScheduleAPISettingSpeedParam scheduleAPISettingSpeedParam) {
if (ObjectUtil.isEmpty(scheduleAPISettingSpeedParam)){
@@ -56,4 +63,12 @@ public class ScheduleSettingAPIProvider implements ScheduleSettingAPI {
}
return result;
}
@Override
public WebResponse settingVolume(Integer volume, String agvId) {
VolumeParam param = new VolumeParam();
param.setAgvId(agvId);
param.setVolume(volume);
return scheduleSettingService.settingVolume(param);
}
}

View File

@@ -2,6 +2,7 @@ package org.nl.schedule.modular.setting.service;
import org.nl.response.WebResponse;
import org.nl.schedule.modular.setting.param.NetworkParam;
import org.nl.schedule.modular.setting.param.VolumeParam;
/**
* @author dsh
@@ -10,9 +11,17 @@ import org.nl.schedule.modular.setting.param.NetworkParam;
public interface ScheduleSettingService {
/**
*
* 网络操作
* @param param
* @return
*/
WebResponse networkOperation(NetworkParam param);
/**
* 音量设置
* @param param
* @return
*/
WebResponse settingVolume(VolumeParam param);
}

View File

@@ -1,6 +1,7 @@
package org.nl.schedule.modular.setting.service.impl;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSON;
@@ -10,6 +11,7 @@ import org.nl.config.language.LangProcess;
import org.nl.exception.BadRequestException;
import org.nl.response.WebResponse;
import org.nl.schedule.modular.setting.param.NetworkParam;
import org.nl.schedule.modular.setting.param.VolumeParam;
import org.nl.schedule.modular.setting.service.ScheduleSettingService;
import org.nl.util.URLConstant;
import org.springframework.stereotype.Service;
@@ -42,4 +44,28 @@ public class ScheduleSettingServiceImpl implements ScheduleSettingService {
}
throw new BadRequestException(LangProcess.msg("schedule_wifi_param_error"));
}
@Override
public WebResponse settingVolume(VolumeParam param) {
if (ObjectUtil.isEmpty(param.getVolume())){
throw new BadRequestException(LangProcess.msg("schedule_volume_empty"));
}
if (StrUtil.isBlank(param.getAgvId())){
throw new BadRequestException(LangProcess.msg("schedule_vehicle_number_empty"));
}
log.info("调度设置音量参数:{}", param);
HttpResponse result = null;
try {
result = HttpRequest.put(URLConstant.SCHEDULE_IP_PORT+"/system/audio/volume")
.body(String.valueOf(JSONObject.toJSON(param)))
.execute();
if (result !=null && result.isOk()){
log.info("调度设置音量响应结果:{}",result.body());
return WebResponse.requestOk();
}
}catch (Exception e){
log.info("调度设置音量失败");
}
throw new BadRequestException(LangProcess.msg("setting_volume_failed"));
}
}

View File

@@ -13,18 +13,18 @@ public class ScheduleTaskArrivedReportParam {
/**
* 点位
*/
@NotBlank(message = "点位不能为空")
@NotBlank(message = "{validation_location_empty}")
private String location;
/**
* 车号
*/
@NotBlank(message = "车号不能为空")
@NotBlank(message = "{validation_vehicle_number_empty}")
private String vehicle_number;
/**
* 任务号
*/
@NotBlank(message = "任务号不能为空")
@NotBlank(message = "{task_code_empty}")
private String task_code;
}

View File

@@ -42,7 +42,11 @@ public enum SettingCodeEnum {
/**
* 显示屏密码
*/
SCREEN_PASSWORD("7", "password", "显示屏密码");
SCREEN_PASSWORD("7", "password", "显示屏密码"),
MODE("8","mode","模式切换"),
VOLUME("9","volume","音量");
private String code;
private String name;

View File

@@ -13,7 +13,7 @@ public class UpdateSettingParam {
/**
* 设置编码
*/
@NotBlank(message = "设置编码不能为空")
@NotBlank(message = "{setting_code_empty}")
private String setting_code;
/**

View File

@@ -2,7 +2,6 @@ package org.nl.setting.modular.service.impl;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -130,6 +129,10 @@ public class SettingServiceImpl extends ServiceImpl<SettingMapper, Setting> impl
String newPassword = RsaUtils.decryptByPrivateKey(RsaUtils.privateKey,setting_value);
setting_value = SaSecureUtil.md5BySalt(newPassword,"salt");
break;
case VOLUME:
log.info("修改音量");
scheduleSettingAPI.settingVolume(Integer.valueOf(setting_value),updateSettingParam.getUpdate_by());
break;
}
settingMapper.update(new LambdaUpdateWrapper<>(Setting.class)

View File

@@ -14,13 +14,13 @@ public class QueryErrorInfoPageParam {
/**
* 当前页
*/
@NotNull(message = "当前页不能为空")
@NotNull(message = "{validation_page_num_empty}")
private Integer pageNum;
/**
* 页大小
*/
@NotNull(message = "页大小不能为空")
@NotNull(message = "{validation_page_size_empty}")
private Integer pageSize;
/**

View File

@@ -43,10 +43,10 @@ public class DeptVo extends BaseDTO implements Serializable {
private Integer dept_sort;
@NotBlank
@NotBlank(message = "{validation_dept_name_empty}")
private String name;
@NotNull
@NotNull(message = "{validation_dept_is_used_empty}")
private Boolean is_used;
private Long pid;

View File

@@ -33,7 +33,7 @@ public class RoleVo implements Serializable {
private Long role_id;
@NotBlank
@NotBlank(message = "{validation_role_name_empty}")
private String name;
private Integer level = 3;

View File

@@ -14,24 +14,24 @@ public class GenerateQRCodeParam {
/**
* 房间号
*/
@NotBlank(message = "房间号不能为空")
@NotBlank(message = "{validation_room_empty}")
private String room;
/**
* 二维码内容(文本/URL/WiFi配置等
*/
@NotBlank(message = "二维码内容不能为空")
@NotBlank(message = "{validation_qrcode_data_empty}")
private String data;
/**
* 二维码宽度(像素)
*/
@NotNull(message = "二维码宽度不能为空")
@NotNull(message = "{validation_qrcode_width_empty}")
private Integer width;
/**
* 二维码高度(像素)
*/
@NotNull(message = "二维码高度不能为空")
@NotNull(message = "{validation_qrcode_height_empty}")
private Integer height;
}

View File

@@ -13,13 +13,13 @@ public class QueryQRCodeParam {
/**
* 当前页
*/
@NotNull(message = "当前页不能为空")
@NotNull(message = "{validation_page_num_empty}")
private Integer pageNum;
/**
* 页大小
*/
@NotNull(message = "页大小不能为空")
@NotNull(message = "{validation_page_size_empty}")
private Integer pageSize;
/**

View File

@@ -14,37 +14,37 @@ public class UpdateQRCodeParam {
/**
* 二维码标识
*/
@NotBlank(message = "二维码标识不能为空")
@NotBlank(message = "{validation_qrcode_id_empty}")
private String qrcode_id;
/**
* 修改之前的房间号
*/
@NotBlank(message = "修改之前的房间号不能为空")
@NotBlank(message = "{validation_old_room_empty}")
private String oldRoom;
/**
* 修改之后的房间号
*/
@NotBlank(message = "修改之后的房间号不能为空")
@NotBlank(message = "{validation_new_room_empty}")
private String newRoom;
/**
* 二维码内容
*/
@NotBlank(message = "二维码内容不能为空")
@NotBlank(message = "{validation_qrcode_data_empty}")
private String qrcode_data;
/**
* 二维码宽度(像素)
*/
@NotNull(message = "二维码宽度不能为空")
@NotNull(message = "{validation_qrcode_width_empty}")
private Integer qrcode_width;
/**
* 二维码高度(像素)
*/
@NotNull(message = "二维码高度不能为空")
@NotNull(message = "{validation_qrcode_height_empty}")
private Integer qrcode_height;

View File

@@ -154,11 +154,16 @@ public class QRCodeServiceImpl implements QRCodeService {
@Override
public WebResponse createTask(TaskRequestParam qrCodeTaskRequestParam) {
// 判断该目标点是否存在任务,如果已存在则不能继续下发
if (taskAPI.queryTaskInfoByDestination(qrCodeTaskRequestParam.getDestinations())){
throw new BadRequestException(LangProcess.msg("qrcode_create_failed_exists_task"));
}
String mode = settingAPI.querySettingParamByCode("mode").getJSONObject("data").getString("value");
// 判断是否在巡航模式 再巡航模式不能下发二维码任务
if ("1".equals(mode)){
throw new BadRequestException(LangProcess.msg("qrcode_create_failed_mode"));
}
return taskAPI.createTask(qrCodeTaskRequestParam, TaskSourceEnum.QRCODE.getName());
}

View File

@@ -13,6 +13,6 @@ public class SecurityParam {
/**
* 密码
*/
@NotBlank(message = "密码不能为空")
@NotBlank(message = "{validation_password_empty}")
private String password;
}

View File

@@ -13,6 +13,6 @@ public class CancelTaskRequestParam {
/**
* 任务编号
*/
@NotBlank(message = "任务号不能为空")
@NotBlank(message = "{task_code_empty}")
private String task_code;
}

View File

@@ -20,7 +20,7 @@ public class CreateCruiseTaskRequestParam {
/**
* 任务类型
*/
@NotBlank(message = "任务类型不能为空")
@NotBlank(message = "{validation_task_type_empty}")
private String type;
/**

View File

@@ -13,13 +13,13 @@ public class CreateTaskRequestParam {
/**
* 目标点
*/
@NotBlank(message = "目标点不能为空")
@NotBlank(message = "{validation_destinations_empty}")
private String destinations;
/**
* 任务类型
*/
@NotBlank(message = "任务类型不能为空")
@NotBlank(message = "{validation_task_type_empty}")
private String type;
/**

View File

@@ -13,12 +13,12 @@ public class OneClickOperationRequestParam {
/**
* 车号
*/
@NotBlank(message = "车号不能为空")
@NotBlank(message = "{validation_vehicle_number_empty}")
private String vehicle_number;
/**
* 一键任务类型
*/
@NotBlank(message = "任务类型不能为空")
@NotBlank(message = "{validation_task_type_empty}")
private String type;
}

View File

@@ -13,6 +13,6 @@ public class PauseAndResumeTaskParam {
/**
* 任务编号
*/
@NotBlank(message = "任务号不能为空")
@NotBlank(message = "{task_code_empty}")
private String task_code;
}

View File

@@ -13,13 +13,13 @@ public class QueryTaskRequestParam {
/**
* 当前页
*/
@NotNull(message = "当前页不能为空")
@NotNull(message = "{validation_page_num_empty}")
private Integer pageNum;
/**
* 页数大小
*/
@NotNull(message = "页数大小不能为空")
@NotNull(message = "{validation_page_size_empty}")
private Integer pageSize;
/**

View File

@@ -5,6 +5,7 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@@ -102,4 +103,9 @@ public class TaskAPIProvider implements TaskAPI {
public WebResponse taskOperationConfirm(String taskCode) {
return taskService.taskOperationConfirm(taskCode);
}
@Override
public boolean queryTaskInfoByDestination(String destination) {
return taskService.count(new LambdaQueryWrapper<>(Task.class).eq(Task::getDestinations, destination).lt(Task::getStatus,TaskStatusEnum.FINISHED.getCode())) >0;
}
}

View File

@@ -1,23 +1,32 @@
package org.nl.exception;
import lombok.extern.slf4j.Slf4j;
import org.nl.config.language.LangProcess;
import org.nl.util.ThrowableUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.Objects;
import jakarta.validation.ConstraintViolationException;
/**
* 全局异常处理器
* @author liejiu
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@Autowired(required = false)
private MessageSource messageSource;
/**
* 处理所有不可知的异常
*/
@@ -28,43 +37,92 @@ public class GlobalExceptionHandler {
return buildResponseEntity(ApiError.error(e.getMessage()));
}
/**
* token 无效的异常拦截
* @param e
* @return
*/
// @ExceptionHandler(value = NotLoginException.class)
// public ResponseEntity<ApiError> notLoginException(Exception e) {
//// log.error(ThrowableUtil.getStackTrace(e));
// return buildResponseEntity(ApiError.error(401,"token 失效"));
// }
/**
* 处理自定义异常
*/
@ExceptionHandler(value = BadRequestException.class)
public ResponseEntity<ApiError> badRequestException(BadRequestException e) {
@ExceptionHandler(value = BadRequestException.class)
public ResponseEntity<ApiError> badRequestException(BadRequestException e) {
// 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e));
log.info(e.getMessage());
return buildResponseEntity(ApiError.error(e.getStatus(),e.getMessage()));
}
}
/**
* 处理所有接口数据验证异常
* 处理 @RequestBody 参数验证异常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiError> handleMethodArgumentNotValidException(MethodArgumentNotValidException e){
// 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e));
String[] str = Objects.requireNonNull(e.getBindingResult().getAllErrors().get(0).getCodes())[1].split("\\.");
// 获取第一个验证错误的消息
String message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
String msg = "不能为空";
if(msg.equals(message)){
message = str[1] + ":" + message;
// 如果消息是 {key} 格式,手动解析国际化
if (message != null && message.startsWith("{") && message.endsWith("}")) {
String key = message.substring(1, message.length() - 1);
try {
// 使用 LangProcess 解析国际化消息
message = LangProcess.msg(key);
} catch (Exception ex) {
log.warn("Failed to resolve i18n message for key: {}", key);
// 如果解析失败,尝试使用 MessageSource
if (messageSource != null) {
try {
message = messageSource.getMessage(key, null, LocaleContextHolder.getLocale());
} catch (Exception ex2) {
log.warn("Failed to resolve message from MessageSource for key: {}", key);
}
}
}
}
log.info("Validation error: {}", message);
return buildResponseEntity(ApiError.error(message));
}
/**
* 处理 @Validated 参数验证异常(用于表单提交)
*/
@ExceptionHandler(BindException.class)
public ResponseEntity<ApiError> handleBindException(BindException e){
log.error(ThrowableUtil.getStackTrace(e));
String message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
// 如果消息是 {key} 格式,手动解析国际化
if (message != null && message.startsWith("{") && message.endsWith("}")) {
String key = message.substring(1, message.length() - 1);
try {
message = LangProcess.msg(key);
} catch (Exception ex) {
log.warn("Failed to resolve i18n message for key: {}", key);
}
}
log.info("Bind validation error: {}", message);
return buildResponseEntity(ApiError.error(message));
}
/**
* 处理 @Validated 参数验证异常(用于方法参数)
*/
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<ApiError> handleConstraintViolationException(ConstraintViolationException e){
log.error(ThrowableUtil.getStackTrace(e));
String message = e.getConstraintViolations().iterator().next().getMessage();
// 如果消息是 {key} 格式,手动解析国际化
if (message != null && message.startsWith("{") && message.endsWith("}")) {
String key = message.substring(1, message.length() - 1);
try {
message = LangProcess.msg(key);
} catch (Exception ex) {
log.warn("Failed to resolve i18n message for key: {}", key);
}
}
log.info("Constraint violation error: {}", message);
return buildResponseEntity(ApiError.error(message));
}

View File

@@ -15,6 +15,7 @@ schedule_task_code_empty = 任务号不能为空
schedule_destinations_empty = 目标点不能为空
schedule_operation_type_empty = 任务操作类型不能为空
schedule_vehicle_number_empty = 车号不能为空
schedule_volume_empty = 音量不能为空
schedule_report_location_empty = 上报点位不能为空
schedule_report_vehicle_empty = 上报车号不能为空
schedule_report_task_code_empty = 上报任务号不能为空
@@ -32,6 +33,7 @@ setting_free_charge_failed = 设置调度自由充电阈值失败
setting_charge_call_value_empty = 修改充电时是否可呼叫,设置值和是否启用值不能为空
setting_usable_task_failed = 设置调度可接任务阈值失败
setting_update_failed = 更新设置失败:{0}
setting_volume_failed = 更新音量失败
# 任务相关
task_type_not_exist = 任务类型不存在
@@ -108,6 +110,7 @@ qrcode_delete_file_failed = 删除二维码文件失败
qrcode_delete_failed = 删除二维码失败
qrcode_station_code_empty = 站号不能为空
qrcode_create_failed_mode = 巡航模式中,无法下发任务
qrcode_create_failed_exists_task = 该目标点已存在任务
# 安全相关
security_password_error = 密码错误

View File

@@ -1,119 +0,0 @@
starting_point = Starting Point
end_point = End Point
successful = successful!
failed = Failed!
latest = Already up to date!
param_is_null = The parameter is empty!
password_error = Wrong account or password
# Schedule related
schedule_speed_param_empty = Dispatch setting delivery speed parameter cannot be empty
schedule_charge_param_empty = Dispatch setting charging parameter cannot be empty
schedule_wifi_param_empty = The wifi parameter set for scheduling cannot be empty
schedule_wifi_param_error = The scheduling network wifi operation failed
schedule_task_code_empty = Task number cannot be empty
schedule_destinations_empty = Destination cannot be empty
schedule_operation_type_empty = Task operation type cannot be empty
schedule_vehicle_number_empty = Vehicle number cannot be empty
schedule_report_location_empty = Report location cannot be empty
schedule_report_vehicle_empty = Report vehicle number cannot be empty
schedule_report_task_code_empty = Report task number cannot be empty
schedule_report_stage_not_found = Report stage not found
schedule_report_type_not_found = Report type not found
schedule_operation_not_confirmed = Operation not confirmed
# Setting related
setting_code_empty = Setting code cannot be empty
setting_code_not_found = Setting code not found
setting_speed_value_empty = Modify delivery speed, setting value cannot be empty
setting_speed_failed = Failed to set dispatch delivery speed
setting_auto_charge_value_empty = Modify auto recharge, setting value and enable value cannot be empty
setting_free_charge_failed = Failed to set dispatch free charge threshold
setting_charge_call_value_empty = Modify whether it can be called while charging, setting value and enable value cannot be empty
setting_usable_task_failed = Failed to set dispatch usable task threshold
setting_update_failed = Failed to update settings:{0}
# Task related
task_type_not_exist = Task type does not exist
task_schedule_create_failed = Failed to create dispatch task
task_create_failed = Failed to create task:{0}
task_code_empty = Task number cannot be empty
task_cancel_failed = Failed to cancel task:{0}
task_pause_schedule_failed = Failed to pause dispatch task
task_pause_failed = Failed to pause task:{0}
task_resume_schedule_failed = Failed to resume dispatch task
task_resume_failed = Failed to resume task:{0}
task_station_code_empty = Station code cannot be empty
task_report_not_arrived = Not reported arrival location, unable to confirm arrival
task_confirm_arrival_failed = Failed to confirm task arrival
task_next_station_failed = Failed to go to next station:{0}
create_cruise_task_error = The mission type is not a cruise type
# Anomaly related
error_info = Anomaly information
error_handling_info = Exception handling information
anomaly_file_not_selected = Please select a file to upload
anomaly_file_name_empty = File name is empty
anomaly_file_format_error = Currently only ZIP format is supported
anomaly_file_parse_failed = Failed to parse file:{0}
anomaly_update_failed = Failed to update anomaly information
# File related
file_size_exceed = File exceeds the specified size
# Department related
dept_parent_cannot_self = Parent cannot be itself
dept_has_users = Department has bound employees, please unbind employees first
# Dictionary related
dict_code_exists = Dictionary[{0}] already exists
dict_not_exist = Dictionary does not exist
dict_label_exists = Label[{0}] already exists
dict_no_permission = No permission to delete data, operation failed!
# Menu related
menu_url_must_http = External link must start with http:// or https://
menu_parent_cannot_self = Parent cannot be itself or its subordinates
# Notice related
notice_not_exist = This message does not exist!
notice_send_failed = Failed to send message
# Parameter related
param_code_not_match = Code cannot be the same
param_code_exists = Parameter[{0}] already exists
# Role related
role_name_empty = Role name cannot be empty!
role_name_exists = Role name {0} already exists!
# User related
user_code_not_exist = Verification code does not exist or has expired
user_code_error = Verification code error
user_account_password_error = Wrong account or password
user_account_not_active = Account not activated
user_old_password_error = Modification failed, old password is wrong
user_password_not_match = The two passwords entered are inconsistent
user_password_error = Password error
# QRCode related
qrcode_data_empty = QR code data cannot be empty
qrcode_room_number_empty = QR code room number cannot be empty
qrcode_generate_failed = Failed to generate QR code
qrcode_room_exists = QR code already exists for this room, cannot generate again
qrcode_room_exists_cannot_update = QR code already exists for this room, cannot update
qrcode_update_failed = Failed to update QR code information
qrcode_id_empty = QR code ID cannot be empty
qrcode_delete_file_failed = Failed to delete QR code file
qrcode_delete_failed = Failed to delete QR code
qrcode_station_code_empty = Station code cannot be empty
qrcode_create_failed_mode = In cruise mode, missions cannot be issued
# Security related
security_password_error = Password error
# System related
system_get_menu_failed = Error getting corresponding system menu
# Common
unsupported_format = Unsupported compression format: {0}