展示页面

This commit is contained in:
18631081161 2026-03-09 17:02:55 +08:00
parent 9698522be2
commit 83785dc20c
12 changed files with 342 additions and 4 deletions

View File

@ -105,6 +105,20 @@ export function setButlerQrcode(imageUrl: string) {
return request.post('/admin/config/butlerQrcode', { imageUrl })
}
/**
*
*/
export function getDisplayPageImage() {
return request.get('/admin/config/displayPageImage')
}
/**
*
*/
export function setDisplayPageImage(imageUrl: string) {
return request.post('/admin/config/displayPageImage', { imageUrl })
}
/**
*
*/

View File

@ -61,7 +61,8 @@ const internalPageOptions = [
{ label: '设置页面', value: '/pages/settings/index' },
{ label: '关于我们', value: '/pages/about/index' },
{ label: '用户协议', value: '/pages/agreement/user' },
{ label: '隐私政策', value: '/pages/agreement/privacy' }
{ label: '隐私政策', value: '/pages/agreement/privacy' },
{ label: '展示页', value: '/pages/display/index' }
]
//

View File

@ -64,7 +64,8 @@ const internalPageOptions = [
{ label: '我解锁的', value: '/pages/interact/myUnlocked' },
{ label: '联系我们', value: '/pages/butler/index' },
{ label: '用户协议', value: '/pages/agreement/index?type=user' },
{ label: '隐私政策', value: '/pages/agreement/index?type=privacy' }
{ label: '隐私政策', value: '/pages/agreement/index?type=privacy' },
{ label: '展示页', value: '/pages/display/index' }
]
//

View File

@ -103,6 +103,28 @@
</div>
</el-form-item>
<!-- 展示页长图设置 -->
<el-form-item label="展示页长图">
<div class="qrcode-upload">
<el-upload
class="qrcode-uploader"
:action="uploadUrl"
:headers="uploadHeaders"
:show-file-list="false"
:on-success="handleDisplayPageImageSuccess"
:before-upload="beforeAvatarUpload"
accept="image/*"
>
<img v-if="configForm.displayPageImage" :src="getFullUrl(configForm.displayPageImage)" class="qrcode-preview" />
<el-icon v-else class="qrcode-uploader-icon"><Plus /></el-icon>
</el-upload>
<div class="avatar-tip">
<p>支持格式JPGPNG</p>
<p>小程序展示页面展示的长图可从Banner金刚位跳转</p>
</div>
</div>
</el-form-item>
<!-- 会员图标设置 -->
<el-form-item label="不限时会员图标">
<div class="icon-upload">
@ -301,6 +323,8 @@ import {
setRealNameBanner,
getButlerQrcode,
setButlerQrcode,
getDisplayPageImage,
setDisplayPageImage,
getMemberIcons,
setMemberIcons,
getMemberEntryImage,
@ -321,6 +345,7 @@ const configForm = ref({
searchBanner: '',
realNameBanner: '',
butlerQrcode: '',
displayPageImage: '',
unlimitedMemberIcon: '',
sincereMemberIcon: '',
familyMemberIcon: '',
@ -352,14 +377,15 @@ const getFullUrl = (url) => {
const loadConfig = async () => {
try {
const [avatarRes, bannerRes, realNameBannerRes, qrcodeRes, memberIconsRes, memberEntryRes, realNamePriceRes] = await Promise.all([
const [avatarRes, bannerRes, realNameBannerRes, qrcodeRes, memberIconsRes, memberEntryRes, realNamePriceRes, displayPageRes] = await Promise.all([
getDefaultAvatar(),
getSearchBanner(),
getRealNameBanner(),
getButlerQrcode(),
getMemberIcons(),
getMemberEntryImage(),
getRealNamePrice()
getRealNamePrice(),
getDisplayPageImage()
])
if (avatarRes) {
configForm.value.defaultAvatar = avatarRes.avatarUrl || ''
@ -385,6 +411,9 @@ const loadConfig = async () => {
if (realNamePriceRes) {
configForm.value.realNamePrice = realNamePriceRes.price || 88
}
if (displayPageRes) {
configForm.value.displayPageImage = displayPageRes.imageUrl || ''
}
} catch (error) {
console.error('加载配置失败:', error)
}
@ -445,6 +474,15 @@ const handleQrcodeSuccess = (response) => {
}
}
const handleDisplayPageImageSuccess = (response) => {
if (response.code === 0 && response.data) {
configForm.value.displayPageImage = response.data.url
ElMessage.success('上传成功')
} else {
ElMessage.error(response.message || '上传失败')
}
}
const handleUnlimitedMemberIconSuccess = (response) => {
if (response.code === 0 && response.data) {
configForm.value.unlimitedMemberIcon = response.data.url
@ -521,6 +559,9 @@ const saveBasicConfig = async () => {
if (configForm.value.butlerQrcode) {
promises.push(setButlerQrcode(configForm.value.butlerQrcode))
}
if (configForm.value.displayPageImage) {
promises.push(setDisplayPageImage(configForm.value.displayPageImage))
}
if (configForm.value.memberEntryImage) {
promises.push(setMemberEntryImage(configForm.value.memberEntryImage))
}

View File

@ -152,6 +152,13 @@
"navigationBarTitleText": "联系我们"
}
},
{
"path": "pages/display/index",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "详情"
}
},
{
"path": "pages/webview/index",
"style": {

View File

@ -0,0 +1,188 @@
<template>
<view class="display-page">
<!-- 页面加载状态 -->
<Loading type="page" :loading="pageLoading" />
<!-- 顶部背景图 -->
<view class="top-bg">
<image src="/static/title_bg.png" mode="aspectFill" class="bg-img" />
</view>
<!-- 自定义导航栏 -->
<view class="custom-navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
<view class="navbar-content">
<view class="navbar-back" @click="handleBack">
<text class="back-icon"></text>
</view>
<text class="navbar-title"></text>
<view class="navbar-placeholder"></view>
</view>
</view>
<!-- 内容区域 - 可滚动 -->
<scroll-view class="content-area" scroll-y
:style="{ marginTop: (statusBarHeight + 44) + 'px', height: 'calc(100vh - ' + (statusBarHeight + 44) + 'px)' }">
<view class="content-wrapper">
<view class="image-card">
<image v-if="displayImage" class="display-img" :src="displayImage" mode="widthFix"
@click="previewImage" />
<view v-else class="image-placeholder">
<text>暂无内容</text>
</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { useConfigStore } from '@/store/config.js'
import { getFullImageUrl } from '@/utils/image.js'
import Loading from '@/components/Loading/index.vue'
const configStore = useConfigStore()
const statusBarHeight = ref(20)
const pageLoading = ref(true)
const displayImage = computed(() => {
const img = configStore.displayPageImage
return img ? getFullImageUrl(img) : ''
})
const getSystemInfo = () => {
try {
const res = uni.getSystemInfoSync()
statusBarHeight.value = res.statusBarHeight || 20
} catch (error) {
console.error('获取系统信息失败:', error)
}
}
const handleBack = () => {
uni.navigateBack()
}
const previewImage = () => {
if (!displayImage.value) return
uni.previewImage({
urls: [displayImage.value]
})
}
const initPage = async () => {
pageLoading.value = true
try {
getSystemInfo()
configStore.isLoaded = false
await configStore.loadAppConfig()
} catch (error) {
console.error('初始化页面失败:', error)
} finally {
pageLoading.value = false
}
}
onMounted(() => {
initPage()
})
</script>
<style lang="scss" scoped>
.display-page {
height: 100vh;
background-color: #f5f6fa;
overflow: hidden;
}
.top-bg {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 400rpx;
z-index: 0;
.bg-img {
width: 100%;
height: 100%;
}
}
.custom-navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
.navbar-content {
height: 44px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24rpx;
.navbar-back {
width: 80rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
.back-icon {
font-size: 56rpx;
color: #333;
font-weight: 300;
}
}
.navbar-title {
font-size: 34rpx;
font-weight: 600;
color: #333;
}
.navbar-placeholder {
width: 80rpx;
}
}
}
.content-area {
position: relative;
z-index: 1;
}
.content-wrapper {
padding: 24rpx 0 80rpx;
}
.image-card {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
.display-img {
width: 100%;
display: block;
}
.image-placeholder {
width: 90%;
height: 400rpx;
background: #fff;
border-radius: 24rpx;
display: flex;
align-items: center;
justify-content: center;
text {
font-size: 28rpx;
color: #999;
}
}
}
</style>

View File

@ -41,6 +41,7 @@ export const useConfigStore = defineStore('config', {
searchBanner: '',
realNameBanner: '',
butlerQrcode: '', // 管家指导二维码
displayPageImage: '', // 展示页长图
memberEntryImage: '', // 会员入口图
// 会员图标配置
@ -133,6 +134,7 @@ export const useConfigStore = defineStore('config', {
this.searchBanner = config.searchBanner || ''
this.realNameBanner = config.realNameBanner || ''
this.butlerQrcode = config.butlerQrcode || ''
this.displayPageImage = config.displayPageImage || ''
this.memberEntryImage = config.memberEntryImage || ''
// 会员图标配置

View File

@ -231,6 +231,34 @@ public class AdminConfigController : ControllerBase
return result ? ApiResponse.Success("设置成功") : ApiResponse.Error(40001, "设置失败");
}
/// <summary>
/// 获取展示页长图
/// </summary>
[HttpGet("displayPageImage")]
public async Task<ApiResponse<DisplayPageImageResponse>> GetDisplayPageImage()
{
var imageUrl = await _configService.GetDisplayPageImageAsync();
return ApiResponse<DisplayPageImageResponse>.Success(new DisplayPageImageResponse
{
ImageUrl = imageUrl
});
}
/// <summary>
/// 设置展示页长图
/// </summary>
[HttpPost("displayPageImage")]
public async Task<ApiResponse> SetDisplayPageImage([FromBody] SetDisplayPageImageRequest request)
{
if (string.IsNullOrWhiteSpace(request.ImageUrl))
{
return ApiResponse.Error(40001, "图片URL不能为空");
}
var result = await _configService.SetDisplayPageImageAsync(request.ImageUrl);
return result ? ApiResponse.Success("设置成功") : ApiResponse.Error(40001, "设置失败");
}
/// <summary>
/// 获取会员图标
/// </summary>
@ -533,3 +561,25 @@ public class SetRealNamePriceRequest
/// </summary>
public decimal Price { get; set; }
}
/// <summary>
/// 展示页长图响应
/// </summary>
public class DisplayPageImageResponse
{
/// <summary>
/// 图片URL
/// </summary>
public string? ImageUrl { get; set; }
}
/// <summary>
/// 设置展示页长图请求
/// </summary>
public class SetDisplayPageImageRequest
{
/// <summary>
/// 图片URL
/// </summary>
public string ImageUrl { get; set; } = string.Empty;
}

View File

@ -101,6 +101,11 @@ public class AppConfigResponse
/// </summary>
public string? ButlerQrcode { get; set; }
/// <summary>
/// 展示页长图URL
/// </summary>
public string? DisplayPageImage { get; set; }
/// <summary>
/// 会员图标配置
/// </summary>

View File

@ -92,6 +92,16 @@ public interface ISystemConfigService
/// </summary>
Task<bool> SetButlerQrcodeAsync(string imageUrl);
/// <summary>
/// 获取展示页长图URL
/// </summary>
Task<string?> GetDisplayPageImageAsync();
/// <summary>
/// 设置展示页长图URL
/// </summary>
Task<bool> SetDisplayPageImageAsync(string imageUrl);
/// <summary>
/// 获取会员图标URL已废弃请使用GetMemberIconsAsync
/// </summary>

View File

@ -49,6 +49,7 @@ public class ConfigService : IConfigService
var searchBanner = await _systemConfigService.GetSearchBannerAsync();
var realNameBanner = await _systemConfigService.GetRealNameBannerAsync();
var butlerQrcode = await _systemConfigService.GetButlerQrcodeAsync();
var displayPageImage = await _systemConfigService.GetDisplayPageImageAsync();
var memberIcons = await _systemConfigService.GetMemberIconsAsync();
var dailyPopup = await GetPopupConfigAsync(1); // 每日弹窗
var serviceAccountPopup = await GetPopupConfigAsync(2); // 服务号关注弹窗
@ -65,6 +66,7 @@ public class ConfigService : IConfigService
SearchBanner = searchBanner,
RealNameBanner = realNameBanner,
ButlerQrcode = butlerQrcode,
DisplayPageImage = displayPageImage,
MemberIcons = memberIcons,
DailyPopup = dailyPopup,
ServiceAccountPopup = serviceAccountPopup,

View File

@ -48,6 +48,11 @@ public class SystemConfigService : ISystemConfigService
/// </summary>
public const string ButlerQrcodeKey = "butler_qrcode";
/// <summary>
/// 展示页长图配置键
/// </summary>
public const string DisplayPageImageKey = "display_page_image";
/// <summary>
/// 会员图标配置键
/// </summary>
@ -240,6 +245,18 @@ public class SystemConfigService : ISystemConfigService
return await SetConfigValueAsync(ButlerQrcodeKey, imageUrl, "管家指导二维码URL");
}
/// <inheritdoc />
public async Task<string?> GetDisplayPageImageAsync()
{
return await GetConfigValueAsync(DisplayPageImageKey);
}
/// <inheritdoc />
public async Task<bool> SetDisplayPageImageAsync(string imageUrl)
{
return await SetConfigValueAsync(DisplayPageImageKey, imageUrl, "展示页长图URL");
}
/// <inheritdoc />
public async Task<string?> GetMemberIconAsync()
{