feat: standardize panel cards and action buttons

This commit is contained in:
2026-05-30 00:10:15 +08:00
parent fa4e00ce8c
commit 8f1a9da4c9
14 changed files with 97 additions and 70 deletions
+2 -2
View File
@@ -251,8 +251,8 @@ watch(() => props.initialValue, value => {
</div> </div>
<div class="flex items-center justify-end gap-3 border-t border-slate-200 px-6 py-4"> <div class="flex items-center justify-end gap-3 border-t border-slate-200 px-6 py-4">
<NButton secondary strong @click="close">取消</NButton> <NButton secondary strong type="default" class="oc-panel-button oc-panel-button--neutral" @click="close">取消</NButton>
<NButton type="primary" secondary strong :loading="saving" @click="save"> <NButton type="default" secondary strong class="oc-panel-button oc-panel-button--sky" :loading="saving" @click="save">
保存修改 保存修改
</NButton> </NButton>
</div> </div>
@@ -29,7 +29,7 @@ const currentColor = computed(() => progressColor(props.isLoggedIn ? props.perce
</script> </script>
<template> <template>
<NCard class="border border-white/80 bg-white/85 shadow-sm backdrop-blur" :bordered="false"> <NCard class="oc-panel-card-soft border border-white/80 bg-white/85 shadow-sm backdrop-blur" :bordered="false">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div> <div>
<p class="text-sm text-slate-500">当前进度</p> <p class="text-sm text-slate-500">当前进度</p>
+3 -2
View File
@@ -194,11 +194,12 @@ onBeforeUnmount(() => {
<div class="flex items-center justify-between border-t border-slate-200 px-6 py-4"> <div class="flex items-center justify-between border-t border-slate-200 px-6 py-4">
<p class="text-sm text-slate-500">{{ footerText }}</p> <p class="text-sm text-slate-500">{{ footerText }}</p>
<div class="flex gap-3"> <div class="flex gap-3">
<NButton secondary strong @click="close">取消</NButton> <NButton secondary strong type="default" class="oc-panel-button oc-panel-button--neutral" @click="close">取消</NButton>
<NButton <NButton
type="primary" type="default"
secondary secondary
strong strong
class="oc-panel-button oc-panel-button--sky"
:disabled="pickedLat === null || pickedLng === null" :disabled="pickedLat === null || pickedLng === null"
@click="confirm" @click="confirm"
> >
+2 -2
View File
@@ -375,8 +375,8 @@ onBeforeUnmount(() => {
</div> </div>
<div class="flex items-center justify-end gap-3 border-t border-slate-200 bg-slate-50 px-5 py-4"> <div class="flex items-center justify-end gap-3 border-t border-slate-200 bg-slate-50 px-5 py-4">
<NButton secondary strong :disabled="uploading" @click="close">关闭</NButton> <NButton secondary strong type="default" class="oc-panel-button oc-panel-button--neutral" :disabled="uploading" @click="close">关闭</NButton>
<NButton type="primary" secondary strong :disabled="uploading || items.length === 0" @click="handleSubmit"> <NButton type="default" secondary strong class="oc-panel-button oc-panel-button--sky" :disabled="uploading || items.length === 0" @click="handleSubmit">
{{ uploading ? '上传中...' : '提交审核' }} {{ uploading ? '上传中...' : '提交审核' }}
</NButton> </NButton>
</div> </div>
+18 -6
View File
@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref, watch } from 'vue' import { computed, ref, watch } from 'vue'
import { NButton, NButtonGroup, NSelect } from 'naive-ui' import { NButton, NSelect } from 'naive-ui'
export interface ContributionHeatmapCell { export interface ContributionHeatmapCell {
date: string date: string
@@ -284,7 +284,7 @@ function formatMonthTooltip(monthKey: string) {
</script> </script>
<template> <template>
<div class="border border-slate-200 bg-white p-6 shadow-sm"> <div class="oc-panel-card border border-slate-200 bg-white p-6 shadow-sm">
<div class="flex flex-wrap items-start justify-between gap-6"> <div class="flex flex-wrap items-start justify-between gap-6">
<div class="min-w-0 flex-1"> <div class="min-w-0 flex-1">
<h3 class="text-2xl font-bold text-slate-900">{{ title }}</h3> <h3 class="text-2xl font-bold text-slate-900">{{ title }}</h3>
@@ -295,14 +295,26 @@ function formatMonthTooltip(monthKey: string) {
</div> </div>
<div class="flex flex-wrap items-center justify-end gap-3"> <div class="flex flex-wrap items-center justify-end gap-3">
<NButtonGroup> <div class="flex flex-wrap items-center gap-2">
<NButton :type="viewMode === 'year' ? 'primary' : 'default'" secondary strong @click="viewMode = 'year'"> <NButton
secondary
strong
type="default"
:class="viewMode === 'year' ? 'oc-panel-button oc-panel-button--teal' : 'oc-panel-button oc-panel-button--neutral'"
@click="viewMode = 'year'"
>
年度视图 年度视图
</NButton> </NButton>
<NButton :type="viewMode === 'month' ? 'primary' : 'default'" secondary strong @click="viewMode = 'month'"> <NButton
secondary
strong
type="default"
:class="viewMode === 'month' ? 'oc-panel-button oc-panel-button--teal' : 'oc-panel-button oc-panel-button--neutral'"
@click="viewMode = 'month'"
>
月度视图 月度视图
</NButton> </NButton>
</NButtonGroup> </div>
<NSelect <NSelect
v-model:value="selectedYear" v-model:value="selectedYear"
:options="yearOptions" :options="yearOptions"
+18 -13
View File
@@ -465,7 +465,7 @@ onMounted(loadAdminData)
</p> </p>
</div> </div>
<NButton secondary strong :loading="loading" @click="loadAdminData"> <NButton secondary strong type="default" class="oc-panel-button oc-panel-button--neutral" :loading="loading" @click="loadAdminData">
<template #icon> <template #icon>
<NIcon><Refresh /></NIcon> <NIcon><Refresh /></NIcon>
</template> </template>
@@ -577,13 +577,14 @@ onMounted(loadAdminData)
<p class="mt-1 text-sm text-slate-500"> {{ pendingImages.length }} 张待处理图片</p> <p class="mt-1 text-sm text-slate-500"> {{ pendingImages.length }} 张待处理图片</p>
</div> </div>
<div class="flex flex-wrap gap-2"> <div class="flex flex-wrap gap-2">
<NButton secondary strong @click="toggleAllPendingSelection"> <NButton secondary strong type="default" class="oc-panel-button oc-panel-button--neutral" @click="toggleAllPendingSelection">
{{ selectedReviewCount === pendingImages.length && pendingImages.length ? '取消全选' : '全选待审核' }} {{ selectedReviewCount === pendingImages.length && pendingImages.length ? '取消全选' : '全选待审核' }}
</NButton> </NButton>
<NButton <NButton
type="success"
secondary secondary
strong strong
type="default"
class="oc-panel-button oc-panel-button--teal"
:disabled="!selectedReviewCount" :disabled="!selectedReviewCount"
:loading="actionLoading" :loading="actionLoading"
@click="updateCloudStatus(Array.from(selectedReviewIds), 'approved')" @click="updateCloudStatus(Array.from(selectedReviewIds), 'approved')"
@@ -591,9 +592,10 @@ onMounted(loadAdminData)
批量通过 {{ selectedReviewCount || '' }} 批量通过 {{ selectedReviewCount || '' }}
</NButton> </NButton>
<NButton <NButton
type="error"
secondary secondary
strong strong
type="default"
class="oc-panel-button oc-panel-button--danger"
:disabled="!selectedReviewCount" :disabled="!selectedReviewCount"
:loading="actionLoading" :loading="actionLoading"
@click="updateCloudStatus(Array.from(selectedReviewIds), 'rejected')" @click="updateCloudStatus(Array.from(selectedReviewIds), 'rejected')"
@@ -624,15 +626,15 @@ onMounted(loadAdminData)
<p class="mt-3 text-sm text-slate-600">{{ item.location_name || '未填写位置' }} · {{ formatDateTime(item.created_at) }}</p> <p class="mt-3 text-sm text-slate-600">{{ item.location_name || '未填写位置' }} · {{ formatDateTime(item.created_at) }}</p>
<p class="mt-2 line-clamp-2 text-sm leading-6 text-slate-500">{{ item.description || '没有图片说明。' }}</p> <p class="mt-2 line-clamp-2 text-sm leading-6 text-slate-500">{{ item.description || '没有图片说明。' }}</p>
<div class="mt-4 flex flex-wrap gap-2"> <div class="mt-4 flex flex-wrap gap-2">
<NButton size="small" type="success" secondary strong :loading="actionLoading" @click="updateCloudStatus([item.id], 'approved')"> <NButton size="small" type="default" secondary strong class="oc-panel-button oc-panel-button--teal" :loading="actionLoading" @click="updateCloudStatus([item.id], 'approved')">
<template #icon><NIcon><Check /></NIcon></template> <template #icon><NIcon><Check /></NIcon></template>
通过 通过
</NButton> </NButton>
<NButton size="small" type="error" secondary strong :loading="actionLoading" @click="updateCloudStatus([item.id], 'rejected')"> <NButton size="small" type="default" secondary strong class="oc-panel-button oc-panel-button--danger" :loading="actionLoading" @click="updateCloudStatus([item.id], 'rejected')">
<template #icon><NIcon><X /></NIcon></template> <template #icon><NIcon><X /></NIcon></template>
拒绝 拒绝
</NButton> </NButton>
<NButton size="small" secondary strong @click="selectedImage = item">查看大图</NButton> <NButton size="small" type="default" secondary strong class="oc-panel-button oc-panel-button--neutral" @click="selectedImage = item">查看大图</NButton>
</div> </div>
</div> </div>
</article> </article>
@@ -669,6 +671,8 @@ onMounted(loadAdminData)
size="small" size="small"
secondary secondary
strong strong
type="default"
class="oc-panel-button oc-panel-button--amber"
:disabled="user.id === authStore.user?.id && user.role === 'admin'" :disabled="user.id === authStore.user?.id && user.role === 'admin'"
:loading="actionLoading" :loading="actionLoading"
@click="updateUserRole(user, user.role === 'admin' ? 'user' : 'admin')" @click="updateUserRole(user, user.role === 'admin' ? 'user' : 'admin')"
@@ -677,9 +681,10 @@ onMounted(loadAdminData)
</NButton> </NButton>
<NButton <NButton
size="small" size="small"
:type="user.is_disabled ? 'success' : 'error'" type="default"
secondary secondary
strong strong
:class="user.is_disabled ? 'oc-panel-button oc-panel-button--teal' : 'oc-panel-button oc-panel-button--danger'"
:disabled="user.id === authStore.user?.id" :disabled="user.id === authStore.user?.id"
:loading="actionLoading" :loading="actionLoading"
@click="toggleUserDisabled(user)" @click="toggleUserDisabled(user)"
@@ -724,10 +729,10 @@ onMounted(loadAdminData)
</NTag> </NTag>
</div> </div>
<div class="mt-4 flex flex-wrap gap-2"> <div class="mt-4 flex flex-wrap gap-2">
<NButton size="small" secondary strong @click="selectedImage = item">查看</NButton> <NButton size="small" type="default" secondary strong class="oc-panel-button oc-panel-button--neutral" @click="selectedImage = item">查看</NButton>
<NButton size="small" type="success" secondary strong :disabled="item.status === 'approved'" :loading="actionLoading" @click="updateCloudStatus([item.id], 'approved')">通过</NButton> <NButton size="small" type="default" secondary strong class="oc-panel-button oc-panel-button--teal" :disabled="item.status === 'approved'" :loading="actionLoading" @click="updateCloudStatus([item.id], 'approved')">通过</NButton>
<NButton size="small" type="error" secondary strong :disabled="item.status === 'rejected'" :loading="actionLoading" @click="updateCloudStatus([item.id], 'rejected')">拒绝</NButton> <NButton size="small" type="default" secondary strong class="oc-panel-button oc-panel-button--danger" :disabled="item.status === 'rejected'" :loading="actionLoading" @click="updateCloudStatus([item.id], 'rejected')">拒绝</NButton>
<NButton size="small" secondary strong :loading="actionLoading" @click="toggleImageVisibility(item)"> <NButton size="small" type="default" secondary strong class="oc-panel-button oc-panel-button--amber" :loading="actionLoading" @click="toggleImageVisibility(item)">
<template #icon> <template #icon>
<NIcon> <NIcon>
<Eye v-if="item.is_hidden" /> <Eye v-if="item.is_hidden" />
@@ -736,7 +741,7 @@ onMounted(loadAdminData)
</template> </template>
{{ item.is_hidden ? '公开' : '隐藏' }} {{ item.is_hidden ? '公开' : '隐藏' }}
</NButton> </NButton>
<NButton size="small" type="error" secondary strong :loading="actionLoading" @click="deleteImage(item)"> <NButton size="small" type="default" secondary strong class="oc-panel-button oc-panel-button--danger" :loading="actionLoading" @click="deleteImage(item)">
<template #icon><NIcon><Trash /></NIcon></template> <template #icon><NIcon><Trash /></NIcon></template>
删除 删除
</NButton> </NButton>
+1 -1
View File
@@ -168,7 +168,7 @@ watch(() => route.params.id, () => {
<div class="max-w-6xl mx-auto px-4 py-8"> <div class="max-w-6xl mx-auto px-4 py-8">
<div class="mb-6"> <div class="mb-6">
<RouterLink to="/encyclopedia"> <RouterLink to="/encyclopedia">
<NButton text type="primary"> 返回图鉴总览</NButton> <NButton type="default" secondary strong class="oc-panel-button oc-panel-button--neutral"> 返回图鉴总览</NButton>
</RouterLink> </RouterLink>
</div> </div>
+2 -2
View File
@@ -96,7 +96,7 @@ onMounted(async () => {
</NAlert> </NAlert>
<div v-if="encyclopediaStore.loadingCloudTypes" class="grid gap-5 md:grid-cols-2 xl:grid-cols-3"> <div v-if="encyclopediaStore.loadingCloudTypes" class="grid gap-5 md:grid-cols-2 xl:grid-cols-3">
<NCard v-for="n in 6" :key="n"> <NCard v-for="n in 6" :key="n" class="oc-panel-card border border-slate-200 shadow-sm" :bordered="false">
<NSkeleton class="h-44 w-full" /> <NSkeleton class="h-44 w-full" />
<NSkeleton class="mt-5 h-5 w-2/5" /> <NSkeleton class="mt-5 h-5 w-2/5" />
<NSkeleton class="mt-3 h-4 w-1/3" /> <NSkeleton class="mt-3 h-4 w-1/3" />
@@ -176,7 +176,7 @@ onMounted(async () => {
</button> </button>
</div> </div>
<div v-else class="border border-dashed border-slate-300 bg-white px-6 py-12"> <div v-else class="oc-empty-card border border-dashed border-slate-300 bg-white px-6 py-12">
<NEmpty description="暂时还没有图鉴数据" /> <NEmpty description="暂时还没有图鉴数据" />
</div> </div>
</div> </div>
+8 -4
View File
@@ -489,7 +489,8 @@ onUnmounted(() => {
strong strong
@click="selectedTypeId = tab.id" @click="selectedTypeId = tab.id"
class="shrink-0" class="shrink-0"
:type="selectedTypeId === tab.id ? 'primary' : 'default'" :class="selectedTypeId === tab.id ? 'oc-panel-button oc-panel-button--sky' : 'oc-panel-button oc-panel-button--neutral'"
type="default"
> >
{{ tab.label }} {{ tab.label }}
</NButton> </NButton>
@@ -508,7 +509,7 @@ onUnmounted(() => {
<div <div
v-for="n in 8" v-for="n in 8"
:key="n" :key="n"
class="mb-3 break-inside-avoid border border-slate-200 bg-white p-3" class="oc-panel-card mb-3 break-inside-avoid border border-slate-200 bg-white p-3"
> >
<NSkeleton class="h-44 w-full" /> <NSkeleton class="h-44 w-full" />
<NSkeleton class="mt-4 h-4 w-3/5" /> <NSkeleton class="mt-4 h-4 w-3/5" />
@@ -563,7 +564,7 @@ onUnmounted(() => {
</button> </button>
</section> </section>
<section v-else class="mt-6 border border-dashed border-slate-300 bg-white px-6 py-12"> <section v-else class="oc-empty-card mt-6 border border-dashed border-slate-300 bg-white px-6 py-12">
<NEmpty description="还没有符合条件的云图"> <NEmpty description="还没有符合条件的云图">
<template #extra> <template #extra>
<p class="text-sm text-slate-500">换个云型筛选试试或者等社区上传更多作品</p> <p class="text-sm text-slate-500">换个云型筛选试试或者等社区上传更多作品</p>
@@ -576,6 +577,7 @@ onUnmounted(() => {
secondary secondary
strong strong
:disabled="currentPage <= 1" :disabled="currentPage <= 1"
class="oc-panel-button oc-panel-button--neutral"
@click="goToPage(currentPage - 1)" @click="goToPage(currentPage - 1)"
> >
上一页 上一页
@@ -586,7 +588,8 @@ onUnmounted(() => {
v-if="page === 1 || page === totalPages || Math.abs(page - currentPage) <= 2" v-if="page === 1 || page === totalPages || Math.abs(page - currentPage) <= 2"
secondary secondary
strong strong
:type="page === currentPage ? 'primary' : 'default'" :class="page === currentPage ? 'oc-panel-button oc-panel-button--sky' : 'oc-panel-button oc-panel-button--neutral'"
type="default"
@click="goToPage(page)" @click="goToPage(page)"
> >
{{ page }} {{ page }}
@@ -601,6 +604,7 @@ onUnmounted(() => {
secondary secondary
strong strong
:disabled="currentPage >= totalPages" :disabled="currentPage >= totalPages"
class="oc-panel-button oc-panel-button--neutral"
@click="goToPage(currentPage + 1)" @click="goToPage(currentPage + 1)"
> >
下一页 下一页
+6 -4
View File
@@ -82,7 +82,7 @@ async function savePassword() {
<div class="min-h-[calc(100vh-4rem)] bg-[linear-gradient(180deg,#e0f2fe_0%,#f8fafc_100%)] px-4 py-10"> <div class="min-h-[calc(100vh-4rem)] bg-[linear-gradient(180deg,#e0f2fe_0%,#f8fafc_100%)] px-4 py-10">
<div class="mx-auto max-w-4xl"> <div class="mx-auto max-w-4xl">
<RouterLink to="/profile"> <RouterLink to="/profile">
<NButton text type="primary"> 返回个人主页</NButton> <NButton type="default" secondary strong class="oc-panel-button oc-panel-button--neutral"> 返回个人主页</NButton>
</RouterLink> </RouterLink>
<div class="mt-6"> <div class="mt-6">
@@ -111,7 +111,7 @@ async function savePassword() {
{{ success }} {{ success }}
</NAlert> </NAlert>
<NCard class="border border-slate-200 bg-white shadow-sm" :bordered="false"> <NCard class="oc-panel-card border border-slate-200 bg-white shadow-sm" :bordered="false">
<div class="grid gap-5 lg:grid-cols-[0.8fr_1.2fr] lg:items-start"> <div class="grid gap-5 lg:grid-cols-[0.8fr_1.2fr] lg:items-start">
<div> <div>
<h2 class="text-2xl font-bold text-slate-900">公开昵称</h2> <h2 class="text-2xl font-bold text-slate-900">公开昵称</h2>
@@ -127,9 +127,10 @@ async function savePassword() {
show-count show-count
/> />
<NButton <NButton
type="primary"
secondary secondary
strong strong
type="default"
class="oc-panel-button oc-panel-button--teal"
:loading="usernameSaving" :loading="usernameSaving"
@click="saveUsername" @click="saveUsername"
> >
@@ -139,7 +140,7 @@ async function savePassword() {
</div> </div>
</NCard> </NCard>
<NCard class="border border-slate-200 bg-white shadow-sm" :bordered="false"> <NCard class="oc-panel-card border border-slate-200 bg-white shadow-sm" :bordered="false">
<div class="grid gap-5 lg:grid-cols-[0.8fr_1.2fr] lg:items-start"> <div class="grid gap-5 lg:grid-cols-[0.8fr_1.2fr] lg:items-start">
<div> <div>
<h2 class="text-2xl font-bold text-slate-900">登录密码</h2> <h2 class="text-2xl font-bold text-slate-900">登录密码</h2>
@@ -166,6 +167,7 @@ async function savePassword() {
<NButton <NButton
secondary secondary
strong strong
class="oc-panel-button oc-panel-button--neutral"
:loading="passwordSaving" :loading="passwordSaving"
@click="savePassword" @click="savePassword"
> >
+17 -14
View File
@@ -476,12 +476,12 @@ watch(selectedUploadDate, async newValue => {
<div class="border-b border-sky-100 bg-[linear-gradient(180deg,#e0f2fe_0%,#f8fafc_100%)]"> <div class="border-b border-sky-100 bg-[linear-gradient(180deg,#e0f2fe_0%,#f8fafc_100%)]">
<div class="max-w-6xl mx-auto px-4 py-10"> <div class="max-w-6xl mx-auto px-4 py-10">
<div v-if="loading" class="grid gap-6 lg:grid-cols-[1.25fr_0.95fr]"> <div v-if="loading" class="grid gap-6 lg:grid-cols-[1.25fr_0.95fr]">
<NCard> <NCard class="oc-panel-card border border-slate-200 shadow-sm" :bordered="false">
<NSkeleton class="h-6 w-1/3" /> <NSkeleton class="h-6 w-1/3" />
<NSkeleton class="mt-4 h-10 w-2/3" /> <NSkeleton class="mt-4 h-10 w-2/3" />
<NSkeleton class="mt-5 h-4 w-full" :repeat="2" /> <NSkeleton class="mt-5 h-4 w-full" :repeat="2" />
</NCard> </NCard>
<NCard> <NCard class="oc-panel-card-soft border border-white/80 bg-white/85 shadow-sm backdrop-blur" :bordered="false">
<NSkeleton class="h-5 w-1/3" /> <NSkeleton class="h-5 w-1/3" />
<NSkeleton class="mt-4 h-8 w-1/2" /> <NSkeleton class="mt-4 h-8 w-1/2" />
<NSkeleton class="mt-5 h-3 w-full" /> <NSkeleton class="mt-5 h-3 w-full" />
@@ -545,7 +545,7 @@ watch(selectedUploadDate, async newValue => {
:is-logged-in="true" :is-logged-in="true"
/> />
<NCard v-else class="border border-white/80 bg-white/85 shadow-sm backdrop-blur" :bordered="false"> <NCard v-else class="oc-panel-card-soft border border-white/80 bg-white/85 shadow-sm backdrop-blur" :bordered="false">
<p class="text-sm text-slate-500">公开贡献</p> <p class="text-sm text-slate-500">公开贡献</p>
<p class="mt-3 text-3xl font-bold text-slate-900">{{ approvedShots }}</p> <p class="mt-3 text-3xl font-bold text-slate-900">{{ approvedShots }}</p>
<p class="mt-2 text-sm text-slate-500">当前公开可见的云图数量</p> <p class="mt-2 text-sm text-slate-500">当前公开可见的云图数量</p>
@@ -585,12 +585,12 @@ watch(selectedUploadDate, async newValue => {
</div> </div>
<div v-else class="grid gap-4 md:grid-cols-2 xl:grid-cols-4"> <div v-else class="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
<NCard class="border border-slate-200 shadow-sm"> <NCard class="oc-panel-card border border-slate-200 shadow-sm" :bordered="false">
<p class="text-sm text-slate-500">总拍摄数</p> <p class="text-sm text-slate-500">总拍摄数</p>
<p class="mt-2 text-3xl font-bold text-slate-900">{{ totalShots }}</p> <p class="mt-2 text-3xl font-bold text-slate-900">{{ totalShots }}</p>
</NCard> </NCard>
<NCard class="border border-slate-200 shadow-sm"> <NCard class="oc-panel-card border border-slate-200 shadow-sm" :bordered="false">
<p class="text-sm text-slate-500">最常拍云型</p> <p class="text-sm text-slate-500">最常拍云型</p>
<p class="mt-2 text-2xl font-bold text-slate-900">{{ mostCommonCloudType.name }}</p> <p class="mt-2 text-2xl font-bold text-slate-900">{{ mostCommonCloudType.name }}</p>
<p class="mt-2 text-sm text-slate-500" v-if="mostCommonCloudType.count"> <p class="mt-2 text-sm text-slate-500" v-if="mostCommonCloudType.count">
@@ -598,12 +598,12 @@ watch(selectedUploadDate, async newValue => {
</p> </p>
</NCard> </NCard>
<NCard class="border border-slate-200 shadow-sm"> <NCard class="oc-panel-card border border-slate-200 shadow-sm" :bordered="false">
<p class="text-sm text-slate-500">拍摄天数</p> <p class="text-sm text-slate-500">拍摄天数</p>
<p class="mt-2 text-3xl font-bold text-slate-900">{{ shootingDays }}</p> <p class="mt-2 text-3xl font-bold text-slate-900">{{ shootingDays }}</p>
</NCard> </NCard>
<NCard class="border border-slate-200 shadow-sm"> <NCard class="oc-panel-card border border-slate-200 shadow-sm" :bordered="false">
<p class="text-sm text-slate-500">{{ isOwnProfile ? '已通过 / 待审核' : '公开通过数' }}</p> <p class="text-sm text-slate-500">{{ isOwnProfile ? '已通过 / 待审核' : '公开通过数' }}</p>
<p class="mt-2 text-2xl font-bold text-slate-900"> <p class="mt-2 text-2xl font-bold text-slate-900">
<template v-if="isOwnProfile">{{ approvedShots }} / {{ pendingShots }}</template> <template v-if="isOwnProfile">{{ approvedShots }} / {{ pendingShots }}</template>
@@ -639,7 +639,8 @@ watch(selectedUploadDate, async newValue => {
v-if="isOwnProfile && selectedCloudCount" v-if="isOwnProfile && selectedCloudCount"
secondary secondary
strong strong
type="error" type="default"
class="oc-panel-button oc-panel-button--danger"
@click="deleteCloudByIds(Array.from(selectedCloudIds))" @click="deleteCloudByIds(Array.from(selectedCloudIds))"
> >
删除已选 {{ selectedCloudCount }} 删除已选 {{ selectedCloudCount }}
@@ -648,23 +649,25 @@ watch(selectedUploadDate, async newValue => {
v-if="isOwnProfile" v-if="isOwnProfile"
secondary secondary
strong strong
class="oc-panel-button oc-panel-button--neutral"
@click="toggleSelectionMode" @click="toggleSelectionMode"
> >
{{ selectionMode ? '取消选择' : '选择图片' }} {{ selectionMode ? '取消选择' : '选择图片' }}
</NButton> </NButton>
<NButton secondary strong @click="loadProfilePage(true)"> <NButton secondary strong class="oc-panel-button oc-panel-button--neutral" @click="loadProfilePage(true)">
刷新数据 刷新数据
</NButton> </NButton>
<NButton <NButton
v-if="selectedUploadDate" v-if="selectedUploadDate"
secondary secondary
strong strong
class="oc-panel-button oc-panel-button--neutral"
@click="clearSelectedUploadDate" @click="clearSelectedUploadDate"
> >
清除筛选 清除筛选
</NButton> </NButton>
<RouterLink v-if="isOwnProfile" to="/upload"> <RouterLink v-if="isOwnProfile" to="/upload">
<NButton secondary strong type="primary">继续上传</NButton> <NButton secondary strong type="default" class="oc-panel-button oc-panel-button--sky">继续上传</NButton>
</RouterLink> </RouterLink>
</div> </div>
</div> </div>
@@ -681,7 +684,7 @@ watch(selectedUploadDate, async newValue => {
<div v-for="n in 2" :key="n"> <div v-for="n in 2" :key="n">
<NSkeleton class="h-6 w-40" /> <NSkeleton class="h-6 w-40" />
<div class="mt-4 grid gap-5 md:grid-cols-2 xl:grid-cols-3"> <div class="mt-4 grid gap-5 md:grid-cols-2 xl:grid-cols-3">
<NCard v-for="m in 3" :key="m"> <NCard v-for="m in 3" :key="m" class="oc-panel-card border border-slate-200 shadow-sm" :bordered="false">
<NSkeleton class="h-52 w-full" /> <NSkeleton class="h-52 w-full" />
<NSkeleton class="mt-4 h-5 w-2/3" /> <NSkeleton class="mt-4 h-5 w-2/3" />
<NSkeleton class="mt-3 h-4 w-1/2" /> <NSkeleton class="mt-3 h-4 w-1/2" />
@@ -764,13 +767,13 @@ watch(selectedUploadDate, async newValue => {
</section> </section>
</div> </div>
<div v-else class="border border-dashed border-slate-300 bg-white p-10"> <div v-else class="oc-empty-card border border-dashed border-slate-300 bg-white p-10">
<NEmpty :description="selectedUploadDate ? '这一天没有上传记录' : (isOwnProfile ? '还没有上传任何云图' : '这位用户还没有公开云图')"> <NEmpty :description="selectedUploadDate ? '这一天没有上传记录' : (isOwnProfile ? '还没有上传任何云图' : '这位用户还没有公开云图')">
<template #extra> <template #extra>
<RouterLink v-if="isOwnProfile && !selectedUploadDate" to="/upload"> <RouterLink v-if="isOwnProfile && !selectedUploadDate" to="/upload">
<NButton secondary strong type="primary">去上传第一张</NButton> <NButton secondary strong type="default" class="oc-panel-button oc-panel-button--sky">去上传第一张</NButton>
</RouterLink> </RouterLink>
<NButton v-else-if="selectedUploadDate" secondary strong @click="clearSelectedUploadDate">返回全部记录</NButton> <NButton v-else-if="selectedUploadDate" secondary strong class="oc-panel-button oc-panel-button--neutral" @click="clearSelectedUploadDate">返回全部记录</NButton>
</template> </template>
</NEmpty> </NEmpty>
</div> </div>
+2 -2
View File
@@ -15,10 +15,10 @@ import { RouterLink } from 'vue-router'
<div class="mt-8 flex flex-wrap items-center justify-center gap-3"> <div class="mt-8 flex flex-wrap items-center justify-center gap-3">
<RouterLink to="/"> <RouterLink to="/">
<NButton type="primary" secondary strong>返回地图</NButton> <NButton type="default" secondary strong class="oc-panel-button oc-panel-button--sky">返回地图</NButton>
</RouterLink> </RouterLink>
<RouterLink to="/profile"> <RouterLink to="/profile">
<NButton secondary strong>前往个人主页</NButton> <NButton type="default" secondary strong class="oc-panel-button oc-panel-button--neutral">前往个人主页</NButton>
</RouterLink> </RouterLink>
</div> </div>
</div> </div>
+2 -2
View File
@@ -15,10 +15,10 @@ import { RouterLink } from 'vue-router'
<div class="mt-8 flex flex-wrap items-center justify-center gap-3"> <div class="mt-8 flex flex-wrap items-center justify-center gap-3">
<RouterLink to="/"> <RouterLink to="/">
<NButton type="primary" secondary strong>返回地图</NButton> <NButton type="default" secondary strong class="oc-panel-button oc-panel-button--sky">返回地图</NButton>
</RouterLink> </RouterLink>
<RouterLink to="/gallery"> <RouterLink to="/gallery">
<NButton secondary strong>去画廊看看</NButton> <NButton type="default" secondary strong class="oc-panel-button oc-panel-button--neutral">去画廊看看</NButton>
</RouterLink> </RouterLink>
</div> </div>
</div> </div>
+7 -7
View File
@@ -252,16 +252,16 @@ onUnmounted(() => {
</div> </div>
<div class="mt-6 flex gap-3"> <div class="mt-6 flex gap-3">
<NButton secondary strong type="primary" class="flex-1" @click="saveBadge(badge)">保存分享卡片</NButton> <NButton secondary strong type="default" class="oc-panel-button oc-panel-button--sky flex-1" @click="saveBadge(badge)">保存分享卡片</NButton>
<NButton secondary strong class="flex-1" @click="router.push(`/encyclopedia/${badge.cloudTypeId}`)">查看详情</NButton> <NButton secondary strong type="default" class="oc-panel-button oc-panel-button--neutral flex-1" @click="router.push(`/encyclopedia/${badge.cloudTypeId}`)">查看详情</NButton>
</div> </div>
</NCard> </NCard>
</div> </div>
<div class="mt-8 flex flex-wrap items-center justify-center gap-3"> <div class="mt-8 flex flex-wrap items-center justify-center gap-3">
<NButton secondary strong @click="resetAfterSuccess">继续上传</NButton> <NButton secondary strong type="default" class="oc-panel-button oc-panel-button--neutral" @click="resetAfterSuccess">继续上传</NButton>
<NButton secondary strong type="primary" @click="router.push('/encyclopedia')">前往图鉴</NButton> <NButton secondary strong type="default" class="oc-panel-button oc-panel-button--sky" @click="router.push('/encyclopedia')">前往图鉴</NButton>
<NButton secondary strong @click="router.push('/profile')">返回个人主页</NButton> <NButton secondary strong type="default" class="oc-panel-button oc-panel-button--neutral" @click="router.push('/profile')">返回个人主页</NButton>
</div> </div>
</div> </div>
</div> </div>
@@ -474,8 +474,8 @@ onUnmounted(() => {
<div class="mt-6 flex items-center justify-between"> <div class="mt-6 flex items-center justify-between">
<p class="text-sm text-gray-500"> {{ items.length }} 张图片</p> <p class="text-sm text-gray-500"> {{ items.length }} 张图片</p>
<div class="flex gap-3"> <div class="flex gap-3">
<NButton secondary strong @click="clearAll()" :disabled="uploading">清空</NButton> <NButton secondary strong type="default" class="oc-panel-button oc-panel-button--neutral" @click="clearAll()" :disabled="uploading">清空</NButton>
<NButton type="primary" secondary strong @click="handleSubmit" :disabled="uploading"> <NButton type="default" secondary strong class="oc-panel-button oc-panel-button--sky" @click="handleSubmit" :disabled="uploading">
{{ uploading ? '上传中...' : '提交上传' }} {{ uploading ? '上传中...' : '提交上传' }}
</NButton> </NButton>
</div> </div>