322 lines
15 KiB
Plaintext
322 lines
15 KiB
Plaintext
<template>
|
|
<view class="admin-decoration-user">
|
|
<!-- 顶部标题与保存按钮 -->
|
|
<view class="page-header border-shadow">
|
|
<view class="header-left">
|
|
<text class="page-title">个人中心装修</text>
|
|
</view>
|
|
<view class="header-right">
|
|
<view class="btn-primary" @click="handleSave">
|
|
<text class="btn-txt">{{ isSaving ? '保存中...' : '保存配置' }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 主要内容区 -->
|
|
<view class="content-container anim-fade-in">
|
|
<view v-if="isLoading" class="loading-state">
|
|
<text>配置加载中...</text>
|
|
</view>
|
|
<view v-else class="main-card border-shadow">
|
|
<!-- 左侧:手机预览 -->
|
|
<view class="preview-panel">
|
|
<view class="phone-mockup">
|
|
<scroll-view class="phone-body" :scroll-y="true">
|
|
|
|
<!-- 样式1 & 样式2 头部 -->
|
|
<view v-if="selectedStyle === 1 || selectedStyle === 2" class="user-header-gradient">
|
|
<view class="header-top">
|
|
<view class="avatar-box">
|
|
<image class="avatar-img" src="/static/logo.png" mode="aspectFill"></image>
|
|
</view>
|
|
<view class="user-info">
|
|
<text class="user-name">演示用户</text>
|
|
<view class="bind-phone">
|
|
<text class="bind-txt">绑定手机号 ></text>
|
|
</view>
|
|
</view>
|
|
<view class="header-icons">
|
|
<view class="ic-msg">🔔</view>
|
|
<view class="ic-set">⚙️</view>
|
|
</view>
|
|
</view>
|
|
<view class="stats-row">
|
|
<view class="stat-item">
|
|
<text class="stat-val">88.00</text>
|
|
<text class="stat-label">我的余额</text>
|
|
</view>
|
|
<view class="stat-item">
|
|
<text class="stat-val">1200</text>
|
|
<text class="stat-label">当前积分</text>
|
|
</view>
|
|
<view class="stat-item">
|
|
<text class="stat-val">5</text>
|
|
<text class="stat-label">优惠券</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 样式1 会员卡 -->
|
|
<view v-if="selectedStyle === 1" class="member-card-s1">
|
|
<view class="mc-content-s1">
|
|
<view class="mc-left">
|
|
<text class="mc-ic">👑</text>
|
|
<text class="mc-txt">尊贵会员服务</text>
|
|
</view>
|
|
<view class="mc-right">
|
|
<text class="mc-btn">立即续费 ></text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 样式2 会员卡 -->
|
|
<view v-if="selectedStyle === 2" class="member-card-s2">
|
|
<view class="mc-content-s2">
|
|
<view class="mc-left">
|
|
<text class="mc-ic">👑</text>
|
|
<view class="mc-info-col">
|
|
<text class="mc-t1">会员可享多项权益</text>
|
|
</view>
|
|
</view>
|
|
<view class="mc-right">
|
|
<text class="mc-btn-white">立即续费 ></text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 样式3 头部 -->
|
|
<view v-if="selectedStyle === 3" class="user-header-s3">
|
|
<view class="header-top-s3">
|
|
<view class="header-top-left">
|
|
<view class="avatar-box-s3">
|
|
<image class="avatar-img" src="/static/logo.png" mode="aspectFill"></image>
|
|
</view>
|
|
<view class="user-info-s3">
|
|
<text class="user-name-s3">演示用户</text>
|
|
</view>
|
|
</view>
|
|
<view class="header-icons-s3">
|
|
<view class="ic-msg-s3">🔔</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="stats-row-s3">
|
|
<view class="stat-item">
|
|
<text class="stat-val-s3">88.00</text>
|
|
<text class="stat-label-s3">余额</text>
|
|
</view>
|
|
<view class="stat-item">
|
|
<text class="stat-val-s3">1200</text>
|
|
<text class="stat-label-s3">积分</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 公共部分:订单中心 -->
|
|
<view class="section-card">
|
|
<view class="section-header">
|
|
<text class="sh-title">订单中心</text>
|
|
<text class="sh-more">查看全部 ></text>
|
|
</view>
|
|
<view class="order-grid">
|
|
<view class="grid-item" v-for="(item, index) in orderItems" :key="index">
|
|
<text class="gi-ic">{{ item.icon }}</text>
|
|
<text class="gi-txt">{{ item.name }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 我的服务 -->
|
|
<view class="section-card">
|
|
<view class="section-header">
|
|
<text class="sh-title">我的服务</text>
|
|
</view>
|
|
<view class="service-grid">
|
|
<view class="grid-item-s" v-for="(item, index) in serviceItems" :key="index">
|
|
<view class="gi-ic-box-s" :style="{backgroundColor: item.color}">
|
|
<text class="gi-ic-s">{{ item.icon }}</text>
|
|
</view>
|
|
<text class="gi-txt-s">{{ item.name }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 右侧:设置面板 -->
|
|
<view class="settings-panel">
|
|
<view class="settings-group">
|
|
<view class="group-title">
|
|
<view class="title-line"></view>
|
|
<text class="title-txt">页面布局风格</text>
|
|
</view>
|
|
<view class="setting-item-row mt-20">
|
|
<view class="radio-group">
|
|
<view class="radio-item" @click="selectedStyle = 1">
|
|
<view :class="['radio-dot', selectedStyle === 1 ? 'active' : '']"></view>
|
|
<text class="radio-txt">样式1 (经典红)</text>
|
|
</view>
|
|
<view class="radio-item" @click="selectedStyle = 2">
|
|
<view :class="['radio-dot', selectedStyle === 2 ? 'active' : '']"></view>
|
|
<text class="radio-txt">样式2 (通透卡片)</text>
|
|
</view>
|
|
<view class="radio-item" @click="selectedStyle = 3">
|
|
<view :class="['radio-dot', selectedStyle === 3 ? 'active' : '']"></view>
|
|
<text class="radio-txt">样式3 (简约白)</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<text class="hint-txt">选择风格后点击右上角“保存”生效,该配置将同步至移动端个人中心页面。</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="uts">
|
|
import { ref, onMounted } from 'vue'
|
|
import { getActiveDiyConfig, saveDiyPage, type DiyPage } from '@/services/admin/decorationService.uts'
|
|
|
|
const selectedStyle = ref(1)
|
|
const isLoading = ref(false)
|
|
const isSaving = ref(false)
|
|
const currentPageId = ref<string | null>(null)
|
|
|
|
const orderItems = [
|
|
{ name: '待付款', icon: '💳' },
|
|
{ name: '待发货', icon: '🚚' },
|
|
{ name: '待收货', icon: '📦' },
|
|
{ name: '待评价', icon: '📝' }
|
|
]
|
|
|
|
const serviceItems = [
|
|
{ name: '积分中心', icon: '🪙', color: '#E6FFFB' },
|
|
{ name: '联系客服', icon: '🎧', color: '#F0F5FF' },
|
|
{ name: '优惠券', icon: '🎫', color: '#FFF1F0' },
|
|
{ name: '我的收藏', icon: '⭐', color: '#FFF2E8' },
|
|
{ name: '地址信息', icon: '📍', color: '#F9F0FF' },
|
|
{ name: '我的余额', icon: '💰', color: '#FCFFE6' }
|
|
]
|
|
|
|
onMounted(() => {
|
|
loadConfig()
|
|
})
|
|
|
|
async function loadConfig() {
|
|
isLoading.value = true
|
|
try {
|
|
const config = await getActiveDiyConfig('user')
|
|
if (config != null) {
|
|
currentPageId.value = config.id
|
|
const style = config.config.getNumber('style')
|
|
if (style != null) {
|
|
selectedStyle.value = style.toInt()
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.error('Failed to load user decoration config', e)
|
|
} finally {
|
|
isLoading.value = false
|
|
}
|
|
}
|
|
|
|
const handleSave = async () => {
|
|
isSaving.value = true
|
|
try {
|
|
const config = { style: selectedStyle.value } as UTSJSONObject
|
|
const id = await saveDiyPage(currentPageId.value, '个人中心默认配置', 'user', config, true)
|
|
if (id != null) {
|
|
currentPageId.value = id
|
|
uni.showToast({ title: '保存成功', icon: 'success' })
|
|
}
|
|
} catch (e) {
|
|
uni.showToast({ title: '保存失败', icon: 'none' })
|
|
} finally {
|
|
isSaving.value = false
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.admin-decoration-user { background-color: #f0f2f5; min-height: 100vh; 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-primary { background-color: #2d8cf0; padding: 8px 20px; border-radius: 4px; cursor: pointer; }
|
|
.btn-txt { color: #fff; font-size: 14px; }
|
|
.content-container { flex: 1; padding: 24px; }
|
|
.main-card { display: flex; flex-direction: row; min-height: 720px; background-color: #fff; border-radius: 4px; }
|
|
.loading-state { padding: 100px; text-align: center; color: #999; }
|
|
|
|
/* 左侧预览区 */
|
|
.preview-panel { width: 400px; padding: 40px; background-color: #f7f8fa; display: flex; justify-content: center; border-right: 1px solid #f0f0f0; }
|
|
.phone-mockup { width: 300px; height: 600px; background-color: #f5f5f5; border: 1px solid #ddd; border-radius: 8px; overflow: hidden; box-shadow: 0 10px 30px rgba(0,0,0,0.1); }
|
|
.phone-body { height: 100%; }
|
|
|
|
.user-header-gradient { background: linear-gradient(135deg, #eb3c2d 0%, #ff5e5e 100%); padding: 25px 0 12px; }
|
|
.header-top { display: flex; flex-direction: row; align-items: center; padding: 0 15px; }
|
|
.avatar-box { width: 44px; height: 44px; border-radius: 22px; border: 2px solid rgba(255,255,255,0.8); overflow: hidden; margin-right: 12px; }
|
|
.avatar-img { width: 100%; height: 100%; }
|
|
.user-info { flex: 1; display: flex; flex-direction: column; }
|
|
.user-name { font-size: 14px; font-weight: bold; color: #fff; }
|
|
.bind-phone { background-color: rgba(0,0,0,0.15); align-self: flex-start; padding: 2px 8px; border-radius: 10px; margin-top: 4px; }
|
|
.bind-txt { color: #fff; font-size: 9px; }
|
|
.header-icons { display: flex; flex-direction: row; gap: 12px; padding: 0 15px; color: #fff; font-size: 16px; }
|
|
|
|
.stats-row { display: flex; flex-direction: row; justify-content: space-around; padding: 15px; }
|
|
.stat-item { display: flex; flex-direction: column; align-items: center; }
|
|
.stat-val { font-size: 15px; font-weight: bold; color: #fff; }
|
|
.stat-label { font-size: 10px; color: rgba(255,255,255,0.8); margin-top: 2px; }
|
|
|
|
.member-card-s1 { background: linear-gradient(90deg, #fdf1d6 0%, #fbd795 100%); margin: 0 10px; border-radius: 8px; padding: 12px; }
|
|
.mc-content-s1 { display: flex; flex-direction: row; justify-content: space-between; align-items: center; }
|
|
.mc-txt { font-size: 11px; color: #7c581c; }
|
|
.mc-btn { font-size: 10px; color: #7c581c; font-weight: bold; }
|
|
|
|
.member-card-s2 { background-color: rgba(255,255,255,0.2); margin: 0 10px; border-radius: 8px; padding: 12px; border: 1px solid rgba(255,255,255,0.3); }
|
|
.mc-content-s2 { display: flex; flex-direction: row; justify-content: space-between; align-items: center; }
|
|
.mc-t1 { font-size: 11px; color: #fff; }
|
|
.mc-btn-white { background-color: #fff; color: #f2270c; font-size: 10px; padding: 3px 10px; border-radius: 10px; }
|
|
|
|
.user-header-s3 { background-color: #fff; padding: 25px 15px 15px; }
|
|
.header-top-s3 { display: flex; flex-direction: row; justify-content: space-between; align-items: center; }
|
|
.header-top-left { display: flex; flex-direction: row; align-items: center; }
|
|
.avatar-box-s3 { width: 48px; height: 44px; border-radius: 24px; overflow: hidden; margin-right: 12px; background: #f5f5f5; }
|
|
.user-name-s3 { font-size: 15px; font-weight: bold; color: #333; }
|
|
.header-icons-s3 { color: #333; font-size: 18px; }
|
|
.stats-row-s3 { display: flex; flex-direction: row; justify-content: space-around; padding-top: 15px; border-top: 1px solid #f5f5f5; margin-top: 15px; }
|
|
.stat-val-s3 { font-size: 16px; font-weight: bold; color: #333; }
|
|
.stat-label-s3 { font-size: 11px; color: #999; }
|
|
|
|
.section-card { background-color: #fff; margin: 10px; border-radius: 8px; padding: 15px; }
|
|
.section-header { display: flex; flex-direction: row; justify-content: space-between; margin-bottom: 12px; }
|
|
.sh-title { font-size: 13px; font-weight: bold; }
|
|
.sh-more { font-size: 11px; color: #999; }
|
|
.order-grid { display: flex; flex-direction: row; justify-content: space-between; }
|
|
.grid-item { display: flex; flex-direction: column; align-items: center; }
|
|
.gi-ic { font-size: 20px; margin-bottom: 4px; }
|
|
.gi-txt { font-size: 10px; color: #666; }
|
|
|
|
.service-grid { display: flex; flex-direction: row; flex-wrap: wrap; }
|
|
.grid-item-s { width: 33.33%; display: flex; flex-direction: column; align-items: center; margin-bottom: 15px; }
|
|
.gi-ic-box-s { width: 34px; height: 34px; border-radius: 17px; display: flex; align-items: center; justify-content: center; margin-bottom: 6px; }
|
|
.gi-txt-s { font-size: 10px; color: #666; }
|
|
|
|
/* 右侧设置区 */
|
|
.settings-panel { flex: 1; padding: 30px; }
|
|
.group-title { display: flex; flex-direction: row; align-items: center; margin-bottom: 20px; }
|
|
.title-line { width: 3px; height: 16px; background-color: #2d8cf0; margin-right: 10px; }
|
|
.title-txt { font-size: 15px; font-weight: bold; color: #333; }
|
|
.radio-group { display: flex; flex-direction: column; gap: 15px; }
|
|
.radio-item { display: flex; flex-direction: row; align-items: center; cursor: pointer; }
|
|
.radio-dot { width: 16px; height: 16px; border: 1px solid #dcdfe6; border-radius: 8px; margin-right: 10px; }
|
|
.radio-dot.active { border-color: #2d8cf0; background-color: #2d8cf0; }
|
|
.radio-txt { font-size: 14px; color: #333; }
|
|
.hint-txt { font-size: 12px; color: #999; margin-top: 20px; line-height: 1.6; }
|
|
|
|
.anim-fade-in { animation: fadeIn 0.4s ease-out; }
|
|
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
|
|
</style>
|