You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1634 lines
52 KiB
1634 lines
52 KiB
<!--客户详情 - 重构版本-->
|
|
<template>
|
|
<view class="assemble">
|
|
<!-- 主要内容区域 -->
|
|
<view class="content">
|
|
<!-- 客户信息卡片 -->
|
|
<ClientInfoCard
|
|
:client-info="clientInfo"
|
|
:actions="[]"
|
|
@call="handleMakeCall"
|
|
@message="handleSendMessage"
|
|
/>
|
|
|
|
<!-- 标签切换器 -->
|
|
<view class="tab-switcher-container">
|
|
<TabSwitcher
|
|
:tabs="tabs"
|
|
:active-tab-id="switch_tags_type"
|
|
@tab-change="handleTabChange"
|
|
/>
|
|
</view>
|
|
|
|
<!-- 学生信息卡片区域 -->
|
|
<view class="student-section" v-if="switch_tags_type == 1 || switch_tags_type == 7">
|
|
<view class="section-header">
|
|
<text class="section-title">学生信息</text>
|
|
<view class="add-student-btn" @click.stop="openAddStudentDialog">
|
|
<text class="add-icon">+</text>
|
|
<text class="add-text">添加学生</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 学生信息滑动卡片 -->
|
|
<view class="student-cards">
|
|
<swiper
|
|
class="student-swiper"
|
|
:indicator-dots="studentList.length > 1"
|
|
:circular="studentList.length > 1"
|
|
indicator-color="rgba(255, 255, 255, 0.3)"
|
|
indicator-active-color="#29D3B4"
|
|
previous-margin="20"
|
|
next-margin="20"
|
|
@change="onStudentSwiperChange">
|
|
<swiper-item v-for="(student, index) in studentList" :key="student.id">
|
|
<view class="student-swiper-content">
|
|
<StudentInfoCard
|
|
:student="student"
|
|
:show-details="true"
|
|
@action="handleStudentAction"
|
|
/>
|
|
</view>
|
|
</swiper-item>
|
|
</swiper>
|
|
</view>
|
|
|
|
<!-- 操作按钮区域 - 移到Swiper外部,独立滑动 -->
|
|
<view class="action-buttons-section" v-if="currentStudent">
|
|
<view
|
|
class="action-item"
|
|
v-for="action in actionButtons"
|
|
:key="action.key"
|
|
@click.stop="handleStudentActionClick(action, currentStudent)"
|
|
>
|
|
<view class="action-icon">
|
|
<text>{{ action.icon }}</text>
|
|
</view>
|
|
<text class="action-text">{{ action.text }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 空状态 -->
|
|
<view v-if="studentList.length === 0" class="empty-state">
|
|
<text class="empty-icon">👤</text>
|
|
<text class="empty-text">暂无学生信息</text>
|
|
<view class="empty-add-btn" @click.stop="openAddStudentDialog">
|
|
<text>添加第一个学生</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 课程信息标签内容 -->
|
|
<view class="course-section" v-if="switch_tags_type == 2">
|
|
<CourseInfoCard
|
|
v-if="courseInfo && courseInfo.length > 0"
|
|
:course-list="courseInfo"
|
|
@view-detail="viewCourseDetail"
|
|
/>
|
|
<view v-else class="empty-state">
|
|
<text class="empty-icon">📚</text>
|
|
<text class="empty-text">暂无课程信息</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 通话记录标签内容 -->
|
|
<view class="call-section" v-if="switch_tags_type == 3">
|
|
<view v-if="listCallUp.length === 0" class="empty-state">
|
|
<text class="empty-icon">📞</text>
|
|
<text class="empty-text">暂无通话记录</text>
|
|
</view>
|
|
<CallRecordCard
|
|
v-for="record in listCallUp"
|
|
:key="record.id"
|
|
:record="record"
|
|
@remark="openAddRemark"
|
|
/>
|
|
</view>
|
|
|
|
<!-- 体测记录标签内容 -->
|
|
<view class="fitness-section" v-if="switch_tags_type == 4">
|
|
<view class="section-header" v-if="currentStudent">
|
|
<text class="context-title">{{ currentStudent.name }}的体测记录</text>
|
|
<view class="add-record-btn" @click.stop="openAddFitnessRecord">
|
|
<text class="add-icon">+</text>
|
|
<text class="add-text">新增记录</text>
|
|
</view>
|
|
</view>
|
|
|
|
<view v-if="currentStudentFitnessRecords.length === 0" class="empty-state">
|
|
<text class="empty-icon">📊</text>
|
|
<text class="empty-text">暂无体测记录</text>
|
|
</view>
|
|
<FitnessRecordCard
|
|
v-for="record in currentStudentFitnessRecords"
|
|
:key="record.id"
|
|
:record="record"
|
|
@edit="openEditFitnessRecord"
|
|
/>
|
|
</view>
|
|
|
|
<!-- 学习计划标签内容 -->
|
|
<view class="study-plan-section" v-if="switch_tags_type == 5">
|
|
<view v-if="!studyPlanList || studyPlanList.length === 0" class="empty-state">
|
|
<text class="empty-icon">📚</text>
|
|
<text class="empty-text">暂无学习计划</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 赠品记录标签内容 -->
|
|
<view class="gift-record-section" v-if="switch_tags_type == 8">
|
|
<view v-if="giftRecords.length === 0" class="empty-state">
|
|
<text class="empty-icon">🎁</text>
|
|
<text class="empty-text">暂无赠品记录</text>
|
|
</view>
|
|
<GiftRecordCard
|
|
v-for="record in giftRecords"
|
|
:key="record.id"
|
|
:record="record"
|
|
/>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 底部弹窗组件 -->
|
|
<BottomPopup
|
|
:visible="currentPopup !== null"
|
|
:title="popupTitle"
|
|
:has-footer="needsFooter"
|
|
@close="closePopup"
|
|
@click.stop
|
|
>
|
|
<!-- 课程信息弹窗 -->
|
|
<CourseInfoCard
|
|
v-if="currentPopup === 'course_info'"
|
|
:course-list="courseInfo"
|
|
@view-detail="viewCourseDetail"
|
|
/>
|
|
|
|
<!-- 体测记录弹窗 -->
|
|
<view
|
|
class="fitness-records-container"
|
|
v-if="currentPopup === 'fitness_record'"
|
|
>
|
|
<!-- 空状态提示 -->
|
|
<view v-if="currentStudentFitnessRecords.length === 0" class="empty-state">
|
|
<view class="empty-icon">📊</view>
|
|
<view class="empty-text">暂无体测记录</view>
|
|
<view class="empty-tip">点击下方"新增"按钮添加体测记录</view>
|
|
</view>
|
|
|
|
<!-- 体测记录列表 -->
|
|
<FitnessRecordCard
|
|
v-for="record in currentStudentFitnessRecords"
|
|
:key="record.id"
|
|
:record="record"
|
|
@edit="openEditFitnessRecord"
|
|
/>
|
|
</view>
|
|
|
|
<!-- 学习计划弹窗 -->
|
|
<StudyPlanCard
|
|
v-if="currentPopup === 'study_plan'"
|
|
:plan-list="studyPlanList"
|
|
@edit="openEditStudyPlan"
|
|
/>
|
|
|
|
<!-- 订单列表弹窗 -->
|
|
<OrderListCard
|
|
v-if="currentPopup === 'order_list'"
|
|
:order-list="orderList"
|
|
@add-order="openAddOrderDialog"
|
|
@pay-order="handlePayOrder"
|
|
@view-detail="viewOrderDetail"
|
|
/>
|
|
|
|
<!-- 服务列表弹窗 -->
|
|
<ServiceListCard
|
|
v-if="currentPopup === 'service_list'"
|
|
:service-list="serviceList"
|
|
/>
|
|
|
|
<!-- 底部操作按钮 -->
|
|
<template #footer>
|
|
<view class="popup-footer-btns">
|
|
<view class="footer-btn cancel-btn" @click.stop="closePopup">关闭</view>
|
|
<view
|
|
class="footer-btn confirm-btn"
|
|
v-if="showAddButton"
|
|
@click.stop="handleAddAction"
|
|
>新增</view>
|
|
</view>
|
|
</template>
|
|
</BottomPopup>
|
|
|
|
<!-- 保留原有的编辑弹窗 -->
|
|
<uni-popup ref="remarkPopup" type="dialog">
|
|
<view class="remark-dialog">
|
|
<textarea
|
|
v-model="remark_content"
|
|
placeholder="请输入备注内容"
|
|
maxlength="200"
|
|
></textarea>
|
|
<view class="dialog-btns">
|
|
<view class="btn cancel" @click="closeRemark">取消</view>
|
|
<view class="btn confirm" @click="confirmRemark">确定</view>
|
|
</view>
|
|
</view>
|
|
</uni-popup>
|
|
|
|
<FitnessRecordPopup ref="fitnessRecordPopup" :resource-id="String(clientInfo.resource_id)" :student-id="currentStudent && currentStudent.id" @confirm="handleFitnessRecordConfirm" />
|
|
<StudentEditPopup ref="studentEditPopup" :resource-id="clientInfo.resource_id" @confirm="handleStudentEditConfirm" />
|
|
<StudyPlanPopup ref="studyPlanPopup" :student-id="currentStudent && currentStudent.id" @confirm="handleStudyPlanConfirm" />
|
|
|
|
<!-- 新增订单弹窗 -->
|
|
<uni-popup ref="orderFormPopup" type="bottom">
|
|
<OrderFormPopup
|
|
:visible="showOrderForm"
|
|
:student-info="currentStudent"
|
|
:resource-id="clientInfo.resource_id"
|
|
@cancel="closeOrderForm"
|
|
@confirm="handleOrderFormConfirm"
|
|
/>
|
|
</uni-popup>
|
|
|
|
<!-- 二维码支付弹窗 -->
|
|
<uni-popup ref="qrCodePopup" type="center" @close="closeQRCodeModal">
|
|
<view class="qrcode-payment-modal" v-if="qrCodePaymentData">
|
|
<!-- 弹窗头部 -->
|
|
<view class="modal-header">
|
|
<text class="modal-title">扫码支付</text>
|
|
<view class="close-btn" @click="closeQRCodeModal">
|
|
<text>✕</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 订单信息 -->
|
|
<view class="order-info">
|
|
<view class="info-row">
|
|
<text class="label">订单号:</text>
|
|
<text class="value">{{ qrCodePaymentData.order.order_no }}</text>
|
|
</view>
|
|
<view class="info-row">
|
|
<text class="label">支付金额:</text>
|
|
<text class="amount">¥{{ qrCodePaymentData.order.total_amount }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 二维码区域 -->
|
|
<view class="qrcode-container">
|
|
<image
|
|
v-if="qrCodePaymentData.qrcodeImage"
|
|
:src="qrCodePaymentData.qrcodeImage"
|
|
class="qrcode-image"
|
|
mode="aspectFit"
|
|
/>
|
|
<text v-else class="qrcode-placeholder">二维码加载中...</text>
|
|
<text class="qrcode-tip">请使用微信扫码完成支付</text>
|
|
</view>
|
|
|
|
<!-- 操作按钮 -->
|
|
<view class="modal-buttons">
|
|
<view class="btn secondary" @click="closeQRCodeModal">取消支付</view>
|
|
<view class="btn primary" @click="confirmQRCodePayment">发送二维码给客户</view>
|
|
</view>
|
|
</view>
|
|
</uni-popup>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import apiRoute from '@/api/apiRoute.js'
|
|
// 组件导入
|
|
import ClientInfoCard from '@/components/client-info-card/client-info-card.vue'
|
|
import StudentInfoCard from '@/components/student-info-card/student-info-card.vue'
|
|
import TabSwitcher from '@/components/tab-switcher/tab-switcher.vue'
|
|
import CallRecordCard from '@/components/call-record-card/call-record-card.vue'
|
|
import FitnessRecordCard from '@/components/fitness-record-card/fitness-record-card.vue'
|
|
import GiftRecordCard from '@/components/gift-record-card/gift-record-card.vue'
|
|
// 新的底部弹窗组件
|
|
import BottomPopup from '@/components/bottom-popup/index.vue'
|
|
import StudyPlanCard from '@/components/study-plan-card/index.vue'
|
|
import CourseInfoCard from '@/components/course-info-card/index.vue'
|
|
import OrderListCard from '@/components/order-list-card/index.vue'
|
|
import ServiceListCard from '@/components/service-list-card/index.vue'
|
|
import OrderFormPopup from '@/components/order-form-popup/index.vue'
|
|
// 编辑弹窗
|
|
import StudentEditPopup from '@/components/student-edit-popup/student-edit-popup.vue'
|
|
import FitnessRecordPopup from '@/components/fitness-record-popup/fitness-record-popup.vue'
|
|
import StudyPlanPopup from '@/components/study-plan-popup/study-plan-popup.vue'
|
|
|
|
export default {
|
|
components: {
|
|
ClientInfoCard,
|
|
StudentInfoCard,
|
|
TabSwitcher,
|
|
CallRecordCard,
|
|
FitnessRecordCard,
|
|
GiftRecordCard,
|
|
BottomPopup,
|
|
StudyPlanCard,
|
|
CourseInfoCard,
|
|
OrderListCard,
|
|
ServiceListCard,
|
|
OrderFormPopup,
|
|
StudentEditPopup,
|
|
FitnessRecordPopup,
|
|
StudyPlanPopup
|
|
},
|
|
data() {
|
|
return {
|
|
switch_tags_type: 1,
|
|
resource_sharing_id: '',
|
|
|
|
|
|
// 基本数据
|
|
clientInfo: { id: '', resource_id: '', customerResource: {} },
|
|
userInfo: {},
|
|
listCallUp: [],
|
|
courseInfo: [],
|
|
fitnessRecords: [],
|
|
giftRecords: [],
|
|
studentList: [],
|
|
currentStudentIndex: 0,
|
|
|
|
// 底部弹窗相关
|
|
currentPopup: null,
|
|
studyPlanList: [],
|
|
orderList: [],
|
|
serviceList: [],
|
|
|
|
// 订单表单弹窗
|
|
showOrderForm: false,
|
|
|
|
// 二维码支付弹窗
|
|
showQRCodeModal: false,
|
|
qrCodePaymentData: null,
|
|
|
|
// 编辑相关
|
|
remark_content: '',
|
|
currentRecord: null,
|
|
|
|
// 配置数据
|
|
tabs: [
|
|
{ id: 1, name: '基本资料' },
|
|
{ id: 3, name: '通话记录' },
|
|
{ id: 7, name: '修改资料' },
|
|
{ id: 6, name: '修改记录' },
|
|
{ id: 8, name: '赠品记录' }
|
|
],
|
|
|
|
actionButtons: [
|
|
{ key: 'course_arrangement', text: '课程安排', icon: '📅' },
|
|
{ key: 'order_list', text: '订单列表', icon: '📋' },
|
|
{ key: 'service_list', text: '服务列表', icon: '🔧' },
|
|
{ key: 'course_info', text: '课程信息', icon: '📚' },
|
|
{ key: 'fitness_record', text: '体测记录', icon: '📊' },
|
|
{ key: 'study_plan', text: '学习计划', icon: '📝' }
|
|
]
|
|
}
|
|
},
|
|
computed: {
|
|
currentStudent() {
|
|
return this.studentList[this.currentStudentIndex] || null
|
|
},
|
|
|
|
currentStudentFitnessRecords() {
|
|
if (!this.currentStudent) return []
|
|
// 体测记录使用resource_id字段,与学生记录的resource_id匹配
|
|
// 如果没有匹配到,则显示所有记录(用于展示Mock数据)
|
|
const filtered = this.fitnessRecords.filter(record =>
|
|
record.student_id === this.currentStudent.id ||
|
|
record.resource_id === this.currentStudent.id ||
|
|
record.resource_id === this.clientInfo.resource_id
|
|
)
|
|
|
|
// 如果没有匹配到任何记录,返回所有记录用于测试
|
|
return filtered.length > 0 ? filtered : this.fitnessRecords
|
|
},
|
|
|
|
popupTitle() {
|
|
const titles = {
|
|
'course_info': '课程信息',
|
|
'fitness_record': '体测记录',
|
|
'study_plan': '学习计划',
|
|
'order_list': '订单列表',
|
|
'service_list': '服务列表'
|
|
}
|
|
return titles[this.currentPopup] || ''
|
|
},
|
|
|
|
needsFooter() {
|
|
// 所有弹窗都显示底部按钮区域
|
|
return this.currentPopup !== null
|
|
},
|
|
|
|
showAddButton() {
|
|
// 只有体测记录和学习计划弹窗显示新增按钮
|
|
return ['fitness_record', 'study_plan'].includes(this.currentPopup)
|
|
},
|
|
|
|
},
|
|
onLoad(options) {
|
|
if (!options?.resource_sharing_id) {
|
|
uni.showToast({ title: '缺少必要参数', icon: 'none' })
|
|
setTimeout(() => uni.navigateBack(), 1500)
|
|
return
|
|
}
|
|
this.resource_sharing_id = options.resource_sharing_id
|
|
},
|
|
|
|
onShow() {
|
|
this.init()
|
|
},
|
|
methods: {
|
|
|
|
async init() {
|
|
try {
|
|
await this.getInfo()
|
|
await Promise.all([
|
|
this.getUserInfo(),
|
|
this.getListCallUp(),
|
|
this.getCourseInfo(),
|
|
this.getFitnessRecords(),
|
|
this.getStudentList()
|
|
])
|
|
} catch (error) {
|
|
console.error('数据加载失败:', error)
|
|
}
|
|
},
|
|
|
|
async getUserInfo() {
|
|
try {
|
|
const res = await apiRoute.getPersonnelInfo({})
|
|
if (res.code === 1) {
|
|
this.userInfo = res.data
|
|
}
|
|
} catch (error) {
|
|
console.error('获取员工信息失败:', error)
|
|
}
|
|
},
|
|
|
|
async getInfo() {
|
|
if (!this.resource_sharing_id) return
|
|
try {
|
|
const res = await apiRoute.xs_resourceSharingInfo({ resource_sharing_id: this.resource_sharing_id })
|
|
if (res.code === 1) {
|
|
this.clientInfo = res.data
|
|
}
|
|
} catch (error) {
|
|
console.error('获取客户详情失败:', error)
|
|
}
|
|
},
|
|
|
|
async getListCallUp() {
|
|
if (!this.clientInfo?.resource_id) return
|
|
try {
|
|
const res = await apiRoute.listCallUp({ resource_id: this.clientInfo.resource_id })
|
|
if (res.code === 1) {
|
|
this.listCallUp = res.data || []
|
|
}
|
|
} catch (error) {
|
|
console.error('获取通话记录失败:', error)
|
|
}
|
|
},
|
|
handleMakeCall() {
|
|
const phone = this.clientInfo?.customerResource?.phone_number
|
|
if (phone) {
|
|
uni.makePhoneCall({ phoneNumber: phone })
|
|
}
|
|
},
|
|
|
|
handleSendMessage() {
|
|
uni.showToast({ title: '发送消息功能待实现', icon: 'none' })
|
|
},
|
|
|
|
openAddRemark(record) {
|
|
this.remark_content = record.remarks || ''
|
|
this.currentRecord = record
|
|
this.$refs.remarkPopup.open()
|
|
},
|
|
|
|
async confirmRemark() {
|
|
if (!this.remark_content.trim() || !this.currentRecord?.id) {
|
|
uni.showToast({ title: '请输入备注内容', icon: 'none' })
|
|
return
|
|
}
|
|
|
|
try {
|
|
const res = await apiRoute.xs_communicationRecordsEdit({
|
|
id: this.currentRecord.id,
|
|
remarks: this.remark_content
|
|
})
|
|
|
|
if (res.code === 1) {
|
|
uni.showToast({ title: '备注更新成功', icon: 'success' })
|
|
await this.getListCallUp()
|
|
}
|
|
} catch (error) {
|
|
uni.showToast({ title: '更新失败', icon: 'none' })
|
|
}
|
|
|
|
this.closeRemark()
|
|
},
|
|
|
|
closeRemark() {
|
|
this.$refs.remarkPopup.close()
|
|
this.remark_content = ''
|
|
this.currentRecord = null
|
|
},
|
|
|
|
async getCourseInfo(studentId = null) {
|
|
if (!this.clientInfo?.resource_id) return
|
|
try {
|
|
const targetStudentId = studentId || this.currentStudent?.id
|
|
const res = await apiRoute.getStudentCourseInfo({
|
|
resource_id: this.clientInfo.resource_id,
|
|
member_id: this.clientInfo.customerResource?.member_id || '',
|
|
student_id: targetStudentId
|
|
})
|
|
if (res.code === 1) {
|
|
this.courseInfo = res.data || []
|
|
|
|
// 为测试数据添加必要的resource_id字段
|
|
if (this.courseInfo.length > 0) {
|
|
this.courseInfo.forEach(course => {
|
|
if (!course.resource_id) {
|
|
course.resource_id = this.clientInfo.resource_id || 1; // 添加resource_id
|
|
}
|
|
if (!course.student_course_id && !course.id) {
|
|
course.student_course_id = Math.floor(Math.random() * 1000); // 添加测试用的ID
|
|
}
|
|
});
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('获取课程信息失败:', error)
|
|
}
|
|
},
|
|
|
|
|
|
// 学生卡片操作按钮点击处理 - 传递具体学生信息
|
|
async handleStudentActionClick(action, student) {
|
|
// 设置当前操作的学生
|
|
this.setCurrentStudent(student)
|
|
|
|
switch (action.key) {
|
|
case 'course_arrangement':
|
|
this.$navigateToPage(`/pages-market/clue/class_arrangement`, {
|
|
resource_id: this.clientInfo.id,
|
|
student_id: student.id
|
|
})
|
|
break
|
|
case 'course_info':
|
|
await this.getCourseInfo(student.id)
|
|
this.currentPopup = 'course_info'
|
|
break
|
|
case 'fitness_record':
|
|
await this.getFitnessRecords(student.id)
|
|
this.currentPopup = 'fitness_record'
|
|
break
|
|
case 'study_plan':
|
|
await this.getStudyPlanList(student.id)
|
|
this.currentPopup = 'study_plan'
|
|
break
|
|
case 'order_list':
|
|
await this.getOrderList(student.id)
|
|
this.currentPopup = 'order_list'
|
|
break
|
|
case 'service_list':
|
|
await this.getServiceList(student.id)
|
|
this.currentPopup = 'service_list'
|
|
break
|
|
}
|
|
},
|
|
|
|
closePopup() {
|
|
console.log('关闭弹窗,当前弹窗类型:', this.currentPopup)
|
|
this.currentPopup = null
|
|
// 重置相关数据
|
|
this.studyPlanList = []
|
|
this.orderList = []
|
|
this.serviceList = []
|
|
this.courseInfo = []
|
|
this.fitnessRecords = []
|
|
},
|
|
|
|
handleAddAction() {
|
|
if (this.currentPopup === 'fitness_record') {
|
|
this.openAddFitnessRecord()
|
|
} else if (this.currentPopup === 'study_plan') {
|
|
this.openAddStudyPlan()
|
|
}
|
|
},
|
|
|
|
|
|
|
|
|
|
viewCourseDetail(course) {
|
|
if (!course?.id) {
|
|
uni.showToast({ title: '课程信息不完整', icon: 'none' })
|
|
return
|
|
}
|
|
this.$navigateToPage(`/pages-market/course/course_detail`, {
|
|
id: course.id,
|
|
resource_id: this.clientInfo.resource_id
|
|
})
|
|
},
|
|
|
|
async handleTabChange({ tabId }) {
|
|
this.switch_tags_type = tabId
|
|
|
|
if (tabId === 2) await this.getCourseInfo()
|
|
if (tabId === 3) await this.getListCallUp()
|
|
if (tabId === 4) await this.getFitnessRecords()
|
|
if (tabId === 6) {
|
|
this.$navigateToPage(`/pages-market/clue/edit_clues_log`, {
|
|
resource_id: this.clientInfo.id
|
|
})
|
|
}
|
|
console.log('切换标签页:', this.clientInfo)
|
|
if (tabId === 7) this.$navigateToPage(`/pages-market/clue/edit_clues`, {
|
|
resource_sharing_id: this.clientInfo.id
|
|
})
|
|
if (tabId === 8) await this.getGiftRecords()
|
|
},
|
|
|
|
handleStudentAction({ action, student }) {
|
|
// this.setCurrentStudent(student)
|
|
console.log('学生操作:', action, student)
|
|
|
|
// 处理不同的学员操作
|
|
switch (action) {
|
|
case 'edit':
|
|
// 编辑学员信息 - 打开编辑弹窗并回显数据
|
|
this.openEditStudentDialog(student)
|
|
break
|
|
case 'view':
|
|
// 查看学员详情
|
|
this.viewStudentDetail(student)
|
|
break
|
|
case 'delete':
|
|
// 删除学员
|
|
this.confirmDeleteStudent(student)
|
|
break
|
|
default:
|
|
console.log('未处理的学员操作:', action)
|
|
}
|
|
},
|
|
|
|
setCurrentStudent(student) {
|
|
const index = this.studentList.findIndex(s => s.id === student.id)
|
|
if (index !== -1) this.currentStudentIndex = index
|
|
},
|
|
|
|
onStudentSwiperChange(e) {
|
|
this.currentStudentIndex = e.detail.current
|
|
},
|
|
|
|
async getFitnessRecords(studentId = null) {
|
|
if (!this.clientInfo?.resource_id) return
|
|
|
|
try {
|
|
// 如果指定了学生ID,则获取该学生的体测记录
|
|
const targetStudentId = studentId || this.currentStudent?.id
|
|
|
|
// 调用体测记录API
|
|
const res = await apiRoute.xy_physicalTest({
|
|
resource_id: this.clientInfo.resource_id,
|
|
student_id: targetStudentId
|
|
})
|
|
|
|
if (res.code === 1 && res.data) {
|
|
// 处理体测记录数据,转换PDF文件格式
|
|
this.fitnessRecords = this.processFitnessRecords(res.data.data || [])
|
|
} else {
|
|
console.warn('获取体测记录失败:', res.msg)
|
|
this.fitnessRecords = []
|
|
}
|
|
} catch (error) {
|
|
console.error('获取体测记录异常:', error)
|
|
this.fitnessRecords = []
|
|
}
|
|
},
|
|
|
|
// 处理体测记录数据,转换PDF文件格式
|
|
processFitnessRecords(records) {
|
|
if (!records || !Array.isArray(records)) return []
|
|
|
|
return records.map(record => {
|
|
const processedRecord = {
|
|
...record,
|
|
test_date: record.created_at ? record.created_at.split(' ')[0] : '', // 从created_at提取日期
|
|
pdf_files: []
|
|
}
|
|
|
|
// 处理PDF文件
|
|
if (record.physical_test_report) {
|
|
// 如果physical_test_report是字符串路径
|
|
if (typeof record.physical_test_report === 'string') {
|
|
const pdfPaths = record.physical_test_report.split(',').filter(path => path.trim())
|
|
processedRecord.pdf_files = pdfPaths.map((path, index) => ({
|
|
id: `${record.id}_${index}`,
|
|
name: this.extractFileName(path) || `体测报告_${index + 1}.pdf`,
|
|
size: 0, // 无法从路径获取大小
|
|
url: this.getFullPdfUrl(path),
|
|
server_path: path.trim(),
|
|
upload_time: record.created_at || ''
|
|
}))
|
|
}
|
|
// 如果physical_test_report已经是数组格式
|
|
else if (Array.isArray(record.physical_test_report)) {
|
|
processedRecord.pdf_files = record.physical_test_report
|
|
}
|
|
}
|
|
|
|
return processedRecord
|
|
})
|
|
},
|
|
|
|
// 从文件路径提取文件名
|
|
extractFileName(filePath) {
|
|
if (!filePath) return ''
|
|
const parts = filePath.split('/')
|
|
return parts[parts.length - 1] || ''
|
|
},
|
|
|
|
// 获取完整的PDF文件URL
|
|
getFullPdfUrl(relativePath) {
|
|
if (!relativePath) return ''
|
|
|
|
// 如果已经是完整URL,直接返回
|
|
if (relativePath.startsWith('http://') || relativePath.startsWith('https://')) {
|
|
return relativePath
|
|
}
|
|
|
|
// 构建完整的URL
|
|
const { img_domian } = require('@/common/config.js')
|
|
|
|
// 处理相对路径
|
|
let cleanPath = relativePath
|
|
if (cleanPath.startsWith('./')) {
|
|
cleanPath = cleanPath.substring(2)
|
|
}
|
|
if (cleanPath.startsWith('/')) {
|
|
cleanPath = cleanPath.substring(1)
|
|
}
|
|
|
|
return `${img_domian}${cleanPath}`
|
|
},
|
|
|
|
openAddFitnessRecord() {
|
|
this.$refs.fitnessRecordPopup.openAdd()
|
|
},
|
|
|
|
openEditFitnessRecord(record) {
|
|
// 确保记录包含正确格式的PDF文件信息
|
|
const processedRecord = {
|
|
...record,
|
|
pdf_files: record.pdf_files || [] // 使用已处理的pdf_files数据
|
|
}
|
|
this.$refs.fitnessRecordPopup.openEdit(processedRecord)
|
|
},
|
|
|
|
async handleFitnessRecordConfirm(result) {
|
|
try {
|
|
const { isEditing, data } = result
|
|
|
|
if (isEditing) {
|
|
// 编辑体测记录
|
|
const response = await apiRoute.xy_physicalTestEdit(data)
|
|
if (response.code === 1) {
|
|
uni.showToast({ title: '编辑成功', icon: 'success' })
|
|
// 刷新体测记录列表
|
|
await this.getFitnessRecords()
|
|
} else {
|
|
uni.showToast({ title: response.msg || '编辑失败', icon: 'none' })
|
|
}
|
|
} else {
|
|
// 新增体测记录
|
|
const response = await apiRoute.xy_physicalTestAdd(data)
|
|
if (response.code === 1) {
|
|
uni.showToast({ title: '新增成功', icon: 'success' })
|
|
// 刷新体测记录列表
|
|
await this.getFitnessRecords()
|
|
} else {
|
|
uni.showToast({ title: response.msg || '新增失败', icon: 'none' })
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('保存体测记录失败:', error)
|
|
uni.showToast({ title: '保存失败,请重试', icon: 'none' })
|
|
}
|
|
},
|
|
|
|
// 学习计划相关方法
|
|
openAddStudyPlan() {
|
|
if (!this.currentStudent) {
|
|
uni.showToast({ title: '请先选择学生', icon: 'none' })
|
|
return
|
|
}
|
|
this.$refs.studyPlanPopup.openAdd()
|
|
},
|
|
|
|
openEditStudyPlan(plan) {
|
|
this.$refs.studyPlanPopup.openEdit(plan)
|
|
},
|
|
|
|
async handleStudyPlanConfirm(result) {
|
|
try {
|
|
const { isEditing, data } = result
|
|
|
|
if (isEditing) {
|
|
// 编辑学习计划
|
|
const response = await apiRoute.editStudyPlan(data)
|
|
if (response.code === 1) {
|
|
uni.showToast({ title: '编辑成功', icon: 'success' })
|
|
// 刷新学习计划列表
|
|
await this.getStudyPlanList()
|
|
} else {
|
|
uni.showToast({ title: response.msg || '编辑失败', icon: 'none' })
|
|
}
|
|
} else {
|
|
// 新增学习计划
|
|
const response = await apiRoute.addStudyPlan(data)
|
|
if (response.code === 1) {
|
|
uni.showToast({ title: '新增成功', icon: 'success' })
|
|
// 刷新学习计划列表
|
|
await this.getStudyPlanList()
|
|
} else {
|
|
uni.showToast({ title: response.msg || '新增失败', icon: 'none' })
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('保存学习计划失败:', error)
|
|
uni.showToast({ title: '保存失败,请重试', icon: 'none' })
|
|
}
|
|
},
|
|
|
|
|
|
async getStudentList() {
|
|
try {
|
|
if (this.clientInfo?.resource_id) {
|
|
const res = await apiRoute.xs_getStudentList({ parent_resource_id: this.clientInfo.resource_id })
|
|
if (res.code === 1) {
|
|
// 处理接口返回的学生数据,转换字段
|
|
this.studentList = await this.processStudentData(res.data || [])
|
|
return
|
|
}
|
|
}
|
|
// 使用模拟数据(匹配真实接口字段结构)
|
|
const mockData = [
|
|
{
|
|
id: 1,
|
|
name: '张小明',
|
|
gender: 1, // 1=男, 2=女
|
|
birthday: '2015-05-10',
|
|
remark: '活泼开朗,学习能力强',
|
|
member_label: 1, // student_label表的ID,需要转换为标签名称
|
|
coach_id: 1, // personnel表的ID,需要转换为教练姓名
|
|
consultant_id: 2, // personnel表的ID,需要转换为顾问姓名
|
|
trial_class_count: 3,
|
|
// 其他原有字段
|
|
age: 9
|
|
}
|
|
]
|
|
|
|
// 处理模拟数据
|
|
this.studentList = await this.processStudentData(mockData)
|
|
} catch (error) {
|
|
console.error('获取学生列表失败:', error)
|
|
}
|
|
},
|
|
|
|
// 处理学生数据,转换字段为显示用的格式
|
|
async processStudentData(students) {
|
|
if (!students || students.length === 0) return []
|
|
|
|
const processedStudents = []
|
|
|
|
for (const student of students) {
|
|
const processedStudent = {
|
|
...student,
|
|
// 转换字段名称和处理逻辑
|
|
student_tags: await this.getStudentLabel(student.member_label),
|
|
class_teacher: await this.getPersonnelName(student.coach_id),
|
|
academic_affairs: await this.getPersonnelName(student.consultant_id),
|
|
trial_course_count: student.trial_class_count || 0,
|
|
// 使用后端API返回的真实到访状态数据
|
|
course_visit_status: this.formatVisitStatus(student.first_visit_status, student.second_visit_status)
|
|
}
|
|
processedStudents.push(processedStudent)
|
|
}
|
|
|
|
return processedStudents
|
|
},
|
|
|
|
// 获取学员标签名称
|
|
async getStudentLabel(labelId) {
|
|
if (!labelId) return []
|
|
|
|
try {
|
|
// 调用接口获取school_student_label表中的标签名称
|
|
const res = await apiRoute.getStudentLabel({ id: labelId })
|
|
if (res.code === 1) {
|
|
return res.data ? [res.data.label_name] : []
|
|
}
|
|
|
|
// 如果接口调用失败,使用模拟数据作为后备
|
|
console.warn('接口调用失败,使用模拟数据:', res.msg)
|
|
const labelMap = {
|
|
1: '优秀学员',
|
|
2: '积极参与',
|
|
3: '需要关注',
|
|
4: '进步明显',
|
|
5: '需要鼓励'
|
|
}
|
|
|
|
return labelMap[labelId] ? [labelMap[labelId]] : []
|
|
} catch (error) {
|
|
console.error('获取学生标签失败:', error)
|
|
// 出现错误时使用模拟数据
|
|
const labelMap = {
|
|
1: '优秀学员',
|
|
2: '积极参与',
|
|
3: '需要关注',
|
|
4: '进步明显',
|
|
5: '需要鼓励'
|
|
}
|
|
|
|
return labelMap[labelId] ? [labelMap[labelId]] : []
|
|
}
|
|
},
|
|
|
|
// 获取人员姓名(教练或顾问)
|
|
async getPersonnelName(personnelId) {
|
|
if (!personnelId) return ''
|
|
|
|
// TODO: 调用接口获取personnel表中的人员姓名
|
|
// const res = await apiRoute.getPersonnelInfo({ id: personnelId })
|
|
|
|
// 模拟数据
|
|
const personnelMap = {
|
|
1: '李老师',
|
|
2: '王主任',
|
|
3: '张教练'
|
|
}
|
|
|
|
return personnelMap[personnelId] || ''
|
|
},
|
|
|
|
// 格式化到访状态 - 使用后端API返回的真实数据
|
|
formatVisitStatus(firstVisitStatus, secondVisitStatus) {
|
|
// 如果都未到访
|
|
if (firstVisitStatus === '未到访' && secondVisitStatus === '未到访') {
|
|
return '未到访'
|
|
}
|
|
// 如果一访已到,二访未到
|
|
else if (firstVisitStatus === '已到访' && secondVisitStatus === '未到访') {
|
|
return '一访已到'
|
|
}
|
|
// 如果一访和二访都已到
|
|
else if (firstVisitStatus === '已到访' && secondVisitStatus === '已到访') {
|
|
return '二访已到'
|
|
}
|
|
// 默认情况
|
|
else {
|
|
return '未到访'
|
|
}
|
|
},
|
|
openAddStudentDialog() {
|
|
// 确保组件已经挂载后再调用
|
|
this.$nextTick(() => {
|
|
if (this.$refs.studentEditPopup) {
|
|
// 传递客户信息给学生编辑弹窗,用于自动填充
|
|
const clientData = {
|
|
contact_phone: this.clientInfo?.customerResource?.phone_number || '',
|
|
emergency_contact: this.clientInfo?.customerResource?.name || ''
|
|
}
|
|
this.$refs.studentEditPopup.openAdd(clientData)
|
|
} else {
|
|
console.error('studentEditPopup 组件引用不存在')
|
|
uni.showToast({
|
|
title: '组件加载中,请稍后再试',
|
|
icon: 'none'
|
|
})
|
|
}
|
|
})
|
|
},
|
|
|
|
// 打开编辑学员信息弹窗
|
|
openEditStudentDialog(student) {
|
|
// 确保组件已经挂载后再调用
|
|
this.$nextTick(() => {
|
|
if (this.$refs.studentEditPopup) {
|
|
console.log('打开编辑学员弹窗,学员信息:', student)
|
|
// 调用组件的 openEdit 方法并传入学员数据进行回显
|
|
this.$refs.studentEditPopup.openEdit(student)
|
|
} else {
|
|
console.error('studentEditPopup 组件引用不存在')
|
|
uni.showToast({
|
|
title: '组件加载中,请稍后再试',
|
|
icon: 'none'
|
|
})
|
|
}
|
|
})
|
|
},
|
|
|
|
// 查看学员详情
|
|
viewStudentDetail(student) {
|
|
console.log('查看学员详情:', student)
|
|
// 可以显示一个详情弹窗或跳转到详情页面
|
|
const detailInfo = `
|
|
姓名:${student.name}
|
|
性别:${student.gender === 1 ? '男' : student.gender === 2 ? '女' : '未知'}
|
|
年龄:${student.age || '未知'}
|
|
生日:${student.birthday || '未知'}
|
|
联系电话:${student.contact_phone || '未填写'}
|
|
紧急联系人:${student.emergency_contact || '未填写'}
|
|
备注:${student.note || '无'}
|
|
状态:${student.status === 1 ? '有效' : '无效'}
|
|
`.trim()
|
|
|
|
uni.showModal({
|
|
title: '学员详情',
|
|
content: detailInfo,
|
|
showCancel: false,
|
|
confirmText: '知道了'
|
|
})
|
|
},
|
|
|
|
// 确认删除学员
|
|
confirmDeleteStudent(student) {
|
|
uni.showModal({
|
|
title: '确认删除',
|
|
content: `确定要删除学员"${student.name}"吗?此操作无法撤销。`,
|
|
success: (res) => {
|
|
if (res.confirm) {
|
|
this.deleteStudent(student)
|
|
}
|
|
}
|
|
})
|
|
},
|
|
|
|
// 删除学员
|
|
async deleteStudent(student) {
|
|
try {
|
|
// 这里需要调用删除学员的API
|
|
// const res = await apiRoute.deleteStudent({ student_id: student.id })
|
|
// if (res.code === 1) {
|
|
uni.showToast({ title: '删除成功', icon: 'success' })
|
|
// 刷新学员列表
|
|
await this.getStudentList()
|
|
// } else {
|
|
// uni.showToast({ title: res.msg || '删除失败', icon: 'none' })
|
|
// }
|
|
} catch (error) {
|
|
console.error('删除学员失败:', error)
|
|
uni.showToast({ title: '删除失败', icon: 'none' })
|
|
}
|
|
},
|
|
|
|
|
|
async handleStudentEditConfirm(result) {
|
|
try {
|
|
console.log('学员编辑确认结果:', result)
|
|
|
|
let res
|
|
if (result.isEditing) {
|
|
// 编辑模式 - 调用学员信息更新API
|
|
console.log('编辑学员信息:', result.studentData)
|
|
res = await apiRoute.xs_editStudent(result.studentData)
|
|
} else {
|
|
// 新增模式 - 调用学员添加API
|
|
console.log('新增学员信息:', result.studentData)
|
|
res = await apiRoute.xs_addStudent(result.studentData)
|
|
}
|
|
|
|
if (res.code === 1) {
|
|
this.$refs.studentEditPopup.close()
|
|
uni.showToast({
|
|
title: result.isEditing ? '编辑成功' : '添加成功',
|
|
icon: 'success'
|
|
})
|
|
// 保存成功后刷新学生列表
|
|
await this.getStudentList()
|
|
} else {
|
|
uni.showToast({ title: res.msg || '保存失败', icon: 'none' })
|
|
}
|
|
} catch (error) {
|
|
console.error('保存学生信息失败:', error)
|
|
uni.showToast({ title: '保存失败', icon: 'none' })
|
|
}
|
|
},
|
|
|
|
// 获取学习计划列表
|
|
async getStudyPlanList(studentId = null) {
|
|
if (!this.clientInfo?.resource_id) return
|
|
const targetStudentId = studentId || this.currentStudent?.id
|
|
|
|
if (!targetStudentId) {
|
|
console.warn('学习计划列表:缺少学生ID')
|
|
this.studyPlanList = []
|
|
return
|
|
}
|
|
|
|
try {
|
|
const response = await apiRoute.getStudyPlanList({
|
|
student_id: targetStudentId
|
|
})
|
|
|
|
if (response.code === 1) {
|
|
this.studyPlanList = response.data || []
|
|
} else {
|
|
console.error('获取学习计划失败:', response.msg)
|
|
this.studyPlanList = []
|
|
}
|
|
} catch (error) {
|
|
console.error('获取学习计划异常:', error)
|
|
this.studyPlanList = []
|
|
}
|
|
},
|
|
|
|
// 获取订单列表
|
|
async getOrderList(studentId = null) {
|
|
if (!this.clientInfo?.resource_id) return
|
|
|
|
try {
|
|
const targetStudentId = studentId || this.currentStudent?.id
|
|
|
|
// 构建查询参数,优先使用student_id
|
|
const params = {}
|
|
if (targetStudentId) {
|
|
params.student_id = targetStudentId
|
|
} else if (this.clientInfo.resource_id) {
|
|
params.resource_id = this.clientInfo.resource_id
|
|
} else {
|
|
console.warn('缺少查询参数')
|
|
this.orderList = []
|
|
return
|
|
}
|
|
|
|
const res = await apiRoute.xs_orderTableList(params)
|
|
|
|
if (res.code === 1) {
|
|
// 处理API返回的数据格式
|
|
this.orderList = this.processOrderData(res.data?.data || [])
|
|
} else {
|
|
console.error('获取订单列表失败:', res.msg)
|
|
this.orderList = []
|
|
}
|
|
} catch (error) {
|
|
console.error('获取订单列表异常:', error)
|
|
this.orderList = []
|
|
}
|
|
},
|
|
|
|
// 处理订单数据格式,适配前端组件
|
|
processOrderData(orders) {
|
|
if (!Array.isArray(orders)) return []
|
|
|
|
return orders.map(order => ({
|
|
id: order.id,
|
|
student_id: order.student_id,
|
|
order_no: order.payment_id || `ORD${order.id}`, // 使用payment_id作为订单号
|
|
product_name: order.course_id_name || '课程',
|
|
total_amount: order.order_amount || '0.00',
|
|
paid_amount: order.order_status === 'paid' ? order.order_amount : '0.00',
|
|
unpaid_amount: order.order_status === 'paid' ? '0.00' : order.order_amount,
|
|
payment_method: this.formatPaymentType(order.payment_type),
|
|
salesperson_name: order.staff_id_name || '未指定',
|
|
course_count: order.total_hours || 0, // 使用课时数
|
|
status: this.mapOrderStatus(order.order_status),
|
|
create_time: order.created_at,
|
|
// 保留原始数据
|
|
_raw: order
|
|
}))
|
|
},
|
|
|
|
// 格式化支付类型
|
|
formatPaymentType(paymentType) {
|
|
const typeMap = {
|
|
'cash': '现金支付',
|
|
'scan_code': '扫码支付',
|
|
'subscription': '订阅支付',
|
|
'wxpay_online': '微信在线代付'
|
|
}
|
|
return typeMap[paymentType] || paymentType || '未知'
|
|
},
|
|
|
|
// 映射订单状态
|
|
mapOrderStatus(orderStatus) {
|
|
const statusMap = {
|
|
'pending': 'pending',
|
|
'paid': 'paid',
|
|
'signed': 'completed',
|
|
'completed': 'completed',
|
|
'transfer': 'partial'
|
|
}
|
|
return statusMap[orderStatus] || 'pending'
|
|
},
|
|
|
|
// 获取服务列表
|
|
async getServiceList(studentId = null) {
|
|
if (!this.clientInfo?.resource_id) return
|
|
const targetStudentId = studentId || this.currentStudent?.id
|
|
|
|
if (!targetStudentId) {
|
|
uni.showToast({ title: '请先选择学生', icon: 'none' })
|
|
return
|
|
}
|
|
|
|
try {
|
|
const response = await apiRoute.getStudentServiceList({
|
|
student_id: targetStudentId
|
|
})
|
|
|
|
if (response.code === 1) {
|
|
this.serviceList = response.data || []
|
|
} else {
|
|
console.error('获取服务记录失败:', response.msg)
|
|
uni.showToast({
|
|
title: response.msg || '获取服务记录失败',
|
|
icon: 'none'
|
|
})
|
|
this.serviceList = []
|
|
}
|
|
} catch (error) {
|
|
console.error('获取服务记录异常:', error)
|
|
uni.showToast({
|
|
title: '网络请求失败',
|
|
icon: 'none'
|
|
})
|
|
this.serviceList = []
|
|
}
|
|
},
|
|
|
|
// 打开新增订单弹窗
|
|
openAddOrderDialog() {
|
|
if (!this.currentStudent) {
|
|
uni.showToast({
|
|
title: '请先选择学生',
|
|
icon: 'none'
|
|
})
|
|
return
|
|
}
|
|
|
|
// 先关闭订单列表弹窗,避免遮挡新增订单弹窗
|
|
this.closePopup()
|
|
|
|
this.showOrderForm = true
|
|
this.$refs.orderFormPopup.open()
|
|
},
|
|
|
|
// 关闭新增订单弹窗
|
|
closeOrderForm() {
|
|
this.showOrderForm = false
|
|
this.$refs.orderFormPopup.close()
|
|
},
|
|
|
|
// 订单表单确认处理
|
|
async handleOrderFormConfirm() {
|
|
try {
|
|
// 关闽弹窗
|
|
this.closeOrderForm()
|
|
|
|
// 刷新订单列表
|
|
await this.getOrderList()
|
|
|
|
uni.showToast({ title: '订单创建成功', icon: 'success' })
|
|
} catch (error) {
|
|
console.error('处理订单确认失败:', error)
|
|
}
|
|
},
|
|
|
|
// 处理订单支付
|
|
handlePayOrder(order) {
|
|
// 关闭当前弹窗
|
|
this.closePopup()
|
|
|
|
// 根据支付类型处理不同的支付流程
|
|
this.processPayment(order)
|
|
},
|
|
|
|
// 处理支付流程
|
|
async processPayment(order) {
|
|
const paymentType = order._raw?.payment_type || order.payment_type
|
|
console.log('paymentType', paymentType)
|
|
try {
|
|
switch(paymentType) {
|
|
case 'cash':
|
|
// 现金支付 - 直接标记为已支付
|
|
await this.confirmCashPayment(order)
|
|
break
|
|
case 'scan_code':
|
|
// 扫码支付 - 显示二维码
|
|
this.showQRCodePayment(order)
|
|
break
|
|
case 'subscription':
|
|
// 订阅支付 - 分期支付流程
|
|
this.showSubscriptionPayment(order)
|
|
break
|
|
case 'wxpay_online':
|
|
// 微信在线代付 - 调用微信支付
|
|
this.showWechatPayment(order)
|
|
break
|
|
default:
|
|
uni.showToast({ title: '不支持的支付方式', icon: 'none' })
|
|
}
|
|
} catch (error) {
|
|
console.error('支付处理失败:', error)
|
|
uni.showToast({ title: '支付处理失败', icon: 'none' })
|
|
}
|
|
},
|
|
|
|
// 现金支付确认
|
|
async confirmCashPayment(order) {
|
|
uni.showModal({
|
|
title: '现金支付确认',
|
|
content: `确认已收到现金支付 ¥${order.total_amount}?`,
|
|
success: async (res) => {
|
|
if (res.confirm) {
|
|
try {
|
|
// 调用API更新订单状态为已支付
|
|
const updateData = {
|
|
order_id: order._raw?.id || order.id,
|
|
order_status: 'paid',
|
|
payment_id: `CASH${Date.now()}` // 生成现金支付单号
|
|
}
|
|
|
|
const result = await apiRoute.xs_orderTableUpdatePaymentStatus(updateData)
|
|
|
|
if (result.code === 1) {
|
|
uni.showToast({ title: '支付确认成功', icon: 'success' })
|
|
// 刷新订单列表
|
|
await this.getOrderList()
|
|
} else {
|
|
uni.showToast({ title: result.msg || '支付确认失败', icon: 'none' })
|
|
}
|
|
} catch (error) {
|
|
console.error('现金支付确认失败:', error)
|
|
uni.showToast({ title: '支付确认失败', icon: 'none' })
|
|
}
|
|
}
|
|
}
|
|
})
|
|
},
|
|
|
|
// 扫码支付
|
|
async showQRCodePayment(order) {
|
|
console.log('扫码支付:', order)
|
|
|
|
try {
|
|
uni.showLoading({ title: '生成支付二维码...' })
|
|
|
|
// 调用接口获取支付二维码
|
|
const res = await apiRoute.getOrderPayQrcode({
|
|
order_id: order._raw?.id || order.id
|
|
})
|
|
|
|
uni.hideLoading()
|
|
|
|
if (res.code === 1 && res.data) {
|
|
// 显示二维码支付弹窗
|
|
this.openQRCodeModal({
|
|
order: order,
|
|
qrcode: res.data.code_url,
|
|
// 优先使用base64编码的二维码(解决微信小程序无法访问localhost的问题)
|
|
qrcodeImage: res.data.qrcode_base64 || res.data.qrcode_url
|
|
})
|
|
} else {
|
|
uni.showToast({
|
|
title: res.msg || '获取支付二维码失败',
|
|
icon: 'none'
|
|
})
|
|
}
|
|
} catch (error) {
|
|
uni.hideLoading()
|
|
console.error('获取支付二维码失败:', error)
|
|
uni.showToast({
|
|
title: '获取支付二维码失败',
|
|
icon: 'none'
|
|
})
|
|
}
|
|
},
|
|
|
|
// 打开二维码支付弹窗
|
|
openQRCodeModal(paymentData) {
|
|
this.qrCodePaymentData = paymentData
|
|
this.showQRCodeModal = true
|
|
this.$refs.qrCodePopup.open()
|
|
},
|
|
|
|
// 关闭二维码支付弹窗
|
|
closeQRCodeModal() {
|
|
this.showQRCodeModal = false
|
|
this.qrCodePaymentData = null
|
|
this.$refs.qrCodePopup.close()
|
|
},
|
|
|
|
// 确认二维码支付完成
|
|
async confirmQRCodePayment() {
|
|
if (!this.qrCodePaymentData?.order) return
|
|
|
|
const order = this.qrCodePaymentData.order
|
|
|
|
uni.showModal({
|
|
title: '支付确认',
|
|
content: '请确认是否已完成扫码支付?',
|
|
success: async (res) => {
|
|
if (res.confirm) {
|
|
try {
|
|
// 更新订单状态为已支付
|
|
await this.updateOrderStatus(order, 'paid', `QR${Date.now()}`)
|
|
this.closeQRCodeModal()
|
|
} catch (error) {
|
|
console.error('支付确认失败:', error)
|
|
uni.showToast({ title: '支付确认失败', icon: 'none' })
|
|
}
|
|
}
|
|
}
|
|
})
|
|
},
|
|
|
|
// 订阅支付
|
|
showSubscriptionPayment(order) {
|
|
uni.showActionSheet({
|
|
itemList: ['确认分期支付方案', '取消支付'],
|
|
success: async (res) => {
|
|
if (res.tapIndex === 0) {
|
|
uni.showModal({
|
|
title: '分期支付确认',
|
|
content: `确认使用分期支付方式支付 ¥${order.total_amount}?`,
|
|
success: async (modalRes) => {
|
|
if (modalRes.confirm) {
|
|
// 这里可以设置为部分支付状态
|
|
await this.updateOrderStatus(order, 'partial', `SUB${Date.now()}`)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
})
|
|
},
|
|
|
|
// 微信支付
|
|
showWechatPayment(order) {
|
|
uni.showModal({
|
|
title: '微信支付',
|
|
content: `将调用微信支付 ¥${order.total_amount}`,
|
|
confirmText: '确认支付',
|
|
cancelText: '取消',
|
|
success: async (res) => {
|
|
if (res.confirm) {
|
|
// 模拟微信支付流程
|
|
uni.showLoading({ title: '正在调用微信支付...' })
|
|
|
|
// 模拟支付延时
|
|
setTimeout(async () => {
|
|
uni.hideLoading()
|
|
|
|
// 模拟支付结果(实际应该调用微信支付API)
|
|
uni.showModal({
|
|
title: '支付结果',
|
|
content: '微信支付完成,请确认是否已收到款项?',
|
|
success: async (confirmRes) => {
|
|
if (confirmRes.confirm) {
|
|
await this.updateOrderStatus(order, 'paid', `WX${Date.now()}`)
|
|
}
|
|
}
|
|
})
|
|
}, 1500)
|
|
}
|
|
}
|
|
})
|
|
},
|
|
|
|
// 统一的订单状态更新方法
|
|
async updateOrderStatus(order, status, paymentId = '') {
|
|
try {
|
|
const updateData = {
|
|
order_id: order._raw?.id || order.id,
|
|
order_status: status,
|
|
payment_id: paymentId
|
|
}
|
|
|
|
const result = await apiRoute.xs_orderTableUpdatePaymentStatus(updateData)
|
|
|
|
if (result.code === 1) {
|
|
const statusText = {
|
|
'paid': '支付成功',
|
|
'partial': '分期支付确认成功',
|
|
'cancelled': '支付已取消'
|
|
}
|
|
uni.showToast({
|
|
title: statusText[status] || '状态更新成功',
|
|
icon: 'success'
|
|
})
|
|
// 刷新订单列表
|
|
await this.getOrderList()
|
|
} else {
|
|
uni.showToast({ title: result.msg || '状态更新失败', icon: 'none' })
|
|
}
|
|
} catch (error) {
|
|
console.error('更新订单状态失败:', error)
|
|
uni.showToast({ title: '状态更新失败', icon: 'none' })
|
|
}
|
|
},
|
|
|
|
// 查看订单详情
|
|
viewOrderDetail(order) {
|
|
const orderInfo = order._raw || order
|
|
const detailText = `
|
|
订单号:${order.order_no}
|
|
课程:${order.product_name}
|
|
金额:¥${order.total_amount}
|
|
已付:¥${order.paid_amount}
|
|
未付:¥${order.unpaid_amount}
|
|
支付方式:${order.payment_method}
|
|
销售顾问:${order.salesperson_name}
|
|
课时数:${order.course_count}节
|
|
状态:${this.getOrderStatusText(order.status)}
|
|
创建时间:${this.formatOrderTime(order.create_time)}
|
|
${orderInfo.paid_at ? '支付时间:' + this.formatOrderTime(orderInfo.paid_at) : ''}
|
|
`.trim()
|
|
|
|
uni.showModal({
|
|
title: '订单详情',
|
|
content: detailText,
|
|
showCancel: false,
|
|
confirmText: '知道了'
|
|
})
|
|
},
|
|
|
|
// 获取订单状态文本
|
|
getOrderStatusText(status) {
|
|
const statusMap = {
|
|
'pending': '待支付',
|
|
'paid': '已支付',
|
|
'partial': '部分支付',
|
|
'cancelled': '已取消',
|
|
'completed': '已完成',
|
|
'refunded': '已退款'
|
|
}
|
|
return statusMap[status] || '未知状态'
|
|
},
|
|
|
|
// 格式化订单时间
|
|
formatOrderTime(timeStr) {
|
|
if (!timeStr) return '未知'
|
|
try {
|
|
const date = new Date(timeStr)
|
|
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`
|
|
} catch (e) {
|
|
return timeStr
|
|
}
|
|
},
|
|
|
|
// 获取赠品记录列表
|
|
async getGiftRecords() {
|
|
if (!this.clientInfo?.resource_id) return
|
|
|
|
try {
|
|
const res = await apiRoute.xs_customerResourcesGetGiftRecordList({
|
|
resource_id: this.clientInfo.resource_id
|
|
})
|
|
|
|
if (res.code === 1) {
|
|
this.giftRecords = res.data || []
|
|
} else {
|
|
console.error('获取赠品记录失败:', res.msg)
|
|
this.giftRecords = []
|
|
}
|
|
} catch (error) {
|
|
console.error('获取赠品记录异常:', error)
|
|
this.giftRecords = []
|
|
}
|
|
}
|
|
},
|
|
}
|
|
</script>
|
|
|
|
<style lang="less" scoped>
|
|
.fitness-records-container {
|
|
max-height: 60vh;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
/* 滚动条样式 */
|
|
.fitness-records-container::-webkit-scrollbar {
|
|
width: 6rpx;
|
|
}
|
|
|
|
.fitness-records-container::-webkit-scrollbar-track {
|
|
background: transparent;
|
|
}
|
|
|
|
.fitness-records-container::-webkit-scrollbar-thumb {
|
|
background: #29D3B4;
|
|
border-radius: 3rpx;
|
|
}
|
|
|
|
.fitness-records-container::-webkit-scrollbar-thumb:hover {
|
|
background: #24B89E;
|
|
}
|
|
@import './clue_info.less';
|
|
</style>
|