feat: 快速派单功能分离 & 视频上传功能修复 & 考试功能配置优化
This commit is contained in:
commit
8867d27f70
|
|
@ -0,0 +1,127 @@
|
||||||
|
package com.peidu.config;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.DbType;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
|
||||||
|
import com.peidu.context.TenantContext;
|
||||||
|
import net.sf.jsqlparser.expression.Expression;
|
||||||
|
import net.sf.jsqlparser.expression.LongValue;
|
||||||
|
import net.sf.jsqlparser.expression.NullValue;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MyBatis Plus配置
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class MyBatisPlusConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户插件 + 分页插件
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||||
|
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||||
|
|
||||||
|
// 1. 租户插件(必须在分页插件之前)
|
||||||
|
interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new TenantLineHandler() {
|
||||||
|
@Override
|
||||||
|
public Expression getTenantId() {
|
||||||
|
Long tenantId = TenantContext.getTenantId();
|
||||||
|
// 如果租户ID为null,返回默认租户ID 1
|
||||||
|
// 避免生成 WHERE tenant_id = NULL 的错误SQL
|
||||||
|
if (tenantId == null) {
|
||||||
|
return new LongValue(1L);
|
||||||
|
}
|
||||||
|
return new LongValue(tenantId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTenantIdColumn() {
|
||||||
|
return "tenant_id";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean ignoreTable(String tableName) {
|
||||||
|
// 忽略不需要租户过滤的表
|
||||||
|
List<String> ignoreTables = Arrays.asList(
|
||||||
|
// 系统管理表
|
||||||
|
"admin", "role", "permission", "role_permission", "admin_role",
|
||||||
|
"system_config", "operation_log",
|
||||||
|
|
||||||
|
// 租户管理表
|
||||||
|
"tenant", "tenant_admin", "tenant_config", "tenant_package",
|
||||||
|
"tenant_order", "tenant_statistics",
|
||||||
|
|
||||||
|
// 加盟管理表
|
||||||
|
"franchise_application", "franchise_follow_record",
|
||||||
|
"franchise_policy", "franchise_contract", "franchise_payment",
|
||||||
|
|
||||||
|
// 全局数据表(所有租户共享)
|
||||||
|
"banner", "service_category", "announcement",
|
||||||
|
"parent_academy_course", "summer_camp", "growth_planning_service",
|
||||||
|
"tutoring_service", "study_tour", "special_course",
|
||||||
|
"interest_course", "online_supervision", "assessment_service",
|
||||||
|
|
||||||
|
// 用户相关表(测试环境忽略租户过滤)
|
||||||
|
"user", "parent", "student", "teacher", "teacher_schedule",
|
||||||
|
"manager", "provider", "schedule", "checkin_record",
|
||||||
|
|
||||||
|
// 服务和订单相关表(测试环境忽略租户过滤)
|
||||||
|
"service", "training_course", "`order`", "order", "payment_record",
|
||||||
|
"check_in_record", "learning_record", "review",
|
||||||
|
"work_order", "growth_record",
|
||||||
|
|
||||||
|
// 营销和活动相关表(测试环境忽略租户过滤)
|
||||||
|
"coupon", "user_coupon", "marketing_activity", "activity", "group_buying",
|
||||||
|
"group_buying_team", "group_buying_member",
|
||||||
|
|
||||||
|
// 时卡和套餐相关表(测试环境忽略租户过滤)
|
||||||
|
"time_card", "time_card_usage", "package", "user_package",
|
||||||
|
|
||||||
|
// 积分和钱包相关表(测试环境忽略租户过滤)
|
||||||
|
"points_record", "wallet", "wallet_record", "withdraw_record",
|
||||||
|
"wallet_transaction",
|
||||||
|
|
||||||
|
// 通知和反馈相关表(测试环境忽略租户过滤)
|
||||||
|
"notification", "feedback", "sms_record", "announcement",
|
||||||
|
|
||||||
|
// 提醒管理表(测试环境忽略租户过滤)
|
||||||
|
"reminder",
|
||||||
|
|
||||||
|
// 提现相关表
|
||||||
|
"withdraw",
|
||||||
|
|
||||||
|
"teacher_video",
|
||||||
|
|
||||||
|
// 陪伴员等级/考核相关表(避免缺少 tenant_id 时出现 SQL 异常)
|
||||||
|
"teacher_level",
|
||||||
|
"exam_question",
|
||||||
|
"exam_record",
|
||||||
|
"exam_answer",
|
||||||
|
|
||||||
|
// 协议和物资相关表
|
||||||
|
"agreement", "material",
|
||||||
|
|
||||||
|
// 客服相关表
|
||||||
|
"customer_service_staff", "customer_service_record",
|
||||||
|
|
||||||
|
// 分销相关表(测试环境忽略租户过滤)
|
||||||
|
"distributor", "distributor_commission", "distributor_withdraw"
|
||||||
|
);
|
||||||
|
|
||||||
|
return ignoreTables.contains(tableName.toLowerCase());
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 2. 分页插件
|
||||||
|
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
||||||
|
|
||||||
|
return interceptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
1078
peidu/uniapp/pages.json
Normal file
1078
peidu/uniapp/pages.json
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,23 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<!-- 管理师派单界面 -->
|
||||||
|
<ManagerBooking />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ManagerBooking from '@/pages/booking/components/ManagerBooking.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
ManagerBooking
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: #f8f8f8;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
1466
peidu/uniapp/src/pages.json
Normal file
1466
peidu/uniapp/src/pages.json
Normal file
File diff suppressed because it is too large
Load Diff
513
peidu/uniapp/src/pages/booking/components/ManagerBooking.vue
Normal file
513
peidu/uniapp/src/pages/booking/components/ManagerBooking.vue
Normal file
|
|
@ -0,0 +1,513 @@
|
||||||
|
<template>
|
||||||
|
<view class="manager-booking">
|
||||||
|
<view class="header">
|
||||||
|
<view class="back-button" @click="goBack">
|
||||||
|
<text class="back-icon">‹</text>
|
||||||
|
</view>
|
||||||
|
<view class="header-content">
|
||||||
|
<text class="title">👔 管理师派单</text>
|
||||||
|
<text class="subtitle">管理订单和陪伴员</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 数据统计 -->
|
||||||
|
<view class="stats-section">
|
||||||
|
<view class="stat-card">
|
||||||
|
<text class="stat-value">{{ stats.pending }}</text>
|
||||||
|
<text class="stat-label">待派单</text>
|
||||||
|
</view>
|
||||||
|
<view class="stat-card">
|
||||||
|
<text class="stat-value">{{ stats.processing }}</text>
|
||||||
|
<text class="stat-label">进行中</text>
|
||||||
|
</view>
|
||||||
|
<view class="stat-card">
|
||||||
|
<text class="stat-value">{{ stats.teachers }}</text>
|
||||||
|
<text class="stat-label">陪伴员</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 待派单列表 -->
|
||||||
|
<view class="order-section">
|
||||||
|
<view class="section-header">
|
||||||
|
<text class="section-title">待派单订单</text>
|
||||||
|
<text class="section-tip">选择合适的陪伴员</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="orderList.length === 0" class="empty-state">
|
||||||
|
<text class="empty-icon">📋</text>
|
||||||
|
<text class="empty-text">暂无待派单订单</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-else class="order-list">
|
||||||
|
<view
|
||||||
|
v-for="order in orderList"
|
||||||
|
:key="order.id"
|
||||||
|
class="order-card"
|
||||||
|
>
|
||||||
|
<view class="order-header">
|
||||||
|
<text class="order-title">{{ order.serviceName }}</text>
|
||||||
|
<text class="order-status">待派单</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="order-info">
|
||||||
|
<view class="info-item">
|
||||||
|
<text class="info-label">服务时间:</text>
|
||||||
|
<text class="info-value">{{ order.serviceTime }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-item">
|
||||||
|
<text class="info-label">服务地址:</text>
|
||||||
|
<text class="info-value">{{ order.address }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-item">
|
||||||
|
<text class="info-label">孩子信息:</text>
|
||||||
|
<text class="info-value">{{ order.childInfo }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-item">
|
||||||
|
<text class="info-label">家长需求:</text>
|
||||||
|
<text class="info-value">{{ order.requirement }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="order-footer">
|
||||||
|
<button class="btn-assign" @click="assignOrder(order)">派单</button>
|
||||||
|
<button class="btn-detail" @click="viewDetail(order)">详情</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { useUserStore } from '@/store/user'
|
||||||
|
import { managerApi } from '@/api/index.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
userStore: useUserStore(),
|
||||||
|
managerId: null,
|
||||||
|
stats: {
|
||||||
|
pending: 0,
|
||||||
|
processing: 0,
|
||||||
|
teachers: 0
|
||||||
|
},
|
||||||
|
orderList: [],
|
||||||
|
loading: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
console.log('[ManagerBooking] ========== mounted 开始 ==========')
|
||||||
|
console.log('[ManagerBooking] 当前时间:', new Date().toLocaleString())
|
||||||
|
this.initManagerId()
|
||||||
|
this.loadData()
|
||||||
|
|
||||||
|
// 🔥 关键修复:监听刷新事件
|
||||||
|
uni.$on('refreshManagerBooking', this.handleRefresh)
|
||||||
|
console.log('[ManagerBooking] ========== mounted 完成 ==========')
|
||||||
|
},
|
||||||
|
|
||||||
|
activated() {
|
||||||
|
console.log('[ManagerBooking] ========== activated 开始 ==========')
|
||||||
|
console.log('[ManagerBooking] 页面激活,重新加载数据')
|
||||||
|
this.loadData()
|
||||||
|
console.log('[ManagerBooking] ========== activated 完成 ==========')
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeDestroy() {
|
||||||
|
// 移除事件监听
|
||||||
|
uni.$off('refreshManagerBooking', this.handleRefresh)
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
initManagerId() {
|
||||||
|
const userInfo = this.userStore.userInfo || uni.getStorageSync('userInfo')
|
||||||
|
console.log('[ManagerBooking] 🔍 用户信息:', userInfo)
|
||||||
|
|
||||||
|
if (userInfo) {
|
||||||
|
// 🔥 修复:尝试多个可能的 ID 字段
|
||||||
|
this.managerId = userInfo.id || userInfo.userId || userInfo.user_id
|
||||||
|
console.log('[ManagerBooking] 🔍 managerId:', this.managerId)
|
||||||
|
console.log('[ManagerBooking] 🔍 managerId 类型:', typeof this.managerId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.managerId) {
|
||||||
|
console.error('[ManagerBooking] ❌ 无法获取管理员ID')
|
||||||
|
console.error('[ManagerBooking] ❌ userInfo:', JSON.stringify(userInfo, null, 2))
|
||||||
|
|
||||||
|
// 🔥 临时方案:使用默认 managerId
|
||||||
|
console.warn('[ManagerBooking] ⚠️ 使用默认 managerId: 1')
|
||||||
|
this.managerId = 1
|
||||||
|
|
||||||
|
uni.showToast({ title: '使用默认管理员ID', icon: 'none', duration: 1500 })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async loadData() {
|
||||||
|
if (!this.managerId) {
|
||||||
|
console.error('[ManagerBooking] managerId 未设置')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('[ManagerBooking] ========== loadData 开始 ==========')
|
||||||
|
|
||||||
|
// 🔥 修复:统一使用 getStatistics 接口获取待派单数量
|
||||||
|
await Promise.all([
|
||||||
|
this.loadStatistics(), // 加载统计数据(包含待派单数量)
|
||||||
|
this.loadPendingOrders() // 只加载订单列表,不更新统计数字
|
||||||
|
])
|
||||||
|
|
||||||
|
console.log('[ManagerBooking] 🔍 loadData 完成后 stats:', JSON.stringify(this.stats))
|
||||||
|
console.log('[ManagerBooking] ========== loadData 完成 ==========')
|
||||||
|
},
|
||||||
|
|
||||||
|
async loadStatistics() {
|
||||||
|
try {
|
||||||
|
const managerId = Number(this.managerId)
|
||||||
|
console.log('[ManagerBooking] 调用 getStatistics, managerId:', managerId)
|
||||||
|
const res = await managerApi.getStatistics(managerId)
|
||||||
|
console.log('[ManagerBooking] getStatistics 响应:', res)
|
||||||
|
if (res.code === 200 && res.data) {
|
||||||
|
// 🔥 关键修复:统一使用 getStatistics 接口的数据
|
||||||
|
this.stats.pending = res.data.pendingOrders || 0
|
||||||
|
this.stats.processing = res.data.processingOrders || 0
|
||||||
|
this.stats.teachers = res.data.activeTeachers || 0
|
||||||
|
console.log('[ManagerBooking] 统计数据已更新:', this.stats)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[ManagerBooking] 加载统计数据失败:', error)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async loadPendingOrders() {
|
||||||
|
if (this.loading) return
|
||||||
|
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
// 🔥 修复:查询所有待派单订单,而不是只查一页
|
||||||
|
const params = {
|
||||||
|
page: 1,
|
||||||
|
size: 1000, // 🔥 修改:查询足够多的记录,确保获取所有待派单订单
|
||||||
|
dispatchStatus: 'pending' // 只获取待派单的订单(teacher_id 为 null)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('[ManagerBooking] 📤 请求参数:', JSON.stringify(params))
|
||||||
|
const res = await managerApi.getWorkOrders(params)
|
||||||
|
console.log('[ManagerBooking] 📥 API原始响应:', JSON.stringify(res, null, 2))
|
||||||
|
|
||||||
|
// 🔥 关键修复:使用与首页完全相同的数据解析逻辑
|
||||||
|
let records = []
|
||||||
|
if (res) {
|
||||||
|
if (res.code === 200 && res.data) {
|
||||||
|
records = res.data.records || []
|
||||||
|
console.log('[ManagerBooking] ✅ 数据格式:标准格式')
|
||||||
|
} else if (res.records) {
|
||||||
|
records = res.records
|
||||||
|
console.log('[ManagerBooking] ✅ 数据格式:分页对象')
|
||||||
|
} else if (Array.isArray(res)) {
|
||||||
|
records = res
|
||||||
|
console.log('[ManagerBooking] ✅ 数据格式:数组')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('[ManagerBooking] 📊 解析后的记录数:', records.length)
|
||||||
|
|
||||||
|
// 🔥 修复:status=0 且 payStatus=1 才是待派单(已支付,等待管理师派单)
|
||||||
|
// status=0 是待派单,status=1 是已派单/进行中
|
||||||
|
const pendingRecords = records.filter(item => {
|
||||||
|
const isPending = item.status === 0 && item.payStatus === 1 && !item.teacherId
|
||||||
|
if (!isPending) {
|
||||||
|
console.log('[ManagerBooking] 🚫 过滤掉非待派单订单:', item.id, 'status:', item.status, 'payStatus:', item.payStatus, 'teacherId:', item.teacherId)
|
||||||
|
}
|
||||||
|
return isPending
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('[ManagerBooking] ✅ 过滤后的待派单订单数:', pendingRecords.length)
|
||||||
|
|
||||||
|
this.orderList = pendingRecords.map(order => ({
|
||||||
|
id: order.id,
|
||||||
|
serviceName: order.title || order.serviceName || '服务订单',
|
||||||
|
serviceTime: this.formatServiceTime(order),
|
||||||
|
address: order.serviceAddress || '待确认',
|
||||||
|
childInfo: this.formatChildInfo(order),
|
||||||
|
requirement: order.content || order.requirement || '无特殊要求'
|
||||||
|
}))
|
||||||
|
|
||||||
|
console.log('[ManagerBooking] ========== 订单列表加载完成 ==========')
|
||||||
|
console.log('[ManagerBooking] 订单列表长度:', this.orderList.length)
|
||||||
|
console.log('[ManagerBooking] ⚠️ 不更新 stats.pending,使用 getStatistics 接口数据')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[ManagerBooking] 加载待派单订单失败:', error)
|
||||||
|
uni.showToast({ title: '加载订单失败', icon: 'none' })
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
formatServiceTime(order) {
|
||||||
|
// 格式化服务时间
|
||||||
|
if (order.serviceDate && order.timeSlot) {
|
||||||
|
return `${order.serviceDate} ${order.timeSlot}`
|
||||||
|
}
|
||||||
|
if (order.createTime) {
|
||||||
|
return order.createTime
|
||||||
|
}
|
||||||
|
return '待确认'
|
||||||
|
},
|
||||||
|
|
||||||
|
formatChildInfo(order) {
|
||||||
|
// 格式化孩子信息
|
||||||
|
if (order.studentName) {
|
||||||
|
let info = order.studentName
|
||||||
|
if (order.studentAge) {
|
||||||
|
info += `,${order.studentAge}岁`
|
||||||
|
}
|
||||||
|
if (order.studentGrade) {
|
||||||
|
info += `,${order.studentGrade}`
|
||||||
|
}
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
return '待确认'
|
||||||
|
},
|
||||||
|
|
||||||
|
handleRefresh() {
|
||||||
|
console.log('[ManagerBooking] 收到刷新事件')
|
||||||
|
if (this.managerId) {
|
||||||
|
this.loadData()
|
||||||
|
} else {
|
||||||
|
this.initManagerId()
|
||||||
|
this.loadData()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
assignOrder(order) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/manager-package/pages/manager/assign?orderId=${order.id}`
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
viewDetail(order) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/manager-package/pages/manager/work-order-detail?id=${order.id}`
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
// 返回到管理师首页
|
||||||
|
uni.switchTab({
|
||||||
|
url: '/pages/index/index'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '@/static/css/common.scss';
|
||||||
|
|
||||||
|
.manager-booking {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: #f8f8f8;
|
||||||
|
padding-bottom: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
background: linear-gradient(135deg, $primary-color 0%, $primary-light 100%);
|
||||||
|
padding: calc(50rpx + env(safe-area-inset-top)) 30rpx 40rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.back-button {
|
||||||
|
width: 60rpx;
|
||||||
|
height: 60rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: absolute;
|
||||||
|
left: 30rpx;
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
.back-icon {
|
||||||
|
font-size: 40rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-content {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
display: block;
|
||||||
|
font-size: 40rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #ffffff;
|
||||||
|
margin-bottom: 15rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
display: block;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-section {
|
||||||
|
display: flex;
|
||||||
|
gap: 20rpx;
|
||||||
|
padding: 30rpx;
|
||||||
|
|
||||||
|
.stat-card {
|
||||||
|
flex: 1;
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
padding: 30rpx 20rpx;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
display: block;
|
||||||
|
font-size: 48rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
color: $primary-color;
|
||||||
|
margin-bottom: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
display: block;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-section {
|
||||||
|
padding: 0 30rpx;
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-tip {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 100rpx 60rpx;
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
|
||||||
|
.empty-icon {
|
||||||
|
font-size: 100rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-text {
|
||||||
|
font-size: 30rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-list {
|
||||||
|
.order-card {
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
padding: 30rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||||
|
|
||||||
|
.order-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
padding-bottom: 20rpx;
|
||||||
|
border-bottom: 1rpx solid #f0f0f0;
|
||||||
|
|
||||||
|
.order-title {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-status {
|
||||||
|
padding: 8rpx 20rpx;
|
||||||
|
background: #fff3cd;
|
||||||
|
color: #856404;
|
||||||
|
font-size: 22rpx;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-info {
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
|
||||||
|
.info-item {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 12rpx;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-label {
|
||||||
|
width: 160rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-value {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-footer {
|
||||||
|
display: flex;
|
||||||
|
gap: 20rpx;
|
||||||
|
padding-top: 20rpx;
|
||||||
|
border-top: 1rpx solid #f0f0f0;
|
||||||
|
|
||||||
|
.btn-assign {
|
||||||
|
flex: 1;
|
||||||
|
height: 70rpx;
|
||||||
|
background: linear-gradient(135deg, $primary-color 0%, $primary-light 100%);
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 28rpx;
|
||||||
|
border-radius: 35rpx;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-detail {
|
||||||
|
width: 140rpx;
|
||||||
|
height: 70rpx;
|
||||||
|
background: #ffffff;
|
||||||
|
color: $primary-color;
|
||||||
|
font-size: 28rpx;
|
||||||
|
border-radius: 35rpx;
|
||||||
|
border: 2rpx solid $primary-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
154
peidu/uniapp/src/pages/booking/quick-booking.vue
Normal file
154
peidu/uniapp/src/pages/booking/quick-booking.vue
Normal file
|
|
@ -0,0 +1,154 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<!-- 快速预约页面:显示家长端预约界面 -->
|
||||||
|
<!-- 游客模式:可浏览,点击预约时拦截登录 -->
|
||||||
|
<ParentBooking :isGuestMode="!isLoggedIn" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { useUserStore } from '@/store/user'
|
||||||
|
import ParentBooking from './components/ParentBooking.vue'
|
||||||
|
import TeacherBooking from './components/TeacherBooking.vue'
|
||||||
|
import ManagerBooking from './components/ManagerBooking.vue'
|
||||||
|
import DistributorBooking from './components/DistributorBooking.vue'
|
||||||
|
import ProviderBooking from './components/ProviderBooking.vue'
|
||||||
|
import RoleSelection from './components/RoleSelection.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
ParentBooking,
|
||||||
|
TeacherBooking,
|
||||||
|
ManagerBooking,
|
||||||
|
DistributorBooking,
|
||||||
|
ProviderBooking,
|
||||||
|
RoleSelection
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isLoggedIn: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
currentRole() {
|
||||||
|
const userStore = useUserStore()
|
||||||
|
return userStore.currentRole
|
||||||
|
},
|
||||||
|
roleName() {
|
||||||
|
const userStore = useUserStore()
|
||||||
|
return userStore.roleName
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onShow() {
|
||||||
|
console.log('[快速预约页面] onShow 触发')
|
||||||
|
this.checkLoginStatus()
|
||||||
|
this.loadTabBarParams()
|
||||||
|
console.log('[快速预约页面] isLoggedIn:', this.isLoggedIn)
|
||||||
|
console.log('[快速预约页面] currentRole:', this.currentRole)
|
||||||
|
|
||||||
|
// 🔥 关键修复:通知子组件刷新数据
|
||||||
|
this.$nextTick(() => {
|
||||||
|
// 使用事件总线通知 ManagerBooking 组件刷新
|
||||||
|
uni.$emit('refreshManagerBooking')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
// 加载 tabBar 参数
|
||||||
|
loadTabBarParams() {
|
||||||
|
// 读取从其他页面传递的参数
|
||||||
|
const params = uni.getStorageSync('bookingQuickBookingParams')
|
||||||
|
if (params) {
|
||||||
|
console.log('[快速预约] 接收到参数:', params)
|
||||||
|
|
||||||
|
// 清除参数(避免重复使用)
|
||||||
|
uni.removeStorageSync('bookingQuickBookingParams')
|
||||||
|
|
||||||
|
// 将参数传递给子组件
|
||||||
|
// 可以通过事件总线或其他方式传递
|
||||||
|
if (params.packageId) {
|
||||||
|
uni.$emit('bookingParams', { packageId: params.packageId })
|
||||||
|
}
|
||||||
|
if (params.serviceId) {
|
||||||
|
uni.$emit('bookingParams', { serviceId: params.serviceId })
|
||||||
|
}
|
||||||
|
if (params.teacherId) {
|
||||||
|
uni.$emit('bookingParams', { teacherId: params.teacherId })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 检查登录状态
|
||||||
|
checkLoginStatus() {
|
||||||
|
const token = uni.getStorageSync('token')
|
||||||
|
const userInfo = uni.getStorageSync('userInfo')
|
||||||
|
this.isLoggedIn = !!(token && userInfo)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 跳转到登录(实际是跳转到"我的"页面)
|
||||||
|
goToLogin() {
|
||||||
|
uni.switchTab({
|
||||||
|
url: '/pages/user/index'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 处理角色选择
|
||||||
|
handleRoleSelect(role) {
|
||||||
|
const userStore = useUserStore()
|
||||||
|
userStore.switchRole(role)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '@/static/css/common.scss';
|
||||||
|
|
||||||
|
.container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-prompt {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 120rpx 60rpx;
|
||||||
|
background: #ffffff;
|
||||||
|
|
||||||
|
.prompt-icon {
|
||||||
|
font-size: 120rpx;
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-title {
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333333;
|
||||||
|
margin-bottom: 15rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-desc {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #666666;
|
||||||
|
margin-bottom: 50rpx;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn {
|
||||||
|
width: 400rpx;
|
||||||
|
height: 88rpx;
|
||||||
|
background: linear-gradient(135deg, $primary-color 0%, $primary-light 100%);
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 44rpx;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
1218
peidu/uniapp/src/pages/index/components/ManagerHome.vue
Normal file
1218
peidu/uniapp/src/pages/index/components/ManagerHome.vue
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user