Files
mp-pilates/packages/app/src/pages/admin/index.vue

191 lines
5.3 KiB
Vue
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="page" :style="{ paddingTop: navBarHeight }">
<CustomNavBar title="管理中心" show-back />
<!-- Section: 课务运营 -->
<view class="section-header">
<text class="section-title">课务运营</text>
</view>
<view class="list">
<view class="list-item" @tap="navigate('/pages/admin/schedule')">
<text class="item-title">排课管理</text>
<text class="arrow-text"></text>
</view>
<view class="list-item" @tap="navigate('/pages/admin/bookings')">
<text class="item-title">预约管理</text>
<text class="arrow-text"></text>
</view>
</view>
<!-- Section: 教学复盘 -->
<view class="section-header">
<text class="section-title">教学复盘</text>
</view>
<view class="list">
<view class="list-item" @tap="navigate('/pages/admin/analytics')">
<text class="item-title">统计分析</text>
<text class="arrow-text"></text>
</view>
<view class="list-item" @tap="navigate('/pages/admin/reviews')">
<text class="item-title">课后评价</text>
<text class="arrow-text"></text>
</view>
</view>
<!-- Section: 会员与订单 -->
<view class="section-header">
<text class="section-title">会员与订单</text>
</view>
<view class="list">
<view class="list-item" @tap="navigate('/pages/admin/members')">
<text class="item-title">会员管理</text>
<text class="arrow-text"></text>
</view>
<view class="list-item" @tap="navigate('/pages/admin/orders')">
<text class="item-title">订单管理</text>
<text class="arrow-text"></text>
</view>
</view>
<!-- Section: 系统设置 -->
<view class="section-header">
<text class="section-title">系统设置</text>
</view>
<view class="list">
<view class="list-item" @tap="navigate('/pages/admin/card-types')">
<text class="item-title">卡种管理</text>
<text class="arrow-text"></text>
</view>
<view class="list-item" @tap="navigate('/pages/admin/studio')">
<text class="item-title">工作室设置</text>
<text class="arrow-text"></text>
</view>
<view class="list-item" @tap="handleIncreaseSubscriptionCount">
<text class="item-title">增加订阅次数</text>
<text class="item-extra">剩余 {{ user?.adminBookingSubscriptionCount ?? 0 }} </text>
<text class="arrow-text">{{ adminSubscribeLoading ? '...' : '' }}</text>
</view>
</view>
<view style="height: 40rpx" />
</view>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { storeToRefs } from 'pinia'
import CustomNavBar from '../../components/CustomNavBar.vue'
import { getSystemLayout } from '../../utils/system'
import { useUserStore } from '../../stores/user'
import { requestAdminBookingSubscriptionCount } from '../../utils/wechat-subscription'
import { getErrorMessage } from '../../utils/auth'
const navBarHeight = ref('64px')
const userStore = useUserStore()
const { user } = storeToRefs(userStore)
const adminSubscribeLoading = ref(false)
function navigate(path: string) {
uni.navigateTo({ url: path })
}
async function handleIncreaseSubscriptionCount() {
if (adminSubscribeLoading.value) {
return
}
adminSubscribeLoading.value = true
try {
const profile = await requestAdminBookingSubscriptionCount()
if (!profile) {
uni.showToast({ title: '已取消本次授权', icon: 'none' })
return
}
userStore.setProfile(profile)
uni.showToast({ title: `订阅次数 +1剩余 ${profile.adminBookingSubscriptionCount}`, icon: 'none' })
} catch (err: unknown) {
uni.showToast({ title: getErrorMessage(err, '订阅授权失败'), icon: 'none' })
} finally {
adminSubscribeLoading.value = false
}
}
onMounted(() => {
navBarHeight.value = `${getSystemLayout().navBarHeight}px`
userStore.fetchProfile()
})
</script>
<style lang="scss" scoped>
/* ── Page ───────────────────────── */
.page {
min-height: 100vh;
padding-bottom: 40rpx;
}
/* ── Section header ───────────────── */
.section-header {
padding: 32rpx 24rpx 12rpx;
}
.section-title {
font-size: 22rpx;
font-weight: 600;
color: #A09080;
letter-spacing: 2rpx;
text-transform: uppercase;
}
/* ── List ───────────────────────── */
.list {
background: #FFFFFF;
margin: 0 24rpx;
border-radius: 20rpx;
overflow: hidden;
box-shadow: 0 4rpx 20rpx rgba(180, 160, 130, 0.08);
border: 1rpx solid rgba(180, 160, 130, 0.1);
}
.list-item {
display: flex;
align-items: center;
gap: 16rpx;
padding: 32rpx 28rpx;
border-bottom: 1rpx solid rgba(180, 160, 130, 0.1);
transition: background 0.15s ease;
&:last-child {
border-bottom: none;
}
&:active {
background: rgba(180, 160, 130, 0.05);
}
}
.item-title {
flex: 1;
font-size: 30rpx;
font-weight: 500;
color: #4A4035;
letter-spacing: 0.5rpx;
}
.item-extra {
font-size: 24rpx;
color: #A09080;
flex-shrink: 0;
}
.arrow-text {
flex-shrink: 0;
font-size: 36rpx;
color: rgba(180, 160, 130, 0.5);
font-weight: 300;
line-height: 1;
}
</style>