This commit is contained in:
2025-12-12 10:35:43 +08:00
parent 396a4749d9
commit 0d9008cf75
2 changed files with 110 additions and 164 deletions

View File

@@ -209,7 +209,7 @@
id, resource_id, title, content, summary, cover_image, tag_id, author, source, is_audited, publish_time,
status,source_url, creator,create_time
) VALUES (
#{id}, #{resourceID}, #{title}, #{content}, #{summary}, #{coverImage}, #{tagID}, #{author}, #{source}, #{isAudited}, #{publistTime}
#{id}, #{resourceID}, #{title}, #{content}, #{summary}, #{coverImage}, #{tagID}, #{author}, #{source}, #{isAudited}, #{publishTime}
#{status}, #{sourceUrl}, #{creator}, #{createTime}
)
</insert>

View File

@@ -1,15 +1,13 @@
<template>
<AdminLayout
title="内容管理"
subtitle="管理网站横幅、栏目、标签等内容信息"
>
<AdminLayout title="内容管理" subtitle="管理网站横幅、栏目、标签等内容信息">
<div class="banner-management">
<!-- 操作栏 -->
<div class="toolbar">
<h3 class="section-title">轮播Banner</h3>
<button class="btn-add" @click="handleCreate">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M8 3.33333V12.6667M3.33333 8H12.6667" stroke="currentColor" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 3.33333V12.6667M3.33333 8H12.6667" stroke="currentColor" stroke-width="1.33333"
stroke-linecap="round" stroke-linejoin="round" />
</svg>
添加Banner
</button>
@@ -23,19 +21,10 @@
<!-- Banner 卡片列表 -->
<div v-else class="banner-list">
<div
v-for="banner in banners"
:key="banner.bannerID"
class="banner-card"
>
<div v-for="banner in banners" :key="banner.bannerID" class="banner-card">
<!-- Banner 图片容器 -->
<div class="banner-image-wrapper">
<img
:src="getBannerImageUrl(banner)"
:alt="banner.title"
class="banner-image"
@error="handleImageError"
/>
<img :src="getBannerImageUrl(banner)" :alt="banner.title" class="banner-image" @error="handleImageError" />
</div>
<!-- Banner 信息区域 -->
@@ -79,15 +68,10 @@
<!-- 分页组件 -->
<div v-if="!loading && pageParam.totalElements && pageParam.totalElements > 0" class="pagination-container">
<el-pagination
v-model:current-page="pageParam.pageNumber"
v-model:page-size="pageParam.pageSize"
:page-sizes="[10, 20, 50, 100]"
:total="pageParam.totalElements"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handlePageSizeChange"
@current-change="handlePageChange"
/>
<el-pagination v-model:current-page="pageParam.pageNumber" v-model:page-size="pageParam.pageSize"
:page-sizes="[10, 20, 50, 100]" :total="pageParam.totalElements"
layout="total, sizes, prev, pager, next, jumper" @size-change="handlePageSizeChange"
@current-change="handlePageChange" />
</div>
<!-- 创建/编辑弹窗 -->
@@ -104,12 +88,7 @@
<span class="required">*</span>
横幅标题
</label>
<input
v-model="currentBanner.title"
type="text"
class="form-input"
placeholder="请输入横幅标题"
/>
<input v-model="currentBanner.title" type="text" class="form-input" placeholder="请输入横幅标题" />
</div>
<div class="form-group">
@@ -117,15 +96,8 @@
<span class="required">*</span>
横幅图片
</label>
<FileUpload
:as-dialog="false"
list-type="cover"
v-model:cover-url="currentBanner.imageUrl"
accept="image/*"
:max-size="10"
tip="支持 jpg、png、gif 格式建议尺寸1920x600"
module="banner"
/>
<FileUpload :as-dialog="false" list-type="cover" v-model:cover-url="currentBanner.imageUrl"
accept="image/*" :max-size="10" tip="支持 jpg、png、gif 格式建议尺寸1920x600" module="banner" />
</div>
<div class="form-group">
@@ -135,27 +107,15 @@
</label>
<div class="radio-group">
<label class="radio-item">
<input
v-model="currentBanner.linkType"
type="radio"
:value="1"
/>
<input v-model="currentBanner.linkType" type="radio" :value="1" />
<span class="radio-label">资源</span>
</label>
<label class="radio-item">
<input
v-model="currentBanner.linkType"
type="radio"
:value="2"
/>
<input v-model="currentBanner.linkType" type="radio" :value="2" />
<span class="radio-label">课程</span>
</label>
<label class="radio-item">
<input
v-model="currentBanner.linkType"
type="radio"
:value="3"
/>
<input v-model="currentBanner.linkType" type="radio" :value="3" />
<span class="radio-label">外部链接</span>
</label>
</div>
@@ -163,19 +123,17 @@
<div class="form-group" v-if="currentBanner.linkType === 1 || currentBanner.linkType === 2">
<label class="form-label">
<span class="required">*</span>
{{ currentBanner.linkType === 1 ? '选择资源' : '选择课程' }}
</label>
<div class="select-container">
<div
class="form-select"
@click="toggleDropdown"
:class="{ 'active': dropdownVisible }"
>
<div class="form-select" @click="toggleDropdown" :class="{ 'active': dropdownVisible }">
<span class="select-value">
{{ getSelectedItemLabel() || `请选择${currentBanner.linkType === 1 ? '资源' : '课程'}` }}
</span>
<svg class="select-arrow" width="12" height="12" viewBox="0 0 12 12" fill="none">
<path d="M2.5 4.5L6 8L9.5 4.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2.5 4.5L6 8L9.5 4.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"
stroke-linejoin="round" />
</svg>
</div>
@@ -183,28 +141,14 @@
<div v-if="dropdownVisible" class="dropdown-list" @click.stop>
<!-- 搜索框 -->
<div class="dropdown-search">
<input
type="text"
v-model="searchKeyword"
class="search-input"
:placeholder="`搜索${currentBanner.linkType === 1 ? '资源' : '课程'}名称`"
@input="handleSearchChange"
/>
<input type="text" v-model="searchKeyword" class="search-input"
:placeholder="`搜索${currentBanner.linkType === 1 ? '资源' : '课程'}名称`" @input="handleSearchChange" />
</div>
<!-- 列表内容 -->
<div
class="dropdown-content"
@scroll="handleScroll"
ref="dropdownContent"
>
<div
v-for="item in selectOptions"
:key="item.id"
class="dropdown-item"
:class="{ 'selected': currentBanner.linkID === item.id }"
@click="handleSelectItem(item)"
>
<div class="dropdown-content" @scroll="handleScroll" ref="dropdownContent">
<div v-for="item in selectOptions" :key="item.id" class="dropdown-item"
:class="{ 'selected': currentBanner.linkID === item.id }" @click="handleSelectItem(item)">
<span class="item-title">{{ item.title }}</span>
<span class="item-id">ID: {{ item.id }}</span>
</div>
@@ -231,44 +175,27 @@
<div class="form-group" v-if="currentBanner.linkType === 3">
<label class="form-label">
<span class="required">*</span>
外部链接
</label>
<input
v-model="currentBanner.linkUrl"
type="text"
class="form-input"
placeholder="请输入外部链接地址"
/>
<input v-model="currentBanner.linkUrl" type="text" class="form-input" placeholder="请输入外部链接地址" />
</div>
<div class="form-row">
<div class="form-group">
<label class="form-label">排序号</label>
<input
v-model.number="currentBanner.orderNum"
type="number"
class="form-input"
placeholder="数字越小越靠前"
/>
<input v-model.number="currentBanner.orderNum" type="number" class="form-input" placeholder="数字越小越靠前" />
</div>
<div class="form-group">
<label class="form-label">状态</label>
<div class="switch-group">
<label class="switch-item">
<input
v-model="currentBanner.status"
type="radio"
:value="1"
/>
<input v-model="currentBanner.status" type="radio" :value="1" />
<span class="switch-label">启用</span>
</label>
<label class="switch-item">
<input
v-model="currentBanner.status"
type="radio"
:value="0"
/>
<input v-model="currentBanner.status" type="radio" :value="0" />
<span class="switch-label">禁用</span>
</label>
</div>
@@ -280,11 +207,7 @@
<button class="btn-secondary" @click="handleCloseDialog">
取消
</button>
<button
class="btn-primary"
@click="handleSubmit"
:disabled="submitting"
>
<button class="btn-primary" @click="handleSubmit" :disabled="submitting">
{{ submitting ? '提交中...' : (isEdit ? '更新' : '创建') }}
</button>
</div>
@@ -464,6 +387,21 @@ async function handleSubmit() {
return;
}
// 校验链接内容:资源、课程或外部链接必须有一个有值
if (currentBanner.value.linkType === 1 || currentBanner.value.linkType === 2) {
// 选择资源或课程时,必须选择具体的资源/课程
if (!currentBanner.value.linkID) {
ElMessage.warning(`请选择${currentBanner.value.linkType === 1 ? '资源' : '课程'}`);
return;
}
} else if (currentBanner.value.linkType === 3) {
// 选择外部链接时,必须输入链接地址
if (!currentBanner.value.linkUrl || currentBanner.value.linkUrl.trim() === '') {
ElMessage.warning('请输入外部链接地址');
return;
}
}
try {
submitting.value = true;
@@ -885,7 +823,9 @@ onMounted(() => {
}
@keyframes spin {
to { transform: rotate(360deg); }
to {
transform: rotate(360deg);
}
}
// Banner 列表
@@ -1124,8 +1064,13 @@ onMounted(() => {
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.dialog-container {
@@ -1145,6 +1090,7 @@ onMounted(() => {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
@@ -1286,12 +1232,12 @@ onMounted(() => {
}
// 分页组件
.pagination-container {
margin-top: 24px;
display: flex;
justify-content: center;
padding: 20px 0;
}
// .pagination-container {
// margin-top: 24px;
// display: flex;
// justify-content: center;
// padding: 20px 0;
// }
// ==================== 下拉选择器样式 ====================
.select-container {