Files
medical-mall/pages/mall/admin/decoration/data-config/index.uvue
2026-03-18 08:36:49 +08:00

262 lines
9.9 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="admin-data-config anim-fade-in">
<!-- 顶部标题 -->
<view class="page-header border-shadow">
<view class="header-left">
<text class="page-title">数据配置</text>
</view>
<view class="header-right">
<view class="btn-save" @click="handleSave">
<text class="save-txt">保存</text>
</view>
</view>
</view>
<!-- 主内容区:三栏布局 -->
<view class="main-content anim-fade-in">
<view class="card-container border-shadow">
<!-- A. 左栏:配置分类菜单 -->
<MenuSide
:categories="categories"
:activeKey="activeKey"
@change="k => activeKey = k"
/>
<!-- B. 中栏:手机预览 -->
<PhonePreview
:activeKey="activeKey"
:activeLabel="activeLabel"
:activeConfig="activeConfig"
/>
<!-- C. 右栏:配置表单 -->
<view class="settings-column">
<view class="settings-header">
<view class="title-marker"></view>
<text class="settings-title">{{ activeTitle }}</text>
</view>
<view class="settings-desc-box">
<text class="settings-desc">{{ activeCategory?.recommendSizeText }}</text>
</view>
<!-- 开屏广告特有字段 -->
<view v-if="activeKey === 'ad'" class="ad-special-fields">
<view class="form-row">
<text class="field-label">开启广告</text>
<switch :checked="activeConfig.enabled" @change="handleSwitchAd" color="#2d8cf0" />
</view>
<view class="form-row">
<text class="field-label">广告时间</text>
<view class="input-with-unit">
<input type="number" class="time-input" v-model="activeConfig.durationSeconds" />
<text class="unit-txt">单位(秒)</text>
</view>
</view>
</view>
<!-- 图片项编辑器 -->
<view v-if="activeKey !== 'ad' || activeConfig.enabled">
<CarouselEditor
:items="activeConfig.items"
:max="activeConfig.max"
@add="handleAddItem"
@remove="handleRemoveItem"
@move="handleMove"
@update-item="handleUpdateItem"
@select-link="handleSelectLink"
/>
</view>
<view v-else class="ad-disabled-placeholder">
<text class="disabled-txt">开屏广告已关闭,开启后可配置图片</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref, computed, reactive } from 'vue'
import { type Category, type ConfigData, type LinkType } from '@/pages/mall/admin/decoration/components/types.uts'
import MenuSide from '@/pages/mall/admin/decoration/components/MenuSide.uvue'
import PhonePreview from '@/pages/mall/admin/decoration/components/PhonePreview.uvue'
import CarouselEditor from '@/pages/mall/admin/decoration/components/CarouselEditor.uvue'
// 状态定义
const activeKey = ref('jingpin')
const categories = reactive<Category[]>([
{ key: 'jingpin', label: '首页精品推荐图片', type: 'carousel', recommendSizeText: '建议尺寸690 * 240px拖拽图片可调整图片顺序哦最多添加五张' },
{ key: 'hot', label: '热门榜单推荐图片', type: 'carousel', recommendSizeText: '建议尺寸690 * 240px拖拽图片可调整图片顺序哦最多添加五张' },
{ key: 'new', label: '首发新品推荐图片', type: 'carousel', recommendSizeText: '建议尺寸690 * 240px拖拽图片可调整图片顺序哦最多添加五张' },
{ key: 'promo', label: '促销单品推荐图片', type: 'carousel', recommendSizeText: '建议尺寸690 * 240px拖拽图片可调整图片顺序哦最多添加五张' },
{ key: 'login', label: '后台登录页面幻灯片', type: 'carousel', recommendSizeText: '建议尺寸690 * 240px拖拽图片可调整图片顺序哦最多添加五张' },
{ key: 'group', label: '拼团列表轮播图', type: 'carousel', recommendSizeText: '建议尺寸710 * 300px拖拽图片可调整图片顺序哦最多添加五张' },
{ key: 'points', label: '积分商城轮播图', type: 'carousel', recommendSizeText: '建议尺寸710 * 300px拖拽图片可调整图片顺序哦最多添加五张' },
{ key: 'ad', label: '开屏广告', type: 'ad', recommendSizeText: '建议尺寸750 * 1334px拖拽图片可调整图片顺序哦最多添加五张' }
])
// 初始化数据
const configMap = reactive<Record<string, ConfigData>>({
'jingpin': { max: 5, items: [{ id: 1, name: '1', imageUrl: '', link: { type: 'internal', value: '/pages/points_mall/integral_index' }, sort: 0 }] },
'hot': { max: 5, items: [{ id: 1, name: '1', imageUrl: '', link: { type: 'internal', value: '/pages/index/index' }, sort: 0 }] },
'new': { max: 5, items: [{ id: 1, name: '1', imageUrl: '', link: { type: 'internal', value: '/pages/index/index' }, sort: 0 }] },
'promo': { max: 5, items: [{ id: 1, name: '1', imageUrl: '', link: { type: 'internal', value: '/pages/points_mall/integral_index' }, sort: 0 }] },
'login': { max: 5, items: [{ id: 1, name: '1', imageUrl: '', link: { type: 'internal', value: '' }, sort: 0 }] },
'group': { max: 5, items: [{ id: 1, name: '拼团', imageUrl: '', link: { type: 'internal', value: '/pages/activity/goods_combination/index' }, sort: 0 }] },
'points': { max: 5, items: [{ id: 1, name: '1', imageUrl: '', link: { type: 'internal', value: '/pages/points_mall/integral_index' }, sort: 0 }] },
'ad': { enabled: false, durationSeconds: 3, max: 5, items: [] }
})
// 计算属性
const activeCategory = computed(() => categories.find(c => c.key === activeKey.value))
const activeLabel = computed(() => activeCategory.value?.label ?? '')
const activeConfig = computed(() => configMap[activeKey.value])
const activeTitle = computed(() => {
if (activeKey.value === 'ad') return '引导页设置'
if (activeKey.value === 'login') return '幻灯片设置'
return '轮播图设置'
})
// 方法
const handleSave = () => {
uni.showLoading({ title: '保存中...' })
setTimeout(() => {
uni.hideLoading()
uni.showToast({ title: '保存成功', icon: 'success' })
}, 800)
}
const handleSwitchAd = (e: any) => {
configMap['ad'].enabled = e.detail.value
}
const handleAddItem = () => {
const config = activeConfig.value
if (config.items.length >= config.max) {
uni.showToast({ title: `最多添加 ${config.max} 条`, icon: 'none' })
return
}
config.items.push({
id: Date.now(),
name: (config.items.length + 1).toString(),
imageUrl: '',
link: { type: 'internal', value: '' },
sort: config.items.length
})
}
const handleRemoveItem = (index: number) => {
activeConfig.value.items.splice(index, 1)
}
const handleMove = (index: number, direction: number) => {
const items = activeConfig.value.items
const targetIndex = index + direction
if (targetIndex < 0 || targetIndex >= items.length) return
const temp = items[index]
items[index] = items[targetIndex]
items[targetIndex] = temp
}
const handleUpdateItem = (payload: any) => {
const { index, key, value } = payload
activeConfig.value.items[index][key] = value
}
const handleSelectLink = (index: number) => {
uni.showActionSheet({
itemList: ['内部页面', '外部链接', '其他小程序'],
success: (res) => {
const types: LinkType[] = ['internal', 'external', 'miniProgram']
activeConfig.value.items[index].link.type = types[res.tapIndex]
uni.showToast({ title: '功能建设中', icon: 'none' })
}
})
}
</script>
<style scoped lang="scss">
.admin-data-config {
padding: 0;
background-color: transparent;
min-height: auto;
display: flex;
flex-direction: column;
}
.border-shadow {
background-color: #fff;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
}
.page-header {
height: 60px;
padding: 0 24px;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
z-index: 100;
}
.page-title { font-size: 16px; font-weight: bold; color: #333; }
.btn-save {
background-color: #2d8cf0;
padding: 6px 24px;
border-radius: 4px;
cursor: pointer;
}
.save-txt { color: #fff; font-size: 14px; }
.main-content {
flex: 1;
padding: 0;
margin-top: 20px;
}
.card-container {
display: flex;
flex-direction: row;
min-height: 800px;
background-color: #fff;
border-radius: 8px;
overflow: hidden;
}
/* 右侧设置 */
.settings-column {
flex: 1;
padding: 30px;
background-color: #fff;
}
.settings-header {
display: flex;
flex-direction: row;
align-items: center;
margin-bottom: 8px;
}
.title-marker { width: 3px; height: 16px; background-color: #1890ff; margin-right: 10px; border-radius: 2px; }
.settings-title { font-size: 16px; font-weight: bold; color: #333; }
.settings-desc-box { margin-bottom: 24px; padding-left: 13px; }
.settings-desc { font-size: 13px; color: #999; }
/* 开屏广告特有样式 */
.ad-special-fields { padding: 20px; background-color: #fff; border: 1px solid #f0f0f0; border-radius: 8px; margin-bottom: 20px; }
.form-row { display: flex; flex-direction: row; align-items: center; margin-bottom: 15px; }
.field-label { width: 80px; font-size: 14px; color: #333; }
.input-with-unit { display: flex; flex-direction: row; align-items: center; }
.time-input { width: 80px; height: 32px; border: 1px solid #dcdfe6; border-radius: 4px; padding: 0 10px; margin-right: 8px; background-color: #fff; }
.unit-txt { font-size: 12px; color: #999; }
.ad-disabled-placeholder { height: 200px; display: flex; align-items: center; justify-content: center; border: 1px dashed #eee; border-radius: 8px; }
.disabled-txt { color: #999; font-size: 14px; }
.anim-fade-in { animation: fadeIn 0.4s ease-out; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
</style>