瀏覽代碼

灵活作业相关接口

车车 5 月之前
父節點
當前提交
4ce4dedc46

+ 72 - 0
ktg-iscs/src/main/java/com/ktg/iscs/controller/FlexibleJobController.java

@@ -0,0 +1,72 @@
+package com.ktg.iscs.controller;
+
+import com.ktg.common.annotation.Log;
+import com.ktg.common.core.controller.BaseController;
+import com.ktg.common.enums.BusinessType;
+import com.ktg.common.pojo.CommonResult;
+import com.ktg.iscs.domain.dto.flexiblejob.AddFlexibleJobDTO;
+import com.ktg.iscs.domain.dto.flexiblejob.KeyTakeDTO;
+import com.ktg.iscs.domain.dto.hardwareApi.ParamDTO;
+import com.ktg.iscs.service.FlexibleJobService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.v3.oas.annotations.Parameter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 灵活作业调用接口
+ *
+ * @author cgj
+ * @date 2025-11-10
+ */
+@Api(tags = "灵活作业调用接口")
+@RestController
+@RequestMapping("/iscs/flexible-job")
+public class FlexibleJobController extends BaseController
+{
+    @Autowired
+    private FlexibleJobService flexibleJobService;
+
+    // ----------------------------------新建作业-------------------------------------------------------
+    @ApiOperation("灵活作业-新增")
+    @Log(title = "灵活作业票", businessType = BusinessType.INSERT)
+    @PostMapping("/insertFlexibleJobTicket")
+    public CommonResult<Long> insertFlexibleJobTicket(@RequestBody @Parameter(name = "dto", description = "新增数据类,放到body") AddFlexibleJobDTO dto) {
+        return CommonResult.success(flexibleJobService.insertFlexibleJobTicket(dto));
+    }
+
+    @ApiOperation("灵活作业-取出钥匙")
+    @Log(title = "灵活作业票", businessType = BusinessType.INSERT)
+    @PostMapping("/insertTakeOutKey")
+    public CommonResult<Boolean> insertTakeOutKey(@RequestBody @Parameter(name = "dto", description = "新增数据类,放到body") KeyTakeDTO dto) {
+        return CommonResult.success(flexibleJobService.insertTakeOutKey(dto.getList()));
+    }
+
+    @ApiOperation("灵活作业-归还钥匙")
+    @Log(title = "灵活作业票", businessType = BusinessType.INSERT)
+    @PostMapping("/updateTakeBackKey")
+    public CommonResult<Boolean> updateTakeBackKey(@RequestBody @Parameter(name = "dto", description = "新增数据类,放到body") KeyTakeDTO dto) {
+        return CommonResult.success(flexibleJobService.updateTakeBackKey(dto.getList()));
+    }
+
+    @ApiOperation("灵活作业-取出挂锁")
+    @Log(title = "灵活作业票", businessType = BusinessType.UPDATE)
+    @PostMapping("/insertTakeOutLock")
+    public CommonResult<Boolean> insertTakeOutLock(@RequestBody @Parameter(name = "list", description = "修改数据类,放到body") ParamDTO dto)
+    {
+        return CommonResult.success(flexibleJobService.insertTakeOutLock(dto.getList()));
+    }
+
+    @ApiOperation("灵活作业-归还挂锁")
+    @Log(title = "灵活作业", businessType = BusinessType.UPDATE)
+    @PostMapping("/updateTakeBackLock")
+    public CommonResult<Boolean> updateTakeBackLock(@RequestBody @Parameter(name = "list", description = "修改数据类,放到body") ParamDTO dto)
+    {
+        return CommonResult.success(flexibleJobService.updateTakeBackLock(dto.getList()));
+    }
+
+}

+ 20 - 0
ktg-iscs/src/main/java/com/ktg/iscs/domain/dto/flexiblejob/AddFlexibleJobDTO.java

@@ -0,0 +1,20 @@
+package com.ktg.iscs.domain.dto.flexiblejob;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 新增灵活作业票
+ *
+ */
+@Data
+public class AddFlexibleJobDTO
+{
+
+    @ApiModelProperty(value = "所属岗位ID")
+    private Long workstationId;
+
+    @ApiModelProperty(value = "SOP类型(清洁、换产、)")
+    private String type;
+
+}

+ 21 - 0
ktg-iscs/src/main/java/com/ktg/iscs/domain/dto/flexiblejob/KeyTakeDTO.java

@@ -0,0 +1,21 @@
+package com.ktg.iscs.domain.dto.flexiblejob;
+
+import com.ktg.iscs.domain.dto.hardwareApi.TakeOutKeyDTO;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 新增灵活作业票
+ *
+ */
+@Data
+public class KeyTakeDTO
+{
+
+    @ApiModelProperty(value = "钥匙信息")
+    private List<TakeOutKeyDTO> list;
+
+
+}

+ 53 - 0
ktg-iscs/src/main/java/com/ktg/iscs/service/FlexibleJobService.java

@@ -0,0 +1,53 @@
+package com.ktg.iscs.service;
+
+import com.ktg.iscs.domain.dto.flexiblejob.AddFlexibleJobDTO;
+import com.ktg.iscs.domain.dto.hardwareApi.TakeOutKeyDTO;
+import com.ktg.iscs.domain.dto.hardwareApi.TakeTicketLockDTO;
+
+import java.util.List;
+
+/**
+ * 灵活作业调用接口
+ *
+ * @author cgj
+ * @date 2025-11-10
+ */
+public interface FlexibleJobService {
+
+
+    /**
+     * 灵活作业-新增
+     * @param dto
+     * @return
+     */
+    Long insertFlexibleJobTicket(AddFlexibleJobDTO dto);
+
+    /**
+     * 灵活作业-取出钥匙
+     * @param list
+     * @return
+     */
+    Boolean insertTakeOutKey(List<TakeOutKeyDTO> list);
+
+    /**
+     * 灵活作业-归还钥匙
+     * @param list
+     * @return
+     */
+    Boolean updateTakeBackKey(List<TakeOutKeyDTO> list);
+
+    /**
+     * 灵活作业-取出挂锁
+     * @param list
+     * @return
+     */
+    Boolean insertTakeOutLock(List<TakeTicketLockDTO> list);
+
+    /**
+     * 灵活作业-归还挂锁
+     * @param list
+     * @return
+     */
+    Boolean updateTakeBackLock(List<TakeTicketLockDTO> list);
+
+}

+ 227 - 0
ktg-iscs/src/main/java/com/ktg/iscs/service/impl/FlexibleJobServiceImpl.java

@@ -0,0 +1,227 @@
+package com.ktg.iscs.service.impl;
+
+import cn.hutool.core.lang.Assert;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.ktg.common.utils.DictUtils;
+import com.ktg.common.utils.SecurityUtils;
+import com.ktg.iscs.domain.*;
+import com.ktg.iscs.domain.dto.flexiblejob.AddFlexibleJobDTO;
+import com.ktg.iscs.domain.dto.hardwareApi.TakeOutKeyDTO;
+import com.ktg.iscs.domain.dto.hardwareApi.TakeTicketLockDTO;
+import com.ktg.iscs.domain.enums.JobStepEnum;
+import com.ktg.iscs.service.*;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 灵活作业调用接口
+ *
+ * @author cgj
+ * @date 2025-11-10
+ */
+@Slf4j
+@Service
+public class FlexibleJobServiceImpl implements FlexibleJobService {
+
+    @Autowired
+    private IIsJobTicketService iIsJobTicketService;
+    @Autowired
+    private IIsWorkstationService iIsWorkstationService;
+    @Autowired
+    private IIsTicketOperLogService isTicketOperLogService;
+    @Autowired
+    private IIsJobTicketStepService iIsJobTicketStepService;
+    @Autowired
+    private IIsJobTicketKeyService iIsJobTicketKeyService;
+    @Autowired
+    private IIsKeyService iIsKeyService;
+    @Autowired
+    private IIsLockService iIsLockService;
+    @Autowired
+    private IIsJobTicketLockService iIsJobTicketLockService;
+
+
+    @Override
+    public Long insertFlexibleJobTicket(AddFlexibleJobDTO dto) {
+        // 1.1自动生成名称
+        String jobName = generateJobName(dto.getWorkstationId(), dto.getType());
+        // 2.新增作业票
+        IsJobTicket jobTicket = new IsJobTicket();
+        jobTicket.setTicketName(jobName);
+        jobTicket.setWorkstationId(dto.getWorkstationId());
+        jobTicket.setCreateBy(String.valueOf(SecurityUtils.getUserId()));
+        jobTicket.setUpdateBy(String.valueOf(SecurityUtils.getUserId()));
+        iIsJobTicketService.save(jobTicket);
+        // 启动作业
+        isTicketOperLogService.addLog1(jobTicket.getTicketId(), jobName);
+
+        // 4.新增八大步骤信息
+        JobStepEnum jobStepEnum = new JobStepEnum();
+        List<String> steps = jobStepEnum.getSteps();
+        List<String> androidSteps = jobStepEnum.getAndroidSteps();
+        List<IsJobTicketStep> isJobTicketSteps = new ArrayList<>();
+        for (int i = 1; i <= steps.size(); i++) {
+            IsJobTicketStep isJobTicketStep = new IsJobTicketStep();
+            isJobTicketStep.setTicketId(jobTicket.getTicketId());
+            isJobTicketStep.setStepIndex(i);
+            isJobTicketStep.setStepStatus(i < 3 ? "1" : "0");
+            isJobTicketStep.setStepContent(steps.get(i - 1));
+            isJobTicketStep.setAndroidStepContent(androidSteps.get(i - 1));
+            isJobTicketSteps.add(isJobTicketStep);
+            iIsJobTicketStepService.save(isJobTicketStep);
+        }
+        // 操作确认
+        for (IsJobTicketStep isJobTicketStep : isJobTicketSteps) {
+            if ("1".equals(isJobTicketStep.getStepStatus())) {
+                isTicketOperLogService.addLog2(jobTicket.getTicketId(), jobName, isJobTicketStep.getAndroidStepContent(), 0L, "系统");
+            }
+        }
+        return jobTicket.getTicketId();
+    }
+
+    public String generateJobName(Long workstationId, String ticketType) {
+        String jobName;
+        int counter = 1;
+        // 2.如果不是sop生成的,则根据数据自己生成
+        IsWorkstation workstation = iIsWorkstationService.getById(workstationId);
+        Assert.notNull(workstation, "岗位信息不存在!");
+        String workstationName = workstation.getWorkstationName();
+        // 2.1如果岗位是有父级的,则处理
+        if (!"0".equals(workstation.getAncestors())) {
+            // 使用 split 方法按逗号分隔字符串
+            String[] items = workstation.getAncestors().split(",");
+            // 将数组转换为 List
+            List<String> list = Arrays.asList(items);
+            List<IsWorkstation> isWorkstationList = iIsWorkstationService.list(Wrappers.<IsWorkstation>lambdaQuery()
+                    .in(IsWorkstation::getWorkstationId, list));
+            if (!isWorkstationList.isEmpty()) {
+                List<String> collect = isWorkstationList.stream().map(IsWorkstation::getWorkstationName).collect(Collectors.toList());
+                workstationName = String.join("-", collect);
+            }
+
+        }
+        String ticketTypeValue = null;
+        if (StringUtils.isNotBlank(ticketType)) {
+            ticketTypeValue = "-" + DictUtils.getDictValue("ticket_type", ticketType);
+        }
+        jobName = "灵活作业" + "-" + workstationName + ticketTypeValue;
+        // 开始生成文件名称尾缀
+        String rname = jobName;
+        while (!iIsJobTicketService.list(Wrappers.<IsJobTicket>lambdaQuery().eq(IsJobTicket::getTicketName, jobName)).isEmpty()) {
+            jobName = rname + "(" + counter + ")";
+            counter++;
+        }
+        return jobName;
+    }
+
+
+    @Transactional
+    @Override
+    public Boolean insertTakeOutKey(List<TakeOutKeyDTO> list) {
+        for (TakeOutKeyDTO dto : list) {
+            Assert.notNull(dto.getTicketId(), "作业id不能为空!");
+            // 检查钥匙是否存在
+            IsKey key = iIsKeyService.getOne(Wrappers.<IsKey>lambdaQuery().eq(IsKey::getKeyNfc, dto.getKeyNfc()));
+            Assert.notNull(key, dto.getKeyNfc() + "对应的钥匙信息不存在!");
+            // 如果已经有了取出记录
+            IsJobTicketKey jobTicketKey = iIsJobTicketKeyService.getOne(Wrappers.<IsJobTicketKey>lambdaQuery()
+                    .eq(IsJobTicketKey::getTicketId, dto.getTicketId())
+                    .eq(IsJobTicketKey::getKeyId, key.getKeyId()));
+            if (jobTicketKey != null) {
+
+            } else {
+                // 如果没有取出记录
+                IsJobTicketKey jobTicketKey1 = new IsJobTicketKey();
+                jobTicketKey1.setTicketId(dto.getTicketId());
+                jobTicketKey1.setKeyId(key.getKeyId());
+                jobTicketKey1.setCollectTime(new Date());
+                jobTicketKey1.setKeyStatus("0");
+                jobTicketKey1.setTicketType(0);
+                iIsJobTicketKeyService.save(jobTicketKey1);
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public Boolean updateTakeBackKey(List<TakeOutKeyDTO> list) {
+        Date date = new Date();
+        for (TakeOutKeyDTO dto : list) {
+            Assert.notNull(dto.getTicketId(), "请告诉我关于哪个作业票!");
+            Assert.notBlank(dto.getKeyNfc(), "请告诉我钥匙的NFC!");
+            // 1.获取作业票数据
+            IsJobTicket jobTicket = iIsJobTicketService.getById(dto.getTicketId());
+            Assert.notNull(jobTicket, "作业票数据丢失啦!");
+            // 1.1获取上锁时取出的锁的信息
+            IsKey startKey = iIsKeyService.getOne(Wrappers.<IsKey>lambdaQuery().eq(IsKey::getKeyNfc, dto.getKeyNfc()));
+            Assert.notNull(startKey, "钥匙数据丢失啦!");
+            // 1.4修改为归还
+            iIsJobTicketKeyService.update(Wrappers.<IsJobTicketKey>lambdaUpdate()
+                    .eq(IsJobTicketKey::getTicketId, jobTicket.getTicketId())
+                    .eq(IsJobTicketKey::getKeyId, startKey.getKeyId())
+                    .ne(IsJobTicketKey::getKeyStatus, "2")
+                    .set(IsJobTicketKey::getKeyStatus, "2")
+                    .set(IsJobTicketKey::getGiveBackTime, date));
+        }
+        return true;
+    }
+
+    @Override
+    public Boolean insertTakeOutLock(List<TakeTicketLockDTO> list) {
+        Date date = new Date();
+        for (TakeTicketLockDTO dto : list) {
+            Assert.notNull(dto.getTicketId(), "作业id不能为空!");
+            // 检查锁是否存在
+            IsLock lock = iIsLockService.getOne(Wrappers.<IsLock>lambdaQuery().eq(IsLock::getLockNfc, dto.getLockNfc()));
+            Assert.notNull(lock, dto.getLockNfc() + "对应的挂锁信息不存在!");
+            // 如果已经有了取出记录
+            IsJobTicketLock jobTicketLock = iIsJobTicketLockService.getOne(Wrappers.<IsJobTicketLock>lambdaQuery()
+                    .eq(IsJobTicketLock::getTicketId, dto.getTicketId())
+                    .eq(IsJobTicketLock::getLockId, lock.getLockId()));
+            if (jobTicketLock != null) {
+
+            } else {
+                // 如果没有取出记录
+                IsJobTicketLock jobTicketLock1 = new IsJobTicketLock();
+                jobTicketLock1.setTicketId(dto.getTicketId());
+                jobTicketLock1.setLockId(lock.getLockId());
+                jobTicketLock1.setLockStatus("1");
+                jobTicketLock1.setCreateTime(date);
+                iIsJobTicketLockService.save(jobTicketLock1);
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public Boolean updateTakeBackLock(List<TakeTicketLockDTO> list) {
+        for (TakeTicketLockDTO dto : list) {
+            Assert.notNull(dto.getTicketId(), "请告诉我关于哪个作业票!");
+            Assert.notBlank(dto.getLockNfc(), "请告诉我挂锁的NFC!");
+            // 1.获取作业票数据
+            IsJobTicket jobTicket = iIsJobTicketService.getById(dto.getTicketId());
+            Assert.notNull(jobTicket, "作业票数据丢失啦!");
+            // 1.1获取锁的信息
+            IsLock isLock = iIsLockService.getOne(Wrappers.<IsLock>lambdaQuery().eq(IsLock::getLockNfc, dto.getLockNfc()));
+            Assert.notNull(isLock, "挂锁数据丢失啦!");
+            // 1.4修改为归还
+            iIsJobTicketLockService.update(Wrappers.<IsJobTicketLock>lambdaUpdate()
+                    .eq(IsJobTicketLock::getTicketId, jobTicket.getTicketId())
+                    .eq(IsJobTicketLock::getLockId, isLock.getLockId())
+                    .ne(IsJobTicketLock::getLockStatus, "5")
+                    .set(IsJobTicketLock::getLockStatus, "5"));
+        }
+        return true;
+    }
+
+
+}

+ 658 - 0
前端中文提示整理.md

@@ -0,0 +1,658 @@
+# 项目前端中文提示整理
+
+本文档整理了项目中所有返回给前端的中文提示信息,按照不同类别进行分类。
+
+## 一、国际化消息文件 (messages.properties)
+
+**文件位置**: `ktg-admin/src/main/resources/i18n/messages.properties`
+
+### 错误消息
+- `not.null`: * 必须填写
+- `user.jcaptcha.error`: 验证码错误
+- `user.jcaptcha.expire`: 验证码已失效
+- `user.not.exists`: 用户不存在/密码错误
+- `user.password.not.match`: 用户不存在/密码错误
+- `user.password.retry.limit.count`: 密码输入错误{0}次
+- `user.password.retry.limit.exceed`: 密码输入错误{0}次,帐户锁定10分钟
+- `user.password.delete`: 对不起,您的账号已被删除
+- `user.blocked`: 用户已封禁,请联系管理员
+- `role.blocked`: 角色已封禁,请联系管理员
+- `user.logout.success`: 退出成功
+- `length.not.valid`: 长度必须在{min}到{max}个字符之间
+- `user.username.not.valid`: * 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
+- `user.password.not.valid`: * 5-50个字符
+- `user.email.not.valid`: 邮箱格式错误
+- `user.mobile.phone.number.not.valid`: 手机号格式错误
+- `user.login.success`: 登录成功
+- `user.register.success`: 注册成功
+- `user.notfound`: 请重新登录
+- `user.forcelogout`: 管理员强制退出,请重新登录
+- `user.unknown.error`: 未知错误,请重新登录
+
+### 文件上传消息
+- `upload.exceed.maxSize`: 上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB!
+- `upload.filename.exceed.length`: 上传的文件名最长{0}个字符
+
+### 权限相关
+- `no.permission`: 您没有数据的权限,请联系管理员添加权限 [{0}]
+- `no.create.permission`: 您没有创建数据的权限,请联系管理员添加权限 [{0}]
+- `no.update.permission`: 您没有修改数据的权限,请联系管理员添加权限 [{0}]
+- `no.delete.permission`: 您没有删除数据的权限,请联系管理员添加权限 [{0}]
+- `no.export.permission`: 您没有导出数据的权限,请联系管理员添加权限 [{0}]
+- `no.view.permission`: 您没有查看数据的权限,请联系管理员添加权限 [{0}]
+
+## 二、全局错误码常量
+
+**文件位置**: `ktg-common/src/main/java/com/ktg/common/exception/enums/GlobalErrorCodeConstants.java`
+
+### 成功消息
+- `SUCCESS`: 成功
+
+### 客户端错误段
+- `BAD_REQUEST`: 请求参数不正确
+- `UNAUTHORIZED`: 账号未登录
+- `FORBIDDEN`: 没有该操作权限
+- `NOT_FOUND`: 请求未找到
+- `METHOD_NOT_ALLOWED`: 请求方法不正确
+- `LOCKED`: 请求失败,请稍后重试
+- `TOO_MANY_REQUESTS`: 请求过于频繁,请稍后重试
+
+### 服务端错误段
+- `INTERNAL_SERVER_ERROR`: 系统异常
+- `NOT_IMPLEMENTED`: 功能未实现/未开启
+- `ERROR_CONFIGURATION`: 错误的配置项
+
+### 自定义错误段
+- `REPEATED_REQUESTS`: 重复请求,请稍后重试
+- `DEMO_DENY`: 演示模式,禁止写操作
+- `ASSERT_ERROR`: 断言异常
+- `UNKNOWN`: 未知错误
+
+## 三、系统错误码常量
+
+**文件位置**: `ktg-system/src/main/java/com/ktg/system/strategy/ErrorCodeConstants.java`
+
+### AUTH 模块
+- `AUTH_LOGIN_BAD_CREDENTIALS`: 登录失败,账号密码不正确
+- `AUTH_LOGIN_USER_DISABLED`: 登录失败,账号被禁用
+- `AUTH_LOGIN_CAPTCHA_CODE_ERROR`: 验证码不正确,原因:{}
+- `AUTH_THIRD_LOGIN_NOT_BIND`: 未绑定账号,需要进行绑定
+- `AUTH_MOBILE_NOT_EXISTS`: 手机号不存在
+
+### 菜单模块
+- `MENU_NAME_DUPLICATE`: 已经存在该名字的菜单
+- `MENU_PARENT_NOT_EXISTS`: 父菜单不存在
+- `MENU_PARENT_ERROR`: 不能设置自己为父菜单
+- `MENU_NOT_EXISTS`: 菜单不存在
+- `MENU_EXISTS_CHILDREN`: 存在子菜单,无法删除
+- `MENU_PARENT_NOT_DIR_OR_MENU`: 父菜单的类型必须是目录或者菜单
+
+### 角色模块
+- `ROLE_NOT_EXISTS`: 角色不存在
+- `ROLE_NAME_DUPLICATE`: 已经存在名为【{}】的角色
+- `ROLE_CODE_DUPLICATE`: 已经存在标识为【{}】的角色
+- `ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE`: 不能操作类型为系统内置的角色
+- `ROLE_IS_DISABLE`: 名字为【{}】的角色已被禁用
+- `ROLE_ADMIN_CODE_ERROR`: 标识【{}】不能使用
+
+### 用户模块
+- `USER_USERNAME_EXISTS`: 用户账号已经存在
+- `USER_MOBILE_EXISTS`: 手机号已经存在
+- `USER_EMAIL_EXISTS`: 邮箱已经存在
+- `USER_NOT_EXISTS`: 用户不存在
+- `USER_IMPORT_LIST_IS_EMPTY`: 导入用户数据不能为空!
+- `USER_PASSWORD_FAILED`: 用户密码校验失败
+- `USER_IS_DISABLE`: 名字为【{}】的用户已被禁用
+- `USER_COUNT_MAX`: 创建用户失败,原因:超过租户最大租户配额({})!
+- `USER_IMPORT_INIT_PASSWORD`: 初始密码不能为空
+
+### 部门模块
+- `DEPT_NAME_DUPLICATE`: 已经存在该名字的部门
+- `DEPT_PARENT_NOT_EXITS`: 父级部门不存在
+- `DEPT_NOT_FOUND`: 当前部门不存在
+- `DEPT_EXITS_CHILDREN`: 存在子部门,无法删除
+- `DEPT_PARENT_ERROR`: 不能设置自己为父部门
+- `DEPT_NOT_ENABLE`: 部门({})不处于开启状态,不允许选择
+- `DEPT_PARENT_IS_CHILD`: 不能设置自己的子部门为父部门
+
+### 岗位模块
+- `POST_NOT_FOUND`: 当前岗位不存在
+- `POST_NOT_ENABLE`: 岗位({}) 不处于开启状态,不允许选择
+- `POST_NAME_DUPLICATE`: 已经存在该名字的岗位
+- `POST_CODE_DUPLICATE`: 已经存在该标识的岗位
+
+### 字典类型
+- `DICT_TYPE_NOT_EXISTS`: 当前字典类型不存在
+- `DICT_TYPE_NOT_ENABLE`: 字典类型不处于开启状态,不允许选择
+- `DICT_TYPE_NAME_DUPLICATE`: 已经存在该名字的字典类型
+- `DICT_TYPE_TYPE_DUPLICATE`: 已经存在该类型的字典类型
+- `DICT_TYPE_HAS_CHILDREN`: 无法删除,该字典类型还有字典数据
+
+### 字典数据
+- `DICT_DATA_NOT_EXISTS`: 当前字典数据不存在
+- `DICT_DATA_NOT_ENABLE`: 字典数据({})不处于开启状态,不允许选择
+- `DICT_DATA_VALUE_DUPLICATE`: 已经存在该值的字典数据
+
+### 通知公告
+- `NOTICE_NOT_FOUND`: 当前通知公告不存在
+
+### 短信相关
+- `SMS_CHANNEL_NOT_EXISTS`: 短信渠道不存在
+- `SMS_CHANNEL_DISABLE`: 短信渠道不处于开启状态,不允许选择
+- `SMS_CHANNEL_HAS_CHILDREN`: 无法删除,该短信渠道还有短信模板
+- `SMS_TEMPLATE_NOT_EXISTS`: 短信模板不存在
+- `SMS_TEMPLATE_CODE_DUPLICATE`: 已经存在编码为【{}】的短信模板
+- `SMS_TEMPLATE_API_ERROR`: 短信 API 模板调用失败,原因是:{}
+- `SMS_TEMPLATE_API_AUDIT_CHECKING`: 短信 API 模版无法使用,原因:审批中
+- `SMS_TEMPLATE_API_AUDIT_FAIL`: 短信 API 模版无法使用,原因:审批不通过,{}
+- `SMS_TEMPLATE_API_NOT_FOUND`: 短信 API 模版无法使用,原因:模版不存在
+- `SMS_SEND_MOBILE_NOT_EXISTS`: 手机号不存在
+- `SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS`: 模板参数({})缺失
+- `SMS_SEND_TEMPLATE_NOT_EXISTS`: 短信模板不存在
+- `SMS_CODE_NOT_FOUND`: 验证码不存在
+- `SMS_CODE_EXPIRED`: 验证码已过期
+- `SMS_CODE_USED`: 验证码已使用
+- `SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY`: 超过每日短信发送数量
+- `SMS_CODE_SEND_TOO_FAST`: 短信发送过于频繁
+
+### 租户相关
+- `TENANT_NOT_EXISTS`: 租户不存在
+- `TENANT_DISABLE`: 名字为【{}】的租户已被禁用
+- `TENANT_EXPIRE`: 名字为【{}】的租户已过期
+- `TENANT_CAN_NOT_UPDATE_SYSTEM`: 系统租户不能进行修改、删除等操作!
+- `TENANT_NAME_DUPLICATE`: 名字为【{}】的租户已存在
+- `TENANT_WEBSITE_DUPLICATE`: 域名为【{}】的租户已存在
+- `TENANT_PACKAGE_NOT_EXISTS`: 租户套餐不存在
+- `TENANT_PACKAGE_USED`: 租户正在使用该套餐,请给租户重新设置套餐后再尝试删除
+- `TENANT_PACKAGE_DISABLE`: 名字为【{}】的租户套餐已被禁用
+
+### 社交用户
+- `SOCIAL_USER_AUTH_FAILURE`: 社交授权失败,原因是:{}
+- `SOCIAL_USER_NOT_FOUND`: 社交授权失败,找不到对应的用户
+- `SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR`: 获得手机号失败
+- `SOCIAL_CLIENT_WEIXIN_MINI_APP_QRCODE_ERROR`: 获得小程序码失败
+- `SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_TEMPLATE_ERROR`: 获得小程序订阅消息模版失败
+- `SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_MESSAGE_ERROR`: 发送小程序订阅消息失败
+- `SOCIAL_CLIENT_NOT_EXISTS`: 社交客户端不存在
+- `SOCIAL_CLIENT_UNIQUE`: 社交客户端已存在配置
+
+### OAuth2 客户端
+- `OAUTH2_CLIENT_NOT_EXISTS`: OAuth2 客户端不存在
+- `OAUTH2_CLIENT_EXISTS`: OAuth2 客户端编号已存在
+- `OAUTH2_CLIENT_DISABLE`: OAuth2 客户端已禁用
+- `OAUTH2_CLIENT_AUTHORIZED_GRANT_TYPE_NOT_EXISTS`: 不支持该授权类型
+- `OAUTH2_CLIENT_SCOPE_OVER`: 授权范围过大
+- `OAUTH2_CLIENT_REDIRECT_URI_NOT_MATCH`: 无效 redirect_uri: {}
+- `OAUTH2_CLIENT_CLIENT_SECRET_ERROR`: 无效 client_secret: {}
+
+### OAuth2 授权
+- `OAUTH2_GRANT_CLIENT_ID_MISMATCH`: client_id 不匹配
+- `OAUTH2_GRANT_REDIRECT_URI_MISMATCH`: redirect_uri 不匹配
+- `OAUTH2_GRANT_STATE_MISMATCH`: state 不匹配
+- `OAUTH2_CODE_NOT_EXISTS`: code 不存在
+- `OAUTH2_CODE_EXPIRE`: code 已过期
+
+### 邮箱账号
+- `MAIL_ACCOUNT_NOT_EXISTS`: 邮箱账号不存在
+- `MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS`: 无法删除,该邮箱账号还有邮件模板
+
+### 邮件模版
+- `MAIL_TEMPLATE_NOT_EXISTS`: 邮件模版不存在
+- `MAIL_TEMPLATE_CODE_EXISTS`: 邮件模版 code({}) 已存在
+
+### 邮件发送
+- `MAIL_SEND_TEMPLATE_PARAM_MISS`: 模板参数({})缺失
+- `MAIL_SEND_MAIL_NOT_EXISTS`: 邮箱不存在
+
+### 站内信模版
+- `NOTIFY_TEMPLATE_NOT_EXISTS`: 站内信模版不存在
+- `NOTIFY_TEMPLATE_CODE_DUPLICATE`: 已经存在编码为【{}】的站内信模板
+
+### 站内信发送
+- `NOTIFY_SEND_TEMPLATE_PARAM_MISS`: 模板参数({})缺失
+
+## 四、全局异常处理器
+
+**文件位置**: `ktg-framework/src/main/java/com/ktg/framework/web/exception/GlobalExceptionHandler.java`
+
+- 权限校验异常: 没有权限,请联系管理员授权
+- 演示模式异常: 演示模式,不允许操作
+
+## 五、AjaxResult 默认消息
+
+**文件位置**: `ktg-common/src/main/java/com/ktg/common/core/domain/AjaxResult.java`
+
+- 操作成功(默认成功消息)
+- 操作失败(默认失败消息)
+
+## 六、Controller 中直接返回的中文提示
+
+### 用户管理相关
+- 新增用户'{用户名}'失败,登录账号已存在
+- 新增用户'{用户名}'失败,手机号码已存在
+- 新增用户'{用户名}'失败,邮箱账号已存在
+- 修改用户'{用户名}'失败,手机号码已存在
+- 修改用户'{用户名}'失败,邮箱账号已存在
+
+### 仓库管理相关
+- 仓库编码已存在!
+- 仓库名称已存在!
+- 库区编码已存在!
+- 库区名称已存在!
+
+### 单据相关(通用)
+- 单据编号已存在!
+- 单据编号已存在
+- 只能删除草稿状态的单据!
+- 只能删除草稿状态单据!
+- 只能删除状态为草稿的单据!
+- 无效单据
+- 当前单据已提交!
+
+### 转移单相关
+- 转移单编号已存在
+- 请添加需要转移的物资!
+- 请添加转移单行信息!
+
+### 盘点相关
+- 未检测到盘点的物资!
+
+### 退货单相关
+- 退货单编号已经存在!
+- 退货单号已存在!
+- 请添加退货单行信息!
+
+### 退料单相关
+- 退料单编号已存在
+- 请选择要退料的物资
+- 请从库存现有量中选择退料的物资!
+
+### 入库单相关
+- 入库单编号已存在!
+- 请添加要入库的产品
+- 请添加入库单行
+- 请添加明细信息!
+- 请指定入库的物资!
+
+### 出库单相关
+- 出库单编号已存在!
+- 出库物资不能为空
+- 请指定领出的物资
+
+### 领料单相关
+- 领料单编号已存在
+
+### 装箱单相关
+- 装箱单编号已存在!
+- 不能添加自己为子箱!
+- 当前子箱已经有外箱包装!
+
+### 条码相关
+- 当前业务内容的条码已存在!
+
+### 工装夹具相关
+- 类型编码已存在!
+- 类型名称已存在!
+- 此工装夹具编码已存在!
+
+### 质检相关
+- 检测模板编号已存在!
+- 检测单编码已存在!
+- 产品已设置检测模板!
+- 当前产品未配置检测模板!
+- 当前工单生产的产品未配置此类型的检验模板!
+- 当前生产的产品未配置此类型的检验模板,请联系质量管理人员!
+- 请填写缺陷内容
+- 请选择缺陷级别
+
+### 出货单相关
+- 出货单编号已存在!
+
+### 外协相关
+- 未找到对应的外协工单/外协任务!
+
+### 生产任务相关
+- 请提供生产任务数据
+
+## 七、Service 中抛出的中文异常
+
+### 用户服务
+- 导入用户数据不能为空!
+- 不允许操作超级管理员用户
+- 没有权限访问用户数据!
+
+### 岗位服务
+- {岗位名称}已分配,不能删除
+
+### 角色服务
+- 不允许操作超级管理员角色
+- 没有权限访问角色数据!
+- {角色名称}已分配,不能删除
+
+### 配置服务
+- 内置参数【{参数键}】不能删除
+
+### 字典类型服务
+- {字典类型名称}已分配,不能删除
+
+### 部门服务
+- 没有权限访问部门数据!
+- 部门停用,不允许新增
+
+### 供应商服务
+- 导入供应商数据不能为空!
+
+### 物料产品服务
+- 导入物料产品数据不能为空!
+
+### 客户服务
+- 导入客户数据不能为空!
+
+### 代码生成服务
+- 导入失败:{错误信息}
+- 渲染模板失败,表名:{表名}
+- 同步数据失败,原表结构不存在
+- 树编码字段不能为空
+- 树父编码字段不能为空
+- 树名称字段不能为空
+- 关联子表的表名不能为空
+- 子表关联的外键名不能为空
+
+### 用户详情服务
+- 登录用户:{用户名} 不存在
+- 对不起,您的账号:{用户名} 已被删除
+- 对不起,您的账号:{用户名} 已停用
+- 对不起,您的账号:{用户名} 已被拉入{模块}模块黑名单,暂时无法登录!
+- 对不起,您的账号:{用户名} 缺失角色权限,暂时无法登录。请前往角色或基础数据配置!
+
+### 移动端登录服务
+- 请前往数据字典【sys_config】中维护注册用户角色编码【register_role_code】
+- 请前往数据字典【sys_config】中维护注册用户部门编码【register_dept_code】
+- 请前往数据字典【sys_config】中维护注册用户岗位编码【register_post_code】
+
+### 限流服务
+- 访问过于频繁,请稍候再试
+
+### 安全工具
+- 获取用户ID异常
+- 获取部门ID异常
+- 获取用户账户异常
+- 获取用户信息异常
+
+## 八、CommonResult 成功消息
+
+- 设备信息:{设备信息}
+- 导入成功,共导入 {数量} 条数据
+
+## 九、Assert 参数校验提示
+
+Assert 用于参数校验,当校验失败时会抛出异常并返回给前端。
+
+### 通用删除提示
+- 请选择需要删除的数据!
+
+### 通用参数校验
+- id不可为空!
+- 主键id不能为空!
+- 主键id不可为空!
+- 无效参数!
+
+### 作业票相关
+- 作业票信息不存在!
+- 作业票数据丢失啦!
+- 作业票信息丢失了!
+- 作业票信息丢失!
+- 作业票id不可为空!
+- 当前作业票id不能为空!
+- 该作业票已执行至第六步,无法取消!
+- 请等待作业票[{作业票名称}]上锁完成!
+- 请告诉我关于哪个作业票!
+- 作业id不能为空!
+- 作业票已完成设备拿取,无法操作!
+- 作业票已完成设备拿取,无法进行操作!
+- 该作业票未开始,请勿共锁!
+- 您已共锁,请勿重复共锁!
+- 您还未共锁,请勿操作解除共锁!
+- 您已解除共锁,请勿重复解除锁!
+- 作业票编号不可为空!
+- 作业票名称不可为空!
+- 请选择隔离点!
+- 人员信息不可为空!
+- 点位信息不能为空!
+
+### 钥匙相关
+- 钥匙数据丢失啦!
+- 该nfc无对应的钥匙信息
+- 请告诉我钥匙的NFC!
+- 钥匙NFC不可为空!
+- {keyNfc}对应的钥匙信息不存在!
+
+### 挂锁相关
+- 挂锁数据丢失啦!
+- 该nfc无对应的挂锁信息!
+- 该nfc无对应的挂锁信息
+- 该锁nfc不能为空!
+- {nfc}对应的挂锁数据不存在!
+- 挂锁nfc缺失!
+- 请告诉我挂锁的NFC!
+- {lockNfc}对应的挂锁信息不存在!
+- {lockName}已被取出!
+- 点位挂锁错误,重复点位[{pointName}]请多锁完成重复点位上锁!
+- 请取出至少一把挂锁!
+
+### 硬件相关
+- 该序列号无对应的硬件信息!
+- 无初始化数据来提供给该挂锁更新
+- 无初始化数据来提供给该辅件更新
+- 硬件编码不可为空!
+- 硬件名称不可为空!
+- {hardwareCode}已被使用!
+- {serialNumber}已被使用!
+- 请告知归还到哪里!
+- 请告知归还到哪一个柜子!
+
+### 隔离点相关
+- 该nfc无对应的隔离点信息
+- {点位名称}点位正在被sop使用,无法删除!
+- {isolationPointName}正在被{lotoName}锁定站使用,请先从锁定站解除绑定!
+- 隔离点名称不可为空!
+- 隔离点编号名称不可为空!
+- 隔离点ID不可为空!
+- 该隔离点名称已被使用!
+- 该NFC已被使用!
+- 该编号已被使用!
+- 该序列号已被使用!
+- 隔离点id不可为空!
+- 查询隔离点信息出错!
+
+### 辅件相关
+- 该nfc无对应的辅件信息
+- 该nfc无对应的辅件信息!
+- 辅件nfc缺失!
+- {locksetNfc}无对应的辅件信息!
+- 请取出至少一个辅件!
+
+### 岗位相关
+- 岗位信息不存在!
+- 岗位名称不可为空!
+- 该岗位名称已被使用!
+- 岗位ID不可为空!
+- 岗位不可为空!
+- 岗位正在被用户使用,无法删除!
+- 岗位下有子岗位,无法删除!
+
+### SOP相关
+- sop数据不存在!
+- sop不存在
+- sopId不可为空!
+- SOP名称不可为空!
+- SOP编号名称不可为空!
+- 该SOP编号已被使用!
+- 排序数据不可为空!
+
+### 设备工艺相关
+- 设备工艺信息不存在!
+- 名称不可为空!
+- 父id不可为空!
+- [{machineryName}]名称已被工艺/设备使用,请重新填写!
+- 请选择隔离点!
+
+### 工作区域相关
+- 区域名称不可为空!
+- 区域编号名称不可为空!
+- 区域ID不可为空!
+- 该区域编号已被使用!
+- {workareaName}下有隔离点,暂不可删除!
+- 请传入区域id
+
+### 锁控柜/物资柜相关
+- 锁控柜id不能为空!
+- 物资柜存在!
+- 物资柜code不能为空!
+- 物资柜信息不存在!
+- 物资柜信息不存在!
+- 物资柜不存在!
+- 无法识别{物资柜code}物资柜身份!
+- 柜子不存在!
+- 请告诉我这是哪台物资柜!
+- cabinetCode不能为空!
+- 该物资柜当前无您的检查计划!
+- 当前物资柜无需您执行的检查计划!
+- 请先清理柜子下的仓位信息!
+- 该编码已被使用,请更换!
+- 该名称已被使用,请更换!
+- 电柜ID不能为空!
+- 请传入电柜id
+- 名称不可为空!
+- 该名称已被使用,请重新填写!
+- 该序列号已被使用,请重新填写!
+
+### 物资相关
+- 物资RFID不能为空!
+- 通过RFID:{RFID}未查询到物资!
+- 通过物资柜code:{物资柜code}未查询到物资柜信息!
+- 请在该柜中放入新物资!
+- 原物资不存在
+- 新物资不存在
+- 该物资编码已被使用!
+- 该RFID已被使用!
+- 该物资不存在!
+- 请告诉我物资的rfid!
+- 请告诉我是借出还是归还!
+- {materialsRfid}物资已经是借出状态,无法再借出!
+- {materialsRfid}物资已经是柜中状态,无法再放入!
+- 物资柜信息不可为空!
+- 请选择物资!
+- 旧物资ID不能为空!
+- 新物资RFID不能为空!
+- 需要更换的物资未取出!
+- 该物资存在所属柜子,不可更换!
+- 更换的物资异常,不可更换!
+- 没有确定要维修或更换的物资!
+- 导入物资数据不能为空!
+
+### 物资分类相关
+- {分类名称}分类下有物资,不可删除!
+- {分类名称}分类下有子类,不可删除!
+- 该物资类型编码已被使用!
+- 借用时长需要大于等于提醒时长!
+
+### 电机相关
+- 该电机数据不存在!
+- 地图主键不能为空
+
+### 地图相关
+- map数据解析失败!
+- 请提供loto柜序列号!
+- 请提供柜序列号!
+- 请传入电柜id
+
+### 检查计划相关
+- 请在基础数据中配置物资检查计划模板!
+- 检查计划planId不能为空!
+
+### 指纹相关
+- 请告知我这是哪个用户的指纹!
+- 指纹分组不可为空!
+- 该人员的指纹录入已上限,最大{数量}条!
+- 该文件指纹无法识别,请重新录入!
+- 指纹相似度相差较大,请重新录入!
+- 指纹信息不能为空!
+
+### 人脸相关
+- 请告知我这是哪个用户的人脸!
+- 该人员的人脸录入已上限,最大{数量}条!
+- 人脸文件无法解析!
+- 请上传人脸文件!
+- 获取人脸失败!
+- 获取人脸特征值失败!
+- 未识别到人脸!
+- 人脸对比异常{errorCode}!
+- 人脸信息不能为空!
+
+### 登录相关
+- 无法根据指纹确定您的身份,请通过其它方式登录!
+- 无法根据人脸确定您的身份,请通过其它方式登录!
+
+### 编码规则相关
+- 编码规则传入字符不能为空!
+- 未获取到指定类型:[{类型}]的业务编码生成规则
+- 未查询到规则{[]}对应的结果记录
+- 传入字符的长度错误!
+- 编码规则[{ruleCode}]流水号方式的组成只能存在一个
+- 规则:[{ruleCode}]生成的编码为空!
+- 生成的编码[{code}]已经超出规则中配置的最大长度:[{maxLength}]
+
+### 业务编码相关
+- 最大长度{最大长度}小于分段长度总和{分段长度总和},请扩容最大长度!
+
+### 文件上传相关
+- 无效参数!
+
+### 统计相关
+- type不能为空!
+
+### 用户相关
+- 用户数据存在同名情况,请修改!
+- 系统中无该用户!
+- 该工作卡未绑定用户!
+- 该员工卡绑定的员工暂无作业任务!
+- 操作的共锁/解锁状态不能为空!
+- 工作卡NFC不能为空!
+
+### 字典数据相关
+- 该字典类型下已存在键值:{dictValue},请重新填写!
+
+### 其他业务逻辑
+- 没有接收到数据啊!
+- 请告知隔离点信息!
+- 请告我是去挂锁还是解锁!
+- 请告我任务当前状态!
+- 点位开关数据不可为空!
+- 锁定站序列号不可为空!
+- 点位序列号不可为空!
+- 通过nfc查询不到相关挂锁信息!
+- 识别到多张人脸,请重新调整位置!
+
+---
+
+## 十、其他提示
+
+(已整合到前面各章节)
+
+---
+
+## 说明
+
+1. 本文档整理了项目中所有返回给前端的中文提示信息,包括:
+   - 国际化消息文件中的提示
+   - 错误码常量中的提示
+   - Controller 中直接返回的提示
+   - Service 中抛出的异常消息
+   - Assert 参数校验失败时的提示
+   - 全局异常处理器中的提示
+2. 部分提示包含占位符(如 {0}、{}、{用户名} 等),实际返回时会替换为具体值
+3. 提示信息按模块和功能进行分类,便于查找和维护
+4. Assert 提示会在参数校验失败时抛出异常,最终通过全局异常处理器返回给前端
+5. 建议后续新增提示时,优先使用国际化消息文件或错误码常量,避免在代码中硬编码中文
+