diff --git a/backend/competition/serializers.py b/backend/competition/serializers.py index 889a12b..689884a 100644 --- a/backend/competition/serializers.py +++ b/backend/competition/serializers.py @@ -80,8 +80,26 @@ class ScoreSerializer(serializers.ModelSerializer): class CommentSerializer(serializers.ModelSerializer): judge_name = serializers.CharField(source='judge.user.nickname', read_only=True) + score = serializers.SerializerMethodField() class Meta: model = Comment - fields = ['id', 'project', 'judge', 'content', 'judge_name', 'created_at'] + fields = ['id', 'project', 'judge', 'content', 'judge_name', 'created_at', 'score'] read_only_fields = ['judge'] + + def get_score(self, obj): + scores = Score.objects.filter(project=obj.project, judge=obj.judge) + if not scores.exists(): + return None + + current_judge_total_score = 0 + current_judge_total_weight = 0 + + for score in scores: + current_judge_total_score += score.score * score.dimension.weight + current_judge_total_weight += score.dimension.weight + + if current_judge_total_weight > 0: + judge_score = current_judge_total_score / current_judge_total_weight + return round(judge_score, 1) + return None diff --git a/frontend/src/components/competition/ProjectDetail.jsx b/frontend/src/components/competition/ProjectDetail.jsx index 6b792c1..7b86cf8 100644 --- a/frontend/src/components/competition/ProjectDetail.jsx +++ b/frontend/src/components/competition/ProjectDetail.jsx @@ -162,7 +162,16 @@ const ProjectDetail = () => { } style={{ backgroundColor: '#00b96b' }} />} - title={{item.judge_name || '评委'}} + title={ +
+ {item.judge_name || '评委'} + {item.score && ( + + {item.score}分 + + )} +
+ } description={
{item.content}
diff --git a/miniprogram/src/components/MarkdownReader/index.scss b/miniprogram/src/components/MarkdownReader/index.scss index 6ee2967..93ec729 100644 --- a/miniprogram/src/components/MarkdownReader/index.scss +++ b/miniprogram/src/components/MarkdownReader/index.scss @@ -55,7 +55,7 @@ .language { color: #9cdcfe; - font-size: 12px; + font-size: 14px; font-weight: 600; text-transform: uppercase; } @@ -75,7 +75,7 @@ .copy-text { color: #ccc; - font-size: 12px; + font-size: 14px; margin-left: 4px; } } @@ -90,7 +90,7 @@ .code-text { color: #d4d4d4; font-family: 'Courier New', Courier, monospace; - font-size: 14px; + font-size: 16px; line-height: 1.5; white-space: pre; display: block; diff --git a/miniprogram/src/components/MarkdownReader/index.tsx b/miniprogram/src/components/MarkdownReader/index.tsx index 8db2af2..fb6894e 100644 --- a/miniprogram/src/components/MarkdownReader/index.tsx +++ b/miniprogram/src/components/MarkdownReader/index.tsx @@ -22,7 +22,7 @@ const MarkdownReader: React.FC = ({ content, themeColor = '#00b96b' }) => renderer.table = (header, body) => { return `
- +
${header}${body}
diff --git a/miniprogram/src/pages/competition/detail.scss b/miniprogram/src/pages/competition/detail.scss index 9f423c2..f94a62b 100644 --- a/miniprogram/src/pages/competition/detail.scss +++ b/miniprogram/src/pages/competition/detail.scss @@ -10,9 +10,9 @@ } .content { - padding: 24px; + padding: 30px; background: #111; - border-radius: 16px 16px 0 0; + border-radius: 20px 20px 0 0; margin-top: -24px; position: relative; z-index: 10; @@ -21,22 +21,22 @@ display: flex; justify-content: space-between; align-items: flex-start; - margin-bottom: 24px; + margin-bottom: 30px; .title { - font-size: 24px; + font-size: 32px; font-weight: bold; color: #fff; line-height: 1.4; } .status { - font-size: 14px; - padding: 4px 8px; - border-radius: 4px; + font-size: 16px; + padding: 6px 10px; + border-radius: 6px; background: #333; color: #ccc; - margin-left: 12px; + margin-left: 16px; white-space: nowrap; &.registration { background: #07c160; color: #fff; } @@ -48,15 +48,15 @@ .tabs { display: flex; - margin-bottom: 24px; + margin-bottom: 30px; border-bottom: 1px solid #333; .tab-item { flex: 1; text-align: center; - padding: 12px 0; + padding: 16px 0; color: #999; - font-size: 16px; + font-size: 18px; position: relative; &.active { @@ -69,8 +69,8 @@ bottom: -1px; left: 50%; transform: translateX(-50%); - width: 24px; - height: 3px; + width: 30px; + height: 4px; background: #00b96b; border-radius: 2px; } @@ -81,28 +81,28 @@ .project-list { .project-card { background: #1f1f1f; - border-radius: 12px; + border-radius: 16px; overflow: hidden; - margin-bottom: 16px; + margin-bottom: 20px; display: flex; .cover { - width: 120px; - height: 90px; + width: 140px; + height: 105px; background: #333; flex-shrink: 0; } .info { flex: 1; - padding: 12px; + padding: 16px; display: flex; flex-direction: column; justify-content: space-between; overflow: hidden; .title { - font-size: 16px; + font-size: 20px; color: #fff; font-weight: 500; display: -webkit-box; @@ -119,14 +119,14 @@ .user { display: flex; align-items: center; - font-size: 12px; + font-size: 14px; color: #999; .avatar { - width: 20px; - height: 20px; + width: 24px; + height: 24px; border-radius: 50%; - margin-right: 6px; + margin-right: 8px; background: #333; } } @@ -134,7 +134,7 @@ .score { color: #faad14; font-weight: bold; - font-size: 14px; + font-size: 16px; } } } @@ -142,7 +142,8 @@ .empty { text-align: center; color: #666; - padding: 40px 0; + padding: 50px 0; + font-size: 16px; } } @@ -150,13 +151,13 @@ .rank-item { display: flex; align-items: center; - padding: 16px 0; + padding: 20px 0; border-bottom: 1px solid #222; .rank-num { - width: 40px; + width: 50px; text-align: center; - font-size: 18px; + font-size: 22px; font-weight: bold; color: #666; @@ -172,10 +173,10 @@ overflow: hidden; .avatar { - width: 40px; - height: 40px; + width: 48px; + height: 48px; border-radius: 50%; - margin-right: 12px; + margin-right: 16px; background: #333; flex-shrink: 0; } @@ -186,8 +187,8 @@ .nickname { color: #fff; - font-size: 16px; - margin-bottom: 4px; + font-size: 18px; + margin-bottom: 6px; display: block; white-space: nowrap; overflow: hidden; @@ -196,7 +197,7 @@ .project-title { color: #666; - font-size: 12px; + font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @@ -205,34 +206,35 @@ } .score { - font-size: 18px; + font-size: 22px; font-weight: bold; color: #00b96b; - margin-left: 12px; + margin-left: 16px; } } .empty { text-align: center; color: #666; - padding: 40px 0; + padding: 50px 0; + font-size: 16px; } } .section { - margin-bottom: 32px; + margin-bottom: 40px; .section-title { - font-size: 18px; + font-size: 24px; font-weight: bold; color: #fff; - margin-bottom: 12px; + margin-bottom: 20px; display: block; - border-left: 4px solid #00b96b; - padding-left: 12px; + border-left: 5px solid #00b96b; + padding-left: 16px; } /* Markdown styling borrowed from Forum */ - font-size: 16px; + font-size: 18px; line-height: 1.8; color: #e0e0e0; letter-spacing: 0.3px; @@ -240,38 +242,38 @@ image { max-width: 100%; border-radius: 12px; - margin: 16px 0; + margin: 20px 0; box-shadow: 0 4px 12px rgba(0,0,0,0.3); } - h1, h2, h3, h4, h5, h6 { margin-top: 24px; margin-bottom: 16px; color: #fff; font-weight: 700; line-height: 1.4; } - h1 { font-size: 24px; border-bottom: 1px solid rgba(255,255,255,0.1); padding-bottom: 12px; } - h2 { font-size: 20px; border-bottom: 1px solid rgba(255,255,255,0.05); padding-bottom: 8px; } - h3 { font-size: 18px; } - h4 { font-size: 17px; } - h5 { font-size: 16px; color: #ddd; } + h1, h2, h3, h4, h5, h6 { margin-top: 30px; margin-bottom: 20px; color: #fff; font-weight: 700; line-height: 1.4; } + h1 { font-size: 32px; border-bottom: 1px solid rgba(255,255,255,0.1); padding-bottom: 16px; } + h2 { font-size: 28px; border-bottom: 1px solid rgba(255,255,255,0.05); padding-bottom: 12px; } + h3 { font-size: 24px; } + h4 { font-size: 20px; } + h5 { font-size: 18px; color: #ddd; } - p { margin-bottom: 16px; } + p { margin-bottom: 20px; } strong { font-weight: 800; color: #fff; } em { font-style: italic; color: #aaa; } del { text-decoration: line-through; color: #666; } - ul, ol { margin-bottom: 16px; padding-left: 20px; } - li { margin-bottom: 6px; list-style-position: outside; } + ul, ol { margin-bottom: 20px; padding-left: 24px; } + li { margin-bottom: 8px; list-style-position: outside; } ul li { list-style-type: disc; } ol li { list-style-type: decimal; } - li input[type="checkbox"] { margin-right: 8px; } + li input[type="checkbox"] { margin-right: 12px; } blockquote { - border-left: 4px solid #00b96b; + border-left: 5px solid #00b96b; background: rgba(255, 255, 255, 0.05); - padding: 12px 16px; - margin: 16px 0; - border-radius: 4px; + padding: 16px 20px; + margin: 20px 0; + border-radius: 6px; color: #bbb; - font-size: 15px; + font-size: 16px; font-style: italic; p { margin-bottom: 0; } @@ -283,20 +285,20 @@ height: 1px; background: rgba(255,255,255,0.1); border: none; - margin: 24px 0; + margin: 30px 0; } table { width: 100%; border-collapse: collapse; - margin: 16px 0; - font-size: 14px; + margin: 20px 0; + font-size: 16px; overflow-x: auto; display: block; th, td { border: 1px solid rgba(255,255,255,0.1); - padding: 10px; + padding: 12px; text-align: left; } @@ -313,20 +315,20 @@ code { background: rgba(255,255,255,0.1); - padding: 2px 6px; - border-radius: 4px; + padding: 4px 8px; + border-radius: 6px; font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; color: #ff7875; - font-size: 14px; - margin: 0 4px; + font-size: 16px; + margin: 0 6px; } pre { background: #161616; - padding: 16px; - border-radius: 12px; + padding: 20px; + border-radius: 16px; overflow-x: auto; - margin: 16px 0; + margin: 20px 0; border: 1px solid #333; box-shadow: inset 0 0 20px rgba(0,0,0,0.5); @@ -334,7 +336,7 @@ background: transparent; color: #a6e22e; padding: 0; - font-size: 13px; + font-size: 14px; margin: 0; white-space: pre; } @@ -348,16 +350,16 @@ left: 0; right: 0; background: #1f1f1f; - padding: 16px 24px; + padding: 20px 30px; border-top: 1px solid #333; z-index: 100; .btn { width: 100%; - height: 48px; - line-height: 48px; - border-radius: 24px; - font-size: 18px; + height: 56px; + line-height: 56px; + border-radius: 28px; + font-size: 20px; font-weight: bold; color: #fff; background: #00b96b; diff --git a/miniprogram/src/pages/competition/project-detail.scss b/miniprogram/src/pages/competition/project-detail.scss index 6803c86..d5f0be1 100644 --- a/miniprogram/src/pages/competition/project-detail.scss +++ b/miniprogram/src/pages/competition/project-detail.scss @@ -1,98 +1,201 @@ .project-detail { background-color: #000; min-height: 100vh; - padding-bottom: 40px; + padding-bottom: 60px; box-sizing: border-box; .cover { width: 100%; - height: 240px; + height: 260px; display: block; } .content { - padding: 24px; + padding: 30px; background: #111; - border-radius: 16px 16px 0 0; - margin-top: -24px; + border-radius: 24px 24px 0 0; + margin-top: -30px; position: relative; z-index: 10; min-height: 60vh; .header { - margin-bottom: 32px; + margin-bottom: 40px; .title { - font-size: 24px; + font-size: 36px; font-weight: bold; color: #fff; - margin-bottom: 16px; + margin-bottom: 24px; line-height: 1.4; display: block; } .author { display: flex; align-items: center; - background: rgba(255, 255, 255, 0.05); - padding: 8px 12px; - border-radius: 20px; + background: rgba(255, 255, 255, 0.08); + padding: 12px 20px; + border-radius: 30px; display: inline-flex; .avatar { - width: 24px; - height: 24px; + width: 36px; + height: 36px; border-radius: 50%; - margin-right: 8px; + margin-right: 12px; background: #333; } .name { - font-size: 14px; - color: #ccc; + font-size: 18px; + color: #ddd; } } } .section { - margin-bottom: 32px; + margin-bottom: 50px; .section-title { - font-size: 18px; + font-size: 28px; font-weight: bold; color: #fff; - margin-bottom: 16px; + margin-bottom: 24px; display: block; - border-left: 4px solid #00b96b; - padding-left: 12px; + border-left: 6px solid #00b96b; + padding-left: 18px; } .text-content { - font-size: 15px; + font-size: 20px; color: #ccc; line-height: 1.8; background: #1f1f1f; - padding: 16px; - border-radius: 12px; + padding: 24px; + border-radius: 20px; + + /* Markdown Styles */ + h1, h2, h3, h4, h5, h6 { margin-top: 40px; margin-bottom: 24px; color: #fff; font-weight: 700; line-height: 1.4; } + h1 { font-size: 34px; border-bottom: 1px solid rgba(255,255,255,0.1); padding-bottom: 16px; } + h2 { font-size: 30px; border-bottom: 1px solid rgba(255,255,255,0.05); padding-bottom: 12px; } + h3 { font-size: 26px; } + h4 { font-size: 24px; } + h5 { font-size: 22px; color: #ddd; } + + p { margin-bottom: 24px; } + + strong { font-weight: 800; color: #fff; } + em { font-style: italic; color: #aaa; } + del { text-decoration: line-through; color: #666; } + + ul, ol { margin-bottom: 24px; padding-left: 28px; } + li { margin-bottom: 10px; list-style-position: outside; } + ul li { list-style-type: disc; } + ol li { list-style-type: decimal; } + + li input[type="checkbox"] { margin-right: 12px; transform: scale(1.2); } + + blockquote { + border-left: 6px solid #00b96b; + background: rgba(255, 255, 255, 0.05); + padding: 20px 24px; + margin: 24px 0; + border-radius: 8px; + color: #bbb; + font-size: 18px; + font-style: italic; + p { margin-bottom: 0; } + } + + a { color: #00b96b; text-decoration: none; border-bottom: 1px solid transparent; transition: border-color 0.2s; } + + hr { + height: 1px; + background: rgba(255,255,255,0.1); + border: none; + margin: 30px 0; + } + + table { + width: 100%; + border-collapse: collapse; + margin: 24px 0; + font-size: 18px; + overflow-x: auto; + display: block; + + th, td { + border: 1px solid rgba(255,255,255,0.1); + padding: 14px; + text-align: left; + } + + th { + background: rgba(255,255,255,0.05); + font-weight: 700; + color: #fff; + } + + tr:nth-child(even) { + background: rgba(255,255,255,0.02); + } + } + + code { + background: rgba(255,255,255,0.1); + padding: 4px 8px; + border-radius: 6px; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + color: #ff7875; + font-size: 18px; + margin: 0 6px; + } + + pre { + background: #161616; + padding: 24px; + border-radius: 16px; + overflow-x: auto; + margin: 24px 0; + border: 1px solid #333; + box-shadow: inset 0 0 20px rgba(0,0,0,0.5); + + code { + background: transparent; + color: #a6e22e; + padding: 0; + font-size: 16px; + margin: 0; + white-space: pre; + } + } + + image { + max-width: 100%; + border-radius: 16px; + margin: 24px 0; + box-shadow: 0 4px 12px rgba(0,0,0,0.3); + } } .empty { - font-size: 14px; + font-size: 18px; color: #666; text-align: center; display: block; - padding: 20px 0; + padding: 40px 0; background: #1f1f1f; - border-radius: 12px; + border-radius: 16px; } .file-list { background: #1f1f1f; - border-radius: 12px; + border-radius: 20px; overflow: hidden; .file-item { display: flex; justify-content: space-between; align-items: center; - padding: 16px; + padding: 24px; border-bottom: 1px solid #333; &:last-child { @@ -100,20 +203,20 @@ } .file-name { - font-size: 14px; + font-size: 18px; color: #ddd; flex: 1; - margin-right: 16px; + margin-right: 20px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .file-action { - font-size: 12px; + font-size: 16px; color: #00b96b; - padding: 4px 12px; + padding: 8px 20px; border: 1px solid #00b96b; - border-radius: 14px; + border-radius: 20px; } } } @@ -121,9 +224,9 @@ .comment-list { .comment-item { background: #1f1f1f; - border-radius: 12px; - padding: 16px; - margin-bottom: 16px; + border-radius: 20px; + padding: 24px; + margin-bottom: 24px; &:last-child { margin-bottom: 0; @@ -132,20 +235,20 @@ .comment-header { display: flex; justify-content: space-between; - margin-bottom: 8px; + margin-bottom: 16px; .judge-name { - font-size: 14px; + font-size: 18px; font-weight: bold; color: #00b96b; } .comment-time { - font-size: 12px; + font-size: 16px; color: #666; } } .comment-content { - font-size: 14px; + font-size: 20px; color: #ccc; line-height: 1.6; display: block; diff --git a/miniprogram/src/pages/competition/project-detail.tsx b/miniprogram/src/pages/competition/project-detail.tsx index d341cc7..ead01c7 100644 --- a/miniprogram/src/pages/competition/project-detail.tsx +++ b/miniprogram/src/pages/competition/project-detail.tsx @@ -141,7 +141,10 @@ export default function ProjectDetail() { {comments.map((c) => ( - {c.judge_name || '评委'} + + {c.judge_name || '评委'} + {c.score && {c.score}分} + {c.created_at?.substring(0, 16)} {c.content}