This commit is contained in:
tamakyi
2026-09-08 10:10:44 +08:00
commit 2ed27dd55e
288 changed files with 67061 additions and 0 deletions
+83
View File
@@ -0,0 +1,83 @@
{{$pinTitle := t .LangCode "ask.pinned"}}
<div id="question-list">
{{range $index, $elem := .PageQuestions}}
<div data-qid="{{$elem.ID}}">
<hr>
<a class="uk-button uk-button-default uk-button-small uk-float-right"
href="/_/{{$.PageUser.Domain}}/{{$elem.ID}}">查看回答</a>
<div class="uk-text-left uk-text-small uk-text-muted">
{{if $elem.IsPinned}}<span class="tb-pin-flag" title="{{t $.LangCode "ask.pinned"}}">⭐</span>{{end}}
{{Date $elem.CreatedAt "Y-m-d H:i:s"}}
</div>
<p class="uk-text-small uk-text-break tb-preline tb-clamp-5">{{MarkdownPlainText $elem.Content}}</p>
</div>
{{end}}
</div>
<!-- 翻页游标与服务端 EncodePinCursor 保持一致:
isPinned(0/1) + createdAt 的 UnixNano + id 组成的复合键集游标。 -->
<!-- 初始 more 由服务端给出:首屏已展示全部提问时按钮直接不渲染,
之后每次加载以接口返回的 has_more 为准,最后一页加载完立即隐藏按钮。 -->
<div x-data="{ more: {{ if .PageQuestionHasMore }}true{{ else }}false{{ end }}, loading: false, cursor: '{{.PageQuestionCursor}}' }">
<button x-show="more" x-bind:disabled="loading" x-on:click.debounce="() => {
if (loading) return
loading = true
fetch(`/api/v1/user/{{.PageUser.Domain}}/questions?cursor=${cursor}`)
.then(response => response.json())
.then(resp => {
loading = false
// 外层为 ctx.JSON 的统一包装 {code, data, message},内层才是分页负载;
// code !== 0(接口报错)时保持 more 不变,仅复位 loading,下次可重试。
if (!resp || resp.code !== 0) return
const payload = resp.data || {}
let items = Array.isArray(payload.data) ? payload.data : []
if (items.length === 0) {
more = false
return
}
// 防重兜底:先扫描 #question-list 下全部已渲染条目(含服务端首屏与既往
// 追加)的 data-qid 构造“已见”集合,仅追加未出现过的提问。若服务端因游标
// 未前进等原因返回了与已见内容相同的批次(重复加载历史 bug 的表现形态),
// 直接按“到底”处理并隐藏按钮,杜绝无限重复追加。
const seenQIDs = new Set()
document.querySelectorAll('#question-list [data-qid]').forEach(el => seenQIDs.add(Number(el.dataset.qid)))
items = items.filter(q => !seenQIDs.has(q.id))
if (items.length === 0) {
more = false
return
}
// 服务端下发复合键集游标(见上方注释),前端不自行拼接;
// has_more 由服务端多取一条探测得出,最后一页加载完立即隐藏按钮。
more = payload.has_more !== false
cursor = payload.next_cursor || cursor
items.forEach(question => {
const div = document.createElement('div')
div.dataset.qid = question.id
div.innerHTML = `
<div>
<hr>
<a class='uk-button uk-button-default uk-button-small uk-float-right'
href='/_/{{.PageUser.Domain}}/${question.id}'>查看回答</a>
<div class='uk-text-left uk-text-small uk-text-muted'>
${question.is_pinned ? '<span class=\'tb-pin-flag\' title=\'{{$pinTitle}}\'>⭐</span>' : ''}
${dayjs(question.created_at).format('YYYY-MM-DD HH:mm:ss')}
</div>
<p class='uk-text-small uk-text-break tb-preline tb-clamp-5'></p>
</div>`
div.getElementsByTagName('p')[0].innerText = question.content
document.getElementById('question-list').appendChild(div)
})
})
// 网络失败/响应非法 JSON 时复位 loading,避免按钮永远停留在加载中状态
.catch(() => { loading = false })
}" class="uk-button uk-button-default uk-width-1-1 uk-margin-small-bottom">
<span x-show="!loading">加载更多</span>
<span x-show="loading"><div uk-spinner="ratio: 0.8"></div> 加载中...</span>
</button>
<div x-show="!more" class="uk-text-meta uk-text-center">
<hr>
无更多留言
<br><br>
</div>
</div>