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