Files
xiaotutongxue/scripts/dev-seed-warn-state.py
T
lovife edb47e8557 verify(h5): 提交页问题清单浮层真浏览器验证通过
两条分支都跑通了(穿透单次要 30 秒左右,耐心等):

  红色分支(阻断)缺身份证材料 + 必填未填
    → 标题「还不能提交」、[必须处理 3]、
      三张红卡(--s3,左边框 #E34D59 / 底 #FDF3F4):
      VAL-16 / VAL-22 / VAL-05
    → 「知道了,去修改」点击后浮层关闭

  黄色分支(可强提)只差一个 VAL-09 重复文件
    → 标题「提交前请确认」、[提醒 1]、
      一张橙卡(--s2,左边框 #ED7B2F)
    → 「仍然提交」→ 弹出「提交成功 / 已提交,等待班主任初审」

提交成功后的状态切换也验证了:
  · 上传按钮与「删除」**全部消失**(canEdit=false)
  · 提交按钮被替换为只读文案「已提交,等待班主任初审」
  · 材料列表显示规范名 + 压缩后体积:
    张同学-361029XXXXXX0015-身份证.jpg  17KB · 900×1200
  · 库:status=1 red=0 yellow=1 submit_time 已写
    日志:提交未通过 ×2 → 提交成功
  · 顺带验证 loadFiles()(重进页面能看到上次传的材料与体积并能删)

⚠️ git add -A 差点把 backend/data/uploads/ 下的**运行时上传文件**提交进来。
   那是数据不是代码 —— 已加进 .gitignore(backend/data/)并从暂存区撤回。

新增 scripts/dev-seed-warn-state.py:把某份草稿快速摆到"只剩黄色警告"的状态,
用来验浮层/审核端的"只有警告"分支,省掉"手填 7 个字段 + 等穿透"。
它**不**替代 E2E —— 逻辑仍由 e2e-m3-submit.py 断言,这个脚本只负责摆状态。

演示态:collect_submission.id=21 现在是「已提交」(本次验证留下)。
它是很好的演示态,但要重跑填报流程必须先删掉它(见交接摘要 §一·十三)。
名册(task 17, id=38)绑定 sys_user.id=151,保持不动。
2026-09-29 13:21:07 +08:00

142 lines
5.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""
把演示草稿(submission 21)摆到"只剩黄色警告"的状态,用来验证浮层的第二个分支。
为什么要用脚本摆而不是在页面上手填:
· 页面上填 7 个字段 + 传 2 张图 + 等穿透,一次要两三分钟;
· 而这一步要验的是**浮层在"只有警告"时的表现**,不是填表本身。
摆状态用接口最快,浮层那一段仍然在真浏览器里点。
跑法:python scripts/_seed_warn_state.py [submissionId]
"""
import base64
import hashlib
import hmac
import io
import json
import os
import re
import sys
import time
import urllib.error
import urllib.request
import uuid
sys.stdout.reconfigure(encoding="utf-8")
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SRC = os.path.join(ROOT, "backend", "xt-server", "src", "main", "resources")
UID = 151
TASK = 17
SID = int(sys.argv[1]) if len(sys.argv) > 1 else 21
def read_cfg() -> dict:
text = "\n".join(open(os.path.join(SRC, f), encoding="utf-8").read()
for f in ("application-dev.yml", "application.yml")
if os.path.exists(os.path.join(SRC, f)))
out = {}
for k, p in [("jwt", r"^\s*secret:\s*(\S+)\s*$"), ("issuer", r"^\s*issuer:\s*(\S+)\s*$")]:
m = re.search(p, text, re.M)
if not m:
raise SystemExit(f"找不到 {k}")
out[k] = m.group(1)
return out
def b64u(b: bytes) -> str:
return base64.urlsafe_b64encode(b).rstrip(b"=").decode()
def mint(secret: str, issuer: str, uid: int, tenant: int) -> str:
key = base64.b64decode(secret)
now = int(time.time())
signing = (b64u(json.dumps({"alg": "HS512"}, separators=(",", ":")).encode()) + "."
+ b64u(json.dumps({"iss": issuer, "sub": str(uid), "tenantId": tenant,
"orgIds": [], "roles": ["STUDENT"], "userType": 4,
"iat": now, "exp": now + 3600}, separators=(",", ":")).encode()))
return signing + "." + b64u(hmac.new(key, signing.encode(), hashlib.sha512).digest())
def call(method, path, token, body=None):
h = {"Content-Type": "application/json; charset=utf-8"}
if token:
h["Authorization"] = f"Bearer {token}"
data = json.dumps(body, ensure_ascii=False).encode() if body is not None else None
req = urllib.request.Request("http://localhost:8080" + path, data=data, headers=h, method=method)
try:
with urllib.request.urlopen(req, timeout=90) as x:
return json.loads(x.read().decode("utf-8"))
except urllib.error.HTTPError as e:
try:
return json.loads(e.read().decode("utf-8"))
except Exception:
return {"_http": e.code}
def upload(token, sid, code, filename, data):
boundary = "----seed" + uuid.uuid4().hex[:12]
parts = []
for k, v in [("submissionId", str(sid)), ("materialCode", code)]:
parts.append(f'--{boundary}\r\nContent-Disposition: form-data; name="{k}"\r\n\r\n{v}\r\n'.encode())
parts.append(f'--{boundary}\r\nContent-Disposition: form-data; name="file"; filename="{filename}"\r\n'
f"Content-Type: image/jpeg\r\n\r\n".encode())
parts.append(data)
parts.append(f"\r\n--{boundary}--\r\n".encode())
req = urllib.request.Request(
"http://localhost:8080/api/v1/mp/files/upload", data=b"".join(parts), method="POST",
headers={"Content-Type": f"multipart/form-data; boundary={boundary}",
"Authorization": f"Bearer {token}"})
try:
with urllib.request.urlopen(req, timeout=90) as x:
return json.loads(x.read().decode("utf-8"))
except urllib.error.HTTPError as e:
try:
return json.loads(e.read().decode("utf-8"))
except Exception:
return {"_http": e.code}
def main() -> int:
cfg = read_cfg()
tok = mint(cfg["jwt"], cfg["issuer"], UID, 1)
# ① 填掉全部必填(key 是 snake_case;is_retake=false 让补考三科不可见 → 不必填)
form = {"work_unit": "无", "is_retake": False, "is_student": True,
"school": "示范职业学校", "major": "数控技术", "enroll_date": "2023-09-01"}
r = call("PUT", f"/api/v1/mp/submissions/{SID}", tok, {"formData": form})
print(f" 填必填字段 code={r.get('code')} msg={r.get('msg')}")
if r.get("code") != 0:
return 1
# ② 传两张**同内容**的图 → VAL-09 重复文件(黄色警告)
from PIL import Image
buf = io.BytesIO()
Image.new("RGB", (900, 1200), (205, 212, 220)).save(buf, "JPEG", quality=90)
img = buf.getvalue()
for name in ("身份证正面.jpg", "身份证反面.jpg"):
up = upload(tok, SID, "IDCARD", name, img)
if up.get("code") != 0:
print(f" 上传 {name} 失败:{up}")
return 1
pr = call("POST", f"/api/v1/mp/files/{up['data']['id']}/process", tok)
d = pr.get("data") or {}
print(f" {name} → {d.get('standardName')} {d.get('rawSize')}→{d.get('finalSize')} 字节")
# ③ 试提交一次,看看还剩什么
r = call("POST", f"/api/v1/mp/submissions/{SID}/submit", tok, {"confirmWarnings": False})
d = r.get("data") or {}
print(f"\n 试提交:code={r.get('code')} submitted={d.get('submitted')} "
f"红={d.get('redCount')} 黄={d.get('yellowCount')} 蓝={d.get('infoCount')}")
for i in d.get("issues") or []:
print(f" [sev{i.get('severity')}] {i.get('ruleCode')} {i.get('title')}")
if (d.get("redCount") or 0) > 0:
print("\n ✗ 还有红色项 —— 浏览器里只会看到「还不能提交」那一支,验不到黄色分支")
return 3
print("\n ok 只剩黄色/蓝色 —— 可以在浏览器里验「提交前请确认」那一支了")
return 0
if __name__ == "__main__":
raise SystemExit(main())