现象:只有 /user/questions 这一页的「卡片」像完全透明的,其它后台页正常。 根因不是主题,是模板本来就没有卡片容器:提问列表是 <div class=uk-margin-medium-bottom> + <hr> 直接铺在页面上,整个模板只有 1 处 .uk-card (还是投票 tab 里的「我的投票」标题条)。默认主题底色是纯白,所以看不出来; 换成带整页插画的主题后,场景整片透上来,就成了「卡片透明」。 给 .qlist-panel 兜一层卡片底(--tb-surface + 圆角 + 阴影),三个 tab 共用; 面板内已有的一张 .uk-card-default 降成 --tb-surface-2 去阴影,避免卡片套卡片。 ≤640px 收紧内边距。与主题无关,默认外观也会多这层卡(和其它后台页一致)。
519 lines
29 KiB
HTML
519 lines
29 KiB
HTML
{{template "base/header" .}}
|
||
|
||
<style>
|
||
.qlist-tabs {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 4px;
|
||
padding: 4px;
|
||
margin: 6px auto 20px;
|
||
max-width: 320px;
|
||
border: 1px solid var(--tb-border);
|
||
border-radius: var(--tb-radius-sm);
|
||
background: var(--tb-surface-2);
|
||
}
|
||
.qlist-tab {
|
||
flex: 1 1 0;
|
||
border: 0;
|
||
border-radius: var(--tb-radius-xs);
|
||
padding: 8px 15px;
|
||
background: transparent;
|
||
color: var(--tb-text-secondary);
|
||
cursor: pointer;
|
||
font-size: var(--tb-fs-md);
|
||
transition: background 0.2s ease, color 0.2s ease;
|
||
}
|
||
.qlist-tab:hover { color: var(--tb-primary); }
|
||
.qlist-tab.is-active {
|
||
background: #fff;
|
||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.10);
|
||
color: var(--tb-primary);
|
||
font-weight: 600;
|
||
}
|
||
.qlist-panel[hidden] { display: none !important; }
|
||
/* 三个面板兜一层卡片底。此前面板内容是裸行(只靠 <hr> 分隔)直接铺在页面背景上,
|
||
默认主题底色是纯白所以看不出来;换成带整页插画的主题后,场景会整片透上来,
|
||
看着就像"这一页的卡片是透明的"。和其它后台页保持一致,也和主题无关。 */
|
||
.qlist-panel {
|
||
background: var(--tb-surface);
|
||
border-radius: var(--tb-radius);
|
||
box-shadow: var(--tb-shadow);
|
||
padding: 18px 20px 8px;
|
||
}
|
||
/* 面板内部本来还有一张卡片(投票 tab 的「我的投票」标题条):降成次级底色,
|
||
否则就是卡片套卡片,阴影会叠一层脏边。 */
|
||
.qlist-panel .uk-card-default { background: var(--tb-surface-2); box-shadow: none; }
|
||
@media (max-width: 640px) {
|
||
.qlist-panel { padding: 14px 12px 4px; }
|
||
}
|
||
.all-votes-list { display: grid; gap: 10px; }
|
||
.all-vote-item {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 16px;
|
||
padding: 14px 16px;
|
||
border-bottom: 1px solid var(--tb-border);
|
||
text-decoration: none;
|
||
}
|
||
.all-vote-item:first-child { border-top: 1px solid var(--tb-border); }
|
||
.all-vote-item:hover { background: #f8fbff; text-decoration: none; }
|
||
.all-vote-item .hot-vote-title { max-width: 100%; }
|
||
.hot-vote-title {
|
||
display: block;
|
||
overflow: hidden;
|
||
color: var(--tb-text);
|
||
font-size: var(--tb-fs-md);
|
||
font-weight: 600;
|
||
line-height: 1.45;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
.hot-vote-title:hover { color: var(--tb-primary); }
|
||
.hot-vote-meta {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
align-items: center;
|
||
gap: 7px;
|
||
margin-top: 8px;
|
||
}
|
||
.hot-vote-meta .uk-label { font-size: var(--tb-fs-xs); line-height: 1.6; }
|
||
.hot-vote-action { flex: 0 0 auto; color: var(--tb-primary); font-size: var(--tb-fs-md); white-space: nowrap; }
|
||
/* 提问列表右上角:状态标签与操作按钮统一尺寸(等宽等高、垂直居中、完全对齐)。
|
||
每个元素显式带 .qlist-pill 类,选择器挂在 .qlist-pills 容器下提升优先级,
|
||
避免浏览器对 <button> 的默认样式或 UIkit .uk-label 造成差异。
|
||
移动端默认显示短文字标签(每语言短词,如 未读→新/New,宽度可控);
|
||
≥640px 显示完整文案(配合 title 悬浮提示,多语言安全)。 */
|
||
.qlist-pills .qlist-pill {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 24px;
|
||
min-width: 40px;
|
||
padding: 0 8px;
|
||
box-sizing: border-box;
|
||
font-size: var(--tb-fs-xs);
|
||
line-height: 1;
|
||
white-space: nowrap;
|
||
border-radius: var(--tb-radius-xs);
|
||
border: 0;
|
||
vertical-align: middle;
|
||
}
|
||
.qlist-pills .tb-short { display: inline; }
|
||
.qlist-pills .tb-text { display: none; }
|
||
/* 按钮额外重置浏览器默认样式,保证与 span 标签渲染完全一致 */
|
||
.qlist-pills .qlist-pill.tb-label-btn {
|
||
cursor: pointer;
|
||
font-family: inherit;
|
||
-webkit-appearance: none;
|
||
appearance: none;
|
||
background-image: none;
|
||
outline: none;
|
||
margin: 0;
|
||
}
|
||
.qlist-pills .qlist-pill.tb-label-btn:hover { opacity: 0.85; }
|
||
@media (min-width: 640px) {
|
||
/* 桌面端纯文字:隐藏移动端短词,只显示完整文案 */
|
||
.qlist-pills .qlist-pill { min-width: 62px; padding: 0 10px; }
|
||
.qlist-pills .tb-short { display: none; }
|
||
.qlist-pills .tb-text { display: inline; }
|
||
}
|
||
html[data-theme="dark"] .qlist-tabs { border-color: var(--tb-border); background: var(--tb-surface-2); }
|
||
html[data-theme="dark"] .qlist-tab { color: var(--tb-text-muted); }
|
||
html[data-theme="dark"] .qlist-tab.is-active { background: var(--tb-surface); color: var(--tb-primary); }
|
||
html[data-theme="dark"] .all-vote-item { border-color: var(--tb-border); }
|
||
html[data-theme="dark"] .all-vote-item:hover { background: rgba(78, 168, 245, 0.10); }
|
||
html[data-theme="dark"] .hot-vote-title { color: var(--tb-text); }
|
||
/* 紧凑统计看板:替代原 UIkit 卡片网格。手机端 4 列(7 项=2 行)、桌面端 7 列 1 行,
|
||
轻量描边小格子、缩字号、去掉大卡片内边距,显著降低纵向高度,减少手机端滚动。
|
||
--4 修饰类用于项数较少的看板(如私聊 4 项),在所有断点固定 4 列,避免末尾留白过多。 */
|
||
.qlist-stats {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 8px;
|
||
margin-bottom: 16px;
|
||
}
|
||
@media (min-width: 768px) {
|
||
.qlist-stats { grid-template-columns: repeat(7, 1fr); }
|
||
}
|
||
.qlist-stats--4 { grid-template-columns: repeat(4, 1fr); }
|
||
@media (min-width: 768px) {
|
||
.qlist-stats--4 { grid-template-columns: repeat(4, 1fr); }
|
||
}
|
||
/* --2 修饰类用于项数很少的看板(如投票 2 项),固定 2 列,避免末尾留白 */
|
||
.qlist-stats--2 { grid-template-columns: repeat(2, 1fr); }
|
||
@media (min-width: 768px) {
|
||
.qlist-stats--2 { grid-template-columns: repeat(2, 1fr); }
|
||
}
|
||
.qlist-stat {
|
||
background: #fff;
|
||
border: 1px solid var(--tb-border);
|
||
border-radius: var(--tb-radius-sm);
|
||
padding: 8px 6px;
|
||
text-align: center;
|
||
}
|
||
.qlist-stat .qlist-stat-num {
|
||
display: block;
|
||
font-size: var(--tb-fs-lg);
|
||
font-weight: 700;
|
||
line-height: 1.15;
|
||
color: #222;
|
||
}
|
||
.qlist-stat .qlist-stat-lbl {
|
||
display: block;
|
||
margin-top: 2px;
|
||
font-size: var(--tb-fs-xs);
|
||
color: #888;
|
||
line-height: 1.15;
|
||
}
|
||
html[data-theme="dark"] .qlist-stat { background: var(--tb-surface); border-color: var(--tb-border); }
|
||
html[data-theme="dark"] .qlist-stat .qlist-stat-num { color: var(--tb-text); }
|
||
html[data-theme="dark"] .qlist-stat .qlist-stat-lbl { color: var(--tb-text-muted); }
|
||
</style>
|
||
|
||
<div class="uk-container">
|
||
<div class="uk-flex uk-flex-middle uk-flex-between uk-margin-small-bottom">
|
||
<h2 class="uk-margin-remove">{{t .LangCode "qlist.title"}}</h2>
|
||
<a class="uk-button uk-button-default uk-button-small" href="/user/profile">{{t .LangCode "admin.featuresEntry"}}</a>
|
||
</div>
|
||
|
||
<!-- 居中切换:提问 / 投票 / 私聊 -->
|
||
<div class="qlist-tabs" role="tablist" aria-label="{{t .LangCode "qlist.title"}}">
|
||
<button type="button" class="qlist-tab is-active" data-qlist-tab="questions" role="tab" aria-selected="true">{{t .LangCode "qlist.questionsTab"}}</button>
|
||
<button type="button" class="qlist-tab" data-qlist-tab="votes" role="tab" aria-selected="false">{{t .LangCode "qlist.votesTab"}}</button>
|
||
<button type="button" class="qlist-tab" data-qlist-tab="chats" role="tab" aria-selected="false">{{t .LangCode "qlist.chatsTab"}}</button>
|
||
</div>
|
||
|
||
<!-- 提问面板(默认展示) -->
|
||
<div class="qlist-panel" data-qlist-panel="questions">
|
||
<!-- 统一提示区:标记已读/未读、置顶等操作的成功/错误提示沿用 base/alert 样式 -->
|
||
{{template "base/alert" .}}
|
||
|
||
{{ if .RestrictionLevel }}
|
||
<!-- 处置期常驻提示:L1 停分发 / L2 新回答不公开 / L3 禁止发布 -->
|
||
<div class="uk-alert-warning" uk-alert>
|
||
<div>{{t .LangCode "qlist.restrictionBanner" (or .RestrictionLevelName .RestrictionLevel) .RestrictionExpiresAt}} <span class="uk-text-meta">·</span> <a href="/rules">{{t .LangCode "qlist.restrictionRulesLink"}}</a></div>
|
||
</div>
|
||
{{ end }}
|
||
|
||
<!-- 提问箱统计看板(紧凑多列网格:手机4列/桌面7列,降低纵向高度) -->
|
||
<div class="qlist-stats">
|
||
<div class="qlist-stat"><span class="qlist-stat-num">{{ .Stats.total }}</span><span class="qlist-stat-lbl">{{t .LangCode "qlist.statsTotal"}}</span></div>
|
||
<div class="qlist-stat"><span class="qlist-stat-num">{{ .Stats.answered }}</span><span class="qlist-stat-lbl">{{t .LangCode "qlist.statsAnswered"}}</span></div>
|
||
<div class="qlist-stat"><span class="qlist-stat-num">{{ .Stats.unanswered }}</span><span class="qlist-stat-lbl">{{t .LangCode "qlist.statsUnanswered"}}</span></div>
|
||
<div class="qlist-stat"><span class="qlist-stat-num">{{ .Stats.read }}</span><span class="qlist-stat-lbl">{{t .LangCode "qlist.statsRead"}}</span></div>
|
||
<div class="qlist-stat"><span class="qlist-stat-num">{{ .Stats.unread }}</span><span class="qlist-stat-lbl">{{t .LangCode "qlist.statsUnread"}}</span></div>
|
||
<div class="qlist-stat"><span class="qlist-stat-num">{{ .Stats.private }}</span><span class="qlist-stat-lbl">{{t .LangCode "qlist.statsPrivate"}}</span></div>
|
||
<div class="qlist-stat"><span class="qlist-stat-num">{{ .Stats.pinned }}</span><span class="qlist-stat-lbl">{{t .LangCode "qlist.statsPinned"}}</span></div>
|
||
</div>
|
||
|
||
<div class="uk-margin-medium-bottom uk-text-center">
|
||
<!-- 全文搜索自己提问箱 -->
|
||
<form method="get" action="" class="uk-form-stacked">
|
||
<div class="uk-flex uk-flex-center uk-flex-nowrap uk-overflow-auto">
|
||
<div class="uk-margin-small-right uk-width-expand" style="max-width: 420px;">
|
||
<input type="text" name="q" class="uk-input uk-form-small" value="{{ .Keyword }}" placeholder="{{t .LangCode "qlist.searchPlaceholder"}}" aria-label="{{t .LangCode "qlist.searchPlaceholder"}}">
|
||
</div>
|
||
<div class="uk-margin-small-right">
|
||
<button type="submit" class="uk-button uk-button-primary uk-button-small">{{t .LangCode "qlist.searchBtn"}}</button>
|
||
</div>
|
||
{{ if ne .Keyword "" }}
|
||
<div>
|
||
<a class="uk-button uk-button-default uk-button-small" href="/user/questions">{{t .LangCode "qlist.searchClear"}}</a>
|
||
</div>
|
||
{{ end }}
|
||
</div>
|
||
</form>
|
||
<form method="get" action="" class="uk-form-stacked uk-margin-small-top">
|
||
<div class="uk-flex uk-flex-center uk-flex-nowrap uk-overflow-auto">
|
||
<div class="uk-margin-small-right" style="width: 120px;">
|
||
<label class="uk-form-label uk-text-small">{{t .LangCode "qlist.sort"}}</label>
|
||
<select name="sort" class="uk-select uk-form-small" onchange="this.form.submit()" style="width: 100%;">
|
||
<option value="latest" {{if eq .SelectedSort "latest"}}selected{{end}}>{{t .LangCode "qlist.latest"}}</option>
|
||
<option value="oldest" {{if eq .SelectedSort "oldest"}}selected{{end}}>{{t .LangCode "qlist.oldest"}}</option>
|
||
</select>
|
||
</div>
|
||
<div class="uk-margin-small-right" style="width: 120px;">
|
||
<label class="uk-form-label uk-text-small">{{t .LangCode "qlist.status"}}</label>
|
||
<select name="status" class="uk-select uk-form-small" onchange="this.form.submit()" style="width: 100%;">
|
||
<option value="all" {{if eq .SelectedStatus "all"}}selected{{end}}>{{t .LangCode "qlist.all"}}</option>
|
||
<option value="answered" {{if eq .SelectedStatus "answered"}}selected{{end}}>{{t .LangCode "qlist.answered"}}</option>
|
||
<option value="unanswered" {{if eq .SelectedStatus "unanswered"}}selected{{end}}>{{t $.LangCode "qlist.unanswered"}}</option>
|
||
</select>
|
||
</div>
|
||
<div class="uk-margin-small-right" style="width: 120px;">
|
||
<label class="uk-form-label uk-text-small">{{t .LangCode "qlist.type"}}</label>
|
||
<select name="type" class="uk-select uk-form-small" onchange="this.form.submit()" style="width: 100%;">
|
||
<option value="all" {{if eq .SelectedType "all"}}selected{{end}}>{{t .LangCode "qlist.all"}}</option>
|
||
<option value="public" {{if eq .SelectedType "public"}}selected{{end}}>{{t .LangCode "qlist.public"}}</option>
|
||
<option value="private_question" {{if eq .SelectedType "private_question"}}selected{{end}}>{{t .LangCode "qlist.privateQuestion"}}</option>
|
||
</select>
|
||
</div>
|
||
<div class="uk-margin-small-right" style="width: 120px;">
|
||
<label class="uk-form-label uk-text-small">{{t .LangCode "qlist.reportFilter"}}</label>
|
||
<select name="reported" class="uk-select uk-form-small" onchange="this.form.submit()" style="width: 100%;">
|
||
<option value="all" {{if eq .SelectedReported "all"}}selected{{end}}>{{t .LangCode "qlist.all"}}</option>
|
||
<option value="reported" {{if eq .SelectedReported "reported"}}selected{{end}}>{{t .LangCode "qlist.reportedOnly"}}</option>
|
||
</select>
|
||
</div>
|
||
<div style="width: 120px;">
|
||
<label class="uk-form-label uk-text-small">{{t .LangCode "qlist.readStatus"}}</label>
|
||
<select name="read" class="uk-select uk-form-small" onchange="this.form.submit()" style="width: 100%;">
|
||
<option value="all" {{if eq .SelectedRead "all"}}selected{{end}}>{{t .LangCode "qlist.all"}}</option>
|
||
<option value="read" {{if eq .SelectedRead "read"}}selected{{end}}>{{t .LangCode "qlist.read"}}</option>
|
||
<option value="unread" {{if eq .SelectedRead "unread"}}selected{{end}}>{{t .LangCode "qlist.unread"}}</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<!-- 我收到的提问(标签右浮同行时间,内容下一行) -->
|
||
<h4>{{t .LangCode "qlist.received"}}</h4>
|
||
{{ if .ReceivedItems }}
|
||
{{ range .ReceivedItems }}
|
||
<div class="uk-margin-medium-bottom" id="question-{{.QuestionID}}">
|
||
<hr>
|
||
<!-- 标签在左、按钮在右:两组分开布局;移动端状态/按钮只显示 emoji 图标,保持单行紧凑 -->
|
||
<div class="uk-flex uk-flex-middle uk-flex-wrap qlist-pills" style="gap: 6px;">
|
||
<!-- 左:时间 + 状态标签 -->
|
||
<div class="uk-flex uk-flex-middle uk-flex-wrap" style="gap: 6px;">
|
||
<span class="uk-text-small uk-text-muted">{{Date .CreatedAt "Y-m-d H:i:s"}}</span>
|
||
{{ if .IsPinned }}
|
||
<span class="uk-label uk-label-warning qlist-pill" title="{{t $.LangCode "qlist.pinned"}}"><span class="tb-short">{{t $.LangCode "qlist.pinnedShort"}}</span><span class="tb-text">{{t $.LangCode "qlist.pinned"}}</span></span>
|
||
{{ end }}
|
||
{{ if eq .Type "question_private" }}
|
||
<span class="uk-label uk-label-warning qlist-pill" title="{{t $.LangCode "qlist.private"}}"><span class="tb-short">{{t $.LangCode "qlist.privateShort"}}</span><span class="tb-text">{{t $.LangCode "qlist.private"}}</span></span>
|
||
{{ end }}
|
||
{{ if not .IsAnswered }}
|
||
<span class="uk-label qlist-pill" title="{{t $.LangCode "qlist.unanswered"}}"><span class="tb-short">{{t $.LangCode "qlist.unansweredShort"}}</span><span class="tb-text">{{t $.LangCode "qlist.unanswered"}}</span></span>
|
||
{{ end }}
|
||
{{ if .ReportCount }}
|
||
<span class="uk-label uk-label-danger qlist-pill" title="{{t $.LangCode "qlist.reported" .ReportCount}}"><span class="tb-short">{{t $.LangCode "qlist.reportedShort" .ReportCount}}</span><span class="tb-text">{{t $.LangCode "qlist.reported" .ReportCount}}</span></span>
|
||
{{ end }}
|
||
{{ if .IsRead }}
|
||
<span class="uk-label uk-label-success qlist-pill" title="{{t $.LangCode "qlist.read"}}"><span class="tb-short">{{t $.LangCode "qlist.readShort"}}</span><span class="tb-text">{{t $.LangCode "qlist.read"}}</span></span>
|
||
{{ else }}
|
||
<span class="uk-label qlist-pill" title="{{t $.LangCode "qlist.unread"}}"><span class="tb-short">{{t $.LangCode "qlist.unreadShort"}}</span><span class="tb-text">{{t $.LangCode "qlist.unread"}}</span></span>
|
||
{{ end }}
|
||
</div>
|
||
<!-- 右:操作按钮(margin-left:auto 推到最右,换行后仍保持右对齐) -->
|
||
<div class="uk-flex uk-flex-middle uk-flex-wrap" style="gap: 6px; margin-left: auto;">
|
||
{{ if not .IsRead }}
|
||
<!-- 快捷标记已读:沿用原 tb-label-btn 样式,display:contents 不破坏 flex 布局 -->
|
||
<form method="post" action="/_/{{$.LoggedUser.Domain}}/{{.QuestionID}}/read" style="margin: 0; display: contents;">
|
||
{{ $.CSRFTokenHTML }}
|
||
<button type="submit" class="uk-label tb-label-btn uk-label-success qlist-pill" title="{{t $.LangCode "qitem.markRead"}}"><span class="tb-short">{{t $.LangCode "qitem.markReadShort"}}</span><span class="tb-text">{{t $.LangCode "qitem.markRead"}}</span></button>
|
||
</form>
|
||
{{ end }}
|
||
<!-- form 用 display:contents 不产生盒子,置顶按钮直接参与 flex 对齐 -->
|
||
<form method="post" action="{{.PinLink}}" style="margin: 0; display: contents;">
|
||
{{ $.CSRFTokenHTML }}
|
||
<button type="submit" class="uk-label tb-label-btn {{ if .IsPinned }}uk-label-danger{{ else }}uk-label-primary{{ end }} qlist-pill" title="{{ if .IsPinned }}{{t $.LangCode "qlist.unpin"}}{{ else }}{{t $.LangCode "qlist.pin"}}{{ end }}"><span class="tb-short">{{ if .IsPinned }}{{t $.LangCode "qlist.unpinShort"}}{{ else }}{{t $.LangCode "qlist.pinShort"}}{{ end }}</span><span class="tb-text">{{ if .IsPinned }}{{t $.LangCode "qlist.unpin"}}{{ else }}{{t $.LangCode "qlist.pin"}}{{ end }}</span></button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<a href="{{.Link}}">
|
||
<div class="uk-text-small uk-text-break tb-preline tb-clamp-5 uk-margin-small-top">{{MarkdownPlainText .Content}}</div>
|
||
</a>
|
||
</div>
|
||
{{ end }}
|
||
{{ if .HasMoreQuestions }}
|
||
<div class="uk-text-center uk-margin-medium-top">
|
||
<a class="uk-button uk-button-default uk-button-small" href="{{ .QuestionLoadMoreURL }}">{{t .LangCode "qlist.loadMore"}}</a>
|
||
</div>
|
||
{{ end }}
|
||
{{ else }}
|
||
<p class="uk-text-muted">{{t .LangCode "qlist.empty"}}</p>
|
||
{{ end }}
|
||
</div>
|
||
|
||
<!-- 投票面板 -->
|
||
<div class="qlist-panel" data-qlist-panel="votes" hidden>
|
||
<!-- 统一提示区:发布/结束/删除等操作的成功/错误提示沿用 base/alert 样式 -->
|
||
{{template "base/alert" .}}
|
||
|
||
<!-- 投票统计看板(与提问/私聊看板一致) -->
|
||
<div class="qlist-stats qlist-stats--2">
|
||
<div class="qlist-stat"><span class="qlist-stat-num">{{ .VoteStats.total }}</span><span class="qlist-stat-lbl">{{t .LangCode "vote.statsTotal"}}</span></div>
|
||
<div class="qlist-stat"><span class="qlist-stat-num">{{ .VoteStats.published }}</span><span class="qlist-stat-lbl">{{t .LangCode "vote.statsPublished"}}</span></div>
|
||
</div>
|
||
|
||
<div class="uk-card uk-card-default uk-card-small uk-card-body uk-margin-bottom uk-flex uk-flex-between uk-flex-middle">
|
||
<div>
|
||
<div class="uk-text-bold">{{t .LangCode "qlist.myVotes"}}</div>
|
||
<div class="uk-text-meta uk-text-small">{{t .LangCode "vote.manageDesc"}}</div>
|
||
</div>
|
||
<a class="uk-button uk-button-primary uk-button-small" href="/user/votes/new">{{t .LangCode "qlist.newVote"}}</a>
|
||
</div>
|
||
|
||
{{ if .MyVotes }}
|
||
{{ range .MyVotes }}
|
||
<div class="uk-margin-medium-bottom">
|
||
<hr>
|
||
<!-- 第一行:标题 + 类型 + 状态 + 元信息 -->
|
||
<div class="uk-flex uk-flex-middle uk-flex-wrap" style="gap: 8px;">
|
||
<span class="uk-text-bold">{{ if .Title }}{{ .Title }}{{ else }}{{t $.LangCode "qlist.untitledVote"}}{{ end }}</span>
|
||
{{ if eq .Type "single" }}<span class="tb-chip">{{t $.LangCode "vote.typeSingle"}}</span>{{ end }}
|
||
{{ if eq .Type "multiple" }}<span class="tb-chip">{{t $.LangCode "vote.typeMultiple"}}</span>{{ end }}
|
||
{{ if eq .Type "rating" }}<span class="tb-chip">{{t $.LangCode "vote.typeRating"}}</span>{{ end }}
|
||
{{ if eq .Type "rank" }}<span class="tb-chip">{{t $.LangCode "vote.typeRank"}}</span>{{ end }}
|
||
{{ if eq .Type "form" }}<span class="tb-chip">{{t $.LangCode "vote.typeForm"}}</span>{{ end }}
|
||
{{ if eq .EffectiveStatus "draft" }}<span class="uk-label">{{t $.LangCode "vote.statusDraft"}}</span>{{ end }}
|
||
{{ if eq .EffectiveStatus "published" }}<span class="uk-label uk-label-success">{{t $.LangCode "vote.statusPublished"}}</span>{{ end }}
|
||
{{ if eq .EffectiveStatus "not_started" }}<span class="tb-chip">{{t $.LangCode "vote.statusNotStarted"}}</span>{{ end }}
|
||
{{ if eq .EffectiveStatus "ended" }}<span class="uk-label uk-label-warning">{{t $.LangCode "vote.statusEnded"}}</span>{{ end }}
|
||
{{ if eq .EffectiveStatus "archived" }}<span class="uk-label uk-label-secondary">{{t $.LangCode "vote.statusArchived"}}</span>{{ end }}
|
||
<span class="uk-text-meta">{{t $.LangCode "vote.participants"}}: {{ .SubmissionCount }}</span>
|
||
{{ if .RemainingText }}<span class="uk-text-meta">{{ .RemainingText }}</span>{{ end }}
|
||
<span class="uk-text-meta">{{t $.LangCode "vote.createdAt"}}: {{ .CreatedAt.Format "2006-01-02 15:04" }}</span>
|
||
</div>
|
||
<!-- 第二行:操作按钮(统一右对齐,所有状态保持一致的两行布局) -->
|
||
<div class="uk-flex uk-flex-wrap uk-margin-small-top" style="gap: 6px; justify-content: flex-end;">
|
||
{{ if eq .EffectiveStatus "draft" }}
|
||
<form method="post" action="/user/votes/{{ .ID }}/publish" class="uk-display-inline">
|
||
{{ $.CSRFTokenHTML }}
|
||
<button class="uk-button uk-button-primary uk-button-small" onclick="return confirm('{{t $.LangCode "vote.confirmPublish"}}')">{{t $.LangCode "vote.publish"}}</button>
|
||
</form>
|
||
<a class="uk-button uk-button-default uk-button-small" href="/user/votes/{{ .ID }}/preview">{{t $.LangCode "vote.preview"}}</a>
|
||
{{ end }}
|
||
{{ if or (eq .EffectiveStatus "published") (eq .EffectiveStatus "not_started") }}
|
||
<form method="post" action="/user/votes/{{ .ID }}/close" class="uk-display-inline">
|
||
{{ $.CSRFTokenHTML }}
|
||
<button class="uk-button uk-button-warning uk-button-small" onclick="return confirm('{{t $.LangCode "vote.confirmClose"}}')">{{t $.LangCode "vote.close"}}</button>
|
||
</form>
|
||
{{ end }}
|
||
{{ if ne .EffectiveStatus "archived" }}
|
||
<a class="uk-button uk-button-default uk-button-small" href="/user/votes/{{ .ID }}/edit">{{t $.LangCode "vote.edit"}}</a>
|
||
{{ end }}
|
||
{{ if ne .EffectiveStatus "draft" }}
|
||
<a class="uk-button uk-button-default uk-button-small" href="/user/votes/{{ .ID }}/results">{{t $.LangCode "vote.results"}}</a>
|
||
<a class="uk-button uk-button-default uk-button-small" href="/user/votes/{{ .ID }}/export">{{t $.LangCode "vote.export"}}</a>
|
||
{{ end }}
|
||
{{ if or (eq .EffectiveStatus "published") (eq .EffectiveStatus "not_started") }}
|
||
<button class="uk-button uk-button-default uk-button-small" onclick="copyShareURL('{{ .LinkToken }}', this)">{{t $.LangCode "vote.share"}}</button>
|
||
{{ end }}
|
||
<form method="post" action="/user/votes/{{ .ID }}/delete" class="uk-display-inline">
|
||
{{ $.CSRFTokenHTML }}
|
||
<button class="uk-button uk-button-danger uk-button-small" onclick="return confirm('{{t $.LangCode "vote.confirmDelete"}}')">{{t $.LangCode "common.delete"}}</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
{{ end }}
|
||
{{ if .HasMoreVotes }}
|
||
<div class="uk-text-center uk-margin-medium-top">
|
||
<a class="uk-button uk-button-default uk-button-small" href="{{ .VoteLoadMoreURL }}">{{t .LangCode "qlist.loadMore"}}</a>
|
||
</div>
|
||
{{ end }}
|
||
{{ else }}
|
||
<div class="uk-alert uk-alert-primary uk-margin-remove">{{t .LangCode "vote.empty"}}</div>
|
||
{{ end }}
|
||
</div>
|
||
|
||
<!-- 私聊面板 -->
|
||
<div class="qlist-panel" data-qlist-panel="chats" hidden>
|
||
<!-- 统一提示区:私聊相关操作的成功/错误提示沿用 base/alert 样式 -->
|
||
{{template "base/alert" .}}
|
||
|
||
<!-- 私聊统计看板(与提问/投票看板一致) -->
|
||
<div class="qlist-stats qlist-stats--4">
|
||
<div class="qlist-stat"><span class="qlist-stat-num">{{ .ChatStats.total }}</span><span class="qlist-stat-lbl">{{t .LangCode "qlist.chatStatsTotal"}}</span></div>
|
||
<div class="qlist-stat"><span class="qlist-stat-num">{{ .ChatStats.received }}</span><span class="qlist-stat-lbl">{{t .LangCode "qlist.chatStatsReceived"}}</span></div>
|
||
<div class="qlist-stat"><span class="qlist-stat-num">{{ .ChatStats.initiated }}</span><span class="qlist-stat-lbl">{{t .LangCode "qlist.chatStatsInitiated"}}</span></div>
|
||
<div class="qlist-stat"><span class="qlist-stat-num">{{ .ChatStats.closed }}</span><span class="qlist-stat-lbl">{{t .LangCode "qlist.chatStatsClosed"}}</span></div>
|
||
</div>
|
||
|
||
<!-- 我收到的私聊 -->
|
||
<h4>{{t .LangCode "qlist.receivedChats"}}({{ .ChatStats.received }})</h4>
|
||
{{ if .ReceivedChats }}
|
||
{{ range .ReceivedChats }}
|
||
<div class="uk-margin-medium-bottom">
|
||
<hr>
|
||
<div class="uk-float-right uk-flex uk-flex-middle uk-flex-wrap" style="gap: 6px;">
|
||
<span class="uk-label uk-label-success">{{t $.LangCode "chat.title"}}</span>
|
||
{{ if .IsBlocked }}
|
||
<span class="uk-label uk-label-danger">{{t $.LangCode "qlist.blocked"}}</span>
|
||
{{ end }}
|
||
</div>
|
||
<a href="{{.Link}}">
|
||
<div class="uk-text-left uk-text-small uk-text-muted">{{Date .CreatedAt "Y-m-d H:i:s"}}</div>
|
||
<div class="uk-text-small uk-text-break tb-preline tb-clamp-5 uk-margin-small-top">{{.Content}}</div>
|
||
</a>
|
||
</div>
|
||
{{ end }}
|
||
{{ else }}
|
||
<p class="uk-text-muted">{{t .LangCode "qlist.chatEmpty"}}</p>
|
||
{{ end }}
|
||
|
||
{{ if .HasMoreChats }}
|
||
<div class="uk-text-center uk-margin-medium-top">
|
||
<a class="uk-button uk-button-default uk-button-small" href="{{ .ChatLoadMoreURL }}">{{t .LangCode "qlist.loadMore"}}</a>
|
||
</div>
|
||
{{ end }}
|
||
|
||
<!-- 我发起的私聊 -->
|
||
{{ if .ConversationDetails }}
|
||
<h4 class="uk-margin-top">{{t .LangCode "qlist.myChats"}}({{ .ChatStats.initiated }})</h4>
|
||
{{ range .ConversationDetails }}
|
||
<a href="/_/{{.OwnerDomain}}/chat/{{.Conversation.Token}}" class="uk-display-block uk-overflow-hidden uk-margin-medium-bottom">
|
||
<div>
|
||
<hr>
|
||
<span class="uk-label uk-label-warning uk-float-right uk-margin-small-right">{{t $.LangCode "chat.title"}}</span>
|
||
{{ if .IsBlocked }}
|
||
<span class="uk-label uk-label-danger uk-float-right uk-margin-small-right">{{t $.LangCode "qlist.blocked"}}</span>
|
||
{{ end }}
|
||
<div class="uk-text-left uk-text-small uk-text-muted">{{Date .Conversation.CreatedAt "Y-m-d H:i:s"}}</div>
|
||
<div class="uk-text-small uk-text-break tb-preline tb-clamp-5 uk-margin-small-top">{{.FirstMessage}}</div>
|
||
</div>
|
||
</a>
|
||
{{ end }}
|
||
{{ end }}
|
||
{{ if .HasMoreAskedChats }}
|
||
<div class="uk-text-center uk-margin-medium-top">
|
||
<a class="uk-button uk-button-default uk-button-small" href="{{ .AskedChatsLoadMoreURL }}">{{t .LangCode "qlist.loadMore"}}</a>
|
||
</div>
|
||
{{ end }}
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
function copyShareURL(token, btn) {
|
||
var url = window.location.origin + "/vote/" + token;
|
||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||
navigator.clipboard.writeText(url).then(function () {
|
||
var old = btn.textContent;
|
||
btn.textContent = '{{t .LangCode "vote.copied"}}';
|
||
setTimeout(function () { btn.textContent = old; }, 1500);
|
||
});
|
||
} else {
|
||
prompt('{{t .LangCode "vote.shareURL"}}', url);
|
||
}
|
||
}
|
||
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
const tabs = document.querySelectorAll('[data-qlist-tab]');
|
||
const panels = document.querySelectorAll('[data-qlist-panel]');
|
||
function showQlistPanel(name) {
|
||
tabs.forEach(function(tab) {
|
||
const active = tab.dataset.qlistTab === name;
|
||
tab.classList.toggle('is-active', active);
|
||
tab.setAttribute('aria-selected', active ? 'true' : 'false');
|
||
});
|
||
panels.forEach(function(panel) {
|
||
panel.hidden = panel.dataset.qlistPanel !== name;
|
||
});
|
||
if (window.history && window.history.replaceState) {
|
||
const hash = name === 'votes' ? '#votes' : (name === 'chats' ? '#chats' : '');
|
||
window.history.replaceState({}, document.title, window.location.pathname + hash);
|
||
}
|
||
}
|
||
tabs.forEach(function(tab) {
|
||
tab.addEventListener('click', function() { showQlistPanel(tab.dataset.qlistTab); });
|
||
});
|
||
if (window.location.hash === '#votes') showQlistPanel('votes');
|
||
if (window.location.hash === '#chats') showQlistPanel('chats');
|
||
});
|
||
</script>
|
||
|
||
{{template "base/footer" .}}
|