feat(app): implement all sub-pages and admin management pages
Sub-pages: card purchase with WeChat Pay flow, my memberships with progress bars, my bookings with tabs, personal info editor Admin: management center grid, week template CRUD, slot adjustment, member management with search, order list with filters, card type CRUD with form modal, studio settings editor Admin Pinia store for all admin API calls
This commit is contained in:
@@ -21,7 +21,7 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Form card -->
|
||||
<!-- Basic info card -->
|
||||
<view class="form-card">
|
||||
<text class="form-card-title">基本信息</text>
|
||||
|
||||
@@ -150,10 +150,10 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { get, put } from '../../utils/request'
|
||||
import type { StudioConfig } from '@mp-pilates/shared'
|
||||
import { useAdminStore } from '../../stores/admin'
|
||||
|
||||
const adminStore = useAdminStore()
|
||||
|
||||
// Form state
|
||||
const form = ref({
|
||||
name: '',
|
||||
address: '',
|
||||
@@ -183,7 +183,7 @@ const bannerStyle = computed(() => {
|
||||
async function fetchStudioInfo() {
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await get<StudioConfig>('/studio/info')
|
||||
const data = await adminStore.fetchStudioConfig()
|
||||
const initial = {
|
||||
name: data.name ?? '',
|
||||
address: data.address ?? '',
|
||||
@@ -228,7 +228,7 @@ async function handleSave() {
|
||||
if (!isNaN(lat)) payload.latitude = lat
|
||||
if (!isNaN(lng)) payload.longitude = lng
|
||||
|
||||
await put('/admin/studio/info', payload)
|
||||
await adminStore.saveStudioConfig(payload as any)
|
||||
original.value = { ...form.value }
|
||||
uni.showToast({ title: '保存成功', icon: 'success' })
|
||||
} catch (e: any) {
|
||||
@@ -249,10 +249,7 @@ onMounted(fetchStudioInfo)
|
||||
}
|
||||
|
||||
/* ── Skeleton ────────────────────────────── */
|
||||
.skeleton-page {
|
||||
padding: 0 24rpx;
|
||||
padding-top: 280rpx;
|
||||
}
|
||||
.skeleton-page { padding: 0 24rpx; padding-top: 280rpx; }
|
||||
|
||||
.skeleton-section {
|
||||
height: 200rpx;
|
||||
@@ -277,7 +274,7 @@ onMounted(fetchStudioInfo)
|
||||
.banner-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
background: rgba(0,0,0,0.35);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@@ -290,13 +287,10 @@ onMounted(fetchStudioInfo)
|
||||
height: 96rpx;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
border: 4rpx solid rgba(255, 255, 255, 0.4);
|
||||
border: 4rpx solid rgba(255,255,255,0.4);
|
||||
}
|
||||
|
||||
.banner-logo {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
}
|
||||
.banner-logo { width: 96rpx; height: 96rpx; }
|
||||
|
||||
.banner-logo-placeholder {
|
||||
width: 100%;
|
||||
@@ -307,17 +301,9 @@ onMounted(fetchStudioInfo)
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.banner-logo-text {
|
||||
font-size: 40rpx;
|
||||
font-weight: 700;
|
||||
color: #1a1a2e;
|
||||
}
|
||||
.banner-logo-text { font-size: 40rpx; font-weight: 700; color: #1a1a2e; }
|
||||
|
||||
.banner-name {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
}
|
||||
.banner-name { font-size: 32rpx; font-weight: 700; color: #ffffff; }
|
||||
|
||||
/* ── Form card ───────────────────────────── */
|
||||
.form-card {
|
||||
@@ -325,7 +311,7 @@ onMounted(fetchStudioInfo)
|
||||
border-radius: 20rpx;
|
||||
margin: 24rpx 24rpx 0;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.form-card-title {
|
||||
@@ -345,9 +331,7 @@ onMounted(fetchStudioInfo)
|
||||
padding: 28rpx;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
|
||||
&--last {
|
||||
border-bottom: none;
|
||||
}
|
||||
&--last { border-bottom: none; }
|
||||
}
|
||||
|
||||
.form-label {
|
||||
@@ -365,10 +349,7 @@ onMounted(fetchStudioInfo)
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.label-group {
|
||||
width: 240rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.label-group { width: 240rpx; flex-shrink: 0; }
|
||||
|
||||
.form-input {
|
||||
flex: 1;
|
||||
@@ -385,9 +366,7 @@ onMounted(fetchStudioInfo)
|
||||
}
|
||||
|
||||
/* ── Save button ─────────────────────────── */
|
||||
.save-wrap {
|
||||
padding: 40rpx 24rpx;
|
||||
}
|
||||
.save-wrap { padding: 40rpx 24rpx; }
|
||||
|
||||
.save-btn {
|
||||
width: 100%;
|
||||
@@ -397,7 +376,7 @@ onMounted(fetchStudioInfo)
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 4rpx 20rpx rgba(26, 26, 46, 0.3);
|
||||
box-shadow: 0 4rpx 20rpx rgba(26,26,46,0.3);
|
||||
|
||||
&:active { opacity: 0.85; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user