package com.ruoyi.asset.service.impl;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.asset.domain.AmsAsset;
import com.ruoyi.asset.domain.AmsRepairOperateContext;
import com.ruoyi.asset.domain.AmsRepairOrder;
import com.ruoyi.asset.domain.AssetTransitionContext;
import com.ruoyi.asset.domain.AssetTransitionResult;
import com.ruoyi.asset.mapper.AmsAssetMapper;
import com.ruoyi.asset.mapper.AmsRepairOrderMapper;
import com.ruoyi.asset.service.IAmsRepairOrderService;
import com.ruoyi.asset.service.IAssetStatusTransitionService;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.service.ISysCodeRuleService;

/**
 * 报修维修管理Service业务层处理
 *
 * 核心职责：处理实物资产从报修（在库/在用状态）到进入维修中（REPAIRING），
 * 并在维修完成后将状态和归属完整恢复至原状态（在库/在用）的生命周期。
 *
 * @author Yangk
 * @date 2026-06-16
 */
@Service
public class AmsRepairOrderServiceImpl implements IAmsRepairOrderService
{
    private static final String REPAIR_ORDER_RULE = "REPAIR_ORDER";
    private static final String DEL_FLAG_NORMAL = "0";

    // 资产状态
    private static final String ASSET_STATUS_IN_STOCK = "IN_STOCK";
    private static final String ASSET_STATUS_IN_USE = "IN_USE";

    // 报修单状态
    private static final String STATUS_DRAFT = "DRAFT";
    private static final String STATUS_PENDING_CONFIRM = "PENDING_CONFIRM";
    private static final String STATUS_REJECTED = "REJECTED";
    private static final String STATUS_WAIT_REPAIR = "WAIT_REPAIR";
    private static final String STATUS_REPAIRING = "REPAIRING";
    private static final String STATUS_REPAIR_DONE = "REPAIR_DONE";

    // 维修方类型
    private static final String REPAIRER_TYPE_INTERNAL = "INTERNAL";
    private static final String REPAIRER_TYPE_EXTERNAL = "EXTERNAL";

    @Autowired
    private AmsRepairOrderMapper amsRepairOrderMapper;

    @Autowired
    private AmsAssetMapper amsAssetMapper;

    @Autowired
    private ISysCodeRuleService sysCodeRuleService;

    @Autowired
    private IAssetStatusTransitionService assetStatusTransitionService;

    /**
     * 查询报修维修管理
     */
    @Override
    public AmsRepairOrder selectAmsRepairOrderByRepairId(Long repairId)
    {
        return amsRepairOrderMapper.selectAmsRepairOrderByRepairId(repairId);
    }

    /**
     * 查询报修维修管理列表
     */
    @Override
    public List<AmsRepairOrder> selectAmsRepairOrderList(AmsRepairOrder amsRepairOrder)
    {
        return amsRepairOrderMapper.selectAmsRepairOrderList(amsRepairOrder);
    }

    /**
     * 新增报修单草稿
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertAmsRepairOrder(AmsRepairOrder amsRepairOrder, AmsRepairOperateContext operateContext)
    {
        validateOperateContext(operateContext);

        // 1. 基础报文非空和长度校验
        validateOrderRequest(amsRepairOrder);

        // 2. 悲观锁锁定资产，校验原状态，并回填属性快照及前置状态
        fillAssetSnapshots(amsRepairOrder, null);

        // 3. 生成 BX 前缀的唯一报修单号
        Date now = DateUtils.getNowDate();
        amsRepairOrder.setRepairNo(sysCodeRuleService.nextCode(REPAIR_ORDER_RULE));
        amsRepairOrder.setReportUserId(operateContext.getOperateUserId());
        amsRepairOrder.setReportUserName(StringUtils.trim(operateContext.getOperateUserName()));
        amsRepairOrder.setReportTime(now);
        amsRepairOrder.setOrderStatus(STATUS_DRAFT);
        amsRepairOrder.setDelFlag(DEL_FLAG_NORMAL);
        amsRepairOrder.setCreateBy(operateContext.getOperateLoginName());
        amsRepairOrder.setCreateTime(now);

        // 重置受控的维修中及维修完成字段，以防篡改
        amsRepairOrder.setRepairerType(null);
        amsRepairOrder.setRepairUserId(null);
        amsRepairOrder.setRepairUserName(null);
        amsRepairOrder.setRepairOrgName(null);
        amsRepairOrder.setRepairContactPhone(null);
        amsRepairOrder.setRepairStartTime(null);
        amsRepairOrder.setRepairFinishTime(null);
        amsRepairOrder.setRepairResult(null);
        amsRepairOrder.setRepairCost(BigDecimal.ZERO);
        amsRepairOrder.setBeforeAssetStatus(null);
        amsRepairOrder.setRejectReason(null);

        return amsRepairOrderMapper.insertAmsRepairOrder(amsRepairOrder);
    }

    /**
     * 修改报修单草稿
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateAmsRepairOrder(AmsRepairOrder amsRepairOrder, AmsRepairOperateContext operateContext)
    {
        validateOperateContext(operateContext);
        if (amsRepairOrder == null || amsRepairOrder.getRepairId() == null)
        {
            throw new ServiceException("单据ID不能为空");
        }

        // 1. 悲观锁锁定并校验状态必须为 DRAFT。非草稿状态严禁修改
        AmsRepairOrder current = requireOrderForUpdate(amsRepairOrder.getRepairId(), STATUS_DRAFT,
                "仅草稿状态的报修单允许修改");

        validateOrderRequest(amsRepairOrder);

        // 2. 锁定资产，校验原状态并重新回填快照
        fillAssetSnapshots(amsRepairOrder, amsRepairOrder.getRepairId());

        // 3. 强行还原单号等受控属性，清空受理及驳回信息，强制复归为 DRAFT
        amsRepairOrder.setRepairNo(current.getRepairNo());
        amsRepairOrder.setReportUserId(current.getReportUserId());
        amsRepairOrder.setReportUserName(current.getReportUserName());
        amsRepairOrder.setReportTime(current.getReportTime());
        amsRepairOrder.setOrderStatus(STATUS_DRAFT);
        amsRepairOrder.setCreateBy(current.getCreateBy());
        amsRepairOrder.setCreateTime(current.getCreateTime());
        amsRepairOrder.setDelFlag(current.getDelFlag());
        amsRepairOrder.setUpdateBy(operateContext.getOperateLoginName());
        amsRepairOrder.setUpdateTime(DateUtils.getNowDate());

        // 重置受控字段
        amsRepairOrder.setRepairerType(current.getRepairerType());
        amsRepairOrder.setRepairUserId(null);
        amsRepairOrder.setRepairUserName(null);
        amsRepairOrder.setRepairOrgName(null);
        amsRepairOrder.setRepairContactPhone(null);
        amsRepairOrder.setRepairStartTime(null);
        amsRepairOrder.setRepairFinishTime(null);
        amsRepairOrder.setRepairResult(null);
        amsRepairOrder.setRepairCost(BigDecimal.ZERO);
        amsRepairOrder.setBeforeAssetStatus(null);
        amsRepairOrder.setRejectReason(null);

        return updateOrderOrThrow(amsRepairOrder, STATUS_DRAFT, "单据状态已发生改变，更新失败");
    }

    /**
     * 批量逻辑删除报修单草稿
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteAmsRepairOrderByRepairIds(String repairIds)
    {
        // 1. 将操作ID排序以彻底防范死锁
        Long[] sortedIds = Arrays.stream(Convert.toStrArray(repairIds))
                .map(Long::valueOf).sorted().toArray(Long[]::new);
        int rows = 0;
        for (Long repairId : sortedIds)
        {
            // 2. 获取排他锁，验证是否为 DRAFT 草稿单
            AmsRepairOrder order = amsRepairOrderMapper.selectAmsRepairOrderByRepairIdForUpdate(repairId);
            if (order == null)
            {
                continue;
            }
            if (!STATUS_DRAFT.equals(order.getOrderStatus()))
            {
                throw new ServiceException(StringUtils.format("报修单【{}】非草稿状态，不允许删除", order.getRepairNo()));
            }
            rows += amsRepairOrderMapper.deleteAmsRepairOrderByRepairId(repairId);
        }
        return rows;
    }

    /**
     * 逻辑删除单个报修单草稿
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteAmsRepairOrderByRepairId(Long repairId)
    {
        AmsRepairOrder order = amsRepairOrderMapper.selectAmsRepairOrderByRepairIdForUpdate(repairId);
        if (order == null)
        {
            return 0;
        }
        if (!STATUS_DRAFT.equals(order.getOrderStatus()))
        {
            throw new ServiceException(StringUtils.format("报修单【{}】非草稿状态，不允许删除", order.getRepairNo()));
        }
        return amsRepairOrderMapper.deleteAmsRepairOrderByRepairId(repairId);
    }

    /**
     * 提交报修申请
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int submitRepair(Long repairId, AmsRepairOperateContext operateContext)
    {
        validateOperateContext(operateContext);
        AmsRepairOrder order = requireOrderForUpdate(repairId, STATUS_DRAFT, "仅草稿状态的报修单允许提交");

        // 二次校验实物状态与占用情况
        validateAssetReadyForRepair(order.getAssetId(), order.getRepairId());

        order.setOrderStatus(STATUS_PENDING_CONFIRM);
        order.setUpdateBy(operateContext.getOperateLoginName());
        order.setUpdateTime(DateUtils.getNowDate());

        return updateOrderOrThrow(order, STATUS_DRAFT, "报修单提交失败，请刷新后重试");
    }

    /**
     * 确认受理报修
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int confirmRepair(Long repairId, AmsRepairOperateContext operateContext)
    {
        validateOperateContext(operateContext);
        AmsRepairOrder order = requireOrderForUpdate(repairId, STATUS_PENDING_CONFIRM, "仅待确认状态的报修单允许受理");

        // 二次校验实物状态与占用情况
        validateAssetReadyForRepair(order.getAssetId(), order.getRepairId());

        order.setOrderStatus(STATUS_WAIT_REPAIR);
        order.setUpdateBy(operateContext.getOperateLoginName());
        order.setUpdateTime(DateUtils.getNowDate());
        order.setRejectReason(null); // 清除可能存在的驳回记录

        return updateOrderOrThrow(order, STATUS_PENDING_CONFIRM, "报修单受理失败，请刷新后重试");
    }

    /**
     * 驳回报修申请
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int rejectRepair(Long repairId, String rejectReason, AmsRepairOperateContext operateContext)
    {
        validateOperateContext(operateContext);
        AmsRepairOrder order = requireOrderForUpdate(repairId, STATUS_PENDING_CONFIRM, "仅待确认状态的报修单允许驳回");
        if (StringUtils.isEmpty(StringUtils.trim(rejectReason)))
        {
            throw new ServiceException("驳回原因不能为空");
        }
        validateLength(rejectReason, 500, "驳回原因");

        order.setOrderStatus(STATUS_REJECTED);
        order.setRejectReason(StringUtils.trim(rejectReason));
        order.setUpdateBy(operateContext.getOperateLoginName());
        order.setUpdateTime(DateUtils.getNowDate());

        return updateOrderOrThrow(order, STATUS_PENDING_CONFIRM, "报修单驳回失败，请刷新后重试");
    }

    /**
     * 开始维修：WAIT_REPAIR → REPAIRING
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int startRepair(AmsRepairOrder amsRepairOrder, AmsRepairOperateContext operateContext)
    {
        validateOperateContext(operateContext);
        if (amsRepairOrder == null || amsRepairOrder.getRepairId() == null)
        {
            throw new ServiceException("参数不能为空");
        }

        // 1. 锁定单据并核查必须处于 WAIT_REPAIR 状态
        AmsRepairOrder order = requireOrderForUpdate(amsRepairOrder.getRepairId(), STATUS_WAIT_REPAIR,
                "仅待维修状态的报修单允许开始维修");

        // 2. 校验维修方信息并填充
        if (StringUtils.isEmpty(amsRepairOrder.getRepairerType()))
        {
            throw new ServiceException("维修方类型不能为空");
        }
        if (!REPAIRER_TYPE_INTERNAL.equals(amsRepairOrder.getRepairerType())
                && !REPAIRER_TYPE_EXTERNAL.equals(amsRepairOrder.getRepairerType()))
        {
            throw new ServiceException("非法的维修方类型");
        }

        if (REPAIRER_TYPE_INTERNAL.equals(amsRepairOrder.getRepairerType()))
        {
            if (StringUtils.isEmpty(amsRepairOrder.getRepairUserName()))
            {
                throw new ServiceException("内部维修人不能为空");
            }
            order.setRepairUserId(amsRepairOrder.getRepairUserId());
            order.setRepairUserName(StringUtils.trim(amsRepairOrder.getRepairUserName()));
            order.setRepairOrgName(null);
        }
        else
        {
            if (StringUtils.isEmpty(amsRepairOrder.getRepairOrgName()))
            {
                throw new ServiceException("外部维修单位不能为空");
            }
            order.setRepairUserId(null);
            order.setRepairUserName(StringUtils.trim(amsRepairOrder.getRepairUserName())); // 允许外修时选记录人
            order.setRepairOrgName(StringUtils.trim(amsRepairOrder.getRepairOrgName()));
        }

        validateLength(amsRepairOrder.getRepairContactPhone(), 30, "联系电话");
        order.setRepairerType(amsRepairOrder.getRepairerType());
        order.setRepairContactPhone(StringUtils.trim(amsRepairOrder.getRepairContactPhone()));

        // 3. 悲观锁定资产，并校验其前置实物状态
        AmsAsset asset = amsAssetMapper.selectAmsAssetByAssetIdForUpdate(order.getAssetId());
        if (asset == null || "1".equals(asset.getDelFlag()))
        {
            throw new ServiceException("资产不存在或已删除");
        }
        if (!ASSET_STATUS_IN_STOCK.equals(asset.getAssetStatus())
                && !ASSET_STATUS_IN_USE.equals(asset.getAssetStatus()))
        {
            throw new ServiceException(StringUtils.format("资产【{}】当前状态【{}】不允许进行维修",
                    asset.getAssetCode(), asset.getAssetStatus()));
        }

        // 4. 调用公共流转服务执行开始维修 (实物变为 REPAIRING 并写入履历)
        AssetTransitionContext context = buildTransitionContext(order, operateContext, "开始资产维修");

        AssetTransitionResult transitionResult = assetStatusTransitionService.startRepair(order.getAssetId(), context);

        // 5. 记录维修前的资产状态快照，用于恢复
        order.setBeforeAssetStatus(transitionResult.getBeforeAsset().getAssetStatus());
        order.setRepairStartTime(DateUtils.getNowDate());
        order.setOrderStatus(STATUS_REPAIRING);
        order.setUpdateBy(operateContext.getOperateLoginName());
        order.setUpdateTime(DateUtils.getNowDate());

        return updateOrderOrThrow(order, STATUS_WAIT_REPAIR, "报修单开始维修失败，请刷新后重试");
    }

    /**
     * 完成维修：REPAIRING → REPAIR_DONE
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int finishRepair(AmsRepairOrder amsRepairOrder, AmsRepairOperateContext operateContext)
    {
        validateOperateContext(operateContext);
        if (amsRepairOrder == null || amsRepairOrder.getRepairId() == null)
        {
            throw new ServiceException("参数不能为空");
        }

        // 1. 锁定单据并核查必须处于 REPAIRING 状态
        AmsRepairOrder order = requireOrderForUpdate(amsRepairOrder.getRepairId(), STATUS_REPAIRING,
                "仅维修中状态的报修单允许提交完成");

        // 2. 校验完成信息
        if (StringUtils.isEmpty(StringUtils.trim(amsRepairOrder.getRepairResult())))
        {
            throw new ServiceException("维修结果不能为空");
        }
        validateLength(amsRepairOrder.getRepairResult(), 500, "维修结果");

        if (amsRepairOrder.getRepairCost() == null || amsRepairOrder.getRepairCost().compareTo(BigDecimal.ZERO) < 0)
        {
            throw new ServiceException("维修费用不能为空且必须为非负数");
        }
        if (amsRepairOrder.getRepairFinishTime() == null)
        {
            throw new ServiceException("维修完成时间不能为空");
        }
        if (order.getRepairStartTime() != null)
        {
            Date startZero = DateUtils.truncate(order.getRepairStartTime(), java.util.Calendar.DATE);
            Date finishZero = DateUtils.truncate(amsRepairOrder.getRepairFinishTime(), java.util.Calendar.DATE);
            if (finishZero.before(startZero))
            {
                throw new ServiceException("维修完成时间不能早于维修开始时间");
            }
        }

        // 3. 悲观锁锁定资产
        AmsAsset asset = amsAssetMapper.selectAmsAssetByAssetIdForUpdate(order.getAssetId());
        if (asset == null || "1".equals(asset.getDelFlag()))
        {
            throw new ServiceException("资产不存在或已删除");
        }

        // 4. 调用公共流转服务执行完成维修 (资产恢复至维修前状态并写履历)
        AssetTransitionContext context = buildTransitionContext(order, operateContext, "完成资产维修");

        assetStatusTransitionService.finishRepair(order.getAssetId(), order.getBeforeAssetStatus(), context);

        // 5. 使用维修完成时间更新资产的上次维保日期last_maintenance_date
        amsAssetMapper.updateAssetMaintenanceDate(order.getAssetId(), amsRepairOrder.getRepairFinishTime(),
                operateContext.getOperateLoginName(), DateUtils.getNowDate());

        // 6. 填充完成属性
        order.setRepairFinishTime(amsRepairOrder.getRepairFinishTime());
        order.setRepairResult(StringUtils.trim(amsRepairOrder.getRepairResult()));
        order.setRepairCost(amsRepairOrder.getRepairCost());
        order.setOrderStatus(STATUS_REPAIR_DONE);
        order.setUpdateBy(operateContext.getOperateLoginName());
        order.setUpdateTime(DateUtils.getNowDate());

        return updateOrderOrThrow(order, STATUS_REPAIRING, "报修单完成维修失败，请刷新后重试");
    }

    /**
     * 查询可用于报修的在库/在用资产列表
     */
    @Override
    public List<AmsAsset> selectAvailableRepairAssetList(AmsAsset asset, Long currentRepairId)
    {
        return amsRepairOrderMapper.selectAvailableRepairAssetList(asset, currentRepairId,
                Arrays.asList(ASSET_STATUS_IN_STOCK, ASSET_STATUS_IN_USE),
                Arrays.asList(STATUS_DRAFT, STATUS_PENDING_CONFIRM, STATUS_WAIT_REPAIR, STATUS_REPAIRING));
    }

    // ========================================== 私有辅助方法 ==========================================

    private AmsRepairOrder requireOrderForUpdate(Long repairId, String expectedStatus, String errMsg)
    {
        AmsRepairOrder order = amsRepairOrderMapper.selectAmsRepairOrderByRepairIdForUpdate(repairId);
        if (order == null)
        {
            throw new ServiceException("报修单不存在或已删除");
        }
        if (!expectedStatus.equals(order.getOrderStatus()))
        {
            throw new ServiceException(errMsg);
        }
        return order;
    }

    private int updateOrderOrThrow(AmsRepairOrder order, String expectedStatus, String errorMessage)
    {
        // 即使当前事务已用 for update 加锁，仍写入期望状态，防止未来绕过锁读路径时误用通用更新 SQL。
        order.getParams().put("expectedOrderStatus", expectedStatus);
        if (amsRepairOrderMapper.updateAmsRepairOrder(order) != 1)
        {
            throw new ServiceException(errorMessage);
        }
        return 1;
    }

    private AssetTransitionContext buildTransitionContext(AmsRepairOrder order, AmsRepairOperateContext operateContext,
            String changeSummary)
    {
        AssetTransitionContext context = new AssetTransitionContext();
        context.setSourceOrderId(order.getRepairId());
        context.setSourceOrderNo(order.getRepairNo());
        context.setOperateUserId(operateContext.getOperateUserId());
        context.setOperateUserName(StringUtils.trim(operateContext.getOperateUserName()));
        context.setOperateLoginName(operateContext.getOperateLoginName());
        context.setChangeSummary(changeSummary);
        context.setRemark(order.getRemark());
        return context;
    }

    private void validateOrderRequest(AmsRepairOrder order)
    {
        if (order == null)
        {
            throw new ServiceException("单据数据不能为空");
        }
        if (order.getAssetId() == null)
        {
            throw new ServiceException("报修的资产不能为空");
        }
        if (StringUtils.isEmpty(StringUtils.trim(order.getFaultDesc())))
        {
            throw new ServiceException("故障描述不能为空");
        }
        validateLength(order.getFaultDesc(), 500, "故障描述");
        validateLength(order.getRemark(), 500, "备注");
        if (order.getExpectedFinishTime() != null)
        {
            Date todayZero = DateUtils.truncate(DateUtils.getNowDate(), java.util.Calendar.DATE);
            if (order.getExpectedFinishTime().before(todayZero))
            {
                throw new ServiceException("期望完成日期不能早于当前日期");
            }
        }
    }

    private void fillAssetSnapshots(AmsRepairOrder order, Long currentRepairId)
    {
        AmsAsset asset = amsAssetMapper.selectAmsAssetByAssetIdForUpdate(order.getAssetId());
        if (asset == null || "1".equals(asset.getDelFlag()))
        {
            throw new ServiceException("所选择的报修资产不存在或已删除");
        }

        // 1. 实物前置状态必须为在库或在用
        if (!ASSET_STATUS_IN_STOCK.equals(asset.getAssetStatus())
                && !ASSET_STATUS_IN_USE.equals(asset.getAssetStatus()))
        {
            throw new ServiceException(StringUtils.format("资产【{}】当前状态【{}】不允许进行报修",
                    asset.getAssetCode(), asset.getAssetStatus()));
        }

        // 2. 校验并发占用
        int occupied = amsRepairOrderMapper.countOtherActiveRepairOrderByAssetId(order.getAssetId(), currentRepairId,
                Arrays.asList(STATUS_DRAFT, STATUS_PENDING_CONFIRM, STATUS_WAIT_REPAIR, STATUS_REPAIRING));
        if (occupied > 0)
        {
            throw new ServiceException(StringUtils.format("资产【{}】当前已被其他未完结报修单占用", asset.getAssetCode()));
        }

        // 3. 回填基本属性与仓位/部门快照
        order.setAssetCode(asset.getAssetCode());
        order.setAssetName(asset.getAssetName());
        order.setCategoryId(asset.getCategoryId());
        order.setCategoryCode(asset.getCategoryCode());
        order.setCategoryName(asset.getCategoryName());
        order.setSpecModel(asset.getSpecModel());
        order.setBrand(asset.getBrand());
    }

    private void validateAssetReadyForRepair(Long assetId, Long currentRepairId)
    {
        AmsAsset asset = amsAssetMapper.selectAmsAssetByAssetIdForUpdate(assetId);
        if (asset == null || "1".equals(asset.getDelFlag()))
        {
            throw new ServiceException("资产不存在或已删除");
        }
        if (!ASSET_STATUS_IN_STOCK.equals(asset.getAssetStatus())
                && !ASSET_STATUS_IN_USE.equals(asset.getAssetStatus()))
        {
            throw new ServiceException(StringUtils.format("资产【{}】当前状态不能借由流程流转", asset.getAssetCode()));
        }
        int occupied = amsRepairOrderMapper.countOtherActiveRepairOrderByAssetId(assetId, currentRepairId,
                Arrays.asList(STATUS_DRAFT, STATUS_PENDING_CONFIRM, STATUS_WAIT_REPAIR, STATUS_REPAIRING));
        if (occupied > 0)
        {
            throw new ServiceException(StringUtils.format("资产【{}】已被其他未完成报修单占用", asset.getAssetCode()));
        }
    }

    private void validateLength(String value, int maxLength, String fieldName)
    {
        if (StringUtils.isNotEmpty(value) && value.length() > maxLength)
        {
            throw new ServiceException(fieldName + "长度不能超过" + maxLength + "个字符");
        }
    }

    private void validateLoginName(String operateLoginName)
    {
        if (StringUtils.isEmpty(operateLoginName))
        {
            throw new ServiceException("操作人账号不能为空");
        }
        validateLength(operateLoginName, 64, "操作账号");
    }

    private void validateOperateContext(AmsRepairOperateContext operateContext)
    {
        if (operateContext == null)
        {
            throw new ServiceException("操作上下文不能为空");
        }
        validateOperator(operateContext.getOperateUserId(), operateContext.getOperateUserName(), "操作人");
        validateLoginName(operateContext.getOperateLoginName());
    }

    private void validateOperator(Long operateUserId, String operateUserName, String fieldPrefix)
    {
        if (operateUserId == null)
        {
            throw new ServiceException(fieldPrefix + "ID不能为空");
        }
        if (StringUtils.isEmpty(StringUtils.trim(operateUserName)))
        {
            throw new ServiceException(fieldPrefix + "名称不能为空");
        }
        validateLength(operateUserName, 100, fieldPrefix + "名称");
    }
}
