Upload 67 files
Browse files- app/static/style.css +186 -2
- app/templates/admin_activities.html +69 -24
app/static/style.css
CHANGED
|
@@ -857,6 +857,175 @@ textarea {
|
|
| 857 |
gap: 14px;
|
| 858 |
}
|
| 859 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 860 |
.task-editor-card {
|
| 861 |
gap: 16px;
|
| 862 |
}
|
|
@@ -1069,7 +1238,8 @@ textarea {
|
|
| 1069 |
.task-page-grid,
|
| 1070 |
.users-admin-grid,
|
| 1071 |
.presence-admin-grid,
|
| 1072 |
-
.review-live-grid
|
|
|
|
| 1073 |
grid-template-columns: 1fr;
|
| 1074 |
}
|
| 1075 |
|
|
@@ -1083,12 +1253,23 @@ textarea {
|
|
| 1083 |
.task-carousel-head,
|
| 1084 |
.carousel-controls,
|
| 1085 |
.presence-item,
|
| 1086 |
-
.activity-actions
|
|
|
|
|
|
|
| 1087 |
grid-template-columns: 1fr;
|
| 1088 |
flex-direction: column;
|
| 1089 |
align-items: stretch;
|
| 1090 |
}
|
| 1091 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1092 |
.task-flip-book {
|
| 1093 |
min-height: 900px;
|
| 1094 |
}
|
|
@@ -1135,3 +1316,6 @@ textarea {
|
|
| 1135 |
.compact-stack-item {
|
| 1136 |
padding: 10px 12px;
|
| 1137 |
}
|
|
|
|
|
|
|
|
|
|
|
|
| 857 |
gap: 14px;
|
| 858 |
}
|
| 859 |
|
| 860 |
+
.activity-catalog-panel {
|
| 861 |
+
overflow: hidden;
|
| 862 |
+
}
|
| 863 |
+
|
| 864 |
+
.activity-catalog-head {
|
| 865 |
+
margin-bottom: 20px;
|
| 866 |
+
}
|
| 867 |
+
|
| 868 |
+
.published-activity-list {
|
| 869 |
+
display: grid;
|
| 870 |
+
gap: 20px;
|
| 871 |
+
}
|
| 872 |
+
|
| 873 |
+
.published-activity-card {
|
| 874 |
+
position: relative;
|
| 875 |
+
display: grid;
|
| 876 |
+
grid-template-columns: minmax(0, 1.55fr) minmax(290px, 0.9fr);
|
| 877 |
+
gap: 22px;
|
| 878 |
+
padding: 22px;
|
| 879 |
+
border-radius: 30px;
|
| 880 |
+
background:
|
| 881 |
+
radial-gradient(circle at 100% 0%, rgba(241, 193, 107, 0.18), transparent 28%),
|
| 882 |
+
linear-gradient(135deg, rgba(255, 255, 255, 0.92), rgba(236, 248, 239, 0.9));
|
| 883 |
+
border: 1px solid rgba(78, 148, 97, 0.16);
|
| 884 |
+
box-shadow: 0 20px 38px rgba(86, 127, 93, 0.12);
|
| 885 |
+
}
|
| 886 |
+
|
| 887 |
+
.published-activity-card::before {
|
| 888 |
+
content: "";
|
| 889 |
+
position: absolute;
|
| 890 |
+
inset: 0 auto auto 24px;
|
| 891 |
+
width: 110px;
|
| 892 |
+
height: 5px;
|
| 893 |
+
border-radius: 999px;
|
| 894 |
+
background: linear-gradient(90deg, rgba(96, 175, 114, 0.9), rgba(241, 193, 107, 0.82));
|
| 895 |
+
}
|
| 896 |
+
|
| 897 |
+
.published-activity-main,
|
| 898 |
+
.published-activity-side,
|
| 899 |
+
.published-activity-form {
|
| 900 |
+
display: grid;
|
| 901 |
+
gap: 16px;
|
| 902 |
+
}
|
| 903 |
+
|
| 904 |
+
.published-activity-main {
|
| 905 |
+
min-width: 0;
|
| 906 |
+
align-content: start;
|
| 907 |
+
}
|
| 908 |
+
|
| 909 |
+
.published-activity-head {
|
| 910 |
+
display: flex;
|
| 911 |
+
align-items: flex-start;
|
| 912 |
+
justify-content: space-between;
|
| 913 |
+
gap: 16px;
|
| 914 |
+
}
|
| 915 |
+
|
| 916 |
+
.published-activity-title {
|
| 917 |
+
margin: 4px 0 0;
|
| 918 |
+
font-size: 1.8rem;
|
| 919 |
+
line-height: 1.12;
|
| 920 |
+
}
|
| 921 |
+
|
| 922 |
+
.published-activity-badges {
|
| 923 |
+
display: flex;
|
| 924 |
+
flex-wrap: wrap;
|
| 925 |
+
justify-content: flex-end;
|
| 926 |
+
gap: 10px;
|
| 927 |
+
}
|
| 928 |
+
|
| 929 |
+
.published-activity-metrics,
|
| 930 |
+
.published-activity-notes {
|
| 931 |
+
display: grid;
|
| 932 |
+
gap: 14px;
|
| 933 |
+
}
|
| 934 |
+
|
| 935 |
+
.published-activity-metrics {
|
| 936 |
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
| 937 |
+
}
|
| 938 |
+
|
| 939 |
+
.published-activity-notes {
|
| 940 |
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
| 941 |
+
}
|
| 942 |
+
|
| 943 |
+
.activity-metric-card,
|
| 944 |
+
.activity-note-card {
|
| 945 |
+
padding: 16px 18px;
|
| 946 |
+
border-radius: 22px;
|
| 947 |
+
border: 1px solid rgba(78, 148, 97, 0.12);
|
| 948 |
+
}
|
| 949 |
+
|
| 950 |
+
.activity-metric-card {
|
| 951 |
+
background: rgba(255, 255, 255, 0.78);
|
| 952 |
+
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.68);
|
| 953 |
+
}
|
| 954 |
+
|
| 955 |
+
.activity-note-card {
|
| 956 |
+
background: rgba(244, 250, 245, 0.88);
|
| 957 |
+
}
|
| 958 |
+
|
| 959 |
+
.activity-metric-card span,
|
| 960 |
+
.activity-note-card span {
|
| 961 |
+
display: block;
|
| 962 |
+
font-size: 0.8rem;
|
| 963 |
+
letter-spacing: 0.08em;
|
| 964 |
+
text-transform: uppercase;
|
| 965 |
+
color: var(--muted);
|
| 966 |
+
}
|
| 967 |
+
|
| 968 |
+
.activity-metric-card strong,
|
| 969 |
+
.activity-note-card strong {
|
| 970 |
+
display: block;
|
| 971 |
+
margin-top: 8px;
|
| 972 |
+
line-height: 1.45;
|
| 973 |
+
color: var(--primary-deep);
|
| 974 |
+
}
|
| 975 |
+
|
| 976 |
+
.activity-metric-card strong {
|
| 977 |
+
font-size: 1.02rem;
|
| 978 |
+
}
|
| 979 |
+
|
| 980 |
+
.published-activity-side {
|
| 981 |
+
align-content: start;
|
| 982 |
+
padding: 18px;
|
| 983 |
+
border-radius: 26px;
|
| 984 |
+
background: linear-gradient(180deg, rgba(247, 252, 248, 0.94), rgba(229, 244, 233, 0.88));
|
| 985 |
+
border: 1px solid rgba(78, 148, 97, 0.14);
|
| 986 |
+
}
|
| 987 |
+
|
| 988 |
+
.published-activity-side .btn,
|
| 989 |
+
.published-delete-form .btn {
|
| 990 |
+
width: 100%;
|
| 991 |
+
justify-content: center;
|
| 992 |
+
}
|
| 993 |
+
|
| 994 |
+
.published-toggle-row {
|
| 995 |
+
display: flex;
|
| 996 |
+
align-items: center;
|
| 997 |
+
justify-content: space-between;
|
| 998 |
+
gap: 14px;
|
| 999 |
+
padding: 14px 16px;
|
| 1000 |
+
border-radius: 20px;
|
| 1001 |
+
background: rgba(255, 255, 255, 0.78);
|
| 1002 |
+
border: 1px solid rgba(78, 148, 97, 0.12);
|
| 1003 |
+
}
|
| 1004 |
+
|
| 1005 |
+
.published-toggle-row > div {
|
| 1006 |
+
display: grid;
|
| 1007 |
+
gap: 4px;
|
| 1008 |
+
}
|
| 1009 |
+
|
| 1010 |
+
.published-toggle-row strong {
|
| 1011 |
+
font-size: 1rem;
|
| 1012 |
+
color: var(--primary-deep);
|
| 1013 |
+
}
|
| 1014 |
+
|
| 1015 |
+
.published-toggle-row span {
|
| 1016 |
+
font-size: 0.88rem;
|
| 1017 |
+
line-height: 1.45;
|
| 1018 |
+
color: var(--muted);
|
| 1019 |
+
}
|
| 1020 |
+
|
| 1021 |
+
.published-toggle-row input {
|
| 1022 |
+
width: 20px;
|
| 1023 |
+
height: 20px;
|
| 1024 |
+
padding: 0;
|
| 1025 |
+
margin: 0;
|
| 1026 |
+
flex: 0 0 auto;
|
| 1027 |
+
}
|
| 1028 |
+
|
| 1029 |
.task-editor-card {
|
| 1030 |
gap: 16px;
|
| 1031 |
}
|
|
|
|
| 1238 |
.task-page-grid,
|
| 1239 |
.users-admin-grid,
|
| 1240 |
.presence-admin-grid,
|
| 1241 |
+
.review-live-grid,
|
| 1242 |
+
.published-activity-card {
|
| 1243 |
grid-template-columns: 1fr;
|
| 1244 |
}
|
| 1245 |
|
|
|
|
| 1253 |
.task-carousel-head,
|
| 1254 |
.carousel-controls,
|
| 1255 |
.presence-item,
|
| 1256 |
+
.activity-actions,
|
| 1257 |
+
.published-activity-head,
|
| 1258 |
+
.published-toggle-row {
|
| 1259 |
grid-template-columns: 1fr;
|
| 1260 |
flex-direction: column;
|
| 1261 |
align-items: stretch;
|
| 1262 |
}
|
| 1263 |
|
| 1264 |
+
.published-activity-metrics,
|
| 1265 |
+
.published-activity-notes {
|
| 1266 |
+
grid-template-columns: 1fr;
|
| 1267 |
+
}
|
| 1268 |
+
|
| 1269 |
+
.published-activity-badges {
|
| 1270 |
+
justify-content: flex-start;
|
| 1271 |
+
}
|
| 1272 |
+
|
| 1273 |
.task-flip-book {
|
| 1274 |
min-height: 900px;
|
| 1275 |
}
|
|
|
|
| 1316 |
.compact-stack-item {
|
| 1317 |
padding: 10px 12px;
|
| 1318 |
}
|
| 1319 |
+
|
| 1320 |
+
|
| 1321 |
+
|
app/templates/admin_activities.html
CHANGED
|
@@ -80,46 +80,91 @@
|
|
| 80 |
</form>
|
| 81 |
</article>
|
| 82 |
|
| 83 |
-
<article class="glass-card table-panel">
|
| 84 |
-
<div class="section-head">
|
| 85 |
<div>
|
| 86 |
<p class="eyebrow">Published Activities</p>
|
| 87 |
<h3>已发布活动</h3>
|
|
|
|
| 88 |
</div>
|
| 89 |
</div>
|
| 90 |
-
<div class="
|
| 91 |
{% for activity in activities %}
|
| 92 |
-
<article class="
|
| 93 |
-
<div>
|
| 94 |
-
<
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
<
|
| 100 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
</div>
|
| 102 |
</div>
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
<
|
| 106 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
<input type="checkbox" name="is_visible" {% if activity.is_visible %}checked{% endif %} />
|
| 108 |
-
<span>用户可见活动</span>
|
| 109 |
</label>
|
| 110 |
-
<label class="
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
<input type="checkbox" name="leaderboard_visible" {% if activity.leaderboard_visible %}checked{% endif %} />
|
| 112 |
-
<span>用户可见排行榜</span>
|
| 113 |
</label>
|
| 114 |
-
<button class="btn btn-secondary
|
| 115 |
</form>
|
| 116 |
-
|
| 117 |
-
|
|
|
|
| 118 |
</form>
|
| 119 |
-
</
|
| 120 |
</article>
|
| 121 |
{% else %}
|
| 122 |
-
<
|
|
|
|
|
|
|
|
|
|
| 123 |
{% endfor %}
|
| 124 |
</div>
|
| 125 |
</article>
|
|
|
|
| 80 |
</form>
|
| 81 |
</article>
|
| 82 |
|
| 83 |
+
<article class="glass-card table-panel activity-catalog-panel">
|
| 84 |
+
<div class="section-head activity-catalog-head">
|
| 85 |
<div>
|
| 86 |
<p class="eyebrow">Published Activities</p>
|
| 87 |
<h3>已发布活动</h3>
|
| 88 |
+
<p class="mini-note">把活动信息、可见性开关和危险操作拆分展示,管理起来会更清晰。</p>
|
| 89 |
</div>
|
| 90 |
</div>
|
| 91 |
+
<div class="published-activity-list">
|
| 92 |
{% for activity in activities %}
|
| 93 |
+
<article class="published-activity-card">
|
| 94 |
+
<div class="published-activity-main">
|
| 95 |
+
<div class="published-activity-head">
|
| 96 |
+
<div>
|
| 97 |
+
<p class="eyebrow">Activity {{ loop.index }}</p>
|
| 98 |
+
<h3 class="published-activity-title">{{ activity.title }}</h3>
|
| 99 |
+
</div>
|
| 100 |
+
<div class="published-activity-badges">
|
| 101 |
+
<span class="status-badge {% if activity.is_visible %}status-approved{% else %}status-rejected{% endif %}">
|
| 102 |
+
{{ '活动可见' if activity.is_visible else '活动隐藏' }}
|
| 103 |
+
</span>
|
| 104 |
+
<span class="status-badge {% if activity.leaderboard_visible %}status-approved{% else %}status-rejected{% endif %}">
|
| 105 |
+
{{ '排行可见' if activity.leaderboard_visible else '排行隐藏' }}
|
| 106 |
+
</span>
|
| 107 |
+
</div>
|
| 108 |
+
</div>
|
| 109 |
+
|
| 110 |
+
<div class="published-activity-metrics">
|
| 111 |
+
<div class="activity-metric-card">
|
| 112 |
+
<span>开始时间</span>
|
| 113 |
+
<strong>{{ activity.start_at|datetime_local }}</strong>
|
| 114 |
+
</div>
|
| 115 |
+
<div class="activity-metric-card">
|
| 116 |
+
<span>截止时间</span>
|
| 117 |
+
<strong>{{ activity.deadline_at|datetime_local }}</strong>
|
| 118 |
+
</div>
|
| 119 |
+
<div class="activity-metric-card">
|
| 120 |
+
<span>任务数量</span>
|
| 121 |
+
<strong>{{ activity.tasks|length }} 个任务</strong>
|
| 122 |
+
</div>
|
| 123 |
+
</div>
|
| 124 |
+
|
| 125 |
+
<div class="published-activity-notes">
|
| 126 |
+
<div class="activity-note-card">
|
| 127 |
+
<span>创建人</span>
|
| 128 |
+
<strong>{{ activity.created_by.display_name }}</strong>
|
| 129 |
+
</div>
|
| 130 |
+
<div class="activity-note-card">
|
| 131 |
+
<span>线索间隔</span>
|
| 132 |
+
<strong>{{ activity.clue_interval_minutes if activity.clue_interval_minutes is not none else '与活动开始同步' }}</strong>
|
| 133 |
+
</div>
|
| 134 |
</div>
|
| 135 |
</div>
|
| 136 |
+
|
| 137 |
+
<aside class="published-activity-side">
|
| 138 |
+
<a class="btn btn-primary" href="/admin/activities/{{ activity.id }}/edit">编辑活动</a>
|
| 139 |
+
|
| 140 |
+
<form method="post" action="/admin/activities/{{ activity.id }}/visibility" class="published-activity-form">
|
| 141 |
+
<label class="published-toggle-row">
|
| 142 |
+
<div>
|
| 143 |
+
<strong>活动对用户可见</strong>
|
| 144 |
+
<span>关闭后,用户端不会显示,也不能直接进入此活动。</span>
|
| 145 |
+
</div>
|
| 146 |
<input type="checkbox" name="is_visible" {% if activity.is_visible %}checked{% endif %} />
|
|
|
|
| 147 |
</label>
|
| 148 |
+
<label class="published-toggle-row">
|
| 149 |
+
<div>
|
| 150 |
+
<strong>排行榜对用户可见</strong>
|
| 151 |
+
<span>管理员始终可见,这里只控制普通用户是否能看到排行榜。</span>
|
| 152 |
+
</div>
|
| 153 |
<input type="checkbox" name="leaderboard_visible" {% if activity.leaderboard_visible %}checked{% endif %} />
|
|
|
|
| 154 |
</label>
|
| 155 |
+
<button class="btn btn-secondary" type="submit">保存显示设置</button>
|
| 156 |
</form>
|
| 157 |
+
|
| 158 |
+
<form method="post" action="/admin/activities/{{ activity.id }}/delete" class="published-delete-form">
|
| 159 |
+
<button class="btn btn-danger" type="submit" onclick="return confirm('确定删除这个活动吗?相关任务、审核记录和本地提交图片都会一并删除。');">删除活动</button>
|
| 160 |
</form>
|
| 161 |
+
</aside>
|
| 162 |
</article>
|
| 163 |
{% else %}
|
| 164 |
+
<article class="empty-state">
|
| 165 |
+
<h3>还没有活动</h3>
|
| 166 |
+
<p>先在左侧发布一个活动,这里会自动整理成更清晰的管理卡片。</p>
|
| 167 |
+
</article>
|
| 168 |
{% endfor %}
|
| 169 |
</div>
|
| 170 |
</article>
|