@@ -251,8 +251,8 @@ watch(() => props.initialValue, value => {
|
||||
</div>
|
||||
|
||||
<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 type="primary" secondary strong :loading="saving" @click="save">
|
||||
<NButton secondary strong type="default" class="oc-panel-button oc-panel-button--neutral" @click="close">取消</NButton>
|
||||
<NButton type="default" secondary strong class="oc-panel-button oc-panel-button--sky" :loading="saving" @click="save">
|
||||
保存修改
|
||||
</NButton>
|
||||
</div>
|
||||
|
||||
@@ -29,7 +29,7 @@ const currentColor = computed(() => progressColor(props.isLoggedIn ? props.perce
|
||||
</script>
|
||||
|
||||
<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>
|
||||
<p class="text-sm text-slate-500">当前进度</p>
|
||||
|
||||
@@ -194,11 +194,12 @@ onBeforeUnmount(() => {
|
||||
<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>
|
||||
<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
|
||||
type="primary"
|
||||
type="default"
|
||||
secondary
|
||||
strong
|
||||
class="oc-panel-button oc-panel-button--sky"
|
||||
:disabled="pickedLat === null || pickedLng === null"
|
||||
@click="confirm"
|
||||
>
|
||||
|
||||
@@ -375,8 +375,8 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
|
||||
<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 type="primary" secondary strong :disabled="uploading || items.length === 0" @click="handleSubmit">
|
||||
<NButton secondary strong type="default" class="oc-panel-button oc-panel-button--neutral" :disabled="uploading" @click="close">关闭</NButton>
|
||||
<NButton type="default" secondary strong class="oc-panel-button oc-panel-button--sky" :disabled="uploading || items.length === 0" @click="handleSubmit">
|
||||
{{ uploading ? '上传中...' : '提交审核' }}
|
||||
</NButton>
|
||||
</div>
|
||||
|
||||
@@ -138,8 +138,31 @@ async function handleLogout() {
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex h-16 items-center justify-between">
|
||||
<RouterLink to="/" class="flex items-center gap-3">
|
||||
<div class="flex h-10 w-10 items-center justify-center border border-slate-300 bg-[linear-gradient(135deg,#ecfeff_0%,#ccfbf1_100%)] text-xl shadow-[4px_4px_0_0_rgba(15,23,42,0.08)]">
|
||||
☁️
|
||||
<div class="flex h-10 w-10 items-center justify-center border border-slate-300 bg-[linear-gradient(135deg,#ecfeff_0%,#ccfbf1_100%)] shadow-[4px_4px_0_0_rgba(15,23,42,0.08)]">
|
||||
<svg
|
||||
class="h-8 w-8"
|
||||
viewBox="0 0 16 16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
shape-rendering="crispEdges"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<rect x="11" y="3" width="1" height="1" fill="#f59e0b" />
|
||||
<rect x="10" y="4" width="3" height="1" fill="#fbbf24" />
|
||||
<rect x="11" y="5" width="1" height="1" fill="#f59e0b" />
|
||||
|
||||
<rect x="5" y="7" width="7" height="1" fill="#38bdf8" />
|
||||
<rect x="4" y="8" width="8" height="1" fill="#38bdf8" />
|
||||
<rect x="4" y="9" width="7" height="1" fill="#38bdf8" />
|
||||
<rect x="5" y="10" width="4" height="1" fill="#38bdf8" />
|
||||
|
||||
<rect x="5" y="5" width="4" height="1" fill="#ffffff" />
|
||||
<rect x="4" y="6" width="7" height="1" fill="#ffffff" />
|
||||
<rect x="3" y="7" width="8" height="1" fill="#ffffff" />
|
||||
<rect x="3" y="8" width="7" height="1" fill="#ffffff" />
|
||||
<rect x="4" y="9" width="5" height="1" fill="#ffffff" />
|
||||
|
||||
<rect x="4" y="11" width="8" height="1" fill="#7dd3fc" opacity="0.55" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-[11px] uppercase tracking-[0.22em] text-slate-500">Live Sky Atlas</div>
|
||||
@@ -186,7 +209,7 @@ async function handleLogout() {
|
||||
class="no-underline"
|
||||
>
|
||||
<span
|
||||
class="inline-flex h-8 items-center border border-sky-200 bg-sky-100 px-3 text-sm font-medium uppercase tracking-[0.12em] text-sky-800 shadow-[4px_4px_0_0_rgba(14,165,233,0.14)] transition-colors hover:bg-sky-50 hover:text-sky-900 md:h-10 md:px-4"
|
||||
class="inline-flex h-8 items-center border border-sky-200 bg-sky-100 px-3 text-sm font-medium uppercase tracking-[0.12em] text-sky-800 shadow-[4px_4px_0_0_rgba(14,165,233,0.14)] transition-[background-color,color,transform,box-shadow] hover:-translate-x-px hover:-translate-y-px hover:bg-sky-50 hover:text-sky-900 hover:shadow-[5px_5px_0_0_rgba(14,165,233,0.18)] md:h-10 md:px-4"
|
||||
:class="route.name === 'upload' ? 'ring-1 ring-sky-300' : ''"
|
||||
>
|
||||
上传
|
||||
@@ -203,8 +226,8 @@ async function handleLogout() {
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex h-8 max-w-[8.5rem] items-center gap-2 border border-teal-100 bg-white/80 px-3 text-sm font-medium text-teal-800 shadow-[3px_3px_0_0_rgba(20,184,166,0.08)] transition-colors hover:border-teal-200 hover:bg-teal-50 md:h-10 md:max-w-none"
|
||||
:class="route.name === 'profile' || route.name === 'profile-settings' ? 'bg-teal-50 ring-1 ring-teal-200' : ''"
|
||||
class="inline-flex h-8 max-w-[8.5rem] items-center gap-2 border border-teal-100 bg-white/80 px-3 text-sm font-medium text-teal-700 shadow-[3px_3px_0_0_rgba(20,184,166,0.08)] transition-[background-color,color,transform,box-shadow,border-color] hover:-translate-x-px hover:-translate-y-px hover:border-teal-200 hover:bg-teal-50/70 hover:text-teal-800 hover:shadow-[4px_4px_0_0_rgba(20,184,166,0.12)] md:h-10 md:max-w-none"
|
||||
:class="route.name === 'profile' || route.name === 'profile-settings' ? 'border-teal-200 bg-teal-50/80 text-teal-800 ring-1 ring-teal-200 shadow-[4px_4px_0_0_rgba(20,184,166,0.12)]' : ''"
|
||||
aria-haspopup="menu"
|
||||
:aria-expanded="accountCardOpen"
|
||||
>
|
||||
@@ -288,7 +311,7 @@ async function handleLogout() {
|
||||
class="no-underline"
|
||||
>
|
||||
<span
|
||||
class="inline-flex h-8 items-center border border-slate-200 bg-white/80 px-3 text-sm font-medium text-slate-700 shadow-[3px_3px_0_0_rgba(15,23,42,0.06)] transition-colors hover:border-teal-200 hover:bg-teal-50 hover:text-teal-800 md:h-10 md:px-4"
|
||||
class="inline-flex h-8 items-center border border-slate-200 bg-white/80 px-3 text-sm font-medium text-slate-700 shadow-[3px_3px_0_0_rgba(15,23,42,0.06)] transition-[background-color,color,transform,box-shadow,border-color] hover:-translate-x-px hover:-translate-y-px hover:border-teal-200 hover:bg-teal-50 hover:text-teal-800 hover:shadow-[4px_4px_0_0_rgba(15,23,42,0.08)] md:h-10 md:px-4"
|
||||
:class="route.name === 'login' ? 'bg-teal-50 ring-1 ring-teal-200 text-teal-800' : ''"
|
||||
>
|
||||
登录
|
||||
@@ -299,7 +322,7 @@ async function handleLogout() {
|
||||
class="no-underline"
|
||||
>
|
||||
<span
|
||||
class="inline-flex h-8 items-center border border-sky-200 bg-sky-100 px-3 text-sm font-medium text-sky-800 shadow-[4px_4px_0_0_rgba(14,165,233,0.14)] transition-colors hover:bg-sky-50 hover:text-sky-900 md:h-10 md:px-4"
|
||||
class="inline-flex h-8 items-center border border-sky-200 bg-sky-100 px-3 text-sm font-medium text-sky-800 shadow-[4px_4px_0_0_rgba(14,165,233,0.14)] transition-[background-color,color,transform,box-shadow] hover:-translate-x-px hover:-translate-y-px hover:bg-sky-50 hover:text-sky-900 hover:shadow-[5px_5px_0_0_rgba(14,165,233,0.18)] md:h-10 md:px-4"
|
||||
:class="route.name === 'register' ? 'ring-1 ring-sky-300' : ''"
|
||||
>
|
||||
注册
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { NButton, NButtonGroup, NSelect } from 'naive-ui'
|
||||
import { NButton, NSelect } from 'naive-ui'
|
||||
|
||||
export interface ContributionHeatmapCell {
|
||||
date: string
|
||||
@@ -284,7 +284,7 @@ function formatMonthTooltip(monthKey: string) {
|
||||
</script>
|
||||
|
||||
<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="min-w-0 flex-1">
|
||||
<h3 class="text-2xl font-bold text-slate-900">{{ title }}</h3>
|
||||
@@ -295,14 +295,26 @@ function formatMonthTooltip(monthKey: string) {
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap items-center justify-end gap-3">
|
||||
<NButtonGroup>
|
||||
<NButton :type="viewMode === 'year' ? 'primary' : 'default'" secondary strong @click="viewMode = 'year'">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<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 :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>
|
||||
</NButtonGroup>
|
||||
</div>
|
||||
<NSelect
|
||||
v-model:value="selectedYear"
|
||||
:options="yearOptions"
|
||||
|
||||
+201
@@ -18,6 +18,207 @@ body {
|
||||
background: rgba(15, 118, 110, 0.18);
|
||||
}
|
||||
|
||||
.oc-primary-button.n-button {
|
||||
transition:
|
||||
background-color 160ms ease,
|
||||
color 160ms ease,
|
||||
border-color 160ms ease,
|
||||
box-shadow 160ms ease,
|
||||
transform 160ms ease;
|
||||
}
|
||||
|
||||
.oc-primary-button.n-button .n-button__content {
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.12em;
|
||||
}
|
||||
|
||||
.oc-primary-button.n-button:not(.n-button--disabled):hover {
|
||||
transform: translate(-1px, -1px);
|
||||
}
|
||||
|
||||
.oc-primary-button--teal.n-button {
|
||||
border-color: rgb(153 246 228) !important;
|
||||
background: rgb(242 250 247) !important;
|
||||
color: rgb(17 94 89) !important;
|
||||
box-shadow: 4px 4px 0 0 rgba(20, 184, 166, 0.1) !important;
|
||||
}
|
||||
|
||||
.oc-primary-button--teal.n-button:hover,
|
||||
.oc-primary-button--teal.n-button:focus-visible {
|
||||
border-color: rgb(94 234 212) !important;
|
||||
background: rgb(234 250 245) !important;
|
||||
color: rgb(19 78 74) !important;
|
||||
}
|
||||
|
||||
.oc-primary-button--teal.n-button:not(.n-button--disabled):hover {
|
||||
box-shadow: 5px 5px 0 0 rgba(20, 184, 166, 0.14) !important;
|
||||
}
|
||||
|
||||
.oc-primary-button--sky.n-button {
|
||||
border-color: rgb(186 230 253) !important;
|
||||
background: rgb(224 242 254) !important;
|
||||
color: rgb(7 89 133) !important;
|
||||
box-shadow: 4px 4px 0 0 rgba(14, 165, 233, 0.14) !important;
|
||||
}
|
||||
|
||||
.oc-primary-button--sky.n-button:hover,
|
||||
.oc-primary-button--sky.n-button:focus-visible {
|
||||
border-color: rgb(125 211 252) !important;
|
||||
background: rgb(240 249 255) !important;
|
||||
color: rgb(12 74 110) !important;
|
||||
}
|
||||
|
||||
.oc-primary-button--sky.n-button:not(.n-button--disabled):hover {
|
||||
box-shadow: 5px 5px 0 0 rgba(14, 165, 233, 0.18) !important;
|
||||
}
|
||||
|
||||
.oc-panel-card {
|
||||
box-shadow: 6px 6px 0 0 rgba(15, 23, 42, 0.05) !important;
|
||||
}
|
||||
|
||||
.oc-panel-card-soft {
|
||||
box-shadow: 6px 6px 0 0 rgba(15, 23, 42, 0.04) !important;
|
||||
}
|
||||
|
||||
.oc-empty-card {
|
||||
box-shadow: 6px 6px 0 0 rgba(15, 23, 42, 0.04);
|
||||
}
|
||||
|
||||
.oc-panel-button.n-button {
|
||||
--n-color: rgb(255 255 255) !important;
|
||||
--n-color-hover: rgb(240 253 250) !important;
|
||||
--n-color-pressed: rgb(236 253 245) !important;
|
||||
--n-border: 1px solid rgb(226 232 240) !important;
|
||||
--n-border-hover: 1px solid rgb(153 246 228) !important;
|
||||
--n-border-pressed: 1px solid rgb(94 234 212) !important;
|
||||
--n-text-color: rgb(71 85 105) !important;
|
||||
--n-text-color-hover: rgb(19 78 74) !important;
|
||||
--n-text-color-pressed: rgb(17 94 89) !important;
|
||||
border-color: rgb(226 232 240) !important;
|
||||
background: rgb(255 255 255) !important;
|
||||
color: rgb(71 85 105) !important;
|
||||
box-shadow: 3px 3px 0 0 rgba(15, 23, 42, 0.06) !important;
|
||||
transition:
|
||||
background-color 160ms ease,
|
||||
color 160ms ease,
|
||||
border-color 160ms ease,
|
||||
box-shadow 160ms ease,
|
||||
transform 160ms ease;
|
||||
}
|
||||
|
||||
.oc-panel-button.n-button .n-button__content {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.oc-panel-button.n-button:not(.n-button--disabled):hover,
|
||||
.oc-panel-button.n-button:focus-visible {
|
||||
transform: translate(-1px, -1px);
|
||||
}
|
||||
|
||||
.oc-panel-button--neutral.n-button:hover,
|
||||
.oc-panel-button--neutral.n-button:focus-visible {
|
||||
border-color: rgb(153 246 228) !important;
|
||||
background: rgb(240 253 250) !important;
|
||||
color: rgb(19 78 74) !important;
|
||||
box-shadow: 4px 4px 0 0 rgba(20, 184, 166, 0.1) !important;
|
||||
}
|
||||
|
||||
.oc-panel-button--sky.n-button {
|
||||
--n-color: rgb(224 242 254) !important;
|
||||
--n-color-hover: rgb(240 249 255) !important;
|
||||
--n-color-pressed: rgb(224 242 254) !important;
|
||||
--n-border: 1px solid rgb(186 230 253) !important;
|
||||
--n-border-hover: 1px solid rgb(125 211 252) !important;
|
||||
--n-border-pressed: 1px solid rgb(56 189 248) !important;
|
||||
--n-text-color: rgb(7 89 133) !important;
|
||||
--n-text-color-hover: rgb(12 74 110) !important;
|
||||
--n-text-color-pressed: rgb(12 74 110) !important;
|
||||
border-color: rgb(186 230 253) !important;
|
||||
background: rgb(224 242 254) !important;
|
||||
color: rgb(7 89 133) !important;
|
||||
box-shadow: 4px 4px 0 0 rgba(14, 165, 233, 0.14) !important;
|
||||
}
|
||||
|
||||
.oc-panel-button--sky.n-button:hover,
|
||||
.oc-panel-button--sky.n-button:focus-visible {
|
||||
border-color: rgb(125 211 252) !important;
|
||||
background: rgb(240 249 255) !important;
|
||||
color: rgb(12 74 110) !important;
|
||||
box-shadow: 5px 5px 0 0 rgba(14, 165, 233, 0.18) !important;
|
||||
}
|
||||
|
||||
.oc-panel-button--teal.n-button {
|
||||
--n-color: rgb(242 250 247) !important;
|
||||
--n-color-hover: rgb(234 250 245) !important;
|
||||
--n-color-pressed: rgb(220 252 231) !important;
|
||||
--n-border: 1px solid rgb(153 246 228) !important;
|
||||
--n-border-hover: 1px solid rgb(94 234 212) !important;
|
||||
--n-border-pressed: 1px solid rgb(45 212 191) !important;
|
||||
--n-text-color: rgb(17 94 89) !important;
|
||||
--n-text-color-hover: rgb(19 78 74) !important;
|
||||
--n-text-color-pressed: rgb(19 78 74) !important;
|
||||
border-color: rgb(153 246 228) !important;
|
||||
background: rgb(242 250 247) !important;
|
||||
color: rgb(17 94 89) !important;
|
||||
box-shadow: 4px 4px 0 0 rgba(20, 184, 166, 0.1) !important;
|
||||
}
|
||||
|
||||
.oc-panel-button--teal.n-button:hover,
|
||||
.oc-panel-button--teal.n-button:focus-visible {
|
||||
border-color: rgb(94 234 212) !important;
|
||||
background: rgb(234 250 245) !important;
|
||||
color: rgb(19 78 74) !important;
|
||||
box-shadow: 5px 5px 0 0 rgba(20, 184, 166, 0.14) !important;
|
||||
}
|
||||
|
||||
.oc-panel-button--danger.n-button {
|
||||
--n-color: rgb(255 241 242) !important;
|
||||
--n-color-hover: rgb(255 228 230) !important;
|
||||
--n-color-pressed: rgb(255 228 230) !important;
|
||||
--n-border: 1px solid rgb(254 205 211) !important;
|
||||
--n-border-hover: 1px solid rgb(253 164 175) !important;
|
||||
--n-border-pressed: 1px solid rgb(251 113 133) !important;
|
||||
--n-text-color: rgb(190 24 93) !important;
|
||||
--n-text-color-hover: rgb(159 18 57) !important;
|
||||
--n-text-color-pressed: rgb(159 18 57) !important;
|
||||
border-color: rgb(254 205 211) !important;
|
||||
background: rgb(255 241 242) !important;
|
||||
color: rgb(190 24 93) !important;
|
||||
box-shadow: 4px 4px 0 0 rgba(244, 63, 94, 0.1) !important;
|
||||
}
|
||||
|
||||
.oc-panel-button--danger.n-button:hover,
|
||||
.oc-panel-button--danger.n-button:focus-visible {
|
||||
border-color: rgb(253 164 175) !important;
|
||||
background: rgb(255 228 230) !important;
|
||||
color: rgb(159 18 57) !important;
|
||||
box-shadow: 5px 5px 0 0 rgba(244, 63, 94, 0.14) !important;
|
||||
}
|
||||
|
||||
.oc-panel-button--amber.n-button {
|
||||
--n-color: rgb(255 251 235) !important;
|
||||
--n-color-hover: rgb(254 243 199) !important;
|
||||
--n-color-pressed: rgb(253 230 138) !important;
|
||||
--n-border: 1px solid rgb(253 230 138) !important;
|
||||
--n-border-hover: 1px solid rgb(252 211 77) !important;
|
||||
--n-border-pressed: 1px solid rgb(245 158 11) !important;
|
||||
--n-text-color: rgb(146 64 14) !important;
|
||||
--n-text-color-hover: rgb(120 53 15) !important;
|
||||
--n-text-color-pressed: rgb(120 53 15) !important;
|
||||
border-color: rgb(253 230 138) !important;
|
||||
background: rgb(255 251 235) !important;
|
||||
color: rgb(146 64 14) !important;
|
||||
box-shadow: 4px 4px 0 0 rgba(245, 158, 11, 0.1) !important;
|
||||
}
|
||||
|
||||
.oc-panel-button--amber.n-button:hover,
|
||||
.oc-panel-button--amber.n-button:focus-visible {
|
||||
border-color: rgb(252 211 77) !important;
|
||||
background: rgb(254 243 199) !important;
|
||||
color: rgb(120 53 15) !important;
|
||||
box-shadow: 5px 5px 0 0 rgba(245, 158, 11, 0.14) !important;
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
[class~='rounded'],
|
||||
[class*='rounded-'] {
|
||||
|
||||
Vendored
+1
@@ -26,6 +26,7 @@ declare namespace AMap {
|
||||
pitch?: number
|
||||
rotation?: number
|
||||
zoom?: number
|
||||
zooms?: [number, number]
|
||||
center?: [number, number]
|
||||
mapStyle?: string
|
||||
features?: string[]
|
||||
|
||||
@@ -465,7 +465,7 @@ onMounted(loadAdminData)
|
||||
</p>
|
||||
</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>
|
||||
<NIcon><Refresh /></NIcon>
|
||||
</template>
|
||||
@@ -577,13 +577,14 @@ onMounted(loadAdminData)
|
||||
<p class="mt-1 text-sm text-slate-500">共 {{ pendingImages.length }} 张待处理图片。</p>
|
||||
</div>
|
||||
<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 ? '取消全选' : '全选待审核' }}
|
||||
</NButton>
|
||||
<NButton
|
||||
type="success"
|
||||
secondary
|
||||
strong
|
||||
type="default"
|
||||
class="oc-panel-button oc-panel-button--teal"
|
||||
:disabled="!selectedReviewCount"
|
||||
:loading="actionLoading"
|
||||
@click="updateCloudStatus(Array.from(selectedReviewIds), 'approved')"
|
||||
@@ -591,9 +592,10 @@ onMounted(loadAdminData)
|
||||
批量通过 {{ selectedReviewCount || '' }}
|
||||
</NButton>
|
||||
<NButton
|
||||
type="error"
|
||||
secondary
|
||||
strong
|
||||
type="default"
|
||||
class="oc-panel-button oc-panel-button--danger"
|
||||
:disabled="!selectedReviewCount"
|
||||
:loading="actionLoading"
|
||||
@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-2 line-clamp-2 text-sm leading-6 text-slate-500">{{ item.description || '没有图片说明。' }}</p>
|
||||
<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>
|
||||
通过
|
||||
</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>
|
||||
拒绝
|
||||
</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>
|
||||
</article>
|
||||
@@ -669,6 +671,8 @@ onMounted(loadAdminData)
|
||||
size="small"
|
||||
secondary
|
||||
strong
|
||||
type="default"
|
||||
class="oc-panel-button oc-panel-button--amber"
|
||||
:disabled="user.id === authStore.user?.id && user.role === 'admin'"
|
||||
:loading="actionLoading"
|
||||
@click="updateUserRole(user, user.role === 'admin' ? 'user' : 'admin')"
|
||||
@@ -677,9 +681,10 @@ onMounted(loadAdminData)
|
||||
</NButton>
|
||||
<NButton
|
||||
size="small"
|
||||
:type="user.is_disabled ? 'success' : 'error'"
|
||||
type="default"
|
||||
secondary
|
||||
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"
|
||||
:loading="actionLoading"
|
||||
@click="toggleUserDisabled(user)"
|
||||
@@ -724,10 +729,10 @@ onMounted(loadAdminData)
|
||||
</NTag>
|
||||
</div>
|
||||
<div class="mt-4 flex flex-wrap gap-2">
|
||||
<NButton size="small" secondary strong @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="error" secondary strong :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--neutral" @click="selectedImage = item">查看</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="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" type="default" secondary strong class="oc-panel-button oc-panel-button--amber" :loading="actionLoading" @click="toggleImageVisibility(item)">
|
||||
<template #icon>
|
||||
<NIcon>
|
||||
<Eye v-if="item.is_hidden" />
|
||||
@@ -736,7 +741,7 @@ onMounted(loadAdminData)
|
||||
</template>
|
||||
{{ item.is_hidden ? '公开' : '隐藏' }}
|
||||
</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>
|
||||
删除
|
||||
</NButton>
|
||||
|
||||
@@ -79,7 +79,7 @@ onUnmounted(() => {
|
||||
<div class="space-y-4">
|
||||
<p class="text-sm text-slate-500">{{ countdown }} 秒后自动跳转登录页面...</p>
|
||||
<RouterLink to="/login" class="no-underline">
|
||||
<NButton type="primary">立即登录</NButton>
|
||||
<NButton type="primary" class="oc-primary-button oc-primary-button--teal">立即登录</NButton>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</template>
|
||||
@@ -90,7 +90,7 @@ onUnmounted(() => {
|
||||
<NResult status="error" title="认证失败" description="邮箱确认链接无效或已过期,请重新注册。">
|
||||
<template #footer>
|
||||
<RouterLink to="/register" class="no-underline">
|
||||
<NButton type="primary">重新注册</NButton>
|
||||
<NButton type="primary" class="oc-primary-button oc-primary-button--sky">重新注册</NButton>
|
||||
</RouterLink>
|
||||
</template>
|
||||
</NResult>
|
||||
|
||||
@@ -122,6 +122,7 @@ async function handleSendResetEmail() {
|
||||
type="primary"
|
||||
block
|
||||
size="large"
|
||||
class="oc-primary-button oc-primary-button--teal"
|
||||
:loading="resetMode ? resetLoading : loading"
|
||||
>
|
||||
<template v-if="resetMode">
|
||||
|
||||
@@ -87,7 +87,7 @@ async function handleRegister() {
|
||||
<span class="font-semibold text-slate-700">{{ email }}</span>
|
||||
</p>
|
||||
<RouterLink to="/login" class="no-underline">
|
||||
<NButton type="primary">去登录</NButton>
|
||||
<NButton type="primary" class="oc-primary-button oc-primary-button--teal">去登录</NButton>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</template>
|
||||
@@ -152,6 +152,7 @@ async function handleRegister() {
|
||||
type="primary"
|
||||
block
|
||||
size="large"
|
||||
class="oc-primary-button oc-primary-button--sky"
|
||||
:loading="loading"
|
||||
>
|
||||
{{ loading ? '注册中...' : '注册' }}
|
||||
|
||||
@@ -80,7 +80,7 @@ async function handleResetPassword() {
|
||||
description="现在可以使用新密码登录。"
|
||||
>
|
||||
<template #footer>
|
||||
<NButton type="primary" @click="router.push('/login')">返回登录</NButton>
|
||||
<NButton type="primary" class="oc-primary-button oc-primary-button--teal" @click="router.push('/login')">返回登录</NButton>
|
||||
</template>
|
||||
</NResult>
|
||||
|
||||
@@ -123,6 +123,7 @@ async function handleResetPassword() {
|
||||
type="primary"
|
||||
block
|
||||
size="large"
|
||||
class="oc-primary-button oc-primary-button--teal"
|
||||
:disabled="!canSubmit"
|
||||
:loading="loading"
|
||||
>
|
||||
|
||||
@@ -168,7 +168,7 @@ watch(() => route.params.id, () => {
|
||||
<div class="max-w-6xl mx-auto px-4 py-8">
|
||||
<div class="mb-6">
|
||||
<RouterLink to="/encyclopedia">
|
||||
<NButton text type="primary">← 返回图鉴总览</NButton>
|
||||
<NButton type="default" secondary strong class="oc-panel-button oc-panel-button--neutral">← 返回图鉴总览</NButton>
|
||||
</RouterLink>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ onMounted(async () => {
|
||||
</NAlert>
|
||||
|
||||
<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="mt-5 h-5 w-2/5" />
|
||||
<NSkeleton class="mt-3 h-4 w-1/3" />
|
||||
@@ -176,7 +176,7 @@ onMounted(async () => {
|
||||
</button>
|
||||
</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="暂时还没有图鉴数据" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -483,15 +483,16 @@ onUnmounted(() => {
|
||||
|
||||
<div class="flex gap-3 overflow-x-auto pb-2">
|
||||
<NButton
|
||||
v-for="tab in filterTabs"
|
||||
:key="tab.id"
|
||||
secondary
|
||||
strong
|
||||
@click="selectedTypeId = tab.id"
|
||||
class="shrink-0"
|
||||
:type="selectedTypeId === tab.id ? 'primary' : 'default'"
|
||||
>
|
||||
{{ tab.label }}
|
||||
v-for="tab in filterTabs"
|
||||
:key="tab.id"
|
||||
secondary
|
||||
strong
|
||||
@click="selectedTypeId = tab.id"
|
||||
class="shrink-0"
|
||||
:class="selectedTypeId === tab.id ? 'oc-panel-button oc-panel-button--sky' : 'oc-panel-button oc-panel-button--neutral'"
|
||||
type="default"
|
||||
>
|
||||
{{ tab.label }}
|
||||
</NButton>
|
||||
</div>
|
||||
</section>
|
||||
@@ -508,7 +509,7 @@ onUnmounted(() => {
|
||||
<div
|
||||
v-for="n in 8"
|
||||
: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="mt-4 h-4 w-3/5" />
|
||||
@@ -563,7 +564,7 @@ onUnmounted(() => {
|
||||
</button>
|
||||
</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="还没有符合条件的云图">
|
||||
<template #extra>
|
||||
<p class="text-sm text-slate-500">换个云型筛选试试,或者等社区上传更多作品。</p>
|
||||
@@ -576,6 +577,7 @@ onUnmounted(() => {
|
||||
secondary
|
||||
strong
|
||||
:disabled="currentPage <= 1"
|
||||
class="oc-panel-button oc-panel-button--neutral"
|
||||
@click="goToPage(currentPage - 1)"
|
||||
>
|
||||
上一页
|
||||
@@ -586,7 +588,8 @@ onUnmounted(() => {
|
||||
v-if="page === 1 || page === totalPages || Math.abs(page - currentPage) <= 2"
|
||||
secondary
|
||||
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)"
|
||||
>
|
||||
{{ page }}
|
||||
@@ -601,6 +604,7 @@ onUnmounted(() => {
|
||||
secondary
|
||||
strong
|
||||
:disabled="currentPage >= totalPages"
|
||||
class="oc-panel-button oc-panel-button--neutral"
|
||||
@click="goToPage(currentPage + 1)"
|
||||
>
|
||||
下一页
|
||||
|
||||
@@ -405,6 +405,7 @@ onMounted(async () => {
|
||||
pitch: 0,
|
||||
rotation: 0,
|
||||
zoom: 5,
|
||||
zooms: [4, 18],
|
||||
center: [104.07, 30.67],
|
||||
mapStyle: 'amap://styles/normal',
|
||||
features: ['bg', 'road', 'building', 'point'],
|
||||
@@ -415,7 +416,7 @@ onMounted(async () => {
|
||||
|
||||
mapInst.addControl(new AMapLib.Scale())
|
||||
mapInst.addControl(new AMapLib.ToolBar({ position: 'LT' } as Record<string, unknown>))
|
||||
mapInst.addControl(new AMapLib.ControlBar({ position: { right: '10px', top: '80px' } } as Record<string, unknown>))
|
||||
mapInst.addControl(new AMapLib.ControlBar({ position: { right: '50px', bottom: '224px' } } as Record<string, unknown>))
|
||||
mapInst.on('click', () => { previewCloud.value = null; hideHoverCard() })
|
||||
mapInst.on('zoomstart', hideHeader)
|
||||
mapInst.on('movestart', hideHeader)
|
||||
@@ -442,7 +443,7 @@ onUnmounted(() => {
|
||||
<div class="relative h-[100dvh] min-h-screen">
|
||||
<div ref="mapEl" class="w-full h-full"></div>
|
||||
|
||||
<div class="absolute bottom-6 right-4 flex flex-col items-end gap-2 z-20">
|
||||
<div class="absolute bottom-6 right-7 z-20 flex w-10 flex-col items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="w-10 h-10 bg-white rounded-lg shadow-md flex items-center justify-center hover:bg-gray-50"
|
||||
@@ -642,6 +643,11 @@ onUnmounted(() => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:deep(.amap-controlbar) {
|
||||
transform: translateX(50%) scale(1);
|
||||
transform-origin: bottom right;
|
||||
}
|
||||
|
||||
.map-archive-button.map-archive-button {
|
||||
border-radius: 9999px !important;
|
||||
}
|
||||
|
||||
@@ -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="mx-auto max-w-4xl">
|
||||
<RouterLink to="/profile">
|
||||
<NButton text type="primary">← 返回个人主页</NButton>
|
||||
<NButton type="default" secondary strong class="oc-panel-button oc-panel-button--neutral">← 返回个人主页</NButton>
|
||||
</RouterLink>
|
||||
|
||||
<div class="mt-6">
|
||||
@@ -111,7 +111,7 @@ async function savePassword() {
|
||||
{{ success }}
|
||||
</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>
|
||||
<h2 class="text-2xl font-bold text-slate-900">公开昵称</h2>
|
||||
@@ -127,9 +127,10 @@ async function savePassword() {
|
||||
show-count
|
||||
/>
|
||||
<NButton
|
||||
type="primary"
|
||||
secondary
|
||||
strong
|
||||
type="default"
|
||||
class="oc-panel-button oc-panel-button--teal"
|
||||
:loading="usernameSaving"
|
||||
@click="saveUsername"
|
||||
>
|
||||
@@ -139,7 +140,7 @@ async function savePassword() {
|
||||
</div>
|
||||
</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>
|
||||
<h2 class="text-2xl font-bold text-slate-900">登录密码</h2>
|
||||
@@ -166,6 +167,7 @@ async function savePassword() {
|
||||
<NButton
|
||||
secondary
|
||||
strong
|
||||
class="oc-panel-button oc-panel-button--neutral"
|
||||
:loading="passwordSaving"
|
||||
@click="savePassword"
|
||||
>
|
||||
|
||||
@@ -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="max-w-6xl mx-auto px-4 py-10">
|
||||
<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="mt-4 h-10 w-2/3" />
|
||||
<NSkeleton class="mt-5 h-4 w-full" :repeat="2" />
|
||||
</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="mt-4 h-8 w-1/2" />
|
||||
<NSkeleton class="mt-5 h-3 w-full" />
|
||||
@@ -545,7 +545,7 @@ watch(selectedUploadDate, async newValue => {
|
||||
: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="mt-3 text-3xl font-bold text-slate-900">{{ approvedShots }}</p>
|
||||
<p class="mt-2 text-sm text-slate-500">当前公开可见的云图数量</p>
|
||||
@@ -585,12 +585,12 @@ watch(selectedUploadDate, async newValue => {
|
||||
</div>
|
||||
|
||||
<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="mt-2 text-3xl font-bold text-slate-900">{{ totalShots }}</p>
|
||||
</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="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">
|
||||
@@ -598,12 +598,12 @@ watch(selectedUploadDate, async newValue => {
|
||||
</p>
|
||||
</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="mt-2 text-3xl font-bold text-slate-900">{{ shootingDays }}</p>
|
||||
</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="mt-2 text-2xl font-bold text-slate-900">
|
||||
<template v-if="isOwnProfile">{{ approvedShots }} / {{ pendingShots }}</template>
|
||||
@@ -639,7 +639,8 @@ watch(selectedUploadDate, async newValue => {
|
||||
v-if="isOwnProfile && selectedCloudCount"
|
||||
secondary
|
||||
strong
|
||||
type="error"
|
||||
type="default"
|
||||
class="oc-panel-button oc-panel-button--danger"
|
||||
@click="deleteCloudByIds(Array.from(selectedCloudIds))"
|
||||
>
|
||||
删除已选 {{ selectedCloudCount }}
|
||||
@@ -648,23 +649,25 @@ watch(selectedUploadDate, async newValue => {
|
||||
v-if="isOwnProfile"
|
||||
secondary
|
||||
strong
|
||||
class="oc-panel-button oc-panel-button--neutral"
|
||||
@click="toggleSelectionMode"
|
||||
>
|
||||
{{ selectionMode ? '取消选择' : '选择图片' }}
|
||||
</NButton>
|
||||
<NButton secondary strong @click="loadProfilePage(true)">
|
||||
<NButton secondary strong class="oc-panel-button oc-panel-button--neutral" @click="loadProfilePage(true)">
|
||||
刷新数据
|
||||
</NButton>
|
||||
<NButton
|
||||
v-if="selectedUploadDate"
|
||||
secondary
|
||||
strong
|
||||
class="oc-panel-button oc-panel-button--neutral"
|
||||
@click="clearSelectedUploadDate"
|
||||
>
|
||||
清除筛选
|
||||
</NButton>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
@@ -681,7 +684,7 @@ watch(selectedUploadDate, async newValue => {
|
||||
<div v-for="n in 2" :key="n">
|
||||
<NSkeleton class="h-6 w-40" />
|
||||
<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="mt-4 h-5 w-2/3" />
|
||||
<NSkeleton class="mt-3 h-4 w-1/2" />
|
||||
@@ -764,13 +767,13 @@ watch(selectedUploadDate, async newValue => {
|
||||
</section>
|
||||
</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 ? '还没有上传任何云图' : '这位用户还没有公开云图')">
|
||||
<template #extra>
|
||||
<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>
|
||||
<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>
|
||||
</NEmpty>
|
||||
</div>
|
||||
|
||||
@@ -15,10 +15,10 @@ import { RouterLink } from 'vue-router'
|
||||
|
||||
<div class="mt-8 flex flex-wrap items-center justify-center gap-3">
|
||||
<RouterLink to="/">
|
||||
<NButton type="primary" secondary strong>返回地图</NButton>
|
||||
<NButton type="default" secondary strong class="oc-panel-button oc-panel-button--sky">返回地图</NButton>
|
||||
</RouterLink>
|
||||
<RouterLink to="/profile">
|
||||
<NButton secondary strong>前往个人主页</NButton>
|
||||
<NButton type="default" secondary strong class="oc-panel-button oc-panel-button--neutral">前往个人主页</NButton>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -15,10 +15,10 @@ import { RouterLink } from 'vue-router'
|
||||
|
||||
<div class="mt-8 flex flex-wrap items-center justify-center gap-3">
|
||||
<RouterLink to="/">
|
||||
<NButton type="primary" secondary strong>返回地图</NButton>
|
||||
<NButton type="default" secondary strong class="oc-panel-button oc-panel-button--sky">返回地图</NButton>
|
||||
</RouterLink>
|
||||
<RouterLink to="/gallery">
|
||||
<NButton secondary strong>去画廊看看</NButton>
|
||||
<NButton type="default" secondary strong class="oc-panel-button oc-panel-button--neutral">去画廊看看</NButton>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -252,16 +252,16 @@ onUnmounted(() => {
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex gap-3">
|
||||
<NButton secondary strong type="primary" class="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--sky flex-1" @click="saveBadge(badge)">保存分享卡片</NButton>
|
||||
<NButton secondary strong type="default" class="oc-panel-button oc-panel-button--neutral flex-1" @click="router.push(`/encyclopedia/${badge.cloudTypeId}`)">查看详情</NButton>
|
||||
</div>
|
||||
</NCard>
|
||||
</div>
|
||||
|
||||
<div class="mt-8 flex flex-wrap items-center justify-center gap-3">
|
||||
<NButton secondary strong @click="resetAfterSuccess">继续上传</NButton>
|
||||
<NButton secondary strong type="primary" @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="resetAfterSuccess">继续上传</NButton>
|
||||
<NButton secondary strong type="default" class="oc-panel-button oc-panel-button--sky" @click="router.push('/encyclopedia')">前往图鉴</NButton>
|
||||
<NButton secondary strong type="default" class="oc-panel-button oc-panel-button--neutral" @click="router.push('/profile')">返回个人主页</NButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -474,8 +474,8 @@ onUnmounted(() => {
|
||||
<div class="mt-6 flex items-center justify-between">
|
||||
<p class="text-sm text-gray-500">共 {{ items.length }} 张图片</p>
|
||||
<div class="flex gap-3">
|
||||
<NButton secondary strong @click="clearAll()" :disabled="uploading">清空</NButton>
|
||||
<NButton type="primary" secondary strong @click="handleSubmit" :disabled="uploading">
|
||||
<NButton secondary strong type="default" class="oc-panel-button oc-panel-button--neutral" @click="clearAll()" :disabled="uploading">清空</NButton>
|
||||
<NButton type="default" secondary strong class="oc-panel-button oc-panel-button--sky" @click="handleSubmit" :disabled="uploading">
|
||||
{{ uploading ? '上传中...' : '提交上传' }}
|
||||
</NButton>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user