feat: problems local stats, user status, admin panel enhancements, rating text

- Problems page: replace Luogu pass rate with local submission stats
  (local_submit_count, local_ac_count)
- Problems page: add user AC/fail status column (user_ac, user_fail_count)
- Admin users: add total_submissions and total_ac columns
- Admin users: add detail panel with submissions/rating/redeem tabs
- Admin: new endpoint GET /api/v1/admin/users/{id}/rating-history
- Rating history: note field includes problem title via JOIN
- Me page: translate task codes to friendly labels with icons
- Me page: problem links in rating history are clickable
- Wrong book service, learning note scoring, note image controller
- Backend SQL uses batch queries for performance

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
这个提交包含在:
cryptocommuniums-afk
2026-02-16 17:35:22 +08:00
父节点 7860414ae5
当前提交 cfbe9a0363
修改 22 个文件,包含 1366 行新增26 行删除

查看文件

@@ -59,6 +59,23 @@ Json::Value ToJson(const WrongBookItem& w) {
j["last_submission_id"] = Json::nullValue;
}
j["note"] = w.note;
j["note_score"] = w.note_score;
j["note_rating"] = w.note_rating;
j["note_feedback_md"] = w.note_feedback_md;
if (!w.note_images_json.empty()) {
Json::Value parsed;
Json::CharReaderBuilder b;
std::string errs;
std::unique_ptr<Json::CharReader> r(b.newCharReader());
if (r->parse(w.note_images_json.data(), w.note_images_json.data() + w.note_images_json.size(), &parsed, &errs) && parsed.isArray()) {
j["note_images"] = parsed;
} else {
j["note_images"] = Json::arrayValue;
}
} else {
j["note_images"] = Json::arrayValue;
}
j["note_scored_at"] = Json::Int64(w.note_scored_at);
j["updated_at"] = Json::Int64(w.updated_at);
return j;
}