智慧教务系统
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.
 
 
 
 
 
 

1225 lines
34 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'"
:student-id="currentStudent && currentStudent.id"
:resource-id="clientInfo.resource_id"
@payment-success="handlePaymentSuccess"
/>
<!-- 服务列表弹窗 -->
<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" />
</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 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,
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: [],
serviceList: [],
// 编辑相关
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)
}
},
async handleMakeCall() {
const phone = this.clientInfo?.customerResource?.phone_number
if (phone) {
let param = {
staff_id: this.userInfo.id, //员工id
resource_id: this.clientInfo?.resource_id, //资源ID
resource_type: '', //资源类型(如设备、文件、系统等)
communication_type: 'phone', //沟通类型: phone-电话, email-邮件, meeting-会议, other-其他
communication_result: 'success', //沟通结果: success-成功, failure-失败, pending-待定
remarks: null, //备注
tag: null, //标签
}
let res = await apiRoute.xs_communicationRecordsAdd(param) //添加通过记录
if (res.code != 1) {
uni.showToast({
title: res.msg,
icon: 'none',
})
return
}
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':
// 订单列表由组件内部自动加载,只需打开弹窗
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.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.resource_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 = []
}
},
/**
* 订单支付成功回调
*/
handlePaymentSuccess(order) {
console.log('订单支付成功:', order)
// 可以在这里添加支付成功后的业务逻辑,例如刷新其他相关数据
},
// 获取赠品记录列表
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>