package com.gxwebsoft.hjc.service; import com.baomidou.mybatisplus.extension.service.IService; import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.hjc.entity.HjcEnterprise; import com.gxwebsoft.hjc.entity.HjcPasswordApply; import com.gxwebsoft.hjc.param.HjcPasswordApplyParam; /** * 汇吉采密码找回申请(材料审核制,见 ADR-0008)。 */ public interface HjcPasswordApplyService extends IService { PageResult pageRel(HjcPasswordApplyParam param); /** 某企业最新一条申请(匿名链路用,显式传租户) */ HjcPasswordApply getLatestByEnterpriseId(Integer enterpriseId, Integer tenantId); /** 某企业最新一条待审核申请;不为 null 即「重复提交」,直接返回它而不新建 */ HjcPasswordApply getPendingByEnterpriseId(Integer enterpriseId, Integer tenantId); /** 写入一条待审核申请 */ HjcPasswordApply submit(HjcEnterprise enterprise, String newPassword, String handbookUrl, Integer tenantId); /** * 审核:仅允许 {@code 0 → 1}(通过,待运维重置)或 {@code 0 → 2}(驳回)。 * *

用「带状态条件的更新」而不是「先查后改」,避免两个管理员同时点通过/驳回时后者覆盖前者。

* * @return 错误文案;成功返回 null */ String audit(Integer id, Integer status, String rejectReason, Integer auditUserId); /** * 标记已重置:仅允许 {@code 1 → 3}。 * *

「审核通过」不等于「已重置」:这一步表示运维已经在核心实例管理后台照申请单执行完毕。

* * @return 错误文案;成功返回 null */ String markReset(Integer id, Integer resetUserId); /** * 频次配额(Redis 原子自增,键名以 {@code hjc:pwd:} 开头,与核心实例的键区分)。 * *

用 {@code StringRedisTemplate} 而不是项目的 {@code RedisUtil}:后者只包了 set/get/delete, * 没有原子自增,而"先读再写"的计数在并发下会漏放。

* * @param bucket 配额桶名,例如 {@code apply-ip} * @param subject 配额主体,例如客户端 IP 或企业 ID * @return true = 未超限(已占用一次配额) */ boolean tryAcquireQuota(String bucket, String subject, int limit, long ttlSeconds); }