登录管理添加流程图

This commit is contained in:
2026-04-25 06:27:00 +08:00
parent 20f686ea5f
commit 84d27f4210
5 changed files with 649 additions and 2 deletions

View File

@@ -0,0 +1,309 @@
<?xml version="1.0" encoding="UTF-8"?>
<mxfile host="app.diagrams.net" modified="2026-04-25T00:00:00.000Z" agent="OpenCode" version="21.0.0">
<!-- ============================================================
5.4.1 找回用户名流程
============================================================ -->
<diagram id="recover-username" name="5.4.1 找回用户名流程">
<mxGraphModel dx="1200" dy="800" grid="1" gridSize="10" guides="1" tooltips="1"
connect="1" arrows="1" fold="1" page="1" pageScale="1"
pageWidth="850" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<!-- Title -->
<mxCell id="t1" value="5.4.1 找回用户名流程" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontStyle=1;" vertex="1" parent="1">
<mxGeometry x="175" y="20" width="500" height="40" as="geometry" />
</mxCell>
<!-- Start -->
<mxCell id="u1" value="用户点击「忘记用户名」" style="ellipse;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=1;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="275" y="80" width="300" height="50" as="geometry" />
</mxCell>
<!-- Decision: Is email format valid? -->
<mxCell id="u2" value="展示「找回用户名」页面
(邮箱输入框 + 发送按钮)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="250" y="170" width="350" height="50" as="geometry" />
</mxCell>
<!-- User inputs email -->
<mxCell id="u3" value="用户输入邮箱并点击「发送」" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="250" y="260" width="350" height="50" as="geometry" />
</mxCell>
<!-- Decision: Email format valid? -->
<mxCell id="u4" value="邮箱格式校验通过?" style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="275" y="350" width="300" height="70" as="geometry" />
</mxCell>
<!-- Format invalid -->
<mxCell id="u5" value="提示「请输入有效的邮箱地址」" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="620" y="360" width="220" height="50" as="geometry" />
</mxCell>
<!-- Backend query -->
<mxCell id="u6" value="服务端查询邮箱是否绑定账号
(不向前端返回查询结果)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="250" y="470" width="350" height="60" as="geometry" />
</mxCell>
<!-- Unified response to frontend -->
<mxCell id="u7" value="统一响应前端:
「如该邮箱已绑定账号,您将收到邮件」
发送按钮进入 60 秒倒计时" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="250" y="580" width="350" height="70" as="geometry" />
</mxCell>
<!-- Decision: Email exists? -->
<mxCell id="u8" value="邮箱已绑定 Tenant Admin 账号?" style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="630" y="475" width="240" height="70" as="geometry" />
</mxCell>
<!-- Email found: send email -->
<mxCell id="u9" value="后台:异步发送邮件
(包含用户名、发送时间)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="640" y="580" width="220" height="60" as="geometry" />
</mxCell>
<!-- Email not found: silent -->
<mxCell id="u10" value="后台:静默处理
(不发送邮件,不报错)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="640" y="660" width="220" height="50" as="geometry" />
</mxCell>
<!-- Rate limit check -->
<mxCell id="u11" value="同一邮箱 1 小时内已发送 ≥ 3 次?" style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="630" y="700" width="240" height="70" as="geometry" />
</mxCell>
<!-- Rate limit exceeded -->
<mxCell id="u12" value="拒绝发送
(达到频率上限)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="900" y="715" width="160" height="50" as="geometry" />
</mxCell>
<!-- User receives email -->
<mxCell id="u13" value="用户查收邮件,获取用户名" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="640" y="810" width="220" height="50" as="geometry" />
</mxCell>
<!-- Return to login -->
<mxCell id="u14" value="点击「返回登录」
回到登录界面" style="ellipse;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="275" y="700" width="300" height="50" as="geometry" />
</mxCell>
<!-- Edges -->
<mxCell id="e1" edge="1" source="u1" target="u2" parent="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e2" edge="1" source="u2" target="u3" parent="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e3" edge="1" source="u3" target="u4" parent="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e4" value="否" edge="1" source="u4" target="u5" parent="1">
<mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="620" y="385" /></Array></mxGeometry>
</mxCell>
<mxCell id="e5" value="" edge="1" source="u5" target="u3" parent="1">
<mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="730" y="285" /></Array></mxGeometry>
</mxCell>
<mxCell id="e6" value="是" edge="1" source="u4" target="u6" parent="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e7" edge="1" source="u6" target="u7" parent="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e8" edge="1" source="u6" target="u8" parent="1">
<mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="600" y="500" /><mxPoint x="630" y="510" /></Array></mxGeometry>
</mxCell>
<mxCell id="e9" value="是" edge="1" source="u8" target="u11" parent="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e10" value="否(普通员工邮箱或不存在)" edge="1" source="u8" target="u10" parent="1">
<mxGeometry relative="1" as="geometry"><mxPoint x="760" y="660" as="targetPoint" /></mxGeometry>
</mxCell>
<mxCell id="e11" value="否(未超限)" edge="1" source="u11" target="u9" parent="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e12" value="是(超过 3 次)" edge="1" source="u11" target="u12" parent="1">
<mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="900" y="735" /></Array></mxGeometry>
</mxCell>
<mxCell id="e13" edge="1" source="u9" target="u13" parent="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e14" edge="1" source="u13" target="u14" parent="1">
<mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="750" y="835" /><mxPoint x="425" y="835" /><mxPoint x="425" y="750" /></Array></mxGeometry>
</mxCell>
<mxCell id="e15" edge="1" source="u7" target="u14" parent="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
<!-- ============================================================
5.4.2 找回密码流程
============================================================ -->
<diagram id="recover-password" name="5.4.2 找回密码流程">
<mxGraphModel dx="1200" dy="800" grid="1" gridSize="10" guides="1" tooltips="1"
connect="1" arrows="1" fold="1" page="1" pageScale="1"
pageWidth="850" pageHeight="1300" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<!-- Title -->
<mxCell id="title" value="5.4.2 找回密码流程" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontStyle=1;" vertex="1" parent="1">
<mxGeometry x="175" y="20" width="500" height="40" as="geometry" />
</mxCell>
<!-- ===== STEP 1 Header ===== -->
<mxCell id="step1hdr" value="步骤一:身份验证" style="text;html=1;strokeColor=none;fillColor=#dae8fc;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=1;fontSize=13;fontStyle=1;" vertex="1" parent="1">
<mxGeometry x="60" y="65" width="730" height="30" as="geometry" />
</mxCell>
<!-- Start -->
<mxCell id="p1" value="用户点击「忘记密码」" style="ellipse;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=1;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="275" y="115" width="300" height="50" as="geometry" />
</mxCell>
<!-- Show form -->
<mxCell id="p2" value="展示「找回密码」页面Stepper
步骤一:用户名 + 绑定邮箱输入框" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="225" y="200" width="400" height="60" as="geometry" />
</mxCell>
<!-- User submits -->
<mxCell id="p3" value="用户输入用户名 + 邮箱,点击「下一步」" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="225" y="300" width="400" height="50" as="geometry" />
</mxCell>
<!-- Backend verification -->
<mxCell id="p4" value="服务端校验用户名与邮箱是否匹配" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="225" y="390" width="400" height="50" as="geometry" />
</mxCell>
<!-- Unified response -->
<mxCell id="p5" value="统一响应前端:
「如信息匹配,重置链接将发送至您的邮箱」" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="225" y="480" width="400" height="60" as="geometry" />
</mxCell>
<!-- Decision: Match? -->
<mxCell id="p6" value="用户名与邮箱匹配?" style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="650" y="395" width="220" height="70" as="geometry" />
</mxCell>
<!-- Rate limit check -->
<mxCell id="p7" value="同一账号 1 小时内已发 ≥ 3 次?" style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="650" y="490" width="220" height="70" as="geometry" />
</mxCell>
<!-- Matched: generate token -->
<mxCell id="p8" value="生成加密 Token
secrets.token_urlsafe(32),有效期 30 分钟)
异步发送重置邮件" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="650" y="590" width="240" height="70" as="geometry" />
</mxCell>
<!-- No match: silent -->
<mxCell id="p9" value="不匹配:静默处理
(不发邮件,不报错)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="900" y="405" width="180" height="60" as="geometry" />
</mxCell>
<!-- Rate limit exceeded -->
<mxCell id="p10" value="已超频率上限
静默处理" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="900" y="505" width="160" height="50" as="geometry" />
</mxCell>
<!-- ===== STEP 2 Header ===== -->
<mxCell id="step2hdr" value="步骤二:用户点击邮件重置链接" style="text;html=1;strokeColor=none;fillColor=#d5e8d4;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=1;fontSize=13;fontStyle=1;" vertex="1" parent="1">
<mxGeometry x="60" y="690" width="730" height="30" as="geometry" />
</mxCell>
<!-- User clicks link -->
<mxCell id="p11" value="用户点击邮件中的重置链接" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="275" y="740" width="300" height="50" as="geometry" />
</mxCell>
<!-- Validate token -->
<mxCell id="p12" value="服务端校验 Token 有效性
is_used=False AND expires_at 未过期)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="250" y="830" width="350" height="60" as="geometry" />
</mxCell>
<!-- Token decision -->
<mxCell id="p13" value="Token 有效?" style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="300" y="930" width="250" height="70" as="geometry" />
</mxCell>
<!-- Invalid token -->
<mxCell id="p14" value="提示「链接已过期或已使用,请重新申请」
提供「重新申请」按钮(跳回步骤一)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="620" y="940" width="260" height="60" as="geometry" />
</mxCell>
<!-- ===== STEP 3 Header ===== -->
<mxCell id="step3hdr" value="步骤三:输入并提交新密码" style="text;html=1;strokeColor=none;fillColor=#fff2cc;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=1;fontSize=13;fontStyle=1;" vertex="1" parent="1">
<mxGeometry x="60" y="1030" width="730" height="30" as="geometry" />
</mxCell>
<!-- Show reset form -->
<mxCell id="p15" value="展示「重置密码」表单
(新密码 + 确认新密码 + 密码强度指示)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="250" y="1080" width="350" height="60" as="geometry" />
</mxCell>
<!-- User submits new password -->
<mxCell id="p16" value="用户输入新密码并提交" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="275" y="1180" width="300" height="50" as="geometry" />
</mxCell>
<!-- Complexity check -->
<mxCell id="p17" value="密码复杂度校验
≥8位含字母+数字,两次一致)" style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="275" y="1265" width="300" height="80" as="geometry" />
</mxCell>
<!-- Complexity fail -->
<mxCell id="p18" value="实时提示不满足的规则
(逐条红色 ✗ / 绿色 ✓ 视觉指引)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="640" y="1275" width="240" height="60" as="geometry" />
</mxCell>
<!-- History check -->
<mxCell id="p19" value="历史密码校验
(不得与最近 3 次历史密码相同)" style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="275" y="1380" width="300" height="80" as="geometry" />
</mxCell>
<!-- History fail -->
<mxCell id="p20" value="提示「不得与最近 3 次密码相同」" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="640" y="1395" width="240" height="50" as="geometry" />
</mxCell>
<!-- Success: update password -->
<mxCell id="p21" value="✅ 校验通过:
① 更新密码PBKDF2+SHA256 哈希存储)
② is_initial_password = False
③ 清除该账号所有有效 Session
④ 标记 Token 为 is_used = True" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="225" y="1500" width="400" height="100" as="geometry" />
</mxCell>
<!-- End -->
<mxCell id="p22" value="跳转登录界面
提示「密码已重置,请使用新密码登录」" style="ellipse;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=12;" vertex="1" parent="1">
<mxGeometry x="275" y="1630" width="300" height="60" as="geometry" />
</mxCell>
<!-- Edges Step 1 -->
<mxCell id="ep1" edge="1" source="p1" target="p2" parent="1"><mxGeometry relative="1" as="geometry" /></mxCell>
<mxCell id="ep2" edge="1" source="p2" target="p3" parent="1"><mxGeometry relative="1" as="geometry" /></mxCell>
<mxCell id="ep3" edge="1" source="p3" target="p4" parent="1"><mxGeometry relative="1" as="geometry" /></mxCell>
<mxCell id="ep4" edge="1" source="p4" target="p5" parent="1"><mxGeometry relative="1" as="geometry" /></mxCell>
<mxCell id="ep5" edge="1" source="p4" target="p6" parent="1">
<mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="625" y="415" /><mxPoint x="650" y="430" /></Array></mxGeometry>
</mxCell>
<mxCell id="ep6" value="否" edge="1" source="p6" target="p9" parent="1">
<mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="900" y="430" /></Array></mxGeometry>
</mxCell>
<mxCell id="ep7" value="是" edge="1" source="p6" target="p7" parent="1"><mxGeometry relative="1" as="geometry" /></mxCell>
<mxCell id="ep8" value="是(超限)" edge="1" source="p7" target="p10" parent="1">
<mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="900" y="525" /></Array></mxGeometry>
</mxCell>
<mxCell id="ep9" value="否(未超限)" edge="1" source="p7" target="p8" parent="1"><mxGeometry relative="1" as="geometry" /></mxCell>
<!-- Step 2 edges -->
<mxCell id="ep10" edge="1" source="p5" target="p11" parent="1"><mxGeometry relative="1" as="geometry" /></mxCell>
<mxCell id="ep11" edge="1" source="p11" target="p12" parent="1"><mxGeometry relative="1" as="geometry" /></mxCell>
<mxCell id="ep12" edge="1" source="p12" target="p13" parent="1"><mxGeometry relative="1" as="geometry" /></mxCell>
<mxCell id="ep13" value="否(无效/过期)" edge="1" source="p13" target="p14" parent="1">
<mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="620" y="965" /></Array></mxGeometry>
</mxCell>
<mxCell id="ep14" value="重新申请" edge="1" source="p14" target="p2" parent="1">
<mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="960" y="970" /><mxPoint x="960" y="230" /><mxPoint x="625" y="230" /></Array></mxGeometry>
</mxCell>
<mxCell id="ep15" value="是(有效)" edge="1" source="p13" target="p15" parent="1"><mxGeometry relative="1" as="geometry" /></mxCell>
<!-- Step 3 edges -->
<mxCell id="ep16" edge="1" source="p15" target="p16" parent="1"><mxGeometry relative="1" as="geometry" /></mxCell>
<mxCell id="ep17" edge="1" source="p16" target="p17" parent="1"><mxGeometry relative="1" as="geometry" /></mxCell>
<mxCell id="ep18" value="不通过" edge="1" source="p17" target="p18" parent="1">
<mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="640" y="1305" /></Array></mxGeometry>
</mxCell>
<mxCell id="ep19" value="" edge="1" source="p18" target="p16" parent="1">
<mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="760" y="1205" /></Array></mxGeometry>
</mxCell>
<mxCell id="ep20" value="通过" edge="1" source="p17" target="p19" parent="1"><mxGeometry relative="1" as="geometry" /></mxCell>
<mxCell id="ep21" value="不通过" edge="1" source="p19" target="p20" parent="1">
<mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="640" y="1420" /></Array></mxGeometry>
</mxCell>
<mxCell id="ep22" value="" edge="1" source="p20" target="p16" parent="1">
<mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="760" y="1205" /></Array></mxGeometry>
</mxCell>
<mxCell id="ep23" value="通过" edge="1" source="p19" target="p21" parent="1"><mxGeometry relative="1" as="geometry" /></mxCell>
<mxCell id="ep24" edge="1" source="p21" target="p22" parent="1"><mxGeometry relative="1" as="geometry" /></mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

View File

@@ -0,0 +1,338 @@
<mxfile host="drawio.ishenwei.online" pages="2">
<diagram name="5.4.1 找回用户名流程" id="5iec1bHWH-Os4IpZJiBD">
<mxGraphModel dx="1106" dy="663" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="t1" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontStyle=1;" value="5.4.1 找回用户名流程" vertex="1">
<mxGeometry height="40" width="500" x="175" y="20" as="geometry" />
</mxCell>
<mxCell id="u1" parent="1" style="ellipse;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=1;fontSize=12;" value="用户点击「忘记用户名」" vertex="1">
<mxGeometry height="50" width="300" x="275" y="80" as="geometry" />
</mxCell>
<mxCell id="u2" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" value="展示「找回用户名」页面 (邮箱输入框 + 发送按钮)" vertex="1">
<mxGeometry height="50" width="350" x="250" y="170" as="geometry" />
</mxCell>
<mxCell id="u3" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" value="用户输入邮箱并点击「发送」" vertex="1">
<mxGeometry height="50" width="350" x="250" y="260" as="geometry" />
</mxCell>
<mxCell id="u4" parent="1" style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" value="邮箱格式校验通过?" vertex="1">
<mxGeometry height="70" width="300" x="275" y="350" as="geometry" />
</mxCell>
<mxCell id="u5" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=12;" value="提示「请输入有效的邮箱地址」" vertex="1">
<mxGeometry height="50" width="220" x="770" y="360" as="geometry" />
</mxCell>
<mxCell id="u6" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" value="服务端查询邮箱是否绑定账号 (不向前端返回查询结果)" vertex="1">
<mxGeometry height="60" width="350" x="250" y="470" as="geometry" />
</mxCell>
<mxCell id="u7" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;" value="统一响应前端: 「如该邮箱已绑定账号,您将收到邮件」 发送按钮进入 60 秒倒计时" vertex="1">
<mxGeometry height="70" width="350" x="250" y="580" as="geometry" />
</mxCell>
<mxCell id="u8" parent="1" style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" value="邮箱已绑定 Tenant Admin 账号?" vertex="1">
<mxGeometry height="70" width="240" x="760" y="465" as="geometry" />
</mxCell>
<mxCell id="u10" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" value="后台:静默处理 (不发送邮件,不报错)" vertex="1">
<mxGeometry height="50" width="220" x="1060" y="920" as="geometry" />
</mxCell>
<mxCell id="u11" parent="1" style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" value="同一邮箱 1 小时内已发送 ≥ 3 次?" vertex="1">
<mxGeometry height="70" width="240" x="1050" y="600" as="geometry" />
</mxCell>
<mxCell id="u12" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=12;" value="拒绝发送 (达到频率上限)" vertex="1">
<mxGeometry height="50" width="160" x="1090" y="780" as="geometry" />
</mxCell>
<mxCell id="u13" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" value="用户查收邮件,获取用户名" vertex="1">
<mxGeometry height="50" width="220" x="770" y="920" as="geometry" />
</mxCell>
<mxCell id="u14" parent="1" style="ellipse;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=12;" value="点击「返回登录」 回到登录界面" vertex="1">
<mxGeometry height="50" width="300" x="275" y="700" as="geometry" />
</mxCell>
<mxCell id="e1" edge="1" parent="1" source="u1" target="u2">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e2" edge="1" parent="1" source="u2" target="u3">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e3" edge="1" parent="1" source="u3" target="u4">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e4" edge="1" parent="1" source="u4" target="u5" value="否">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="620" y="385" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="e5" edge="1" parent="1" source="u5" target="u3" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="880" y="280" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="e6" edge="1" parent="1" source="u4" target="u6" value="是">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e7" edge="1" parent="1" source="u6" target="u7">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e8" edge="1" parent="1" source="u6" target="u8">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="600" y="500" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="e9" edge="1" parent="1" source="u8" target="u11" value="是">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1170" y="500" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="e10" edge="1" parent="1" source="u9" target="u10" value="否(普通员工邮箱或不存在)">
<mxGeometry relative="1" as="geometry">
<mxPoint x="760" y="660" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="e11" edge="1" parent="1" source="u11" target="u9" value="否(未超限)">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e12" edge="1" parent="1" source="u11" target="u12" value="是(超过 3 次)">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1170" y="720" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="e13" edge="1" parent="1" source="u9" target="u13">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="880" y="780" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="e14" edge="1" parent="1" source="u13" target="u14">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="425" y="940" />
<mxPoint x="425" y="835" />
<mxPoint x="425" y="750" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="e15" edge="1" parent="1" source="u7" target="u14">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="sNxHsQaDJQvd_aw6okKy-1" edge="1" parent="1" source="u8" target="u9" value="">
<mxGeometry relative="1" as="geometry">
<mxPoint x="860" y="529" as="sourcePoint" />
<mxPoint x="768" y="660" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="u9" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;" value="后台:异步发送邮件 (包含用户名、发送时间)" vertex="1">
<mxGeometry height="60" width="220" x="770" y="610" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
<diagram name="5.4.2 找回密码流程" id="YPy-6OBmoH41auZikELT">
<mxGraphModel dx="1106" dy="663" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1300" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="title" parent="1" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontStyle=1;" value="5.4.2 找回密码流程" vertex="1">
<mxGeometry height="40" width="500" x="175" y="20" as="geometry" />
</mxCell>
<mxCell id="step1hdr" parent="1" style="text;html=1;strokeColor=none;fillColor=#dae8fc;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=1;fontSize=13;fontStyle=1;" value="步骤一:身份验证" vertex="1">
<mxGeometry height="30" width="730" x="60" y="65" as="geometry" />
</mxCell>
<mxCell id="p1" parent="1" style="ellipse;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontStyle=1;fontSize=12;" value="用户点击「忘记密码」" vertex="1">
<mxGeometry height="50" width="300" x="275" y="115" as="geometry" />
</mxCell>
<mxCell id="p2" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" value="展示「找回密码」页面Stepper 步骤一:用户名 + 绑定邮箱输入框" vertex="1">
<mxGeometry height="60" width="400" x="225" y="200" as="geometry" />
</mxCell>
<mxCell id="p3" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" value="用户输入用户名 + 邮箱,点击「下一步」" vertex="1">
<mxGeometry height="50" width="400" x="225" y="300" as="geometry" />
</mxCell>
<mxCell id="p4" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" value="服务端校验用户名与邮箱是否匹配" vertex="1">
<mxGeometry height="50" width="400" x="225" y="390" as="geometry" />
</mxCell>
<mxCell id="p5" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;" value="统一响应前端: 「如信息匹配,重置链接将发送至您的邮箱」" vertex="1">
<mxGeometry height="60" width="400" x="225" y="480" as="geometry" />
</mxCell>
<mxCell id="p6" parent="1" style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" value="用户名与邮箱匹配?" vertex="1">
<mxGeometry height="70" width="220" x="650" y="395" as="geometry" />
</mxCell>
<mxCell id="p7" parent="1" style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" value="同一账号 1 小时内已发 ≥ 3 次?" vertex="1">
<mxGeometry height="70" width="220" x="650" y="490" as="geometry" />
</mxCell>
<mxCell id="p8" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;" value="生成加密 Token secrets.token_urlsafe(32),有效期 30 分钟) 异步发送重置邮件" vertex="1">
<mxGeometry height="70" width="240" x="650" y="590" as="geometry" />
</mxCell>
<mxCell id="p9" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" value="不匹配:静默处理 (不发邮件,不报错)" vertex="1">
<mxGeometry height="60" width="180" x="950" y="405" as="geometry" />
</mxCell>
<mxCell id="p10" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=12;" value="已超频率上限 静默处理" vertex="1">
<mxGeometry height="50" width="160" x="960" y="500" as="geometry" />
</mxCell>
<mxCell id="step2hdr" parent="1" style="text;html=1;strokeColor=none;fillColor=#d5e8d4;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=1;fontSize=13;fontStyle=1;" value="步骤二:用户点击邮件重置链接" vertex="1">
<mxGeometry height="30" width="730" x="60" y="690" as="geometry" />
</mxCell>
<mxCell id="p11" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" value="用户点击邮件中的重置链接" vertex="1">
<mxGeometry height="50" width="300" x="275" y="740" as="geometry" />
</mxCell>
<mxCell id="p12" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" value="服务端校验 Token 有效性 is_used=False AND expires_at 未过期)" vertex="1">
<mxGeometry height="60" width="350" x="250" y="830" as="geometry" />
</mxCell>
<mxCell id="p13" parent="1" style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" value="Token 有效?" vertex="1">
<mxGeometry height="70" width="250" x="300" y="930" as="geometry" />
</mxCell>
<mxCell id="p14" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=12;" value="提示「链接已过期或已使用,请重新申请」 提供「重新申请」按钮(跳回步骤一)" vertex="1">
<mxGeometry height="60" width="260" x="640" y="940" as="geometry" />
</mxCell>
<mxCell id="step3hdr" parent="1" style="text;html=1;strokeColor=none;fillColor=#fff2cc;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=1;fontSize=13;fontStyle=1;" value="步骤三:输入并提交新密码" vertex="1">
<mxGeometry height="30" width="730" x="60" y="1030" as="geometry" />
</mxCell>
<mxCell id="p15" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" value="展示「重置密码」表单 (新密码 + 确认新密码 + 密码强度指示)" vertex="1">
<mxGeometry height="60" width="350" x="250" y="1080" as="geometry" />
</mxCell>
<mxCell id="p16" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontSize=12;" value="用户输入新密码并提交" vertex="1">
<mxGeometry height="50" width="300" x="275" y="1180" as="geometry" />
</mxCell>
<mxCell id="p17" parent="1" style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" value="密码复杂度校验 ≥8位含字母+数字,两次一致)" vertex="1">
<mxGeometry height="80" width="300" x="275" y="1265" as="geometry" />
</mxCell>
<mxCell id="p18" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=12;" value="实时提示不满足的规则 (逐条红色 ✗ / 绿色 ✓ 视觉指引)" vertex="1">
<mxGeometry height="60" width="240" x="640" y="1275" as="geometry" />
</mxCell>
<mxCell id="p19" parent="1" style="rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=12;" value="历史密码校验 (不得与最近 3 次历史密码相同)" vertex="1">
<mxGeometry height="80" width="300" x="275" y="1380" as="geometry" />
</mxCell>
<mxCell id="p20" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=12;" value="提示「不得与最近 3 次密码相同」" vertex="1">
<mxGeometry height="50" width="240" x="640" y="1395" as="geometry" />
</mxCell>
<mxCell id="p21" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=12;" value="✅ 校验通过: ① 更新密码PBKDF2+SHA256 哈希存储) ② is_initial_password = False ③ 清除该账号所有有效 Session ④ 标记 Token 为 is_used = True" vertex="1">
<mxGeometry height="100" width="400" x="225" y="1500" as="geometry" />
</mxCell>
<mxCell id="p22" parent="1" style="ellipse;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=12;" value="跳转登录界面 提示「密码已重置,请使用新密码登录」" vertex="1">
<mxGeometry height="60" width="300" x="275" y="1630" as="geometry" />
</mxCell>
<mxCell id="ep1" edge="1" parent="1" source="p1" target="p2">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ep2" edge="1" parent="1" source="p2" target="p3">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ep3" edge="1" parent="1" source="p3" target="p4">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ep4" edge="1" parent="1" source="p4" target="p5">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ep5" edge="1" parent="1" source="p4" target="p6">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="625" y="415" />
<mxPoint x="650" y="430" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="ep6" edge="1" parent="1" source="p6" target="p9" value="否">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="900" y="430" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="ep7" edge="1" parent="1" source="p6" target="p7" value="是">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ep8" edge="1" parent="1" source="p7" target="p10" value="是(超限)">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="900" y="525" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="ep9" edge="1" parent="1" source="p7" target="p8" value="否(未超限)">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ep10" edge="1" parent="1" source="p5" target="p11">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ep11" edge="1" parent="1" source="p11" target="p12">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ep12" edge="1" parent="1" source="p12" target="p13">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ep13" edge="1" parent="1" source="p13" target="p14" value="否(无效/过期)">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="620" y="965" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="ep14" edge="1" parent="1" source="p14" target="p2" value="重新申请">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1160" y="970" />
<mxPoint x="1160" y="230" />
<mxPoint x="625" y="230" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="ep15" edge="1" parent="1" source="p13" target="p15" value="是(有效)">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ep16" edge="1" parent="1" source="p15" target="p16">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ep17" edge="1" parent="1" source="p16" target="p17">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ep18" edge="1" parent="1" source="p17" target="p18" value="不通过">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="640" y="1305" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="ep19" edge="1" parent="1" source="p18" target="p16" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="760" y="1205" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="ep20" edge="1" parent="1" source="p17" target="p19" value="通过">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ep21" edge="1" parent="1" source="p19" target="p20" value="不通过">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="640" y="1420" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="ep22" edge="1" parent="1" source="p20" style="exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.98;entryY=0.08;entryDx=0;entryDy=0;entryPerimeter=0;" target="p16" value="">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="920" y="1420" />
<mxPoint x="920" y="1180" />
<mxPoint x="750" y="1180" />
</Array>
<mxPoint x="920" y="1400" as="sourcePoint" />
</mxGeometry>
</mxCell>
<mxCell id="ep23" edge="1" parent="1" source="p19" target="p21" value="通过">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="ep24" edge="1" parent="1" source="p21" target="p22">
<mxGeometry relative="1" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB