feat(admin): 模板页卡片增加图文缩略预览

方便运营对照科技蓝与 LOGO 蓝版式差异后再启用,缩略图居中且不占满整行。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
wuzilongandCursor committed 2026-11-10 18:13:07 +08:00
1 parent 73237eff6f
commit cb4ecd4349
2 files changed
+394 -1

No files matched your search

@@ -0,0 +1,376 @@
<!-- 首页模板缩略预览:示意版式差异,便于选型 -->
<template>
<div class="thumb" :class="variant" aria-hidden="true">
<template v-if="variant === 'tech'">
<div class="thumb__mast">
<div class="thumb__brand">
<span class="thumb__mark" />
<span class="thumb__title">甘肃省房地产价格评估行业协会</span>
</div>
<div class="thumb__slogan">
<strong>{{ sloganText }}</strong>
<em>{{ valueText }}</em>
</div>
</div>
<div class="thumb__nav">
<i /><i /><i /><i /><i />
</div>
<div class="thumb__hero">
<span>{{ heroCaption }}</span>
</div>
<div class="thumb__cols">
<div v-for="col in columns" :key="col" class="thumb__col">
<b>{{ col }}</b>
<i /><i /><i />
</div>
</div>
</template>
<template v-else>
<div class="thumb__head">
<div class="thumb__identity">
<span class="thumb__crest" />
<span class="thumb__title">甘肃省房地产价格评估行业协会</span>
</div>
<div class="thumb__slogan thumb__slogan--side">
<strong>{{ sloganText }}</strong>
<em>{{ valueText }}</em>
</div>
</div>
<div class="thumb__nav thumb__nav--bar">
<i /><i /><i /><i /><i />
</div>
<div class="thumb__hero thumb__hero--brand">
<span>{{ heroCaption }}</span>
</div>
<div class="thumb__sheet">
<div v-for="col in brandColumns" :key="col" class="thumb__tile">
<b>{{ col }}</b>
<i /><i />
</div>
</div>
</template>
</div>
</template>
<script setup lang="ts">
defineOptions({ name: 'TemplateThumb' })
const props = withDefaults(
defineProps<{
name: string
slogan?: string
valueProposition?: string
}>(),
{
slogan: '',
valueProposition: ''
}
)
const variant = computed(() => (props.name === 'LOGO蓝' ? 'brand' : 'tech'))
const sloganText = computed(() => props.slogan?.trim() || '定位标语')
const valueText = computed(() => props.valueProposition?.trim() || '价值主张说明')
const heroCaption = computed(() => (variant.value === 'tech' ? '轮播焦点图' : '首页轮播'))
const columns = ['新闻动态', '通知公告', '政策法规']
const brandColumns = ['新闻动态', '通知公告', '政策法规', '数据看板']
</script>
<style scoped>
.thumb {
overflow: hidden;
border: 1px solid var(--el-border-color-lighter);
border-radius: 8px;
pointer-events: none;
user-select: none;
}
.thumb.tech {
--c: #1677ff;
--bg: #f0f5ff;
--text: #0b1f3a;
--muted: #5b6b85;
--line: #d6e4ff;
--surface: #fff;
--foot: #041833;
background:
radial-gradient(180px 70px at 12% -10%, rgba(22, 119, 255, 0.22), transparent 60%),
radial-gradient(140px 60px at 90% 0%, rgba(0, 194, 255, 0.16), transparent 55%),
var(--bg);
padding: 8px 8px 10px;
}
.thumb.brand {
--c: #0858a3;
--brass: #b08948;
--bg: #fff;
--text: #1c2430;
--muted: #6d645b;
--line: #e6e8eb;
--foot: #06243f;
background: var(--bg);
padding: 0 0 10px;
}
.thumb__mast {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 6px 4px 4px;
background: rgba(255, 255, 255, 0.86);
border-radius: 6px 6px 0 0;
}
.thumb__brand {
display: flex;
align-items: center;
gap: 6px;
min-width: 0;
}
.thumb__mark {
flex: none;
width: 18px;
height: 18px;
border-radius: 5px;
background: linear-gradient(145deg, #1677ff, #0a4fd6);
box-shadow: 0 0 0 1px rgba(22, 119, 255, 0.25);
}
.thumb__title {
overflow: hidden;
color: var(--text);
font-size: 10px;
font-weight: 650;
letter-spacing: 0.04em;
white-space: nowrap;
text-overflow: ellipsis;
}
.thumb__slogan {
flex: none;
max-width: 42%;
padding-left: 8px;
border-left: 2px solid #0b3a66;
text-align: right;
}
.thumb.brand .thumb__slogan {
border-left-color: var(--brass);
}
.thumb__slogan strong,
.thumb__slogan em {
display: block;
overflow: hidden;
font-style: normal;
white-space: nowrap;
text-overflow: ellipsis;
}
.thumb__slogan strong {
color: #0b2a4a;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.04em;
}
.thumb__slogan em {
margin-top: 2px;
color: #0b3a66;
font-size: 9px;
font-weight: 600;
letter-spacing: 0.08em;
}
.thumb.brand .thumb__slogan strong {
color: #12304f;
font-size: 10px;
font-weight: 600;
}
.thumb.brand .thumb__slogan em {
color: var(--c);
font-weight: 500;
}
.thumb__nav {
display: flex;
gap: 4px;
padding: 4px 2px 6px;
}
.thumb__nav i {
display: block;
width: 28px;
height: 4px;
border-radius: 2px;
background: var(--line);
}
.thumb__nav i:first-child {
background: var(--c);
}
.thumb__nav--bar {
justify-content: center;
gap: 10px;
margin-top: 2px;
padding: 7px 8px;
background: var(--c);
}
.thumb__nav--bar i {
width: 22px;
background: rgba(247, 243, 235, 0.45);
}
.thumb__nav--bar i:first-child {
background: #e4c98a;
}
.thumb__hero {
position: relative;
height: 72px;
border-radius: 8px;
overflow: hidden;
background:
linear-gradient(120deg, rgba(4, 24, 51, 0.15), transparent 40%),
linear-gradient(160deg, #4aa3ff, #1677ff 45%, #0a3a66);
box-shadow: 0 6px 14px rgba(10, 40, 100, 0.14);
}
.thumb__hero::after {
content: '';
position: absolute;
inset: auto 0 0;
height: 42%;
background: linear-gradient(transparent, rgba(4, 24, 51, 0.55));
}
.thumb__hero span {
position: absolute;
z-index: 1;
right: 10px;
bottom: 8px;
left: 10px;
color: #fff;
font-size: 10px;
font-weight: 650;
}
.thumb__hero--brand {
margin: 8px 8px 0;
height: 68px;
border: 1px solid var(--line);
border-radius: 6px;
background:
linear-gradient(120deg, rgba(6, 36, 63, 0.12), transparent 45%),
linear-gradient(150deg, #3d7eb8, #0858a3 50%, #06243f);
box-shadow: none;
}
.thumb__hero--brand::after {
display: none;
}
.thumb__hero--brand span {
inset: auto 0 0;
padding: 5px 8px;
background: rgba(6, 36, 63, 0.82);
font-size: 9px;
font-weight: 500;
}
.thumb__cols {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 6px;
margin-top: 8px;
}
.thumb__col,
.thumb__tile {
padding: 6px;
border: 1px solid var(--line);
border-radius: 6px;
background: var(--surface, #fff);
}
.thumb__col b,
.thumb__tile b {
display: block;
margin-bottom: 4px;
color: var(--c);
font-size: 9px;
font-weight: 650;
}
.thumb__col i,
.thumb__tile i {
display: block;
height: 3px;
margin-top: 3px;
border-radius: 2px;
background: #e8efff;
}
.thumb.brand .thumb__tile i {
background: #eceff2;
}
.thumb__col i:nth-child(3),
.thumb__tile i:nth-child(3) {
width: 72%;
}
.thumb__head {
display: grid;
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
align-items: center;
column-gap: 8px;
padding: 10px 10px 8px;
}
.thumb__identity {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
grid-column: 2;
min-width: 0;
}
.thumb__crest {
width: 22px;
height: 22px;
border-radius: 50%;
background: linear-gradient(145deg, #fff, #e8eef5);
box-shadow:
0 0 0 1px #e3d9cc,
0 0 0 3px #fff,
0 0 0 4px var(--brass);
}
.thumb.brand .thumb__title {
max-width: 180px;
color: #12304f;
font-size: 11px;
font-weight: 600;
letter-spacing: 0.1em;
}
.thumb__slogan--side {
grid-column: 3;
justify-self: end;
max-width: 100%;
}
.thumb__sheet {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 6px;
margin: 8px 8px 0;
}
</style>
+18 -1
View File
@@ -24,7 +24,14 @@
:class="{ 'is-active': activeTemplate === item.name }"
@click="choose(item.name)"
>
<div class="flex items-center justify-between gap-3">
<div class="template-card__preview">
<TemplateThumb
:name="item.name"
:slogan="item.slogan"
:value-proposition="item.valueProposition"
/>
</div>
<div class="flex items-center justify-between gap-3 mt-3">
<div class="flex items-center gap-2">
<span
class="template-card__mark"
@@ -67,6 +74,7 @@
<script setup lang="ts">
import { saveAdminHome } from '@/api/home'
import TemplateThumb from '../components/TemplateThumb.vue'
import { useHomeEditor } from '../shared'
defineOptions({ name: 'HomeTemplate' })
@@ -100,6 +108,15 @@
box-shadow 0.2s;
}
.template-card__preview {
display: flex;
justify-content: center;
}
.template-card__preview :deep(.thumb) {
width: min(100%, 280px);
}
.template-card.is-active {
border-color: var(--el-color-primary);
box-shadow: 0 0 0 1px var(--el-color-primary);