文件
csp/backend/src/domain/json.cc
cryptocommuniums-afk cfbe9a0363 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>
2026-02-16 17:35:22 +08:00

122 行
3.3 KiB
C++

#include "csp/domain/json.h"
namespace csp::domain {
Json::Value ToPublicJson(const User& u) {
Json::Value j;
j["id"] = Json::Int64(u.id);
j["username"] = u.username;
j["rating"] = u.rating;
j["created_at"] = Json::Int64(u.created_at);
return j;
}
Json::Value ToJson(const Problem& p) {
Json::Value j;
j["id"] = Json::Int64(p.id);
j["slug"] = p.slug;
j["title"] = p.title;
j["statement_md"] = p.statement_md;
j["difficulty"] = p.difficulty;
j["source"] = p.source;
j["statement_url"] = p.statement_url;
j["llm_profile_json"] = p.llm_profile_json;
j["sample_input"] = p.sample_input;
j["sample_output"] = p.sample_output;
j["created_at"] = Json::Int64(p.created_at);
return j;
}
Json::Value ToJson(const Submission& s) {
Json::Value j;
j["id"] = Json::Int64(s.id);
j["user_id"] = Json::Int64(s.user_id);
j["problem_id"] = Json::Int64(s.problem_id);
if (s.contest_id.has_value()) {
j["contest_id"] = Json::Int64(*s.contest_id);
} else {
j["contest_id"] = Json::nullValue;
}
j["language"] = ToString(s.language);
j["status"] = ToString(s.status);
j["score"] = s.score;
j["rating_delta"] = s.rating_delta;
j["time_ms"] = s.time_ms;
j["memory_kb"] = s.memory_kb;
j["compile_log"] = s.compile_log;
j["runtime_log"] = s.runtime_log;
j["created_at"] = Json::Int64(s.created_at);
return j;
}
Json::Value ToJson(const WrongBookItem& w) {
Json::Value j;
j["user_id"] = Json::Int64(w.user_id);
j["problem_id"] = Json::Int64(w.problem_id);
if (w.last_submission_id.has_value()) {
j["last_submission_id"] = Json::Int64(*w.last_submission_id);
} else {
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;
}
Json::Value ToJson(const Contest& c) {
Json::Value j;
j["id"] = Json::Int64(c.id);
j["title"] = c.title;
j["starts_at"] = Json::Int64(c.starts_at);
j["ends_at"] = Json::Int64(c.ends_at);
j["rule_json"] = c.rule_json;
return j;
}
Json::Value ToJson(const KbArticle& a) {
Json::Value j;
j["id"] = Json::Int64(a.id);
j["slug"] = a.slug;
j["title"] = a.title;
j["content_md"] = a.content_md;
j["created_at"] = Json::Int64(a.created_at);
return j;
}
Json::Value ToJson(const GlobalLeaderboardEntry& e) {
Json::Value j;
j["user_id"] = Json::Int64(e.user_id);
j["username"] = e.username;
j["rating"] = e.rating;
j["created_at"] = Json::Int64(e.created_at);
return j;
}
Json::Value ToJson(const ContestLeaderboardEntry& e) {
Json::Value j;
j["user_id"] = Json::Int64(e.user_id);
j["username"] = e.username;
j["solved"] = e.solved;
j["penalty_sec"] = Json::Int64(e.penalty_sec);
return j;
}
} // namespace csp::domain