add lightbox
Some checks failed
Deploy / deploy (build, debian, 22, /root/OJDeploy/data/clientnext) (push) Has been cancelled
Deploy / deploy (build:staging, school, 8822, /root/OJ/data/dist) (push) Has been cancelled

This commit is contained in:
2026-04-02 07:05:54 -06:00
parent 52f274fdc9
commit 2ba77e7465
3 changed files with 57 additions and 23 deletions

View File

@@ -58,7 +58,11 @@ watch(
// AC 或失败次数 >= 3 时加载推荐 // AC 或失败次数 >= 3 时加载推荐
watch( watch(
() => [problem.value?._id, problem.value?.my_status, problemStore.totalFailCount], () => [
problem.value?._id,
problem.value?.my_status,
problemStore.totalFailCount,
],
([, status, failCount]) => { ([, status, failCount]) => {
if (status === 0 || (failCount as number) >= 3) { if (status === 0 || (failCount as number) >= 3) {
loadSimilarProblems() loadSimilarProblems()

View File

@@ -236,11 +236,7 @@ watch(isMobile, (value) => {
> >
<ProblemComment /> <ProblemComment />
</n-tab-pane> </n-tab-pane>
<n-tab-pane <n-tab-pane name="submission" tab="提交" :disabled="!!props.problemSetId">
name="submission"
tab="提交"
:disabled="!!props.problemSetId"
>
<ProblemSubmission /> <ProblemSubmission />
</n-tab-pane> </n-tab-pane>
</n-tabs> </n-tabs>

View File

@@ -22,6 +22,40 @@ const [show, toggleShow] = useToggle(false)
const { isDesktop } = useBreakpoints() const { isDesktop } = useBreakpoints()
const isDefaultAvatar = computed(
() => profile.value?.avatar.endsWith("default.png") ?? true,
)
const problemsFlexRef = ref<HTMLElement | null>(null)
const itemsPerRow = ref(8)
function updateItemsPerRow() {
if (!problemsFlexRef.value) return
const buttons = problemsFlexRef.value.querySelectorAll("button")
if (!buttons.length) return
const firstTop = buttons[0].offsetTop
let count = 0
for (const btn of buttons) {
if (btn.offsetTop === firstTop) count++
else break
}
if (count > 0) itemsPerRow.value = count
}
useResizeObserver(problemsFlexRef, updateItemsPerRow)
watch(problems, async () => {
await nextTick()
updateItemsPerRow()
})
const visibleProblems = computed(() =>
show.value ? problems.value : problems.value.slice(0, itemsPerRow.value * 3),
)
const hasMoreProblems = computed(
() => problems.value.length > itemsPerRow.value * 3,
)
// 分组徽章接口 // 分组徽章接口
interface GroupedBadge { interface GroupedBadge {
icon: string icon: string
@@ -157,7 +191,18 @@ onMounted(init)
align="center" align="center"
v-if="!loading && profile" v-if="!loading && profile"
> >
<n-avatar round :size="140" :src="profile.avatar" /> <n-image
:width="140"
:height="140"
:src="profile.avatar"
:preview-disabled="isDefaultAvatar"
object-fit="cover"
:style="{
borderRadius: '50%',
overflow: 'hidden',
cursor: isDefaultAvatar ? 'default' : 'pointer',
}"
/>
<h2>{{ profile.user.username }}</h2> <h2>{{ profile.user.username }}</h2>
<p class="desc">{{ profile.mood }}</p> <p class="desc">{{ profile.mood }}</p>
</n-flex> </n-flex>
@@ -213,35 +258,24 @@ onMounted(init)
<n-button <n-button
text text
type="primary" type="primary"
v-if="problems.length > 21" v-if="hasMoreProblems"
@click="toggleShow(!show)" @click="toggleShow(!show)"
> >
{{ show ? "隐藏全部" : "显示全部" }} {{ show ? "隐藏全部" : "显示全部" }}
</n-button> </n-button>
</n-flex> </n-flex>
</template> </template>
<n-flex vertical> <div ref="problemsFlexRef">
<n-flex> <n-flex>
<n-button <n-button
v-for="id in problems.slice(0, 21)" v-for="id in visibleProblems"
key="id" :key="id"
@click="router.push('/problem/' + id)" @click="router.push('/problem/' + id)"
> >
{{ id }} {{ id }}
</n-button> </n-button>
</n-flex> </n-flex>
<n-collapse-transition :show="show" v-if="problems.length > 21"> </div>
<n-flex>
<n-button
v-for="id in problems.slice(21)"
key="id"
@click="router.push('/problem/' + id)"
>
{{ id }}
</n-button>
</n-flex>
</n-collapse-transition>
</n-flex>
</n-descriptions-item> </n-descriptions-item>
</n-descriptions> </n-descriptions>
<n-empty v-if="!loading && !profile" description="该用户不存在"> <n-empty v-if="!loading && !profile" description="该用户不存在">