51 changed files with 322 additions and 18962 deletions
@ -1,263 +0,0 @@ |
|||
<template> |
|||
<view class="main_box"> |
|||
<view class="main_section"> |
|||
<!--教务待办事项--> |
|||
<view class="section_3"> |
|||
<view class="title_box"> |
|||
<view class="top_box"> |
|||
<text>教务待办</text> |
|||
<view></view> |
|||
</view> |
|||
<view class="line"></view> |
|||
</view> |
|||
<view class="ul" v-if="infoData.todo_list && infoData.todo_list.length > 0"> |
|||
<view class="li" v-for="(v,k) in infoData.todo_list" :key="k" @click="openViewTodoDetail(v)"> |
|||
<view class="top_box"> |
|||
<view class="title">任务:{{ v.title }}</view> |
|||
<view class="title">创建时间:{{ v.create_time }}</view> |
|||
<view class="title">截止时间:{{ v.deadline }}</view> |
|||
</view> |
|||
<view class="botton_box"> |
|||
<view class="box"> |
|||
<view>优先级:{{ v.priority_text }}</view> |
|||
<view> |
|||
查看 |
|||
<fui-icon size="35" color="#fff" name="arrowright"></fui-icon> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view |
|||
v-if="v.status == 'pending'" |
|||
class="tag" |
|||
style="background:#007ACC;">待处理 |
|||
</view> |
|||
<view |
|||
v-if="v.status == 'processing'" |
|||
class="tag" |
|||
style="background:#fad24e;">处理中 |
|||
</view> |
|||
<view |
|||
v-if="v.status == 'completed'" |
|||
class="tag" |
|||
style="background:#29d3b4;">已完成 |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view v-else class="empty_box"> |
|||
<image src="/static/images/empty.png" mode="aspectFit"></image> |
|||
<text>暂无待办事项</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!--统计数据--> |
|||
<view class="section_3"> |
|||
<view class="title_box"> |
|||
<view class="top_box"> |
|||
<text>数据统计</text> |
|||
<view></view> |
|||
</view> |
|||
<view class="line"></view> |
|||
</view> |
|||
<view class="stats_grid"> |
|||
<view class="stat_item" @click="openViewStats('students')"> |
|||
<view class="stat_number">{{ infoData.student_count || 0 }}</view> |
|||
<view class="stat_label">学员总数</view> |
|||
</view> |
|||
<view class="stat_item" @click="openViewStats('courses')"> |
|||
<view class="stat_number">{{ infoData.course_count || 0 }}</view> |
|||
<view class="stat_label">课程总数</view> |
|||
</view> |
|||
<view class="stat_item" @click="openViewStats('teachers')"> |
|||
<view class="stat_number">{{ infoData.teacher_count || 0 }}</view> |
|||
<view class="stat_label">教师总数</view> |
|||
</view> |
|||
<view class="stat_item" @click="openViewStats('classes')"> |
|||
<view class="stat_number">{{ infoData.class_count || 0 }}</view> |
|||
<view class="stat_label">班级总数</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import apiRoute from '@/api/apiRoute.js'; |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
infoData: { |
|||
todo_list: [], |
|||
student_count: 0, |
|||
course_count: 0, |
|||
teacher_count: 0, |
|||
class_count: 0 |
|||
} |
|||
} |
|||
}, |
|||
onShow() { |
|||
this.init() |
|||
}, |
|||
methods: { |
|||
async init() { |
|||
try { |
|||
// 获取教务首页数据 |
|||
const res = await apiRoute.getAcademicHomeData(); |
|||
if (res && res.code === 1) { |
|||
this.infoData = res.data; |
|||
} |
|||
} catch (error) { |
|||
console.error('获取教务数据失败:', error); |
|||
} |
|||
}, |
|||
|
|||
// 打开待办事项详情 |
|||
openViewTodoDetail(item) { |
|||
this.$navigateTo({ |
|||
url: `/pages/academic/todo/detail?id=${item.id}` |
|||
}); |
|||
}, |
|||
|
|||
// 打开统计页面 |
|||
openViewStats(type) { |
|||
this.$navigateTo({ |
|||
url: `/pages/academic/stats/index?type=${type}` |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.main_box { |
|||
width: 100%; |
|||
background-color: #f5f5f5; |
|||
min-height: 100vh; |
|||
padding-bottom: 140rpx; |
|||
} |
|||
|
|||
.main_section { |
|||
padding: 30rpx; |
|||
} |
|||
|
|||
.section_3 { |
|||
margin-bottom: 30rpx; |
|||
} |
|||
|
|||
.title_box { |
|||
.top_box { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 20rpx; |
|||
|
|||
text { |
|||
font-size: 36rpx; |
|||
font-weight: bold; |
|||
color: #007ACC; |
|||
} |
|||
} |
|||
|
|||
.line { |
|||
height: 4rpx; |
|||
background: linear-gradient(to right, #007ACC, #4DA6FF); |
|||
border-radius: 2rpx; |
|||
} |
|||
} |
|||
|
|||
.ul { |
|||
margin-top: 30rpx; |
|||
} |
|||
|
|||
.li { |
|||
background: #fff; |
|||
border-radius: 20rpx; |
|||
padding: 30rpx; |
|||
margin-bottom: 20rpx; |
|||
box-shadow: 0 4rpx 20rpx rgba(0, 122, 204, 0.1); |
|||
position: relative; |
|||
|
|||
.top_box { |
|||
.title { |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
margin-bottom: 15rpx; |
|||
line-height: 1.4; |
|||
} |
|||
} |
|||
|
|||
.botton_box { |
|||
margin-top: 20rpx; |
|||
|
|||
.box { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
background: #007ACC; |
|||
color: #fff; |
|||
padding: 20rpx 30rpx; |
|||
border-radius: 15rpx; |
|||
font-size: 26rpx; |
|||
margin-bottom: 10rpx; |
|||
} |
|||
} |
|||
|
|||
.tag { |
|||
position: absolute; |
|||
top: 30rpx; |
|||
right: 30rpx; |
|||
padding: 10rpx 20rpx; |
|||
border-radius: 20rpx; |
|||
color: #fff; |
|||
font-size: 22rpx; |
|||
} |
|||
} |
|||
|
|||
.empty_box { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
padding: 100rpx 0; |
|||
|
|||
image { |
|||
width: 200rpx; |
|||
height: 200rpx; |
|||
margin-bottom: 30rpx; |
|||
opacity: 0.5; |
|||
} |
|||
|
|||
text { |
|||
color: #999; |
|||
font-size: 28rpx; |
|||
} |
|||
} |
|||
|
|||
.stats_grid { |
|||
display: grid; |
|||
grid-template-columns: 1fr 1fr; |
|||
gap: 20rpx; |
|||
margin-top: 30rpx; |
|||
} |
|||
|
|||
.stat_item { |
|||
background: #fff; |
|||
border-radius: 20rpx; |
|||
padding: 40rpx 30rpx; |
|||
text-align: center; |
|||
box-shadow: 0 4rpx 20rpx rgba(0, 122, 204, 0.1); |
|||
|
|||
.stat_number { |
|||
font-size: 48rpx; |
|||
font-weight: bold; |
|||
color: #007ACC; |
|||
margin-bottom: 10rpx; |
|||
} |
|||
|
|||
.stat_label { |
|||
font-size: 26rpx; |
|||
color: #666; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,638 +0,0 @@ |
|||
<!--班级-详情--> |
|||
<template> |
|||
<view class="main_box"> |
|||
<!--自定义导航栏--> |
|||
<!-- <view class="navbar_section">--> |
|||
<!-- <view class="title">班级详情</view>--> |
|||
<!-- </view>--> |
|||
|
|||
<view class="main_section"> |
|||
<view class="section_1"> |
|||
<view class="left"> |
|||
<image class="pic" :src="classInfo.head_coach_head_img"></image> |
|||
<view class="name">{{classInfo.head_coach_name}}</view> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="item"> |
|||
班级:{{classInfo.class_name}} |
|||
</view> |
|||
|
|||
<view class="item"> |
|||
校区:{{classInfo.campus_name}} |
|||
</view> |
|||
|
|||
<!-- <view class="item"> |
|||
<!-- 课程:篮球少儿课 |
|||
<!-- </view>--> |
|||
|
|||
<view class="item"> |
|||
人数:{{classInfo.classPersonnelRel.length}}人 |
|||
</view> |
|||
<!-- |
|||
<view class="item"> |
|||
|
|||
时间:{{classInfo.start_date}} - {{classInfo.end_date}} |
|||
</view> --> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- <view class="section_2">--> |
|||
<!-- <view class="title_box">--> |
|||
<!-- <view>最近课程</view>--> |
|||
<!-- </view>--> |
|||
<!-- <view class="tag_list">--> |
|||
<!-- <view class="item" @click="openViewCourseInfo({id:1})">--> |
|||
<!-- <view class="title">--> |
|||
<!-- 篮球少儿课--> |
|||
<!-- </view>--> |
|||
<!-- <view>--> |
|||
<!-- 2020.05.30 15:30 - 17:30--> |
|||
<!-- </view>--> |
|||
<!-- </view>--> |
|||
<!-- <view class="item" @click="openViewCourseInfo({id:2})">--> |
|||
<!-- <view class="title">--> |
|||
<!-- 篮球少儿课--> |
|||
<!-- </view>--> |
|||
<!-- <view>--> |
|||
<!-- 2020.05.30 15:30 - 17:30--> |
|||
<!-- </view>--> |
|||
<!-- </view>--> |
|||
<!-- </view>--> |
|||
<!-- </view>--> |
|||
|
|||
<view class="section_3"> |
|||
<view class="btn_box"> |
|||
<view :class="['btn', tabType=='1'?'select':'']" @click="tabChange(1)"> |
|||
班级成员 |
|||
</view> |
|||
<view :class="['btn', tabType=='2'?'select':'']" @click="tabChange(2)"> |
|||
课程计划 |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 班级成员列表--> |
|||
<view class="section_4" v-if="tabType=='1'"> |
|||
<view class="ul"> |
|||
<view class="li" v-for="(v,k) in classInfo.classPersonnelRel" :key="k" |
|||
@click="openViewStudentInfo(v)"> |
|||
<view class="left"> |
|||
<view class="box_1"> |
|||
<image class="pic" :src="$util.img(v.student.customerResources.member.headimg)"></image> |
|||
<view class="tag_box" v-if="v.expire"> |
|||
即将到期 |
|||
</view> |
|||
</view> |
|||
<view class="box_2"> |
|||
<view class="name">{{ v.student.name }}</view> |
|||
<view class="date">课程截止时间:{{ $util.formatToDateTime(v.end_date, 'Y-m-d') }}</view> |
|||
</view> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="item"> |
|||
<view>{{ v.studentCoursesInfo.use_gift_hours + v.studentCoursesInfo.use_gift_hours }} |
|||
</view> |
|||
<view>已上课时</view> |
|||
</view> |
|||
<view class="item"> |
|||
<view> |
|||
{{ (v.studentCoursesInfo.total_hours + v.studentCoursesInfo.gift_hours) - (v.studentCoursesInfo.use_gift_hours + v.studentCoursesInfo.use_gift_hours) }} |
|||
</view> |
|||
<view>剩余课时</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!--课程计划--> |
|||
<scroll-view v-if="tabType=='2'" class="section_5" scroll-y="true" :lower-threshold="lowerThreshold" |
|||
@scrolltolower="loadMoreData" style="height: 65vh;"> |
|||
<view class="ul"> |
|||
<view class="li" v-for="(v,k) in courseList" :key="k" @click="openViewCourseInfo(v)"> |
|||
<view class="top_box"> |
|||
<view class="title"> |
|||
课程:{{v.course.course_name}} |
|||
</view> |
|||
<view class="title"> |
|||
时间:{{v.course_date}} |
|||
</view> |
|||
<view class="title"> |
|||
地点:{{v.campus_name}} |
|||
</view> |
|||
</view> |
|||
<view class="bottom_box"> |
|||
<view class="item"> |
|||
<view class="left">应到学员({{v.student.length}})</view> |
|||
<view class="right"> |
|||
查看 |
|||
<fui-icon size="35" color="#fff" name="arrowright"></fui-icon> |
|||
</view> |
|||
</view> |
|||
<view class="item"> |
|||
<view class="left">已签到学生({{v.student_courses.length}}/{{v.student.length}})</view> |
|||
<view class="right"> |
|||
查看 |
|||
<fui-icon size="35" color="#fff" name="arrowright"></fui-icon> |
|||
</view> |
|||
</view> |
|||
<!-- <view class="item">--> |
|||
<!-- <view class="left">作业完成率(80%)</view>--> |
|||
<!-- <view class="right">--> |
|||
<!-- 查看--> |
|||
<!-- <fui-icon size="35" color="#fff" name="arrowright"></fui-icon>--> |
|||
<!-- </view>--> |
|||
<!-- </view>--> |
|||
</view> |
|||
|
|||
<view class="tag" v-if="isCourseFuture(v.student_courses[0].start_date)" |
|||
style="background-color:#20CAAF;"> |
|||
未开始 |
|||
</view> |
|||
<view class="tag" v-if="isNowBetween(v.student_courses[0].start_date, v.student_courses[0].end_date)" |
|||
style="background-color:#fad24e;"> |
|||
上课中 |
|||
</view> |
|||
<view class="tag" v-if="!isCourseFuture(v.student_courses[0].end_date)" style="background-color:#e2e2e2;"> |
|||
已结束 |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</scroll-view> |
|||
</view> |
|||
|
|||
<!-- 底部导航--> |
|||
<!-- <AQTabber/>--> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import memberApi from '@/api/member.js'; |
|||
import AQTabber from "@/components/AQ/AQTabber.vue" |
|||
import apiRoute from '@/api/apiRoute.js'; |
|||
|
|||
export default { |
|||
components: { |
|||
AQTabber, |
|||
}, |
|||
data() { |
|||
return { |
|||
class_id: '', //班级id |
|||
classInfo: {}, //班级数据 |
|||
classMemberList: {}, //班级成员 |
|||
|
|||
tabType: '1', //1=班级成员,2=课程计划 |
|||
|
|||
|
|||
loading: false, //加载状态 |
|||
lowerThreshold: 100, //距离底部多远触发 |
|||
isReachedBottom: false, //防止重复加载|true=不可加载|false=可加载 |
|||
|
|||
//筛选条件 |
|||
filteredData: { |
|||
page: 1, //当前页码 |
|||
limit: 10, //每页返回数据条数 |
|||
total: 10, //数据总条数 |
|||
class_id: '', //班级id |
|||
}, |
|||
courseList: [], //课程计划数据 |
|||
} |
|||
}, |
|||
onLoad(options) { |
|||
this.class_id = options.class_id //课程id |
|||
}, |
|||
onShow() { |
|||
this.init() |
|||
}, |
|||
//下拉刷新 |
|||
async onPullDownRefresh() { |
|||
//重置为第一页 |
|||
await this.loadData() |
|||
await this.getCourseList() |
|||
}, |
|||
methods: { |
|||
|
|||
async init() { |
|||
// member/course_list//课程列表 |
|||
// member/class_info//班级详情+成员详情 |
|||
this.getClassInfo() //获取班级详情 |
|||
await this.getCourseList() //获取课程列表 |
|||
|
|||
}, |
|||
|
|||
isNowBetween(start_date, end_date) { |
|||
const now = new Date(); |
|||
const start = new Date(start_date); |
|||
const end = new Date(end_date); |
|||
|
|||
return now >= start && now <= end; |
|||
}, |
|||
|
|||
isCourseFuture(courseDate) { |
|||
const courseTime = new Date(courseDate).getTime(); |
|||
const nowTime = new Date().getTime(); |
|||
return courseTime > nowTime; |
|||
}, |
|||
|
|||
//教练端-获取班级详情 |
|||
async getClassInfo() { |
|||
let res = await apiRoute.jlClassInfo({ |
|||
class_id: this.class_id |
|||
}) //班级详情 |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
console.log('获取班级列表', res.data) |
|||
this.classInfo = res.data |
|||
this.classMemberList = res.data.students_list |
|||
}, |
|||
|
|||
|
|||
//加载更过(下一页) |
|||
loadMoreData() { |
|||
//判断是否加载 |
|||
if (!this.isReachedBottom) { |
|||
this.isReachedBottom = true; //设置为不可请求状态 |
|||
this.getCourseList(); |
|||
} |
|||
}, |
|||
//重置为第一页 |
|||
async loadData() { |
|||
this.isReachedBottom = false; // 重置状态,以便下次触发加载更多 |
|||
|
|||
this.filteredData.page = 1 //当前页码 |
|||
this.filteredData.limit = 10 //每页返回数据条数 |
|||
this.filteredData.total = 10 //数据总条数 |
|||
}, |
|||
//教练端-获取课程列表 |
|||
async getCourseList() { |
|||
|
|||
let data = { |
|||
...this.filteredData |
|||
} |
|||
data.class_id = this.class_id |
|||
|
|||
console.log(12123, this.courseList) |
|||
|
|||
if (data.page == 1) { |
|||
this.courseList = [] |
|||
} |
|||
|
|||
//判断是否还有数据 |
|||
if ((this.filteredData.page - 1) * this.filteredData.limit >= this.filteredData.total) { |
|||
this.loading = false |
|||
uni.showToast({ |
|||
title: '暂无更多', |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
let res = await apiRoute.classCourseList(data) |
|||
this.loading = false |
|||
this.isReachedBottom = false; |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
|
|||
this.courseList = this.courseList.concat(res.data.data) // 使用 concat 方法 将新数据追加到数组中 |
|||
|
|||
this.filteredData.total = res.data.total |
|||
console.log('获取课程列表', this.courseList) |
|||
this.filteredData.page++ |
|||
|
|||
}, |
|||
|
|||
|
|||
|
|||
//切换tab |
|||
tabChange(tabType) { |
|||
this.tabType = tabType |
|||
}, |
|||
|
|||
//打开课程详情 |
|||
openViewCourseInfo(item) { |
|||
let id = item.id |
|||
this.$navigateTo({ |
|||
url: `/pages/coach/course/info_list?id=${id}` |
|||
}) |
|||
}, |
|||
//打开学员详情页 |
|||
openViewStudentInfo(item) { |
|||
let students_id = item.student.id |
|||
this.$navigateTo({ |
|||
url: `/pages/coach/student/info?students_id=${students_id}` |
|||
}) |
|||
}, |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.main_box { |
|||
background: #292929; |
|||
} |
|||
|
|||
//自定义导航栏 |
|||
.navbar_section { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
background: #292929; |
|||
|
|||
.title { |
|||
padding: 40rpx 0rpx; |
|||
|
|||
/* 小程序端样式 */ |
|||
// #ifdef MP-WEIXIN |
|||
padding: 80rpx 0rpx; |
|||
// #endif |
|||
|
|||
|
|||
font-size: 30rpx; |
|||
color: #fff; |
|||
} |
|||
} |
|||
|
|||
.main_section { |
|||
min-height: 100vh; |
|||
background: #292929 100%; |
|||
padding: 0 24rpx; |
|||
padding-top: 40rpx; |
|||
padding-bottom: 150rpx; |
|||
font-size: 24rpx; |
|||
color: #FFFFFF; |
|||
|
|||
.section_1 { |
|||
background: #333333; |
|||
border-radius: 16rpx; |
|||
padding: 34rpx 64rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 38rpx; |
|||
|
|||
.left { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
gap: 12rpx; |
|||
|
|||
.pic { |
|||
width: 92rpx; |
|||
height: 92rpx; |
|||
border-radius: 50%; |
|||
} |
|||
} |
|||
|
|||
.right { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 12rpx; |
|||
|
|||
.item {} |
|||
} |
|||
} |
|||
|
|||
.section_2 { |
|||
margin-top: 42rpx; |
|||
|
|||
.title_box { |
|||
font-size: 32rpx; |
|||
} |
|||
|
|||
.tag_list { |
|||
margin-top: 26rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 26rpx; |
|||
|
|||
.item { |
|||
padding-left: 20rpx; |
|||
width: 330rpx; |
|||
height: 162rpx; |
|||
border: 1px solid #00e5bb; |
|||
border-radius: 10rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
gap: 10rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
//按钮切换 |
|||
.section_3 { |
|||
margin-top: 54rpx; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
|
|||
.btn_box { |
|||
width: 698rpx; |
|||
border-radius: 8rpx; |
|||
background-color: rgba(22, 132, 252, 1); |
|||
border: 1rpx solid rgba(22, 132, 252, 1); |
|||
|
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
overflow: hidden; |
|||
|
|||
.btn { |
|||
width: 100%; |
|||
height: 76rpx; |
|||
line-height: 76rpx; |
|||
text-align: center; |
|||
color: #fff; |
|||
font-size: 26rpx; |
|||
} |
|||
|
|||
.select { |
|||
color: #1684fc; |
|||
background-color: #fff; |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
//班级成员列表 |
|||
.section_4 { |
|||
margin-top: 40rpx; |
|||
|
|||
.ul { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 10rpx; |
|||
|
|||
.li { |
|||
padding: 20rpx 0; |
|||
padding-bottom: 40rpx; |
|||
border-bottom: 2px solid #D7D7D7; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
|
|||
.left { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 30rpx; |
|||
|
|||
.box_1 { |
|||
padding-left: 20rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
position: relative; |
|||
|
|||
.pic { |
|||
width: 84rpx; |
|||
height: 84rpx; |
|||
border-radius: 50%; |
|||
} |
|||
|
|||
.tag_box { |
|||
position: absolute; |
|||
bottom: -30rpx; |
|||
width: 120rpx; |
|||
height: 38rpx; |
|||
background-color: #F59A23; |
|||
border-radius: 4rpx; |
|||
line-height: 35rpx; |
|||
text-align: center; |
|||
font-size: 20rpx; |
|||
} |
|||
} |
|||
|
|||
.box_2 { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 20rpx; |
|||
|
|||
.name { |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.date { |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.right { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 14rpx; |
|||
|
|||
.item { |
|||
border: 1px solid #00E5BB; |
|||
border-radius: 10rpx; |
|||
width: 102rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
|
|||
view { |
|||
text-align: center; |
|||
height: 50rpx; |
|||
line-height: 50rpx; |
|||
} |
|||
|
|||
view:nth-child(1) { |
|||
font-size: 32rpx; |
|||
background-color: #fff; |
|||
color: #00e5bb; |
|||
} |
|||
|
|||
view:nth-child(2) { |
|||
font-size: 20rpx; |
|||
background-color: #00e5bb; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
//课程计划 |
|||
.section_5 { |
|||
margin-top: 36rpx; |
|||
|
|||
.ul { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 30rpx; |
|||
|
|||
.li { |
|||
position: relative; |
|||
border-radius: 10rpx; |
|||
background-color: rgba(63, 63, 67, 1); |
|||
border: 2rpx solid rgba(0, 229, 187, 1); |
|||
padding: 20rpx 14rpx; |
|||
|
|||
display: flex; |
|||
flex-direction: column; |
|||
|
|||
.top_box { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 10rpx; |
|||
|
|||
.title { |
|||
color: rgba(255, 255, 255, 1); |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
|
|||
.bottom_box { |
|||
padding-top: 10rpx; |
|||
margin-top: 20rpx; |
|||
border-top: 1px dashed #F2F2F2; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 10rpx; |
|||
|
|||
.item { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
|
|||
color: rgba(215, 215, 215, 1); |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
|
|||
.tag { |
|||
position: absolute; |
|||
right: 0rpx; |
|||
top: 0rpx; |
|||
width: 110rpx; |
|||
height: 60rpx; |
|||
line-height: 58rpx; |
|||
border-radius: 0rpx 8rpx 0rpx 24rpx; |
|||
background-color: rgba(32, 202, 175, 1); |
|||
color: rgba(255, 255, 255, 1); |
|||
font-size: 24rpx; |
|||
text-align: center; |
|||
border: 0rpx solid rgba(121, 121, 121, 1); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
} |
|||
</style> |
|||
@ -1,299 +0,0 @@ |
|||
<!--班级-列表--> |
|||
<template> |
|||
<view class="main_box"> |
|||
<!--自定义导航栏--> |
|||
<view class="navbar_section"> |
|||
<view class="title">班级</view> |
|||
</view> |
|||
|
|||
<view class="main_section"> |
|||
<view class="section_1"> |
|||
<fui-input class="input_item" borderTop clearable="true" placeholder="搜索" v-model="filteredData.name" @confirm="search" @input="search"></fui-input> |
|||
</view> |
|||
|
|||
<view class="section_2"> |
|||
<scroll-view |
|||
class="ul" |
|||
scroll-y="true" |
|||
:lower-threshold="lowerThreshold" |
|||
@scrolltolower="loadMoreData" |
|||
style="height: 65vh;" |
|||
> |
|||
<view |
|||
class="li" |
|||
v-for="(v,k) in tableList" |
|||
:key="k" |
|||
@click="openViewClassInfo(v)" |
|||
> |
|||
<view class="left"> |
|||
<image class="pic" :src="v.head_coach_head_img"></image> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="box_1"> |
|||
<view class="name"> |
|||
{{v.class_name}} |
|||
</view> |
|||
<view class="btn_box"> |
|||
<view v-if="v.end_count">{{v.end_count}}人即将到期</view> |
|||
</view> |
|||
</view> |
|||
<view class="box_2"> |
|||
<view class="user_list" v-for="(v2,k2) in v.classPersonnelRel" :key="k2"> |
|||
<image |
|||
:src="$util.img(v2.student.customerResources.member.headimg)"></image> |
|||
</view> |
|||
<view class="num">{{v.students_count}}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</scroll-view> |
|||
</view> |
|||
|
|||
</view> |
|||
|
|||
<!-- 底部导航--> |
|||
<AQTabber/> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import memberApi from '@/api/member.js'; |
|||
import AQTabber from "@/components/AQ/AQTabber.vue" |
|||
import apiRoute from '@/api/apiRoute.js'; |
|||
|
|||
export default { |
|||
components: { |
|||
AQTabber, |
|||
}, |
|||
data() { |
|||
return { |
|||
loading:false,//加载状态 |
|||
lowerThreshold: 100,//距离底部多远触发 |
|||
isReachedBottom: false,//防止重复加载|true=不可加载|false=可加载 |
|||
|
|||
//筛选条件 |
|||
filteredData:{ |
|||
page:1,//当前页码 |
|||
limit:10,//每页返回数据条数 |
|||
total:10,//数据总条数 |
|||
name: '',//班级名称 |
|||
}, |
|||
tableList:[],//聊天数据列表 |
|||
} |
|||
}, |
|||
onLoad(options) {}, |
|||
onShow(){ |
|||
this.init()//初始化 |
|||
}, |
|||
methods: { |
|||
//初始化 |
|||
async init(){ |
|||
this.getList() |
|||
}, |
|||
|
|||
//加载更多(下一页) |
|||
loadMoreData() { |
|||
//判断是否加载 |
|||
if (!this.isReachedBottom) { |
|||
this.isReachedBottom = true;//设置为不可请求状态 |
|||
this.getList(); |
|||
} |
|||
}, |
|||
//重置为第一页 |
|||
async resetFilteredData() { |
|||
this.isReachedBottom = false; // 重置状态,以便下次触发加载更多 |
|||
|
|||
this.filteredData.page = 1//当前页码 |
|||
this.filteredData.limit = 10//每页返回数据条数 |
|||
this.filteredData.total = 10//数据总条数 |
|||
}, |
|||
//获取列表 |
|||
async getList(){ |
|||
this.loading = true |
|||
|
|||
let data = {...this.filteredData} |
|||
|
|||
console.log(111,(this.filteredData.page * this.filteredData.limit) ,(this.filteredData.total)) |
|||
|
|||
//判断是否还有数据 |
|||
if ((this.filteredData.page - 1) * this.filteredData.limit >= this.filteredData.total) { |
|||
this.loading = false |
|||
uni.showToast({ |
|||
title: '暂无更多', |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
if(data.page == 1){ |
|||
this.tableList = [] |
|||
} |
|||
|
|||
let res = await apiRoute.jlClassList(data) |
|||
this.loading = false |
|||
this.isReachedBottom = false; |
|||
if (res.code != 1){ |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
this.tableList = this.tableList.concat(res.data.data); // 使用 concat 方法 将新数据追加到数组中 |
|||
|
|||
console.log('列表',this.tableList) |
|||
this.filteredData.total = res.data.total |
|||
this.filteredData.page++ |
|||
}, |
|||
|
|||
async search(e){ |
|||
await this.resetFilteredData() |
|||
this.filteredData.name = e |
|||
await this.getList() |
|||
}, |
|||
|
|||
//打开班级详情页 |
|||
openViewClassInfo(item){ |
|||
let class_id = item.id |
|||
this.$navigateTo({ |
|||
url: `/pages/coach/class/info?class_id=${class_id}` |
|||
}) |
|||
}, |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
|
|||
.main_box{ |
|||
background: #292929 ; |
|||
} |
|||
|
|||
//自定义导航栏 |
|||
.navbar_section{ |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
background: #292929; |
|||
.title{ |
|||
padding: 40rpx 0rpx; |
|||
|
|||
/* 小程序端样式 */ |
|||
// #ifdef MP-WEIXIN |
|||
padding: 80rpx 0rpx; |
|||
// #endif |
|||
|
|||
|
|||
font-size: 30rpx; |
|||
color: #fff; |
|||
} |
|||
} |
|||
|
|||
.main_section{ |
|||
// min-height: 100vh; |
|||
background: #292929 100%; |
|||
padding: 0 24rpx; |
|||
padding-top: 40rpx; |
|||
padding-bottom: 150rpx; |
|||
font-size: 24rpx; |
|||
color: #FFFFFF; |
|||
|
|||
.section_1 { |
|||
border-radius: 10rpx; |
|||
background-color: #525252; |
|||
::v-deep .fui-input__wrap{ |
|||
border-radius: 10rpx !important; |
|||
background-color: #525252 !important; |
|||
} |
|||
::v-deep .fui-input__background{ |
|||
background-color: #525252 !important; |
|||
} |
|||
.input_item { |
|||
height: 60rpx; |
|||
::v-deep .uni-input-wrapper{ |
|||
.uni-input-placeholder { |
|||
font-size: 28rpx !important; |
|||
|
|||
} |
|||
|
|||
} |
|||
} |
|||
::v-deep .uni-input-input { |
|||
color: #fff; |
|||
} |
|||
} |
|||
|
|||
.section_2{ |
|||
margin-top: 34rpx; |
|||
.ul{ |
|||
display: flex; |
|||
flex-direction: column; |
|||
//gap: 24rpx; |
|||
.li{ |
|||
margin-bottom: 24rpx; |
|||
background: #404045; |
|||
padding: 50rpx 36rpx 46rpx; |
|||
border-radius: 16rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 32rpx; |
|||
.left{ |
|||
.pic{ |
|||
border-radius: 50%; |
|||
width: 92rpx; |
|||
height: 92rpx; |
|||
} |
|||
} |
|||
.right{ |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 28rpx; |
|||
.box_1{ |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 36rpx; |
|||
.name{ |
|||
font-size: 28rpx; |
|||
} |
|||
.btn_box{ |
|||
view{ |
|||
border: 1px solid #FAD04D; |
|||
border-radius: 10rpx; |
|||
width: 182rpx; |
|||
height: 48rpx; |
|||
line-height: 42rpx; |
|||
text-align: center; |
|||
font-size: 26rpx; |
|||
color: #FAD04D; |
|||
} |
|||
} |
|||
} |
|||
.box_2{ |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 44rpx; |
|||
.user_list{ |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 14rpx; |
|||
image{ |
|||
border-radius: 50%; |
|||
width: 48rpx; |
|||
height: 48rpx; |
|||
} |
|||
} |
|||
.num{} |
|||
} |
|||
|
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
} |
|||
|
|||
|
|||
</style> |
|||
@ -1,234 +0,0 @@ |
|||
<!--课程-详情--> |
|||
<template> |
|||
<view class="main_box"> |
|||
<view class="main_section"> |
|||
<view class="section_1"> |
|||
<view class="title_box">青少儿篮球课</view> |
|||
<view class="ul"> |
|||
<view class="li"> |
|||
<view class="title">课程名称</view> |
|||
<view class="content">青少年篮球课</view> |
|||
</view> |
|||
|
|||
<view class="li"> |
|||
<view class="title">班级</view> |
|||
<view class="content">班级名称</view> |
|||
</view> |
|||
|
|||
<view class="li"> |
|||
<view class="title">上课时间</view> |
|||
<view class="content">2020.03.25 15:30-17:00</view> |
|||
</view> |
|||
|
|||
<view class="li"> |
|||
<view class="title">上课地址</view> |
|||
<view class="content">xxxx体育馆302室</view> |
|||
</view> |
|||
|
|||
<view class="li"> |
|||
<view class="title">课程名称</view> |
|||
<view class="content">青少年篮球课</view> |
|||
</view> |
|||
|
|||
<view class="li"> |
|||
<view class="title">教练</view> |
|||
<view class="content">包子皮</view> |
|||
</view> |
|||
|
|||
<view class="li"> |
|||
<view class="title">教练号码</view> |
|||
<view class="content">18888888888</view> |
|||
</view> |
|||
|
|||
<view class="li"> |
|||
<view class="title">扣除课时</view> |
|||
<view class="content">2个课时</view> |
|||
</view> |
|||
|
|||
<view class="state_box"> |
|||
<view>已上</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
// import user from '@/api/user.js'; |
|||
import AQTabber from "@/components/AQ/AQTabber.vue" |
|||
|
|||
|
|||
export default { |
|||
components: { |
|||
AQTabber, |
|||
}, |
|||
data() { |
|||
return { |
|||
formData:{}, |
|||
|
|||
//课程下拉菜单相关 |
|||
show_course:false,//是否显示下拉菜单 |
|||
//课程下拉菜单 |
|||
course_name:'课程',//选中的下拉菜单名称 |
|||
options_course: [ |
|||
{ |
|||
text: '请选择课程', |
|||
value: '', |
|||
checked: true |
|||
}, { |
|||
text: '羽毛球课程1', |
|||
value: '1' |
|||
}, { |
|||
text: '篮球课程2', |
|||
value: '2' |
|||
} |
|||
], |
|||
|
|||
//课室下拉菜单相关 |
|||
show_classroom:false,//是否显示下拉菜单 |
|||
//课程下拉菜单 |
|||
classroom_name:'课室',//选中的下拉菜单名称 |
|||
options_classroom: [ |
|||
{ |
|||
text: '请选择课室', |
|||
value: '', |
|||
checked: true |
|||
}, { |
|||
text: '羽毛球201', |
|||
value: '1' |
|||
}, { |
|||
text: '篮球室101', |
|||
value: '2' |
|||
} |
|||
], |
|||
} |
|||
}, |
|||
onLoad() { |
|||
}, |
|||
methods: { |
|||
//选中课程下拉菜单点击事件 |
|||
clickCourse(e){ |
|||
console.log(e) |
|||
this.course_name = e.text |
|||
this.show_course = true |
|||
}, |
|||
//显示下拉菜单 |
|||
filterTapCourse() { |
|||
//显示下拉框 |
|||
this.$refs.ref_course.show() |
|||
this.show_course = true; |
|||
}, |
|||
|
|||
|
|||
|
|||
//选中课室 |
|||
clickClassroom(e){ |
|||
console.log(e) |
|||
this.classroom_name = e.text |
|||
this.show_classroom = true |
|||
}, |
|||
//显示课室下拉菜单 |
|||
filterTapClassroom() { |
|||
//显示下拉框 |
|||
this.$refs.ref_classroom.show() |
|||
this.show_classroom = true; |
|||
}, |
|||
|
|||
//打开课时详情页 |
|||
openViewCourseInfo(item){ |
|||
this.$navigateTo({ |
|||
url: '/pages/coach/course/info' |
|||
}) |
|||
}, |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
|
|||
.main_box{ |
|||
background: #292929 ; |
|||
} |
|||
|
|||
//自定义导航栏 |
|||
.navbar_section{ |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
background: #292929; |
|||
.title{ |
|||
padding: 40rpx 0rpx; |
|||
|
|||
/* 小程序端样式 */ |
|||
// #ifdef MP-WEIXIN |
|||
padding: 80rpx 0rpx; |
|||
// #endif |
|||
|
|||
|
|||
font-size: 30rpx; |
|||
color: #fff; |
|||
} |
|||
} |
|||
|
|||
.main_section{ |
|||
min-height: 100vh; |
|||
background: #292929 100%; |
|||
padding: 30rpx 24rpx; |
|||
padding-top: 40rpx; |
|||
padding-bottom: 150rpx; |
|||
font-size: 24rpx; |
|||
color: #FFFFFF; |
|||
|
|||
.section_1{ |
|||
border-radius: 22rpx; |
|||
padding: 20rpx 40rpx; |
|||
background: #333333 100%; |
|||
width: 100%; |
|||
.title_box{ |
|||
padding: 10rpx; |
|||
padding-left: 30rpx; |
|||
font-size: 32rpx; |
|||
} |
|||
.ul{ |
|||
padding: 40rpx 10rpx; |
|||
padding-bottom: 350rpx; |
|||
margin-top: 10rpx; |
|||
border-top: 1px solid #555555; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 40rpx; |
|||
|
|||
position: relative; |
|||
|
|||
.li{ |
|||
display: flex; |
|||
gap: 72rpx; |
|||
.title{ |
|||
width: 120rpx; |
|||
text-align: right; |
|||
} |
|||
.content{} |
|||
} |
|||
.state_box{ |
|||
position: absolute; |
|||
bottom: 50rpx; |
|||
right: 10rpx; |
|||
view{ |
|||
width: 154rpx; |
|||
height: 154rpx; |
|||
border-radius: 50%; |
|||
background-color: rgba(41,211,180,0.17); |
|||
color: rgba(41,211,180,1); |
|||
font-size: 26rpx; |
|||
text-align: center; |
|||
line-height: 150rpx; |
|||
transform: rotate(-35deg); /* 旋转 */ |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
</style> |
|||
@ -1,793 +0,0 @@ |
|||
<!--课程-详情列表--> |
|||
<template> |
|||
<view class="main_box"> |
|||
<view class="main_section"> |
|||
<view class="section_1"> |
|||
<view class="title">日期:{{courseInfo.course_date}}</view> |
|||
<view class="title">时间:{{courseInfo.time_slot}}</view> |
|||
<view class="title">地点:{{courseInfo.venue.venue_name}}</view> |
|||
<view class="title">课程:{{courseInfo.course.course_name}}</view> |
|||
<view class="title">教练:{{courseInfo.coach.name}}</view> |
|||
<view class="title">人数:{{courseInfo.venue.capacity}}</view> |
|||
<view class="isbtn" @click="addStudent"> |
|||
添加学员 |
|||
</view> |
|||
<view v-if="courseInfo.student_courses[0] && isNowBetween(courseInfo.student_courses[0].start_date, courseInfo.student_courses[0].end_date)" class="tag" style="background-color: #FAD24E;">上课中 |
|||
</view> |
|||
<view v-if="courseInfo.student_courses[0] && !isCourseFuture(courseInfo.student_courses[0].end_date)" class="tag" style="background-color: #e2e2e2;">已结束 |
|||
</view> |
|||
<view v-if="courseInfo.student_courses[0] && isCourseFuture(courseInfo.student_courses[0].start_date)" class="tag" style="background-color: #1cd188;">未开始 |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="section_2"> |
|||
<view :class="['table', tableType==1 ? 'select':'']" @click="switchTag(1)">学员情况</view> |
|||
<view :class="['table', tableType==2 ? 'select':'']" @click="switchTag(2)">作业情况</view> |
|||
</view> |
|||
|
|||
<!--签到情况--> |
|||
<view class="section_3" v-if="tableType == 1"> |
|||
|
|||
<view class="tip_title" v-if="courseInfo.student_courses.length == 0">暂无数据</view> |
|||
|
|||
<view class="item" v-for="(v,k) in courseInfo.student_courses" :key="k"> |
|||
<view class="left" @click="openViewCourseInfo(v)"> |
|||
<image class="pic" model="aspectFit" :src="$util.img(v.avatar)"></image> |
|||
<view class="box"> |
|||
<view class="title">{{v.name}}</view> |
|||
<view class="title">来源:{{v.source}}</view> |
|||
<view class="title">一访情况:{{v['school_six_speed'].first_visit_time}}</view> |
|||
<view class="title">一访时间:{{v['school_six_speed'].first_visit_status}}</view> |
|||
|
|||
<view class="title">课程截止时间:{{v.end_date}}</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="right" v-if="courseInfo.status == 'pending'"> |
|||
<view class="tag leave-tag" @click="written(v.student_id)" v-if="!isWithinTimeSlot(courseInfo.time_slot) && v.status !== 'signed'">请假</view> |
|||
<view class="tag signin-tag" @click="signIn(v.student_id)" v-if="isWithinTimeSlot(courseInfo.time_slot) && v.status !== 'signed'">签到</view> |
|||
<view class="tag signed-tag" v-if="v.status === 'signed'">已签到</view> |
|||
</view> |
|||
</view> |
|||
|
|||
</view> |
|||
|
|||
<!--作业情况--> |
|||
<view class="section_4" v-if="tableType == 2"> |
|||
<view class="item_box"> |
|||
<!-- 待批改--> |
|||
<fui-collapse-item @change="changeCollapse(1)" open="true" isBorder="false" contentBg="#434544"> |
|||
<view class="title_box"> |
|||
<text>待批改({{courseInfo.groupedByStatus1.length}})</text> |
|||
</view> |
|||
<template v-slot:content> |
|||
<view class="ul"> |
|||
<view v-for="(v,k) in courseInfo.groupedByStatus1" :key="k" class="li" |
|||
@click="openViewWorkDetails(v)"> |
|||
<view class="left"> |
|||
<image class="pic" model="aspectFit" |
|||
:src="$util.img(v.student.customerResources.member.headimg)"></image> |
|||
<view class="box"> |
|||
<view class="title">{{v.student.name}}</view> |
|||
<view class="title"> |
|||
<view>提交时间</view> |
|||
<view>{{v.created_at}}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- <view class="right"> |
|||
<view class="btn">查看并批改</view> |
|||
</view> --> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
</fui-collapse-item> |
|||
</view> |
|||
|
|||
<!-- 未提交--> |
|||
<view class="item_box"> |
|||
<fui-collapse-item @change="changeCollapse(2)" isBorder="false" contentBg="#434544"> |
|||
<view class="title_box"> |
|||
<text>未提交({{courseInfo.groupedByStatus2.length}})</text> |
|||
</view> |
|||
<template v-slot:content> |
|||
<view class="ul"> |
|||
<view class="li" v-for="(v,k) in courseInfo.groupedByStatus2" :key="k" |
|||
@click="openViewWorkDetails(v)"> |
|||
<view class="left"> |
|||
<image class="pic" model="aspectFit" |
|||
:src="$util.img(v.student.customerResources.member.headimg)"></image> |
|||
<view class="box"> |
|||
<view class="title">{{v.student.name}}</view> |
|||
<view class="title"> |
|||
<view>提交时间</view> |
|||
<!-- <view>{{v.created_at}}</view> --> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- <view class="right"> |
|||
<view class="btn">查看并批改</view> |
|||
</view> --> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
</fui-collapse-item> |
|||
</view> |
|||
|
|||
<!-- 已提交--> |
|||
<view class="item_box"> |
|||
<fui-collapse-item @change="changeCollapse(3)" isBorder="false" contentBg="#434544"> |
|||
<view class="title_box"> |
|||
<text>已提交({{courseInfo.groupedByStatus3.length}})</text> |
|||
</view> |
|||
<template v-slot:content> |
|||
<view class="ul"> |
|||
<view class="li" v-for="(v,k) in courseInfo.groupedByStatus3" :key="k" |
|||
@click="openViewWorkDetails(v)"> |
|||
<view class="left"> |
|||
<image class="pic" model="aspectFit" |
|||
:src="$util.img(v.student.customerResources.member.headimg)"></image> |
|||
<view class="box"> |
|||
<view class="title">{{v.student.name}}</view> |
|||
<view class="title"> |
|||
<view>提交时间</view> |
|||
<view>{{v.created_at}}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- <view class="right"> |
|||
<view class="btn">查看并批改</view> |
|||
</view> --> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
</fui-collapse-item> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<fui-modal :show="show" title="选择学员" @click="handleModalClick" :buttons="[]" @cancel="cancel"> |
|||
<view class="student-list"> |
|||
<view class="student-item" v-for="(item, index) in StudentList" :key="index" @click="change(item)"> |
|||
<view class="student-info"> |
|||
<view class="student-name">{{item.text}}</view> |
|||
<view class="student-details"> |
|||
<text>年龄: {{item.age || '未知'}}</text> |
|||
<text>来源: {{item.source || '未知'}}</text> |
|||
<text>渠道: {{item.source_channel || '未知'}}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="empty-list" v-if="StudentList.length === 0"> |
|||
<text>暂无可添加的学员</text> |
|||
</view> |
|||
</view> |
|||
</fui-modal> |
|||
<fui-picker :options="StudentList" :linkage="false" :show="false" :layer="1" @change="change" |
|||
@cancel="cancel"></fui-picker> |
|||
<fui-actionsheet :show="written_show" :tips="written_tips" :isCancel="isCancel" |
|||
:itemList="itemList" @cancel="written_cancel" @click="written_click"></fui-actionsheet> |
|||
|
|||
<uni-popup ref="popup" type="center"> |
|||
<view class="popup-content">{{ tipContent }}</view> |
|||
</uni-popup> |
|||
<AQTabber /> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import memberApi from '@/api/member.js'; |
|||
import AQTabber from "@/components/AQ/AQTabber.vue" |
|||
import apiRoute from '@/api/apiRoute.js'; |
|||
|
|||
export default { |
|||
components: { |
|||
AQTabber, |
|||
}, |
|||
data() { |
|||
return { |
|||
course_id: '', //课程id |
|||
courseInfo: { |
|||
sign_list: [], //签到列表 |
|||
assignments: { |
|||
dpg_list: [], // 待批改作业列表 |
|||
wtj_list: [], // 未提交作业列表 |
|||
ypg_list: [] // 已批改作业列表 |
|||
}, |
|||
}, //课时详情 |
|||
|
|||
tableType: 1, //1=签到情况,2=作业情况 |
|||
show: false, |
|||
StudentList: [], |
|||
written_show: false, |
|||
written_tips: '确认请假', |
|||
isCancel: false, |
|||
itemList: ['确认', '取消'], |
|||
qingjia_student_id: 0 |
|||
} |
|||
}, |
|||
onLoad(options) { |
|||
this.course_id = options.id |
|||
}, |
|||
onShow() { |
|||
this.init() |
|||
}, |
|||
methods: { |
|||
//初始化 |
|||
async init() { |
|||
this.getCourseInfo() |
|||
}, |
|||
|
|||
isNowBetween(start_date, end_date) { |
|||
const now = new Date(); |
|||
const start = new Date(start_date); |
|||
const end = new Date(end_date); |
|||
|
|||
return now >= start && now <= end; |
|||
}, |
|||
|
|||
isCourseFuture(courseDate) { |
|||
const courseTime = new Date(courseDate).getTime(); |
|||
const nowTime = new Date().getTime(); |
|||
return courseTime > nowTime; |
|||
}, |
|||
|
|||
//教练端-课程详情 |
|||
async getCourseInfo() { |
|||
let res = await apiRoute.courseInfo({ |
|||
id: this.course_id |
|||
}) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
console.log('课程详情', res.data) |
|||
this.courseInfo = res.data |
|||
|
|||
|
|||
// 使用模拟数据 |
|||
// this.courseInfo = { |
|||
// id: this.course_id || '1', |
|||
// course_date: '2025-07-25', |
|||
// time_slot: '14:00-15:30', |
|||
// status: 'pending', |
|||
// venue: { |
|||
// venue_name: '总部校区 305教室', |
|||
// capacity: 20 |
|||
// }, |
|||
// course: { |
|||
// course_name: '少儿英语基础班' |
|||
// }, |
|||
// coach: { |
|||
// name: '王教练' |
|||
// }, |
|||
// student_courses: [ |
|||
// { |
|||
// student_id: '1001', |
|||
// name: '张三', |
|||
// avatar: '', |
|||
// start_date: '2025-07-25', |
|||
// end_date: '2025-10-25', |
|||
// status: 'pending' |
|||
// }, |
|||
// { |
|||
// student_id: '1002', |
|||
// name: '李四', |
|||
// avatar: '', |
|||
// start_date: '2025-07-25', |
|||
// end_date: '2025-10-25', |
|||
// status: 'pending' |
|||
// } |
|||
// ], |
|||
// groupedByStatus1: [], // 待批改 |
|||
// groupedByStatus2: [], // 未提交 |
|||
// groupedByStatus3: [] // 已提交 |
|||
// }; |
|||
|
|||
// console.log('课程详情(模拟数据)', this.courseInfo); |
|||
}, |
|||
|
|||
//切换标签 |
|||
switchTag(type) { |
|||
this.tableType = type |
|||
}, |
|||
|
|||
//打开课时详情页 |
|||
openViewCourseInfo(item) { |
|||
// this.$navigateTo({ |
|||
// url: '/pages/coach/course/info' |
|||
// }) |
|||
uni.navigateTo({ |
|||
url: `/pages/market/clue/clue_info?resource_sharing_id=25` |
|||
}); |
|||
}, |
|||
|
|||
// 作业情况 |
|||
changeCollapse(type) {}, |
|||
|
|||
//跳转页面-作业详情 |
|||
openViewWorkDetails(item) { |
|||
let id = item.id |
|||
this.$navigateTo({ |
|||
url: `/pages/coach/student/work_details?id=${id}` |
|||
}) |
|||
}, |
|||
|
|||
//获取添加学员列表 |
|||
async addStudent() { |
|||
let res = await apiRoute.addStudentList({ |
|||
id: this.course_id |
|||
}) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
this.StudentList = res.data |
|||
if (this.StudentList.length == 0) { |
|||
uni.showToast({ |
|||
title: '暂无可填加的学员', |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} else { |
|||
// 显示学员选择弹窗 |
|||
this.show = true |
|||
} |
|||
}, |
|||
// 处理模态框点击事件 |
|||
handleModalClick(e) { |
|||
// 如果需要响应按钮事件可在这里处理 |
|||
console.log('模态框点击事件', e) |
|||
}, |
|||
async change(student) { |
|||
this.show = false |
|||
// 获取学生的student_id和resource_id |
|||
let studentId = student.value |
|||
let resourceId = student.resource_id |
|||
|
|||
let res = await apiRoute.addStudent({ |
|||
student_id: studentId, |
|||
schedule_id: this.course_id, |
|||
time_slot: this.courseInfo.time_slot, |
|||
course_date: this.courseInfo.course_date, |
|||
resource_id: resourceId // 添加resource_id参数 |
|||
}) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
uni.showToast({ |
|||
title: '添加学员成功', |
|||
icon: 'success' |
|||
}) |
|||
|
|||
// 刷新页面数据 |
|||
this.init() |
|||
}, |
|||
cancel() { |
|||
this.show = false |
|||
}, |
|||
//请假 |
|||
written(student_id) { |
|||
this.qingjia_student_id = student_id |
|||
this.written_show = true |
|||
}, |
|||
written_cancel() { |
|||
this.written_show = false |
|||
}, |
|||
async written_click(e) { |
|||
if(e.text == '取消'){ |
|||
this.written_show = false |
|||
} else { |
|||
let res = await apiRoute.delStudentCourse({ |
|||
student_id: this.qingjia_student_id, |
|||
course_id: this.course_id, |
|||
}) |
|||
if (res.data) { |
|||
uni.showToast({ |
|||
title: '请假成功', |
|||
icon: 'none' |
|||
}) |
|||
this.init() |
|||
} else { |
|||
// uni.showToast({ |
|||
// title: '学员不存在', |
|||
// icon: 'none' |
|||
// }) |
|||
} |
|||
this.written_show = false |
|||
} |
|||
|
|||
}, |
|||
isWithinTimeSlot(time_slot) { |
|||
const [startStr, endStr] = time_slot.split('-'); |
|||
const [startHours, startMinutes] = startStr.split(':').map(Number); |
|||
const [endHours, endMinutes] = endStr.split(':').map(Number); |
|||
|
|||
const now = new Date(); |
|||
const startTime = new Date(now.getFullYear(), now.getMonth(), now.getDate(), startHours, startMinutes); |
|||
const endTime = new Date(now.getFullYear(), now.getMonth(), now.getDate(), endHours, endMinutes); |
|||
|
|||
return now >= startTime && now < endTime; |
|||
}, |
|||
signIn(student_id) { |
|||
uni.showToast({ |
|||
title: '签到成功', |
|||
icon: 'success' |
|||
}); |
|||
|
|||
// 在实际应用中,这里应该调用签到API |
|||
// 例如: |
|||
// apiRoute.studentSignIn({ |
|||
// student_id: student_id, |
|||
// course_id: this.course_id, |
|||
// }).then(res => { |
|||
// if (res.code == 1) { |
|||
// uni.showToast({ |
|||
// title: '签到成功', |
|||
// icon: 'success' |
|||
// }); |
|||
// this.init(); |
|||
// } else { |
|||
// uni.showToast({ |
|||
// title: res.msg, |
|||
// icon: 'none' |
|||
// }); |
|||
// } |
|||
// }); |
|||
|
|||
// 更新当前学生的状态(模拟) |
|||
const studentIndex = this.courseInfo.student_courses.findIndex(s => s.student_id === student_id); |
|||
if (studentIndex !== -1) { |
|||
this.courseInfo.student_courses[studentIndex].status = 'signed'; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.main_box { |
|||
background: #292929; |
|||
} |
|||
|
|||
//自定义导航栏 |
|||
.navbar_section { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
background: #292929; |
|||
|
|||
.title { |
|||
padding: 40rpx 0rpx; |
|||
|
|||
/* 小程序端样式 */ |
|||
// #ifdef MP-WEIXIN |
|||
padding: 80rpx 0rpx; |
|||
// #endif |
|||
|
|||
font-size: 30rpx; |
|||
color: #fff; |
|||
} |
|||
} |
|||
|
|||
/* 学员选择列表样式 */ |
|||
.student-list { |
|||
max-height: 600rpx; |
|||
overflow-y: auto; |
|||
} |
|||
|
|||
.student-item { |
|||
padding: 20rpx 30rpx; |
|||
border-bottom: 1px solid #eee; |
|||
background-color: #f8f8f8; |
|||
margin-bottom: 10rpx; |
|||
border-radius: 8rpx; |
|||
} |
|||
|
|||
.student-item:active { |
|||
background-color: #e0e0e0; |
|||
} |
|||
|
|||
.student-info { |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.student-name { |
|||
font-size: 32rpx; |
|||
font-weight: bold; |
|||
color: #333; |
|||
margin-bottom: 10rpx; |
|||
} |
|||
|
|||
.student-details { |
|||
display: flex; |
|||
flex-direction: column; |
|||
font-size: 24rpx; |
|||
color: #666; |
|||
} |
|||
|
|||
.student-details text { |
|||
margin-bottom: 6rpx; |
|||
} |
|||
|
|||
.empty-list { |
|||
padding: 40rpx; |
|||
text-align: center; |
|||
color: #999; |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.main_section { |
|||
min-height: 100vh; |
|||
background: #292929 100%; |
|||
padding: 30rpx 24rpx; |
|||
padding-top: 40rpx; |
|||
padding-bottom: 150rpx; |
|||
font-size: 24rpx; |
|||
color: #FFFFFF; |
|||
|
|||
.section_1 { |
|||
position: relative; |
|||
padding: 18rpx 34rpx 50rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 15rpx; |
|||
color: #fff; |
|||
font-size: 24rpx; |
|||
background-color: #434544; |
|||
border-radius: 22rpx; |
|||
|
|||
.tag { |
|||
position: absolute; |
|||
top: 0; |
|||
right: 0; |
|||
|
|||
width: 110rpx; |
|||
height: 60rpx; |
|||
line-height: 55rpx; |
|||
border-radius: 0rpx 24rpx 0rpx 24rpx; |
|||
color: #fff; |
|||
font-size: 24rpx; |
|||
text-align: center; |
|||
} |
|||
} |
|||
|
|||
.section_2 { |
|||
margin-top: 44rpx; |
|||
color: #fff; |
|||
font-size: 30rpx; |
|||
|
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
|
|||
.table { |
|||
width: 50%; |
|||
height: 64rpx; |
|||
background-color: #1684FCFF; |
|||
|
|||
line-height: 62rpx; |
|||
text-align: center; |
|||
} |
|||
|
|||
.table:nth-child(1) { |
|||
border-top-left-radius: 8rpx; |
|||
border-bottom-left-radius: 8rpx; |
|||
} |
|||
|
|||
.table:nth-child(2) { |
|||
border-top-right-radius: 8rpx; |
|||
border-bottom-right-radius: 8rpx; |
|||
} |
|||
|
|||
.select { |
|||
background-color: #fff; |
|||
color: #1684FCFF; |
|||
} |
|||
} |
|||
|
|||
.section_3 { |
|||
margin-top: 44rpx; |
|||
min-height: 20vh; |
|||
padding: 30rpx 0; |
|||
border-radius: 22rpx; |
|||
background-color: #434544; |
|||
display: flex; |
|||
flex-direction: column; |
|||
|
|||
//提示 |
|||
.tip_title { |
|||
text-align: center; |
|||
font-size: 30rpx; |
|||
color: #FFFFFF; |
|||
} |
|||
|
|||
.item { |
|||
border-top: 1px solid #D7D7D7; |
|||
padding: 20rpx 33rpx 20rpx 14rpx; |
|||
|
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
|
|||
.left { |
|||
width: 80%; |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 26rpx; |
|||
|
|||
.pic { |
|||
width: 92rpx; |
|||
height: 92rpx; |
|||
border-radius: 50%; |
|||
background-color: #797979FF; |
|||
} |
|||
|
|||
.box { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 10rpx; |
|||
|
|||
.title { |
|||
color: #fff; |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.right { |
|||
.tag { |
|||
width: 93rpx; |
|||
height: 93rpx; |
|||
border-radius: 50%; |
|||
line-height: 90rpx; |
|||
font-size: 26rpx; |
|||
text-align: center; |
|||
border: 0rpx; |
|||
//旋转45° |
|||
transform: rotate(-30deg); |
|||
} |
|||
|
|||
.leave-tag { |
|||
background-color: rgba(254, 250, 131, 0.62); |
|||
color: rgba(255, 255, 255, 1); |
|||
} |
|||
|
|||
.signin-tag { |
|||
background-color: #1cd188; |
|||
color: #FFFFFF; |
|||
} |
|||
|
|||
.signed-tag { |
|||
background-color: #a4adb3; |
|||
color: #FFFFFF; |
|||
transform: none; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.item:nth-child(1) { |
|||
border-top: 0px; |
|||
} |
|||
} |
|||
|
|||
.section_4 { |
|||
margin-top: 44rpx; |
|||
padding: 30rpx 0; |
|||
border-radius: 22rpx; |
|||
background-color: #434544; |
|||
display: flex; |
|||
flex-direction: column; |
|||
|
|||
.item_box { |
|||
margin-bottom: 30rpx; |
|||
padding-left: 24rpx; |
|||
padding-right: 32rpx; |
|||
|
|||
|
|||
font-size: 28rpx; |
|||
color: #fff; |
|||
background-color: #434544; |
|||
|
|||
::v-deep .fui-collapse-item__title { |
|||
background-color: #434544 !important; |
|||
} |
|||
|
|||
::v-deep .fui-collapse__border-color { |
|||
border-top: none !important; |
|||
/* 取消上边框 */ |
|||
background: #434544 !important; |
|||
} |
|||
|
|||
.title_box {} |
|||
|
|||
.ul { |
|||
background-color: #434544; |
|||
|
|||
.li { |
|||
background-color: #434544; |
|||
border-top: 1px solid #D7D7D7; |
|||
padding: 20rpx 33rpx 20rpx 14rpx; |
|||
|
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
|
|||
.left { |
|||
width: 80%; |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 26rpx; |
|||
|
|||
.pic { |
|||
width: 92rpx; |
|||
height: 92rpx; |
|||
border-radius: 50%; |
|||
background-color: #797979FF; |
|||
} |
|||
|
|||
.box { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 10rpx; |
|||
|
|||
.title { |
|||
color: #fff; |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.right { |
|||
.btn { |
|||
background-color: #a4adb3; |
|||
color: #fff; |
|||
|
|||
width: 160rpx; |
|||
height: 60rpx; |
|||
line-height: 60rpx; |
|||
border-radius: 8rpx; |
|||
background-color: rgba(164, 173, 179, 1); |
|||
color: rgba(255, 255, 255, 1); |
|||
font-size: 24rpx; |
|||
text-align: center; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.li:nth-child(1) { |
|||
border-top: none !important; |
|||
/* 取消上边框 */ |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.isbtn { |
|||
border: 1px solid #FAD04D; |
|||
border-radius: 10rpx; |
|||
background: #434544; |
|||
color: #FAD04D; |
|||
width: 110rpx; |
|||
height: 60rpx; |
|||
line-height: 55rpx; |
|||
text-align: center; |
|||
font-size: 24rpx; |
|||
position: absolute; |
|||
bottom: 20rpx; |
|||
right: 15rpx; |
|||
} |
|||
</style> |
|||
@ -1,648 +0,0 @@ |
|||
<!--课程-列表--> |
|||
<template> |
|||
<view class="main_box"> |
|||
<view class="main_section"> |
|||
<view class="section_1"> |
|||
<view class="ul"> |
|||
<view class="li" v-for="(v,k) in dates" :key="k" @click="selectDate(v.date)"> |
|||
<text>{{v.weekday}}</text> |
|||
<text :class="[filteredData.schedule_date == v.date ? 'today':'']">{{today == v.date ? '今':v.dayOfMonth}}</text> |
|||
</view> |
|||
</view> |
|||
<view class="btn" @click="show_calendar=true"> |
|||
查看更多 <fui-icon name="arrowdown" color="#A4ADB3" size="45"></fui-icon> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- <view class="section_2">--> |
|||
<!-- <view class="item_box">--> |
|||
<!-- <fui-dropdown-menu :size="28" selectedColor="#465CFF" :options="options_course" @click="clickCourse" @close="show_course=false" ref="ref_course">--> |
|||
<!-- <view class="fui-filter__item" @tap="filterTapCourse">--> |
|||
<!-- <text>{{course_name}}</text>--> |
|||
<!-- <view class="fui-filter__icon" :class="{'fui-icon__ani':show_course}">--> |
|||
<!-- <fui-icon name="turningdown" :size="32" color="#FFF"></fui-icon>--> |
|||
<!-- </view>--> |
|||
<!-- </view>--> |
|||
<!-- </fui-dropdown-menu>--> |
|||
<!-- </view>--> |
|||
<!-- <view class="item_box">--> |
|||
<!-- <fui-dropdown-menu :size="28" selectedColor="#465CFF" :options="options_classroom" @click="clickClassroom" @close="show_classroom=false" ref="ref_classroom">--> |
|||
<!-- <view class="fui-filter__item" @tap="filterTapClassroom">--> |
|||
<!-- <text>{{classroom_name}}</text>--> |
|||
<!-- <view class="fui-filter__icon" :class="{'fui-icon__ani':show_classroom}">--> |
|||
<!-- <fui-icon name="turningdown" :size="32" color="#FFF"></fui-icon>--> |
|||
<!-- </view>--> |
|||
<!-- </view>--> |
|||
<!-- </fui-dropdown-menu>--> |
|||
<!-- </view>--> |
|||
|
|||
<!-- </view>--> |
|||
|
|||
|
|||
|
|||
<scroll-view class="section_3" scroll-y="true" :lower-threshold="lowerThreshold" |
|||
@scrolltolower="loadMoreData" style="height: 100vh;"> |
|||
<view class="ul"> |
|||
<view class="li" v-for="(v,k) in tableList" :key="k" @click="openViewCourseInfoList(v)"> |
|||
<view class="top_box"> |
|||
<view class="center_box"> |
|||
<view>时间:{{v.course_date}}</view> |
|||
<view>课室:{{v.venue.venue_name}}</view> |
|||
<view>课程:{{v.course.course_name}}</view> |
|||
<view>人数:{{v.venue.capacity}}</view> |
|||
</view> |
|||
<view class="right_box"> |
|||
<!-- v.status|1=未开始,2=进行中,3=已结束--> |
|||
<!-- <view class="tag" |
|||
:style="{background: v.status == 'pending' ? '#1cd188' : v.status == 'ongoing' ? '#fad24e' : '#ff4d4f'}"> |
|||
{{ v.status === 'pending' ? '未开始' : v.status === 'ongoing' ? '上课中' : '已结束' }} |
|||
</view> --> |
|||
<!-- <view class="tag" style="background:#1cd188;">待上课</view>--> |
|||
</view> |
|||
</view> |
|||
<!-- <view class="bottom_box" v-if="v.status !== 'pending'"> --> |
|||
<view class="bottom_box"> |
|||
<view class="hint"> |
|||
已签到学生 ({{v.student.length }}/{{v.venue.capacity}}) |
|||
</view> |
|||
<view class="list_box"> |
|||
<view class="list"> |
|||
<view class="itme" v-for="(item,index) in v.student || 0" :key="index"> |
|||
<image :src="$util.img(item.avatar)"></image> |
|||
</view> |
|||
</view> |
|||
<view class="btn"> |
|||
详情 |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- <view class="isbtn" v-if="v.status === 'pending'"> |
|||
详情 |
|||
</view> --> |
|||
</view> |
|||
</view> |
|||
</scroll-view> |
|||
</view> |
|||
|
|||
<!-- 日历选择--> |
|||
<fui-bottom-popup :show="show_calendar" @close="show_calendar=false"> |
|||
<view class="fui-custom__wrap"> |
|||
<uni-calendar :insert="true" :lunar="false" :selected="calendarSelected" :startDate="startDate" |
|||
:endDate="endDate" @change="changeCalendar" /> |
|||
</view> |
|||
</fui-bottom-popup> |
|||
|
|||
|
|||
<!-- 底部导航--> |
|||
<AQTabber /> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
// import user from '@/api/user.js'; |
|||
import memberApi from '@/api/member.js'; |
|||
import commonApi from '@/api/common.js'; |
|||
import AQTabber from "@/components/AQ/AQTabber.vue" |
|||
import apiRoute from '@/api/apiRoute.js'; |
|||
|
|||
export default { |
|||
components: { |
|||
AQTabber, |
|||
}, |
|||
data() { |
|||
return { |
|||
loading: false, //加载状态 |
|||
lowerThreshold: 100, //距离底部多远触发 |
|||
isReachedBottom: false, //防止重复加载|true=不可加载|false=可加载 |
|||
|
|||
//筛选条件 |
|||
filteredData: { |
|||
page: 1, //当前页码 |
|||
limit: 10, //每页返回数据条数 |
|||
total: 10, //数据总条数 |
|||
schedule_date: '', //日期 |
|||
venue_id: '', //场地id |
|||
}, |
|||
tableList: [], //表格数据 |
|||
venuesInfo: {}, //场地信息 |
|||
|
|||
formData: {}, |
|||
|
|||
//课程下拉菜单相关 |
|||
show_course: false, //是否显示下拉菜单 |
|||
//课程下拉菜单 |
|||
course_name: '课程', //选中的下拉菜单名称 |
|||
options_course: [{ |
|||
text: '请选择课程', |
|||
value: '', |
|||
checked: true |
|||
}, { |
|||
text: '羽毛球课程1', |
|||
value: '1' |
|||
}, { |
|||
text: '篮球课程2', |
|||
value: '2' |
|||
}], |
|||
|
|||
//课室下拉菜单相关 |
|||
show_classroom: false, //是否显示下拉菜单 |
|||
//课程下拉菜单 |
|||
classroom_name: '课室', //选中的下拉菜单名称 |
|||
options_classroom: [{ |
|||
text: '请选择课室', |
|||
value: '', |
|||
checked: true |
|||
}, { |
|||
text: '羽毛球201', |
|||
value: '1' |
|||
}, { |
|||
text: '篮球室101', |
|||
value: '2' |
|||
}], |
|||
|
|||
//今日日期 |
|||
today: '', |
|||
dateList: [], //日期列表 |
|||
|
|||
//日历选择相关 |
|||
show_calendar: false, //是否展示日期 |
|||
startDate: '', //开始日期 |
|||
endDate: '', //结束日期 |
|||
calendarSelected: [], //日历打点 |
|||
dates: {} |
|||
} |
|||
}, |
|||
|
|||
onLoad() {}, |
|||
onShow() { |
|||
this.init() //初始化 |
|||
}, |
|||
//下拉刷新 |
|||
async onPullDownRefresh() { |
|||
//重置为第一页 |
|||
this.getThisDate() |
|||
let schedule_date = this.filteredData.schedule_date |
|||
await this.loadData() |
|||
this.filteredData.schedule_date = schedule_date |
|||
await this.getList() |
|||
}, |
|||
methods: { |
|||
//初始化 |
|||
async init() { |
|||
|
|||
await this.getThisDate() |
|||
await this.getHeadDate() |
|||
await this.getList() |
|||
// this.getDateRange() |
|||
// this.setCalendarSelected() |
|||
}, |
|||
|
|||
//选中课程下拉菜单点击事件 |
|||
clickCourse(e) { |
|||
console.log(e) |
|||
this.course_name = e.text |
|||
this.show_course = true |
|||
}, |
|||
//显示下拉菜单 |
|||
filterTapCourse() { |
|||
//显示下拉框 |
|||
this.$refs.ref_course.show() |
|||
this.show_course = true; |
|||
}, |
|||
|
|||
|
|||
|
|||
//选中课室 |
|||
clickClassroom(e) { |
|||
console.log(e) |
|||
this.classroom_name = e.text |
|||
this.show_classroom = true |
|||
}, |
|||
//显示课室下拉菜单 |
|||
filterTapClassroom() { |
|||
//显示下拉框 |
|||
this.$refs.ref_classroom.show() |
|||
this.show_classroom = true; |
|||
}, |
|||
|
|||
//打开课时详情页 |
|||
openViewCourseInfoList(item) { |
|||
let id = item.id |
|||
this.$navigateTo({ |
|||
url: `/pages/coach/course/info_list?id=${id}` |
|||
}) |
|||
}, |
|||
|
|||
|
|||
|
|||
getDatesAroundToday(offsetDays = 0) { |
|||
const date = new Date(); |
|||
date.setDate(date.getDate() + offsetDays); |
|||
const year = date.getFullYear(); |
|||
const month = String(date.getMonth() + 1).padStart(2, '0'); |
|||
const day = String(date.getDate()).padStart(2, '0'); |
|||
const weekDay = ['日', '一', '二', '三', '四', '五', '六'][date.getDay()]; |
|||
return { |
|||
date: `${year}-${month}-${day}`, |
|||
weekday: `星期${weekDay}`, |
|||
dayOfMonth: day // 👈 新增字段:几号 |
|||
}; |
|||
}, |
|||
|
|||
//获取课程头日期 |
|||
async getHeadDate() { |
|||
// let res = await commonApi.getDate() |
|||
// if (res.code != 1) { |
|||
// //提示 |
|||
// uni.showToast({ |
|||
// title: res.msg, |
|||
// icon: 'none', |
|||
// }) |
|||
// return |
|||
// } |
|||
|
|||
// this.dateList = [] |
|||
// res.data.forEach((v, k) => { |
|||
// let today = v.date.split("-")[2]; // "09" |
|||
// this.dateList.push({ |
|||
// date: v.date, |
|||
// status: v.status, //1是正常 2请假 |
|||
// week: v.week, |
|||
// today: today, |
|||
// }) |
|||
// }) |
|||
|
|||
this.dates = {}; |
|||
for (let i = -3; i <= 3; i++) { |
|||
const key = i === 0 ? '今天' : `${Math.abs(i)}天${i < 0 ? '前' : '后'}`; |
|||
this.dates[key] = this.getDatesAroundToday(i); |
|||
} |
|||
}, |
|||
|
|||
//获取当前日期 |
|||
async getThisDate() { |
|||
let date = new Date(); |
|||
let year = date.getFullYear(); |
|||
let month = String(date.getMonth() + 1).padStart(2, '0'); // 月份前补零 |
|||
let day = String(date.getDate()).padStart(2, '0'); // 日期前补零 |
|||
let hour = date.getHours(); |
|||
let minute = date.getMinutes(); |
|||
let second = date.getSeconds(); |
|||
|
|||
let res = `${year}-${month}-${day}`; // 格式化日期 |
|||
this.today = res; |
|||
this.filteredData.schedule_date = res; |
|||
}, |
|||
|
|||
//选择日期 |
|||
async selectDate(date) { |
|||
this.loadData() |
|||
this.filteredData.schedule_date = date |
|||
this.getList() |
|||
}, |
|||
|
|||
//加载更过(下一页) |
|||
loadMoreData() { |
|||
//判断是否加载 |
|||
if (!this.isReachedBottom) { |
|||
this.isReachedBottom = true; //设置为不可请求状态 |
|||
this.getList(); |
|||
} |
|||
}, |
|||
//重置为第一页 |
|||
async loadData() { |
|||
this.isReachedBottom = false; // 重置状态,以便下次触发加载更多 |
|||
this.filteredData.page = 1 //当前页码 |
|||
this.filteredData.limit = 10 //每页返回数据条数 |
|||
this.filteredData.total = 10 //数据总条数 |
|||
this.filteredData.schedule_date = '' |
|||
}, |
|||
//获取列表 |
|||
async getList() { |
|||
this.loading = true |
|||
|
|||
let data = { |
|||
...this.filteredData |
|||
} |
|||
|
|||
//判断是否还有数据 |
|||
if (this.filteredData.page * this.filteredData.limit > this.filteredData.total || this.filteredData.limit > this.filteredData.total) { |
|||
this.loading = false |
|||
uni.showToast({ |
|||
title: '暂无更多', |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
let res = await apiRoute.courseList(data) |
|||
this.loading = false |
|||
this.isReachedBottom = false; |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
this.tableList = res.data.data |
|||
//场地信息 |
|||
this.venuesInfo = res.data.venues_info |
|||
|
|||
this.filteredData.total = res.data.total |
|||
|
|||
this.filteredData.page++ |
|||
}, |
|||
|
|||
//日历选择相关 |
|||
// 获取日期范围 |
|||
getDateRange() { |
|||
const today = new Date(); // 获取今天的日期 |
|||
const startDate = new Date(today); // 复制今天的日期 |
|||
const endDate = new Date(today); // 复制今天的日期 |
|||
|
|||
// 计算 startDate:往前推 1 个月 |
|||
startDate.setMonth(today.getMonth() - 1); |
|||
|
|||
// 计算 endDate:往后推 1 个月 |
|||
endDate.setMonth(today.getMonth() + 2); |
|||
|
|||
// 将日期格式化为 YYYY-MM-DD |
|||
const formatDate = (date) => { |
|||
const year = date.getFullYear(); |
|||
const month = String(date.getMonth() + 1).padStart(2, '0'); |
|||
const day = String(date.getDate()).padStart(2, '0'); |
|||
return `${year}-${month}-${day}`; |
|||
}; |
|||
|
|||
// 更新 data 中的 startDate 和 endDate |
|||
this.startDate = formatDate(startDate); |
|||
this.endDate = formatDate(endDate); |
|||
console.log([this.startDate, this.endDate]) |
|||
}, |
|||
//设置日期打点 |
|||
async setCalendarSelected() { |
|||
//获取当前月份 |
|||
let month = new Date().getMonth() + 1; |
|||
|
|||
let res = await commonApi.getMonthDate({ |
|||
month: month |
|||
}) |
|||
if (res.code != 1) { |
|||
//提示 |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none', |
|||
duration: 2000 |
|||
}) |
|||
return |
|||
} |
|||
this.calendarSelected = [] |
|||
res.data.forEach((v, k) => { |
|||
this.calendarSelected.push({ |
|||
date: v.date, |
|||
}) |
|||
}) |
|||
|
|||
// this.calendarSelected = [ |
|||
// { |
|||
// date: '2025-04-07', |
|||
// }, |
|||
// { |
|||
// date: '2025-04-08', |
|||
// }, |
|||
// { |
|||
// date: '2025-04-09', |
|||
// } |
|||
// ] |
|||
}, |
|||
//日历选择 |
|||
changeCalendar(e) { |
|||
console.log('日历', e) |
|||
this.show_calendar = false |
|||
this.loadData() |
|||
this.filteredData.schedule_date = e.fulldate |
|||
this.getList() |
|||
}, |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.main_box { |
|||
background: #292929; |
|||
} |
|||
|
|||
//自定义导航栏 |
|||
.navbar_section { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
background: #292929; |
|||
|
|||
.title { |
|||
padding: 40rpx 0rpx; |
|||
|
|||
/* 小程序端样式 */ |
|||
// #ifdef MP-WEIXIN |
|||
padding: 80rpx 0rpx; |
|||
// #endif |
|||
|
|||
font-size: 30rpx; |
|||
color: #fff; |
|||
} |
|||
} |
|||
|
|||
.main_section { |
|||
min-height: 100vh; |
|||
background: #292929 100%; |
|||
padding-top: 40rpx; |
|||
padding-bottom: 150rpx; |
|||
font-size: 24rpx; |
|||
color: #FFFFFF; |
|||
|
|||
.section_1 { |
|||
background: #333333 100%; |
|||
width: 100%; |
|||
padding: 30rpx 28rpx; |
|||
padding-bottom: 15rpx; |
|||
|
|||
.ul { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
|
|||
.li { |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
align-items: center; |
|||
gap: 10rpx; |
|||
|
|||
text { |
|||
font-size: 24rpx; |
|||
color: #FFFFFF; |
|||
text-align: center; |
|||
} |
|||
|
|||
text:nth-child(2) { |
|||
width: 44rpx; |
|||
height: 44rpx; |
|||
} |
|||
|
|||
text:nth-child(3) { |
|||
width: 8rpx; |
|||
height: 8rpx; |
|||
} |
|||
|
|||
.today { |
|||
border-radius: 50%; |
|||
background: #29D3B4; |
|||
text-align: center; |
|||
line-height: 42rpx; |
|||
} |
|||
|
|||
.select_plan { |
|||
background: #F59A23; |
|||
border-radius: 50%; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.btn { |
|||
margin-top: 20rpx; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
color: #A4ADB3; |
|||
} |
|||
} |
|||
|
|||
.section_2 { |
|||
margin-top: 30rpx; |
|||
padding: 0 20rpx; |
|||
color: #fff; |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 20rpx; |
|||
|
|||
.item_box { |
|||
width: 45%; |
|||
|
|||
.fui-filter__item { |
|||
display: flex; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.section_3 { |
|||
margin-top: 36rpx; |
|||
color: #fff; |
|||
font-size: 24rpx; |
|||
|
|||
.ul { |
|||
padding: 0 26rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 30rpx; |
|||
|
|||
.li { |
|||
position: relative; |
|||
border-radius: 22rpx; |
|||
background: #434544 100%; |
|||
padding: 14rpx 0; |
|||
padding-bottom: 30rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
|
|||
.top_box { |
|||
padding: 20rpx 30rpx; |
|||
|
|||
.center_box { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 10rpx; |
|||
|
|||
view {} |
|||
} |
|||
|
|||
.right_box { |
|||
.tag { |
|||
position: absolute; |
|||
top: 0rpx; |
|||
right: 0rpx; |
|||
padding: 10rpx; |
|||
width: 102rpx; |
|||
text-align: center; |
|||
font-size: 24rpx; |
|||
border-bottom-left-radius: 20rpx; |
|||
border-top-right-radius: 20rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.bottom_box { |
|||
border-top: 1px dashed #F2F2F2; |
|||
padding: 26rpx 16rpx 0 26rpx; |
|||
|
|||
.hint { |
|||
color: #D7D7D7; |
|||
} |
|||
|
|||
.list_box { |
|||
margin-top: 22rpx; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
|
|||
.list { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 14rpx; |
|||
|
|||
.itme { |
|||
image { |
|||
width: 48rpx; |
|||
height: 48rpx; |
|||
border-radius: 50%; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.btn { |
|||
border: 1px solid #FAD04D; |
|||
border-radius: 10rpx; |
|||
background: #434544; |
|||
color: #FAD04D; |
|||
width: 110rpx; |
|||
height: 60rpx; |
|||
line-height: 55rpx; |
|||
text-align: center; |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
.isbtn { |
|||
border: 1px solid #FAD04D; |
|||
border-radius: 10rpx; |
|||
background: #434544; |
|||
color: #FAD04D; |
|||
width: 110rpx; |
|||
height: 60rpx; |
|||
line-height: 55rpx; |
|||
text-align: center; |
|||
font-size: 24rpx; |
|||
position: absolute; |
|||
bottom: 20rpx; |
|||
right: 15rpx; |
|||
} |
|||
</style> |
|||
@ -1,407 +0,0 @@ |
|||
<!--发布作业--> |
|||
<template> |
|||
<view class="main_section"> |
|||
<fui-form class="formData" ref="form"> |
|||
<view class="radio_input"> |
|||
<fui-form-item label="发布类型" asterisk> |
|||
<fui-radio-group name="radio" v-model="formData.type" @change="changeType"> |
|||
<view class="fui-list__item"> |
|||
<fui-label> |
|||
<view class="fui-align__center"> |
|||
<fui-radio value="1" checked></fui-radio> |
|||
<text class="fui-text">班级作业</text> |
|||
</view> |
|||
</fui-label> |
|||
<fui-label :margin="['0','0','0','40rpx']"> |
|||
<view class="fui-align__center"> |
|||
<fui-radio value="2"></fui-radio> |
|||
<text class="fui-text">学员作业</text> |
|||
</view> |
|||
</fui-label> |
|||
</view> |
|||
</fui-radio-group> |
|||
</fui-form-item> |
|||
|
|||
</view> |
|||
|
|||
<view class="radio_input"> |
|||
<fui-form-item label="作业类型" asterisk> |
|||
<fui-radio-group name="radio" v-model="formData.content_type" @change="changeContentType"> |
|||
<view class="fui-list__item"> |
|||
<fui-label> |
|||
<view class="fui-align__center"> |
|||
<fui-radio value="1" checked></fui-radio> |
|||
<text class="fui-text">图片作业</text> |
|||
</view> |
|||
</fui-label> |
|||
<fui-label :margin="['0','0','0','40rpx']"> |
|||
<view class="fui-align__center"> |
|||
<fui-radio value="2"></fui-radio> |
|||
<text class="fui-text">视频作业</text> |
|||
</view> |
|||
</fui-label> |
|||
</view> |
|||
</fui-radio-group> |
|||
</fui-form-item> |
|||
|
|||
</view> |
|||
|
|||
<view v-if="formData.type == 1"> |
|||
<fui-input required label="班级" borderTop placeholder="请选择班级" v-model="formData.classes_id_name" |
|||
@click="show_class=true"></fui-input> |
|||
<fui-picker layer="1" :linkage="true" :options="options_class_arr" :show="show_class" @change="changeClass" |
|||
@cancel="show_class=false"></fui-picker> |
|||
</view> |
|||
|
|||
<view v-if="formData.type != 1"> |
|||
<fui-input required label="学员" borderTop placeholder="请选择学员" v-model="formData.students_ids_name" |
|||
@click="show_student=true"></fui-input> |
|||
<!--下拉多选--> |
|||
<fui-select |
|||
:show="show_student" |
|||
:options="options_student_arr" |
|||
title="请选择学员" |
|||
multiple |
|||
isReverse |
|||
checkboxColor="#FFC529" |
|||
btnBackground="#FFC529" |
|||
btnColor="#1A1D26" |
|||
closeColor="#6D758A" |
|||
@confirm="changeStudent" |
|||
@close="show_student=false"> |
|||
</fui-select> |
|||
|
|||
</view> |
|||
|
|||
<view> |
|||
<fui-input required label="课程" borderTop placeholder="请选择课程" v-model="formData.course_id_name" |
|||
@click="show_course=true"></fui-input> |
|||
<fui-picker |
|||
layer="1" |
|||
:linkage="true" |
|||
:options="options_course_arr" :show="show_course" @change="changeCourse" |
|||
@cancel="show_course=false"></fui-picker> |
|||
</view> |
|||
|
|||
<view> |
|||
<fui-textarea required flexStart label="作业" placeholder="请输入内容" v-model="formData.description"></fui-textarea> |
|||
</view> |
|||
|
|||
<view class="submet_btn" @click="submetForm">提交</view> |
|||
|
|||
</fui-form> |
|||
|
|||
<!--吸顶消息提示--> |
|||
<fui-message ref="msg" :background="`#ff2b2b`"></fui-message> |
|||
<!-- 底部导航--> |
|||
<AQTabber/> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import memberApi from '@/api/member.js'; |
|||
import AQTabber from "@/components/AQ/AQTabber.vue" |
|||
import apiRoute from '@/api/apiRoute.js'; |
|||
//校验规则 |
|||
const rules = [ |
|||
// { |
|||
// name: "classes_id_name", |
|||
// rule: ["required"], |
|||
// msg: ["请选择班级"] |
|||
// }, |
|||
{ |
|||
name: "course_id_name", |
|||
rule: ["required"], |
|||
msg: ["请选择课程"] |
|||
}, |
|||
{ |
|||
name: "description", |
|||
rule: ["required"], |
|||
msg: ["请输入作业内容"] |
|||
}, |
|||
]; |
|||
export default { |
|||
components: { |
|||
AQTabber, |
|||
}, |
|||
data() { |
|||
return { |
|||
show_class:false, |
|||
show_course:false, |
|||
show_student:false, |
|||
|
|||
|
|||
//班级可选值列表 |
|||
options_class_arr:[ |
|||
// { value: 1, text: '班级1' }, |
|||
], |
|||
//课程可选值列表 |
|||
options_course_arr:[ |
|||
// { value: 1, text: '课程1' }, |
|||
], |
|||
//学员可选值列表 |
|||
options_student_arr:[ |
|||
// { |
|||
// text: '标签3', |
|||
// value: '3', |
|||
// checked: false,//是否选中 |
|||
// } |
|||
], |
|||
|
|||
|
|||
//表单数据 |
|||
formData: { |
|||
type: '1',//作业类型(单选)|1班级,2学员 |
|||
course_id: '',//课程id(下拉) |
|||
course_id_name: '',//课程id(中文名字) |
|||
|
|||
content_type: '1',//作业类型(单选)|1图片,2视频 |
|||
description: '',//文字作业内容 |
|||
|
|||
class_id: '',//班级id(下拉) |
|||
classes_id_name: '',//班级id(中文名字) |
|||
|
|||
student_id: '',//学员id 逗号拼接 |
|||
students_ids_name:'',//学员id数组(中文名字) |
|||
} |
|||
} |
|||
}, |
|||
onLoad() { |
|||
|
|||
}, |
|||
onShow() { |
|||
this.init() |
|||
}, |
|||
methods: { |
|||
//初始化 |
|||
async init() { |
|||
// 获取班级-学员二级联动(用来获取班级列表) |
|||
this.getClassesList() |
|||
// 全部课程名称列表 |
|||
this.getCoursesList() |
|||
// 学员列表 |
|||
this.getStudentList() |
|||
}, |
|||
|
|||
//获取班级列表 |
|||
async getClassesList(){ |
|||
let res = await apiRoute.jlGetClassesList({}) |
|||
if(res.code != 1){ |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
this.options_class_arr = [] |
|||
res.data.forEach((v,k)=>{ |
|||
this.options_class_arr.push({ |
|||
text: v.class_name, |
|||
value: v.id, |
|||
}) |
|||
}) |
|||
}, |
|||
//获取课程列表 |
|||
async getCoursesList(){ |
|||
let res = await apiRoute.jlGetCoursesList({}) |
|||
if(res.code != 1){ |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
this.options_course_arr = [] |
|||
res.data.forEach((v,k)=>{ |
|||
this.options_course_arr.push({ |
|||
text: v.course_name, |
|||
value: v.id, |
|||
}) |
|||
}) |
|||
}, |
|||
|
|||
//获取学员列表 |
|||
async getStudentList() { |
|||
let res = await apiRoute.jlGetStudentList({}) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
this.options_student_arr = [] |
|||
res.data.forEach((v, k) => { |
|||
this.options_student_arr.push({ |
|||
text: v.name, |
|||
value: v.id, |
|||
checked: false,//是否选中 |
|||
}) |
|||
}) |
|||
}, |
|||
|
|||
|
|||
//监听选择器-班级 |
|||
changeClass(e) { |
|||
console.log('选择器-班级', e); |
|||
this.formData.class_id = e.value; // 更新 class_id |
|||
this.formData.classes_id_name = e.text; // 更新 class_name |
|||
this.show_class = false; // 关闭选择器 |
|||
}, |
|||
//监听选择器-课程 |
|||
changeCourse(e) { |
|||
console.log('选择器-课程', e); |
|||
this.formData.course_id = e.value; // 更新 course_id |
|||
this.formData.course_id_name = e.text; // 更新 course_name |
|||
this.show_course = false; // 关闭选择器 |
|||
}, |
|||
//监听选择器-学员 |
|||
changeStudent(e) { |
|||
console.log('选择器-学员', e); |
|||
let id_arr = [] |
|||
let name_arr = [] |
|||
e.options.forEach((v,k)=>{ |
|||
id_arr.push(v.value) |
|||
name_arr.push(v.text) |
|||
}) |
|||
//数组转字符 |
|||
this.formData.student_id = id_arr.join(',') |
|||
this.formData.students_ids_name = name_arr.join(',') |
|||
this.show_student = false; // 关闭选择器 |
|||
}, |
|||
|
|||
//监听选择器-发布类型 |
|||
changeType(e) { |
|||
console.log('选择器-作业类型', e); |
|||
this.formData.type = e.detail.value; // 更新 type |
|||
|
|||
//1=班级作业 |
|||
if(e.detail.value == 1){ |
|||
//清空学员选择信息 |
|||
this.formData.student_id = '' |
|||
this.formData.students_ids_name = '' |
|||
}else{ |
|||
// 2=学生作业 |
|||
this.formData.class_id = '' |
|||
this.formData.classes_id_name = '' |
|||
} |
|||
}, |
|||
|
|||
//监听选择器-作业类型 |
|||
changeContentType(e) { |
|||
console.log('选择器-作业类型', e); |
|||
this.formData.content_type = e.detail.value; // 更新 type |
|||
}, |
|||
|
|||
//表单验证 |
|||
async validatorForm(data) { |
|||
let res = await this.$refs.form.validator(data, rules) |
|||
return res |
|||
}, |
|||
|
|||
//吸顶消息意识 |
|||
showMsg(msg) { |
|||
let options = {} |
|||
//text值可不传 |
|||
options.text = msg |
|||
this.$refs.tips.show(options) |
|||
}, |
|||
|
|||
//发布作业 |
|||
async submetForm(){ |
|||
let data = {...this.formData} |
|||
console.log('提交',data) |
|||
let vf = await this.validatorForm(data)//表单验证 |
|||
|
|||
|
|||
if(data.type == 1){ |
|||
//班级作业 |
|||
if(!data.class_id){ |
|||
this.showMsg('请选择班级') |
|||
return |
|||
} |
|||
}else{ |
|||
//学生作业 |
|||
if(!data.student_id){ |
|||
this.showMsg('请选择学员') |
|||
return |
|||
} |
|||
} |
|||
|
|||
|
|||
if(!vf.isPassed){ |
|||
console.log('验证',vf) |
|||
return |
|||
} |
|||
|
|||
//发布作业 |
|||
let res = await apiRoute.jlPublishJob(data) |
|||
if (res.code != 1){ |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'success' |
|||
}) |
|||
//延迟1s |
|||
setTimeout(() => { |
|||
//关闭当前页跳转新页面 |
|||
uni.redirectTo({ |
|||
url: '/pages/coach/home/index' |
|||
}) |
|||
}, 1000) |
|||
}, |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
|
|||
.main_section{ |
|||
min-height: 100vh; |
|||
background: #292929 100%; |
|||
padding: 0 24rpx; |
|||
padding-top: 40rpx; |
|||
padding-bottom: 150rpx; |
|||
font-size: 28rpx; |
|||
.formData{ |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 40rpx; |
|||
.radio_input{ |
|||
.fui-form__item-wrap{ |
|||
border-radius: 8rpx !important; |
|||
} |
|||
.fui-list__item{ |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
} |
|||
.submet_btn{ |
|||
margin: 0 auto; |
|||
margin-top: 40rpx; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
background-color: #29d3b4; |
|||
border-radius: 8rpx; |
|||
|
|||
width: 648rpx; |
|||
height: 88rpx; |
|||
color: rgba(255,255,255,1); |
|||
font-size: 32rpx; |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
} |
|||
|
|||
|
|||
</style> |
|||
@ -1,836 +0,0 @@ |
|||
<!--作业列表--> |
|||
<template> |
|||
<view class="main_section"> |
|||
|
|||
<scroll-view class="section_3" scroll-y="true" :lower-threshold="lowerThreshold" @scrolltolower="loadMoreData" |
|||
style="height: 80vh;"> |
|||
<view class="ul"> |
|||
<view class="li" v-for="(v,k) in tableList" :key="k" @click="openViewWorkDetails(v)"> |
|||
<!-- <view class="left_box"> |
|||
<view class="date_box"> |
|||
<text>{{v.wc_count}}</text> |
|||
<text>/</text> |
|||
<text>{{v.student_count}}</text> |
|||
</view> |
|||
<view class="ratio"> |
|||
完成率:{{v.rate}}% |
|||
</view> |
|||
</view> --> |
|||
<view class="center_box"> |
|||
<view>班级:{{v.class_name}}</view> |
|||
<view>时间:{{v.create_time}}</view> |
|||
<view>课程:{{v.course_name}} |
|||
</view> |
|||
</view> |
|||
<view class="right_box"> |
|||
<view class="tag" v-if="v.status == 1" style="background:#1cd188;">未提交</view> |
|||
<view class="tag" v-if="v.status == 2" style="background:#1cd188;">已提交</view> |
|||
<view class="tag" v-if="v.status == 3" style="background:#1cd188;">待批改</view> |
|||
<view class="tag" v-if="v.status == 4" style="background:#1cd188;">已批改</view> |
|||
|
|||
</view> |
|||
</view> |
|||
</view> |
|||
</scroll-view> |
|||
|
|||
<!-- 底部发布作业按钮 --> |
|||
<view class="publish-btn" @click="openPublishPopup"> |
|||
<text class="btn-text">发布作业</text> |
|||
</view> |
|||
|
|||
<!-- 底部导航--> |
|||
<AQTabber /> |
|||
|
|||
<!-- 发布作业弹窗 --> |
|||
<uni-popup ref="publishPopup" type="center"> |
|||
<view class="popup-content"> |
|||
<view class="popup-title">发布作业</view> |
|||
<!-- |
|||
<view class="form-item"> |
|||
<text class="form-label">类型</text> |
|||
<input class="form-input" type="number" v-model="formData.type" placeholder="请输入类型" /> |
|||
</view> |
|||
--> |
|||
<view class="form-item"> |
|||
<text class="form-label">班级</text> |
|||
<!-- <input class="form-input" type="number" v-model="formData.class_id" placeholder="请输入班级ID" /> --> |
|||
|
|||
<picker mode="selector" :range="class_id_options" range-key="name" @change="handleClassChange" |
|||
class="form-picker"> |
|||
<view v-if="selectedClassName" class="picker-text">{{ selectedClassName }}</view> |
|||
<view v-else class="picker-placeholder">请选择班级</view> |
|||
</picker> |
|||
</view> |
|||
|
|||
|
|||
<view class="form-item"> |
|||
<text class="form-label">课程</text> |
|||
<!-- <input class="form-input" type="number" v-model="formData.course_id" placeholder="请输入课程" /> --> |
|||
|
|||
<picker mode="selector" :range="course_list" range-key="name" @change="handleCourseChange" |
|||
class="form-picker"> |
|||
<view v-if="selectedCourseName" class="picker-text">{{ selectedCourseName }}</view> |
|||
<view v-else class="picker-placeholder">请选择课程</view> |
|||
</picker> |
|||
|
|||
</view> |
|||
|
|||
<view class="form-item"> |
|||
<text class="form-label">学生</text> |
|||
<!-- <input class="form-input" type="number" v-model="formData.student_id" placeholder="请输入学生ID" /> --> |
|||
<picker mode="selector" :range="student_list" range-key="name" @change="handleStudentChange" |
|||
class="form-picker"> |
|||
<view v-if="selectedStudentName" class="picker-text">{{ selectedStudentName }}</view> |
|||
<view v-else class="picker-placeholder">请选择学生</view> |
|||
</picker> |
|||
</view> |
|||
|
|||
<view class="form-item"> |
|||
<text class="form-label">作业描述</text> |
|||
<textarea class="form-textarea" v-model="formData.description" placeholder="请输入作业描述" /> |
|||
</view> |
|||
|
|||
<!-- <view class="form-item"> |
|||
<text class="form-label">内容类型</text> |
|||
<picker class="form-picker" :value="contentTypeIndex" :range="contentTypes" |
|||
@change="contentTypeChange"> |
|||
<view class="picker-text">{{contentTypes[contentTypeIndex]}}</view> |
|||
</picker> |
|||
</view> --> |
|||
|
|||
<!-- 根据内容类型显示不同的上传控件 --> |
|||
<!-- 图片类型 --> |
|||
<!-- <view class="form-item" v-if="formData.content_type === '1'"> |
|||
<text class="form-label">上传图片</text> |
|||
<view class="upload-container"> |
|||
<view class="image-preview" v-if="uploadedFiles.image"> |
|||
<image class="preview-image" :src="uploadedFiles.image" mode="aspectFill"></image> |
|||
<view class="delete-btn" @click="deleteFile('image')"> |
|||
<text class="delete-icon">×</text> |
|||
</view> |
|||
</view> |
|||
<view class="upload-btn" v-if="!uploadedFiles.image" @click="chooseFile('image')"> |
|||
<text class="upload-icon">+</text> |
|||
<text class="upload-text">上传图片</text> |
|||
</view> |
|||
</view> |
|||
</view> --> |
|||
|
|||
<!-- 视频类型 --> |
|||
<!-- <view class="form-item" v-if="formData.content_type === '2'"> |
|||
<text class="form-label">上传视频</text> |
|||
<view class="upload-container"> |
|||
<view class="video-preview" v-if="uploadedFiles.video"> |
|||
<video class="preview-video" :src="uploadedFiles.video" controls></video> |
|||
<view class="delete-btn" @click="deleteFile('video')"> |
|||
<text class="delete-icon">×</text> |
|||
</view> |
|||
</view> |
|||
<view class="upload-btn" v-if="!uploadedFiles.video" @click="chooseFile('video')"> |
|||
<text class="upload-icon">+</text> |
|||
<text class="upload-text">上传视频</text> |
|||
</view> |
|||
</view> |
|||
</view> --> |
|||
|
|||
<!-- 文本类型 --> |
|||
<!-- <view class="form-item" v-if="formData.content_type === '3'"> |
|||
<text class="form-label">内容文本</text> |
|||
<textarea class="form-textarea" v-model="formData.content_text" placeholder="请输入内容文本" /> |
|||
</view> --> |
|||
|
|||
<view class="form-buttons"> |
|||
<button class="btn-cancel" @click="closePublishPopup">取消</button> |
|||
<button class="btn-submit" @click="submitForm">提交</button> |
|||
</view> |
|||
</view> |
|||
</uni-popup> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import memberApi from '@/api/member.js'; |
|||
import AQTabber from "@/components/AQ/AQTabber.vue" |
|||
import apiRoute from '@/api/apiRoute.js'; |
|||
|
|||
export default { |
|||
components: { |
|||
AQTabber, |
|||
}, |
|||
data() { |
|||
return { |
|||
loading: false, //加载状态 |
|||
lowerThreshold: 100, //距离底部多远触发 |
|||
isReachedBottom: false, //防止重复加载|true=不可加载|false=可加载 |
|||
|
|||
//筛选条件 |
|||
filteredData: { |
|||
page: 1, //当前页码 |
|||
limit: 10, //每页返回数据条数 |
|||
total: 10, //数据总条数 |
|||
}, |
|||
tableList: [], //数据列表 |
|||
|
|||
// 发布作业表单数据 |
|||
formData: { |
|||
class_id: '', |
|||
course_id: '', |
|||
student_id: '', |
|||
description: '', |
|||
}, |
|||
class_id_options: [ |
|||
|
|||
], |
|||
selectedClassName:'', |
|||
course_list:[], |
|||
selectedCourseName:'', |
|||
student_list:[], |
|||
selectedStudentName:'', |
|||
// 内容类型选择器 |
|||
contentTypes: ['图片', '视频', '文本'], |
|||
contentTypeIndex: 0, |
|||
|
|||
// 上传的文件 |
|||
uploadedFiles: { |
|||
image: '', |
|||
video: '' |
|||
}, |
|||
|
|||
// 模拟数据 |
|||
mockData: [] |
|||
} |
|||
}, |
|||
onLoad() { |
|||
|
|||
}, |
|||
onShow() { |
|||
this.init() |
|||
// this.getData() |
|||
}, |
|||
methods: { |
|||
handleClassChange(e) { |
|||
const index = e.detail.value; |
|||
const selectedClass = this.class_id_options[index]; |
|||
this.formData.class_id = selectedClass.id; |
|||
this.selectedClassName = selectedClass.name; |
|||
}, |
|||
|
|||
handleCourseChange(e) { |
|||
const index = e.detail.value; |
|||
const selectedCourse = this.course_list[index]; |
|||
this.formData.course_id = selectedCourse.id; |
|||
this.selectedCourseName = selectedCourse.name; |
|||
}, |
|||
handleStudentChange(e) { |
|||
const index = e.detail.value; |
|||
const selectedStudent = this.student_list[index]; |
|||
this.formData.student_id = selectedStudent.id; |
|||
this.selectedStudentName = selectedStudent.name; |
|||
}, |
|||
async getClassList() { |
|||
let params = { |
|||
status: 1, //班级状态(1开启 2关闭) |
|||
} |
|||
|
|||
let res = await apiRoute.common_getClassAll(params) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
console.log('班级列表', res.data) |
|||
let arr = [] |
|||
res.data.forEach((v, k) => { |
|||
arr.push({ |
|||
name: `${v.campus_name}-${v.class_name}`, |
|||
id: v.id, |
|||
}) |
|||
}) |
|||
this.class_id_options = arr |
|||
this.getCourseList() |
|||
}, |
|||
async getCourseList() { |
|||
|
|||
let res = await apiRoute.common_getCourseAll({}) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
let arr = [] |
|||
res.data.forEach((v, k) => { |
|||
arr.push({ |
|||
name: `${v.course_name}`, |
|||
id: v.id, |
|||
}) |
|||
}) |
|||
this.course_list = arr |
|||
this.getStudentList() |
|||
}, |
|||
async getStudentList() { |
|||
|
|||
let res = await apiRoute.jlGetStudentList({}) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
let arr = [] |
|||
res.data.forEach((v, k) => { |
|||
arr.push({ |
|||
name: `${v.name}`, |
|||
id: v.id, |
|||
}) |
|||
}) |
|||
this.student_list = arr |
|||
}, |
|||
|
|||
async init() { |
|||
this.getList() |
|||
}, |
|||
async getData() { |
|||
this.getClassList() |
|||
}, |
|||
|
|||
//加载更多(下一页) |
|||
loadMoreData() { |
|||
//判断是否加载 |
|||
if (!this.isReachedBottom) { |
|||
this.isReachedBottom = true; //设置为不可请求状态 |
|||
this.getList(); |
|||
} |
|||
}, |
|||
//重置为第一页 |
|||
async resetFilteredData() { |
|||
this.isReachedBottom = false; // 重置状态,以便下次触发加载更多 |
|||
|
|||
this.filteredData.page = 1 //当前页码 |
|||
this.filteredData.limit = 10 //每页返回数据条数 |
|||
this.filteredData.total = 10 //数据总条数 |
|||
}, |
|||
//获取列表 |
|||
async getList() { |
|||
this.loading = true |
|||
|
|||
let data = { |
|||
...this.filteredData |
|||
} |
|||
|
|||
//判断是否还有数据 |
|||
if ((this.filteredData.page - 1) * this.filteredData.limit >= this.filteredData.total) { |
|||
this.loading = false |
|||
uni.showToast({ |
|||
title: '暂无更多', |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
if (data.page == 1) { |
|||
this.tableList = [] |
|||
} |
|||
|
|||
let res = await memberApi.jsGetAssignmentsList(data) |
|||
this.loading = false |
|||
this.isReachedBottom = false; |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
this.tableList = this.tableList.concat(res.data.data); // 使用 concat 方法 将新数据追加到数组中 |
|||
|
|||
console.log('列表', this.tableList) |
|||
this.filteredData.total = res.data.total |
|||
this.filteredData.page++ |
|||
|
|||
this.getData() |
|||
}, |
|||
|
|||
//跳转页面-作业详情 |
|||
openViewWorkDetails(item) { |
|||
let id = item.id |
|||
this.$navigateTo({ |
|||
url: `/pages/coach/student/work_details?id=${id}` |
|||
}) |
|||
}, |
|||
|
|||
// 打开发布作业弹窗 |
|||
openPublishPopup() { |
|||
this.$refs.publishPopup.open() |
|||
}, |
|||
|
|||
// 关闭发布作业弹窗 |
|||
closePublishPopup() { |
|||
this.$refs.publishPopup.close() |
|||
}, |
|||
|
|||
// 内容类型选择器变化 |
|||
contentTypeChange(e) { |
|||
this.contentTypeIndex = e.detail.value |
|||
this.formData.content_type = String(parseInt(e.detail.value) + 1) |
|||
}, |
|||
|
|||
// 选择文件(图片或视频) |
|||
chooseFile(type) { |
|||
if (type === 'image') { |
|||
// 选择图片 |
|||
uni.chooseImage({ |
|||
count: 1, |
|||
sizeType: ['compressed'], |
|||
sourceType: ['album', 'camera'], |
|||
success: (res) => { |
|||
// 模拟上传 |
|||
uni.showLoading({ |
|||
title: '上传中...' |
|||
}) |
|||
|
|||
setTimeout(() => { |
|||
uni.hideLoading() |
|||
this.uploadedFiles.image = res.tempFilePaths[0] |
|||
|
|||
// 模拟上传成功 |
|||
uni.showToast({ |
|||
title: '图片上传成功', |
|||
icon: 'success' |
|||
}) |
|||
|
|||
// 设置内容文本为图片路径 |
|||
this.formData.content_text = res.tempFilePaths[0] |
|||
}, 1000) |
|||
} |
|||
}) |
|||
} else if (type === 'video') { |
|||
// 选择视频 |
|||
uni.chooseVideo({ |
|||
count: 1, |
|||
sourceType: ['album', 'camera'], |
|||
maxDuration: 60, |
|||
camera: 'back', |
|||
success: (res) => { |
|||
// 模拟上传 |
|||
uni.showLoading({ |
|||
title: '上传中...' |
|||
}) |
|||
|
|||
setTimeout(() => { |
|||
uni.hideLoading() |
|||
this.uploadedFiles.video = res.tempFilePath |
|||
|
|||
// 模拟上传成功 |
|||
uni.showToast({ |
|||
title: '视频上传成功', |
|||
icon: 'success' |
|||
}) |
|||
|
|||
// 设置内容文本为视频路径 |
|||
this.formData.content_text = res.tempFilePath |
|||
}, 1500) |
|||
} |
|||
}) |
|||
} |
|||
}, |
|||
|
|||
// 删除已上传的文件 |
|||
deleteFile(type) { |
|||
if (type === 'image') { |
|||
this.uploadedFiles.image = '' |
|||
this.formData.content_text = '' |
|||
} else if (type === 'video') { |
|||
this.uploadedFiles.video = '' |
|||
this.formData.content_text = '' |
|||
} |
|||
}, |
|||
|
|||
// 预览文件 |
|||
previewFile(type) { |
|||
if (type === 'image' && this.uploadedFiles.image) { |
|||
uni.previewImage({ |
|||
urls: [this.uploadedFiles.image] |
|||
}) |
|||
} |
|||
// 视频不需要额外预览,因为已经有视频播放器 |
|||
}, |
|||
|
|||
// 提交表单 |
|||
async submitForm() { |
|||
// 检查必填项 |
|||
if (!this.formData.class_id) { |
|||
uni.showToast({ |
|||
title: '请输入班级ID', |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
if (!this.formData.course_id) { |
|||
uni.showToast({ |
|||
title: '请输入课程ID', |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
if (!this.formData.description) { |
|||
uni.showToast({ |
|||
title: '请输入作业描述', |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
// 检查内容 |
|||
// if (this.formData.content_type === '1' && !this.uploadedFiles.image) { |
|||
// uni.showToast({ |
|||
// title: '请上传图片', |
|||
// icon: 'none' |
|||
// }) |
|||
// return |
|||
// } |
|||
|
|||
// if (this.formData.content_type === '2' && !this.uploadedFiles.video) { |
|||
// uni.showToast({ |
|||
// title: '请上传视频', |
|||
// icon: 'none' |
|||
// }) |
|||
// return |
|||
// } |
|||
|
|||
// if (this.formData.content_type === '3' && !this.formData.content_text) { |
|||
// uni.showToast({ |
|||
// title: '请输入内容文本', |
|||
// icon: 'none' |
|||
// }) |
|||
// return |
|||
// } |
|||
|
|||
|
|||
|
|||
let res = await apiRoute.jlPublishJob(this.formData) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
|
|||
uni.showToast({ |
|||
title: '发布成功', |
|||
icon: 'success' |
|||
}) |
|||
|
|||
// 关闭弹窗 |
|||
this.closePublishPopup() |
|||
|
|||
// 重置表单 |
|||
this.formData = { |
|||
class_id: '', |
|||
course_id: '', |
|||
student_id: '', |
|||
description: '', |
|||
} |
|||
|
|||
this.init() |
|||
// this.contentTypeIndex = 0 |
|||
// this.uploadedFiles = { |
|||
// image: '', |
|||
// video: '' |
|||
// } |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.main_section { |
|||
min-height: 100vh; |
|||
background: #292929 100%; |
|||
padding: 0 24rpx; |
|||
padding-top: 40rpx; |
|||
padding-bottom: 150rpx; |
|||
font-size: 28rpx; |
|||
|
|||
.section_3 { |
|||
margin-top: 36rpx; |
|||
color: #fff; |
|||
font-size: 24rpx; |
|||
|
|||
.title_box { |
|||
display: flex; |
|||
flex-direction: column; |
|||
|
|||
.top_box { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
|
|||
text { |
|||
font-size: 30rpx; |
|||
} |
|||
} |
|||
|
|||
.line { |
|||
width: 90rpx; |
|||
height: 2px; |
|||
background: #29D3B4; |
|||
} |
|||
} |
|||
|
|||
.ul { |
|||
margin-top: 30rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 20rpx; |
|||
|
|||
.li { |
|||
position: relative; |
|||
border-radius: 22rpx; |
|||
background: #434544 100%; |
|||
padding: 14rpx 0; |
|||
display: flex; |
|||
align-items: center; |
|||
|
|||
.left_box { |
|||
margin-left: 28rpx; |
|||
width: 146rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 10rpx; |
|||
|
|||
.date_box { |
|||
display: flex; |
|||
font-size: 48rpx; |
|||
|
|||
text:nth-child(1) { |
|||
color: #29D3B4; |
|||
} |
|||
} |
|||
|
|||
.ratio { |
|||
color: #AAAAAA; |
|||
} |
|||
} |
|||
|
|||
.center_box { |
|||
margin-left: 52rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 10rpx; |
|||
} |
|||
|
|||
.right_box { |
|||
.tag { |
|||
position: absolute; |
|||
top: 0rpx; |
|||
right: 0rpx; |
|||
padding: 10rpx; |
|||
width: 102rpx; |
|||
text-align: center; |
|||
font-size: 24rpx; |
|||
border-bottom-left-radius: 20rpx; |
|||
border-top-right-radius: 20rpx; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 发布作业按钮样式 |
|||
.publish-btn { |
|||
position: fixed; |
|||
bottom: 220rpx; |
|||
right: 40rpx; |
|||
width: 120rpx; |
|||
height: 120rpx; |
|||
background: #29D3B4; |
|||
border-radius: 50%; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
box-shadow: 0 4rpx 20rpx rgba(41, 211, 180, 0.4); |
|||
z-index: 99; |
|||
|
|||
.btn-text { |
|||
color: #fff; |
|||
font-size: 26rpx; |
|||
text-align: center; |
|||
} |
|||
} |
|||
|
|||
// 弹窗内容样式 |
|||
.popup-content { |
|||
width: 650rpx; |
|||
background: #333; |
|||
border-radius: 20rpx; |
|||
padding: 30rpx; |
|||
max-height: 80vh; |
|||
overflow-y: auto; |
|||
|
|||
.popup-title { |
|||
font-size: 36rpx; |
|||
color: #fff; |
|||
text-align: center; |
|||
margin-bottom: 30rpx; |
|||
font-weight: bold; |
|||
} |
|||
|
|||
.form-item { |
|||
margin-bottom: 20rpx; |
|||
|
|||
.form-label { |
|||
display: block; |
|||
color: #fff; |
|||
font-size: 28rpx; |
|||
margin-bottom: 10rpx; |
|||
} |
|||
|
|||
.form-input, |
|||
.form-textarea, |
|||
.form-picker { |
|||
width: 100%; |
|||
background: #444; |
|||
border-radius: 10rpx; |
|||
padding: 16rpx; |
|||
color: #fff; |
|||
font-size: 28rpx; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.form-textarea { |
|||
height: 150rpx; |
|||
} |
|||
|
|||
.picker-text { |
|||
height: 60rpx; |
|||
line-height: 60rpx; |
|||
} |
|||
|
|||
// 上传控件样式 |
|||
.upload-container { |
|||
margin-top: 10rpx; |
|||
} |
|||
|
|||
.upload-btn { |
|||
width: 200rpx; |
|||
height: 200rpx; |
|||
background: #444; |
|||
border-radius: 10rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
border: 1px dashed #666; |
|||
|
|||
.upload-icon { |
|||
font-size: 60rpx; |
|||
color: #29D3B4; |
|||
line-height: 60rpx; |
|||
} |
|||
|
|||
.upload-text { |
|||
font-size: 24rpx; |
|||
color: #aaa; |
|||
margin-top: 10rpx; |
|||
} |
|||
} |
|||
|
|||
// 图片预览 |
|||
.image-preview { |
|||
position: relative; |
|||
width: 200rpx; |
|||
height: 200rpx; |
|||
border-radius: 10rpx; |
|||
overflow: hidden; |
|||
|
|||
.preview-image { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
|
|||
.delete-btn { |
|||
position: absolute; |
|||
top: 0; |
|||
right: 0; |
|||
width: 40rpx; |
|||
height: 40rpx; |
|||
background: rgba(0, 0, 0, 0.6); |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
|
|||
.delete-icon { |
|||
color: #fff; |
|||
font-size: 28rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 视频预览 |
|||
.video-preview { |
|||
position: relative; |
|||
width: 100%; |
|||
height: 300rpx; |
|||
border-radius: 10rpx; |
|||
overflow: hidden; |
|||
|
|||
.preview-video { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
|
|||
.delete-btn { |
|||
position: absolute; |
|||
top: 0; |
|||
right: 0; |
|||
width: 40rpx; |
|||
height: 40rpx; |
|||
background: rgba(0, 0, 0, 0.6); |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
|
|||
.delete-icon { |
|||
color: #fff; |
|||
font-size: 28rpx; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.form-buttons { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
margin-top: 40rpx; |
|||
|
|||
button { |
|||
width: 45%; |
|||
height: 80rpx; |
|||
line-height: 80rpx; |
|||
border-radius: 40rpx; |
|||
font-size: 30rpx; |
|||
} |
|||
|
|||
.btn-cancel { |
|||
background: #555; |
|||
color: #fff; |
|||
} |
|||
|
|||
.btn-submit { |
|||
background: #29D3B4; |
|||
color: #fff; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,276 +0,0 @@ |
|||
<!--到课统计-详情--> |
|||
<template> |
|||
<view class="main_box"> |
|||
|
|||
<view class="main_section"> |
|||
|
|||
<scroll-view |
|||
class="section_3" |
|||
scroll-y="true" |
|||
:lower-threshold="lowerThreshold" |
|||
@scrolltolower="loadMoreData" |
|||
style="height: 90vh;" |
|||
> |
|||
<view class="ul"> |
|||
<view class="li" |
|||
v-for="(v,k) in courseList" |
|||
:key="k" |
|||
@click="openViewCourseInfo(v)" |
|||
> |
|||
<view class="left_box"> |
|||
<view class="date_box"> |
|||
<text>{{v.has_sign_count}}</text> |
|||
<text>/</text> |
|||
<text>{{v.students_count}}</text> |
|||
</view> |
|||
<view class="ratio"> |
|||
到课率:{{v.attendance_rate}}% |
|||
</view> |
|||
</view> |
|||
<view class="center_box"> |
|||
<view>班级:{{v.classes_name}}</view> |
|||
<view>时间:{{v.date_time}} {{v.time_slot ? v.time_slot.replace(",", " - ") : ""}}</view> |
|||
<view>课室:{{v.address}} |
|||
</view> |
|||
<view>课程:{{v.courses_name}} |
|||
</view> |
|||
</view> |
|||
<view class="right_box"> |
|||
<view v-if="!(['1','2'].includes(String(v.status)))" class="tag" style="background:#20CAAF;">未开始</view> |
|||
|
|||
<view v-if="v.status == 1" class="tag" style="background:#fad24e;">上课中</view> |
|||
<view v-if="v.status == 2" class="tag" style="background:#e2e2e2;">已结束</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</scroll-view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import memberApi from '@/api/member.js'; |
|||
import AQTabber from "@/components/AQ/AQTabber.vue" |
|||
|
|||
|
|||
export default { |
|||
components: { |
|||
AQTabber, |
|||
}, |
|||
data() { |
|||
return { |
|||
loading: false,//加载状态 |
|||
lowerThreshold: 100,//距离底部多远触发 |
|||
isReachedBottom: false,//防止重复加载|true=不可加载|false=可加载 |
|||
|
|||
//筛选条件 |
|||
filteredData: { |
|||
page: 1,//当前页码 |
|||
limit: 10,//每页返回数据条数 |
|||
total: 10,//数据总条数 |
|||
class_id: '',//班级id |
|||
}, |
|||
courseList:[],//课程列表 |
|||
} |
|||
}, |
|||
onLoad() { |
|||
}, |
|||
onShow(){ |
|||
this.init() |
|||
}, |
|||
methods: { |
|||
//初始化 |
|||
async init(){ |
|||
this.getCourseList() |
|||
}, |
|||
|
|||
//课程列表 .courseList |
|||
//加载更过(下一页) |
|||
loadMoreData() { |
|||
//判断是否加载 |
|||
if (!this.isReachedBottom) { |
|||
this.isReachedBottom = true;//设置为不可请求状态 |
|||
this.getCourseList(); |
|||
} |
|||
}, |
|||
//重置为第一页 |
|||
async loadData() { |
|||
this.isReachedBottom = false; // 重置状态,以便下次触发加载更多 |
|||
|
|||
this.filteredData.page = 1//当前页码 |
|||
this.filteredData.limit = 10//每页返回数据条数 |
|||
this.filteredData.total = 10//数据总条数 |
|||
}, |
|||
//教练端-获取课程列表 |
|||
async getCourseList(){ |
|||
|
|||
let data = {...this.filteredData} |
|||
data.class_id = this.class_id |
|||
|
|||
console.log(12123,this.courseList) |
|||
|
|||
if(data.page == 1){ |
|||
this.courseList = [] |
|||
} |
|||
|
|||
//判断是否还有数据 |
|||
if ((this.filteredData.page - 1) * this.filteredData.limit >= this.filteredData.total) { |
|||
this.loading = false |
|||
uni.showToast({ |
|||
title: '暂无更多', |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
let res = await memberApi.courseList(data) |
|||
this.loading = false |
|||
this.isReachedBottom = false; |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
let arr = [] |
|||
res.data.list.data.forEach((v,k)=>{ |
|||
let item = v |
|||
item.attendance_rate = (v.students_count && !isNaN(v.students_count) && v.students_count > 0) ? |
|||
parseFloat(((v.has_sign_count / v.students_count) * 100).toFixed(1)) : 0; |
|||
arr.push(item) |
|||
}) |
|||
|
|||
|
|||
|
|||
this.courseList = this.courseList.concat(res.data.list.data)// 使用 concat 方法 将新数据追加到数组中 |
|||
|
|||
this.filteredData.total = res.data.list.total |
|||
console.log('获取课程列表',this.courseList) |
|||
this.filteredData.page++ |
|||
|
|||
}, |
|||
|
|||
|
|||
//打开课程详情 |
|||
openViewCourseInfo(item){ |
|||
let id= item.id |
|||
this.$navigateTo({ |
|||
url: `/pages/coach/course/info_list?id=${id}` |
|||
}) |
|||
}, |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
|
|||
.main_box{ |
|||
background: #292929 ; |
|||
} |
|||
|
|||
//自定义导航栏 |
|||
.navbar_section{ |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
background: #29d3b4; |
|||
.title{ |
|||
padding: 40rpx 0rpx; |
|||
|
|||
/* 小程序端样式 */ |
|||
// #ifdef MP-WEIXIN |
|||
padding: 80rpx 0rpx; |
|||
// #endif |
|||
|
|||
font-size: 30rpx; |
|||
color: #315d55; |
|||
} |
|||
} |
|||
|
|||
.main_section{ |
|||
min-height: 100vh; |
|||
background: #292929 100%; |
|||
padding: 0 24rpx; |
|||
padding-top: 32rpx; |
|||
padding-bottom: 150rpx; |
|||
font-size: 28rpx; |
|||
.section_3{ |
|||
color: #fff; |
|||
font-size: 24rpx; |
|||
.title_box{ |
|||
display: flex; |
|||
flex-direction: column; |
|||
.top_box{ |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
text{ |
|||
font-size: 30rpx; |
|||
} |
|||
} |
|||
.line{ |
|||
width: 90rpx; |
|||
height: 2px; |
|||
background: #29D3B4; |
|||
} |
|||
} |
|||
.ul{ |
|||
margin-top: 30rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 20rpx; |
|||
.li{ |
|||
position: relative; |
|||
border-radius: 22rpx; |
|||
background: #434544 100%; |
|||
padding: 14rpx 0; |
|||
display: flex; |
|||
align-items: center; |
|||
.left_box{ |
|||
margin-left: 28rpx; |
|||
width: 175rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 10rpx; |
|||
.date_box{ |
|||
display: flex; |
|||
font-size: 48rpx; |
|||
text:nth-child(1){ |
|||
color: #29D3B4; |
|||
} |
|||
} |
|||
.ratio{ |
|||
color: #AAAAAA; |
|||
} |
|||
} |
|||
.center_box{ |
|||
margin-left: 22rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 10rpx; |
|||
} |
|||
.right_box{ |
|||
.tag{ |
|||
position:absolute; |
|||
top: 0rpx; |
|||
right: 0rpx; |
|||
padding: 10rpx; |
|||
width: 102rpx; |
|||
text-align: center; |
|||
font-size: 24rpx; |
|||
border-bottom-left-radius: 20rpx; |
|||
border-top-right-radius: 20rpx; |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
|
|||
</style> |
|||
@ -1,431 +0,0 @@ |
|||
<!--我的-首页--> |
|||
<template> |
|||
<view class="main_box"> |
|||
<view style="background:#29D3B4;"> |
|||
<!--用户信息--> |
|||
<view class="user_section"> |
|||
<view class="box"> |
|||
<view class="left" @click="openViewMyInfo()"> |
|||
<image class="pic" :src="$util.img(memberInfo.head_img)"></image> |
|||
<view class="name">{{memberInfo.name}}</view> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="btn"></view> |
|||
<!-- <view class="btn">切换身份</view>--> |
|||
<!-- <view class="btn" @click="openViewArrivalStatistics()">到课率统计</view> --> |
|||
<!-- <view class="btn">到课率统计</view> --> |
|||
<view class="btn"></view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!--统计信息--> |
|||
<view class="count_section"> |
|||
<view class="main"> |
|||
<view class="course_box"> |
|||
<view class="top"> |
|||
<view class="item"> |
|||
<view class="num">{{statisticsInfo.courseNum}}</view> |
|||
<view class="intro">总授课数/节</view> |
|||
</view> |
|||
<view class="item"> |
|||
<view class="num">{{statisticsInfo.classNum}}</view> |
|||
<view class="intro">总授班级/个</view> |
|||
</view> |
|||
<view class="item"> |
|||
<view class="num">{{statisticsInfo.studentNum}}</view> |
|||
<view class="intro">总负责学员/名 |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="bg_box bg_top"></view> |
|||
<view class="bg_box bg_bottom"></view> |
|||
</view> |
|||
</view> |
|||
|
|||
|
|||
|
|||
<view class="main_section"> |
|||
<view class="section_box"> |
|||
<view class="item" @click="openViewDueSoon()"> |
|||
<view>即将到期</view> |
|||
<view></view> |
|||
</view> |
|||
|
|||
<view class="item" @click="openViewSchoolingStatisticsReal()"> |
|||
<view>授课统计</view> |
|||
<view></view> |
|||
</view> |
|||
|
|||
<!-- <view class="item"> --> |
|||
<view class="item" @click="openViewMyAttendance()"> |
|||
<view>我的考勤</view> |
|||
<view></view> |
|||
</view> |
|||
|
|||
<!-- <view class="item"> --> |
|||
<view class="item" @click="openViewSchoolingStatistics()"> |
|||
<view>我的消息</view> |
|||
<view></view> |
|||
</view> |
|||
|
|||
<view class="item" @click="teachingResearchManagement()"> |
|||
<view>教研管理</view> |
|||
<view></view> |
|||
</view> |
|||
|
|||
<view class="item" @click="openServiceDetail()"> |
|||
<view>服务详情</view> |
|||
<view></view> |
|||
</view> |
|||
|
|||
<view class="item" @click="goCourseSchedule()"> |
|||
<view>课程安排</view> |
|||
<view></view> |
|||
</view> |
|||
|
|||
<view class="item" @click="my_contract()"> |
|||
<view>我的合同</view> |
|||
<view></view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="section_box"> |
|||
<!-- <view class="item" @click="openViewFeedback()"> |
|||
<view>意见反馈</view> |
|||
<view></view> |
|||
</view> --> |
|||
|
|||
<view class="item" @click="openViewSetUp()"> |
|||
<view>设置</view> |
|||
<view></view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 底部导航--> |
|||
<AQTabber /> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
// import memberApi from '@/api/member.js'; |
|||
import AQTabber from "@/components/AQ/AQTabber.vue" |
|||
import apiRoute from '@/api/apiRoute.js'; |
|||
|
|||
export default { |
|||
components: { |
|||
AQTabber, |
|||
}, |
|||
data() { |
|||
return { |
|||
memberInfo: {}, |
|||
statisticsInfo: [] |
|||
} |
|||
}, |
|||
onLoad() { |
|||
|
|||
}, |
|||
onShow() { |
|||
|
|||
this.init(); |
|||
}, |
|||
methods: { |
|||
async init() { |
|||
this.getStatistics() |
|||
}, |
|||
my_contract(){ |
|||
this.$navigateTo({ |
|||
url: '/pages/common/contract/my_contract' |
|||
}) |
|||
}, |
|||
//教练详情(个人信息详情) |
|||
async getMemberInfo() { |
|||
let res = await apiRoute.getPersonnelInfo({}) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
this.memberInfo = res.data |
|||
}, |
|||
|
|||
//获取统计个数 |
|||
async getStatistics() { |
|||
let res = await apiRoute.getStatisticsInfo({}) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
this.statisticsInfo = res.data |
|||
|
|||
this.getMemberInfo() |
|||
}, |
|||
|
|||
//打开到课率统计 |
|||
openViewArrivalStatistics() { |
|||
this.$navigateTo({ |
|||
url: '/pages/coach/my/arrival_statistics' |
|||
}) |
|||
}, |
|||
|
|||
//打开即将到期 |
|||
openViewDueSoon() { |
|||
this.$navigateTo({ |
|||
url: '/pages/coach/my/due_soon' |
|||
}) |
|||
}, |
|||
|
|||
//我的消息 |
|||
openViewSchoolingStatistics() { |
|||
this.$navigateTo({ |
|||
url: '/pages/common/my_message' |
|||
}) |
|||
}, |
|||
|
|||
//打开教研管理 |
|||
teachingResearchManagement() { |
|||
this.$navigateTo({ |
|||
url: '/pages/coach/my/teaching_management' |
|||
}) |
|||
}, |
|||
|
|||
//打开意见反馈 |
|||
openViewFeedback() { |
|||
this.$navigateTo({ |
|||
url: '/pages/common/feedback' |
|||
}) |
|||
}, |
|||
|
|||
//打开个人资料 |
|||
openViewMyInfo() { |
|||
this.$navigateTo({ |
|||
url: '/pages/coach/my/info' |
|||
}) |
|||
}, |
|||
|
|||
//打开设置 |
|||
openViewSetUp() { |
|||
this.$navigateTo({ |
|||
url: '/pages/coach/my/set_up' |
|||
}) |
|||
}, |
|||
|
|||
//跳转页面-我的考勤 |
|||
openViewMyAttendance() { |
|||
this.$navigateTo({ |
|||
url: `/pages/common/my_attendance` |
|||
}) |
|||
}, |
|||
|
|||
//打开服务详情 |
|||
openServiceDetail() { |
|||
this.$navigateTo({ |
|||
url: '/pages/coach/my/service_list' |
|||
}) |
|||
}, |
|||
|
|||
//打开授课统计(真实的授课统计页面) |
|||
openViewSchoolingStatisticsReal() { |
|||
this.$navigateTo({ |
|||
url: '/pages/coach/my/schooling_statistics' |
|||
}) |
|||
}, |
|||
|
|||
goCourseSchedule(){ |
|||
this.$navigateTo({ |
|||
url: '/pages/coach/schedule/schedule_table' |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.main_box { |
|||
background: #292929; |
|||
min-height: 28vh; |
|||
} |
|||
|
|||
//自定义导航栏 |
|||
.navbar_section { |
|||
border: 1px solid #29D3B4; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
background: #29D3B4; |
|||
|
|||
.title { |
|||
padding: 40rpx 0rpx; |
|||
|
|||
/* 小程序端样式 */ |
|||
// #ifdef MP-WEIXIN |
|||
padding: 80rpx 0rpx; |
|||
// #endif |
|||
|
|||
font-size: 30rpx; |
|||
color: #fff; |
|||
} |
|||
} |
|||
|
|||
//用户信息 |
|||
.user_section { |
|||
background-color: #29D3B4; |
|||
padding-top: 58rpx; |
|||
padding-bottom: 42rpx; |
|||
color: #fff; |
|||
font-size: 28rpx; |
|||
|
|||
.box { |
|||
padding-left: 19rpx; |
|||
padding-right: 29rpx; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
gap: 15rpx; |
|||
|
|||
.left { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 20rpx; |
|||
|
|||
.pic { |
|||
width: 144rpx; |
|||
height: 144rpx; |
|||
border-radius: 50%; |
|||
} |
|||
|
|||
.name { |
|||
font-size: 28rpx; |
|||
} |
|||
} |
|||
|
|||
.right { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 20rpx; |
|||
|
|||
.btn { |
|||
min-height: 28rpx; |
|||
font-size: 28rpx; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
//统计信息 |
|||
.count_section { |
|||
position: relative; |
|||
|
|||
.main { |
|||
position: relative; |
|||
z-index: 2; |
|||
padding: 0rpx 24rpx; |
|||
display: flex; |
|||
justify-content: center; |
|||
|
|||
.course_box { |
|||
padding: 42rpx 28rpx; |
|||
width: 692rpx; |
|||
border-radius: 20rpx; |
|||
background-color: #fff; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 32rpx; |
|||
|
|||
.top { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
|
|||
.item { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
gap: 12rpx; |
|||
|
|||
.num { |
|||
color: #29D3B4; |
|||
font-size: 56rpx; |
|||
} |
|||
|
|||
.intro { |
|||
color: #AAAAAA; |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.bottom { |
|||
font-size: 24rpx; |
|||
color: #333333; |
|||
|
|||
text { |
|||
color: #29D3B4; |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
.bg_box { |
|||
z-index: 1; |
|||
width: 100%; |
|||
height: 150rpx; |
|||
} |
|||
|
|||
.bg_top { |
|||
position: absolute; |
|||
top: 0; |
|||
background-color: #29D3B4; |
|||
} |
|||
|
|||
.bg_bottom { |
|||
top: 50%; |
|||
position: absolute; |
|||
background-color: #292929; |
|||
} |
|||
} |
|||
|
|||
.main_section { |
|||
background: #292929 100%; |
|||
padding: 0 24rpx; |
|||
padding-top: 40rpx; |
|||
padding-bottom: 150rpx; |
|||
font-size: 24rpx; |
|||
color: #333333; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 22rpx; |
|||
|
|||
.section_box { |
|||
background: #fff; |
|||
border-radius: 16rpx; |
|||
padding: 6rpx 24rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
|
|||
.item { |
|||
padding: 24rpx 78rpx; |
|||
border-top: 1px solid #F2F2F2; |
|||
font-size: 28rpx; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
} |
|||
|
|||
.item:nth-child(1) { |
|||
border-top: 0; |
|||
} |
|||
|
|||
|
|||
} |
|||
|
|||
} |
|||
</style> |
|||
@ -1,497 +0,0 @@ |
|||
<!--我的考勤-详情--> |
|||
<template> |
|||
<view class="main_box"> |
|||
<fui-segmented-control |
|||
:values="optionTable" |
|||
type="text" |
|||
activeColor="#29d3b4" |
|||
color="#fff" |
|||
@click="segmented"> |
|||
</fui-segmented-control> |
|||
|
|||
<view class="main_section"> |
|||
<!--考勤--> |
|||
<scroll-view |
|||
class="section_1" |
|||
v-if="filteredData.type == '1'" |
|||
scroll-y="true" |
|||
:lower-threshold="lowerThreshold" |
|||
@scrolltolower="loadMoreData" |
|||
style="height: 100vh;" |
|||
> |
|||
<view class="ul"> |
|||
<view class="li"> |
|||
<view class="left"> |
|||
<image src="http://www.firstui.cn:4000/vipdoc/img/img_logo.png" model="aspectFill"></image> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="content">篮球课</view> |
|||
<view class="content">考勤正常</view> |
|||
<view class="content">2025-01-01 00:00:00 - 2025-01-01 00:00:00</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="li"> |
|||
<view class="left"> |
|||
<image src="http://www.firstui.cn:4000/vipdoc/img/img_logo.png" model="aspectFill"></image> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="content">篮球课</view> |
|||
<view class="content">考勤正常</view> |
|||
<view class="content">2025-01-01 00:00:00 - 2025-01-01 00:00:00</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="li"> |
|||
<view class="left"> |
|||
<image src="http://www.firstui.cn:4000/vipdoc/img/img_logo.png" model="aspectFill"></image> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="content">篮球课</view> |
|||
<view class="content">考勤正常</view> |
|||
<view class="content">2025-01-01 00:00:00 - 2025-01-01 00:00:00</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="title_box">普通考勤</view> |
|||
<view class="subhead_box">请假</view> |
|||
<view class="subhead_box">2025-01-01 00:00:00 - 2505-01-01 00:00:00</view> |
|||
|
|||
<view class="ul"> |
|||
<view class="li"> |
|||
<view class="left"> |
|||
<image src="http://www.firstui.cn:4000/vipdoc/img/img_logo.png" model="aspectFill"></image> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="content">普通考勤</view> |
|||
<view class="content">迟到</view> |
|||
<view class="content">2025-01-01 00:00:00 - 2025-01-01 00:00:00</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="li"> |
|||
<view class="left"> |
|||
<image src="http://www.firstui.cn:4000/vipdoc/img/img_logo.png" model="aspectFill"></image> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="content">普通考勤</view> |
|||
<view class="content">早退</view> |
|||
<view class="content">2025-01-01 00:00:00 - 2025-01-01 00:00:00</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="li"> |
|||
<view class="left"> |
|||
<image src="http://www.firstui.cn:4000/vipdoc/img/img_logo.png" model="aspectFill"></image> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="content">普通记录</view> |
|||
<view class="content">本周考勤情况:周一到周五均按时打卡,未请假,综合表现良好。 |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
</scroll-view> |
|||
|
|||
<!--请假--> |
|||
<scroll-view |
|||
class="section_1" |
|||
v-if="filteredData.type == '2'" |
|||
scroll-y="true" |
|||
:lower-threshold="lowerThreshold" |
|||
@scrolltolower="loadMoreData" |
|||
style="height: 100vh;" |
|||
> |
|||
<view class="ul"> |
|||
<view class="li"> |
|||
<view class="left"> |
|||
<image src="http://www.firstui.cn:4000/vipdoc/img/img_logo.png" model="aspectFill"></image> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="content">篮球课</view> |
|||
<view class="content">考勤正常</view> |
|||
<view class="content">2025-01-01 00:00:00 - 2025-01-01 00:00:00</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="li"> |
|||
<view class="left"> |
|||
<image src="http://www.firstui.cn:4000/vipdoc/img/img_logo.png" model="aspectFill"></image> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="content">篮球课</view> |
|||
<view class="content">考勤正常</view> |
|||
<view class="content">2025-01-01 00:00:00 - 2025-01-01 00:00:00</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="li"> |
|||
<view class="left"> |
|||
<image src="http://www.firstui.cn:4000/vipdoc/img/img_logo.png" model="aspectFill"></image> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="content">篮球课</view> |
|||
<view class="content">考勤正常</view> |
|||
<view class="content">2025-01-01 00:00:00 - 2025-01-01 00:00:00</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="title_box">普通考勤</view> |
|||
<view class="subhead_box">请假</view> |
|||
<view class="subhead_box">2025-01-01 00:00:00 - 2505-01-01 00:00:00</view> |
|||
|
|||
<view class="ul"> |
|||
<view class="li"> |
|||
<view class="left"> |
|||
<image src="http://www.firstui.cn:4000/vipdoc/img/img_logo.png" model="aspectFill"></image> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="content">普通考勤</view> |
|||
<view class="content">迟到</view> |
|||
<view class="content">2025-01-01 00:00:00 - 2025-01-01 00:00:00</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="li"> |
|||
<view class="left"> |
|||
<image src="http://www.firstui.cn:4000/vipdoc/img/img_logo.png" model="aspectFill"></image> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="content">普通考勤</view> |
|||
<view class="content">早退</view> |
|||
<view class="content">2025-01-01 00:00:00 - 2025-01-01 00:00:00</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="li"> |
|||
<view class="left"> |
|||
<image src="http://www.firstui.cn:4000/vipdoc/img/img_logo.png" model="aspectFill"></image> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="content">普通记录</view> |
|||
<view class="content">本周考勤情况:周一到周五均按时打卡,未请假,综合表现良好。 |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
</scroll-view> |
|||
|
|||
<!--异常--> |
|||
<scroll-view |
|||
class="section_1" |
|||
v-if="filteredData.type == '3'" |
|||
scroll-y="true" |
|||
:lower-threshold="lowerThreshold" |
|||
@scrolltolower="loadMoreData" |
|||
style="height: 100vh;" |
|||
> |
|||
<view class="ul"> |
|||
<view class="li"> |
|||
<view class="left"> |
|||
<image src="http://www.firstui.cn:4000/vipdoc/img/img_logo.png" model="aspectFill"></image> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="content">篮球课</view> |
|||
<view class="content">考勤正常</view> |
|||
<view class="content">2025-01-01 00:00:00 - 2025-01-01 00:00:00</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="li"> |
|||
<view class="left"> |
|||
<image src="http://www.firstui.cn:4000/vipdoc/img/img_logo.png" model="aspectFill"></image> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="content">篮球课</view> |
|||
<view class="content">考勤正常</view> |
|||
<view class="content">2025-01-01 00:00:00 - 2025-01-01 00:00:00</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="li"> |
|||
<view class="left"> |
|||
<image src="http://www.firstui.cn:4000/vipdoc/img/img_logo.png" model="aspectFill"></image> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="content">篮球课</view> |
|||
<view class="content">考勤正常</view> |
|||
<view class="content">2025-01-01 00:00:00 - 2025-01-01 00:00:00</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="title_box">普通考勤</view> |
|||
<view class="subhead_box">请假</view> |
|||
<view class="subhead_box">2025-01-01 00:00:00 - 2505-01-01 00:00:00</view> |
|||
|
|||
<view class="ul"> |
|||
<view class="li"> |
|||
<view class="left"> |
|||
<image src="http://www.firstui.cn:4000/vipdoc/img/img_logo.png" model="aspectFill"></image> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="content">普通考勤</view> |
|||
<view class="content">迟到</view> |
|||
<view class="content">2025-01-01 00:00:00 - 2025-01-01 00:00:00</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="li"> |
|||
<view class="left"> |
|||
<image src="http://www.firstui.cn:4000/vipdoc/img/img_logo.png" model="aspectFill"></image> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="content">普通考勤</view> |
|||
<view class="content">早退</view> |
|||
<view class="content">2025-01-01 00:00:00 - 2025-01-01 00:00:00</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="li"> |
|||
<view class="left"> |
|||
<image src="http://www.firstui.cn:4000/vipdoc/img/img_logo.png" model="aspectFill"></image> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="content">普通记录</view> |
|||
<view class="content">本周考勤情况:周一到周五均按时打卡,未请假,综合表现良好。 |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
</scroll-view> |
|||
|
|||
<view class="section_btn"> |
|||
<view class="btn">请假</view> |
|||
</view> |
|||
|
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import marketApi from '@/api/market.js'; |
|||
import AQTabber from "@/components/AQ/AQTabber.vue" |
|||
|
|||
|
|||
export default { |
|||
components: { |
|||
AQTabber, |
|||
}, |
|||
data() { |
|||
return { |
|||
//tab切换 |
|||
optionTable: [ |
|||
{ |
|||
id: 1, |
|||
name: '考勤' |
|||
}, |
|||
{ |
|||
id: 2, |
|||
name: '请假' |
|||
}, |
|||
{ |
|||
id: 3, |
|||
name: '异常' |
|||
} |
|||
], |
|||
|
|||
loading:false,//加载状态 |
|||
lowerThreshold: 100,//距离底部多远触发 |
|||
isReachedBottom: false,//防止重复加载|true=不可加载|false=可加载 |
|||
|
|||
//筛选条件 |
|||
filteredData:{ |
|||
page:1,//当前页码 |
|||
limit:10,//每页返回数据条数 |
|||
total:10,//数据总条数 |
|||
type: '1',//1=考勤,2=请假,3=异常 |
|||
}, |
|||
tableList:[],//表格数据 |
|||
} |
|||
}, |
|||
onLoad(options) {}, |
|||
onShow(){ |
|||
this.init()//初始化 |
|||
}, |
|||
methods: { |
|||
//初始化 |
|||
async init(){ |
|||
await this.getList(); |
|||
}, |
|||
|
|||
//切换tag列表 |
|||
async segmented(e) { |
|||
//重置为第一页 |
|||
await this.resetFilteredData() |
|||
this.filteredData.type = e.id//1=考勤,2=请假,3=异常 |
|||
await this.getList() |
|||
}, |
|||
|
|||
//加载更多(下一页) |
|||
loadMoreData() { |
|||
//判断是否加载 |
|||
if (!this.isReachedBottom) { |
|||
this.isReachedBottom = true;//设置为不可请求状态 |
|||
this.getList(); |
|||
} |
|||
}, |
|||
//重置为第一页 |
|||
async resetFilteredData() { |
|||
this.isReachedBottom = false; // 重置状态,以便下次触发加载更多 |
|||
|
|||
this.filteredData.page = 1//当前页码 |
|||
this.filteredData.limit = 10//每页返回数据条数 |
|||
this.filteredData.total = 10//数据总条数 |
|||
}, |
|||
//获取列表 |
|||
async getList(){ |
|||
this.loading = true |
|||
|
|||
let data = {...this.filteredData} |
|||
|
|||
//判断是否还有数据 |
|||
if ((this.filteredData.page - 1) * this.filteredData.limit >= this.filteredData.total) { |
|||
this.loading = false |
|||
uni.showToast({ |
|||
title: '暂无更多', |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
if(data.page == 1){ |
|||
this.tableList = [] |
|||
} |
|||
|
|||
let res = await marketApi.myClient(data) |
|||
this.loading = false |
|||
this.isReachedBottom = false; |
|||
if (res.code != 1){ |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
this.tableList = this.tableList.concat(res.data.list.data); // 使用 concat 方法 将新数据追加到数组中 |
|||
|
|||
console.log('列表',this.tableList) |
|||
this.filteredData.total = res.data.list.total |
|||
this.filteredData.page++ |
|||
|
|||
this.countArr = { |
|||
type_0:res.data.count[0], |
|||
type_1:res.data.count[1], |
|||
type_2:res.data.count[2], |
|||
type_3:res.data.count[3], |
|||
max_count:res.data.gh.max_count, |
|||
lq_count:res.data.gh.lq_count, |
|||
} |
|||
|
|||
}, |
|||
|
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
|
|||
.main_box{ |
|||
background: #292929 ; |
|||
} |
|||
|
|||
//自定义导航栏 |
|||
.navbar_section{ |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
background: #29d3b4; |
|||
.title{ |
|||
padding: 40rpx 0rpx; |
|||
|
|||
/* 小程序端样式 */ |
|||
// #ifdef MP-WEIXIN |
|||
padding: 80rpx 0rpx; |
|||
// #endif |
|||
|
|||
font-size: 30rpx; |
|||
color: #315d55; |
|||
} |
|||
} |
|||
|
|||
.main_section{ |
|||
min-height: 100vh; |
|||
background: #292929 100%; |
|||
padding: 0 24rpx; |
|||
padding-top: 32rpx; |
|||
padding-bottom: 150rpx; |
|||
font-size: 28rpx; |
|||
.section_1{ |
|||
color: #fff; |
|||
font-size: 28rpx; |
|||
.ul{ |
|||
margin-top: 23rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 24rpx; |
|||
.li{ |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 43rpx; |
|||
.left{ |
|||
image{ |
|||
width: 174rpx; |
|||
height: 174rpx; |
|||
border-radius: 24rpx; |
|||
background-color: #333333; |
|||
} |
|||
} |
|||
.right{ |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 18rpx; |
|||
.content{ |
|||
font-size: 24rpx; |
|||
} |
|||
.content:nth-child(1){ |
|||
font-size: 28rpx; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
.title_box{ |
|||
margin-top: 46rpx; |
|||
font-size: 28rpx; |
|||
} |
|||
.subhead_box{ |
|||
margin-top: 22rpx; |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
|
|||
.section_btn{ |
|||
display: flex; |
|||
justify-content: center; |
|||
.btn{ |
|||
width: 722rpx; |
|||
height: 64rpx; |
|||
line-height: 64rpx; |
|||
border-radius: 8rpx; |
|||
background-color: rgba(32,202,175,1); |
|||
color: rgba(255,255,255,1); |
|||
font-size: 28rpx; |
|||
text-align: center; |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
|
|||
</style> |
|||
@ -1,870 +0,0 @@ |
|||
<!--服务详情页面--> |
|||
<template> |
|||
<view class="container"> |
|||
<view class="main-content"> |
|||
<!-- 加载状态 --> |
|||
<view v-if="loading" class="loading-container"> |
|||
<uni-load-more status="loading" content-text="加载中..."></uni-load-more> |
|||
</view> |
|||
|
|||
<!-- 服务记录列表 --> |
|||
<view v-else class="service-cards"> |
|||
<view class="service-card" v-for="(service, index) in serviceList" :key="index" @click="viewServiceDetail(service)"> |
|||
<!-- 服务预览图 --> |
|||
<view class="service-preview" v-if="service.preview_image_url"> |
|||
<image :src="getImageUrl(service.preview_image_url)" class="preview-image" mode="aspectFill"></image> |
|||
</view> |
|||
|
|||
<view class="card-content"> |
|||
<!-- 服务名称和状态 --> |
|||
<view class="card-header"> |
|||
<view class="service-name">{{ service.service_name }}</view> |
|||
<view class="service-status" :class="service.status === 1 ? 'status-active' : (service.status === 0 ? 'status-pending' : 'status-inactive')"> |
|||
{{ service.status === 1 ? '已完成' : (service.status === 0 ? '待处理' : '未知状态') }} |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 服务信息 --> |
|||
<view class="service-info"> |
|||
<view class="info-item" v-if="service.service_type"> |
|||
<text class="label">服务类型:</text> |
|||
<text class="value">{{ service.service_type }}</text> |
|||
</view> |
|||
<view class="info-item" v-if="service.description"> |
|||
<text class="label">服务描述:</text> |
|||
<text class="value">{{ service.description }}</text> |
|||
</view> |
|||
<view class="info-item" v-if="service.service_remark || service.status !== 1"> |
|||
<text class="label">服务结果:</text> |
|||
<view class="value-content" v-if="service.service_remark"> |
|||
<rich-text :nodes="formatRichText(service.service_remark)"></rich-text> |
|||
</view> |
|||
<text class="value placeholder" v-else-if="service.status !== 1">点击编辑服务结果</text> |
|||
</view> |
|||
<view class="info-item" v-if="service.feedback"> |
|||
<text class="label">家长反馈:</text> |
|||
<text class="value">{{ service.feedback }}</text> |
|||
</view> |
|||
<view class="info-item" v-if="service.score"> |
|||
<text class="label">家长评分:</text> |
|||
<text class="value score">{{ service.score }}分</text> |
|||
</view> |
|||
<view class="info-item"> |
|||
<text class="label">创建时间:</text> |
|||
<text class="value">{{ formatDate(service.created_at) }}</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 操作按钮 --> |
|||
<view class="card-actions" v-if="service.status !== 1"> |
|||
<button class="edit-btn" @click.stop="editServiceRemark(service)"> |
|||
<text class="iconfont icon-edit"></text> |
|||
编辑服务结果 |
|||
</button> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 箭头图标 --> |
|||
<view class="card-arrow"> |
|||
<text class="iconfont icon-arrow-right"></text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 空状态 --> |
|||
<view class="empty-state" v-if="!loading && serviceList.length === 0"> |
|||
<view class="empty-icon">📝</view> |
|||
<view class="empty-text">暂无服务记录</view> |
|||
</view> |
|||
|
|||
<!-- 底部加载更多 --> |
|||
<view v-if="hasMore && !loading && serviceList.length > 0" class="load-more"> |
|||
<uni-load-more :status="loadMoreStatus" @clickLoadMore="loadMore"></uni-load-more> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 编辑服务结果弹窗 --> |
|||
<view v-if="showEditModal" class="edit-modal" @click="closeEditModal"> |
|||
<view class="modal-content" @click.stop> |
|||
<view class="modal-header"> |
|||
<text class="modal-title">编辑服务结果</text> |
|||
<view class="modal-close" @click="closeEditModal"> |
|||
<text class="iconfont icon-close"></text> |
|||
</view> |
|||
</view> |
|||
<view class="modal-body"> |
|||
<view class="form-item"> |
|||
<text class="form-label">服务结果:</text> |
|||
|
|||
<!-- 富文本工具栏 --> |
|||
<view class="editor-toolbar"> |
|||
<view class="toolbar-group"> |
|||
<view class="tool-btn" :class="{ active: bold }" @click="toggleBold"> |
|||
<text class="tool-text">B</text> |
|||
</view> |
|||
<view class="tool-btn" :class="{ active: italic }" @click="toggleItalic"> |
|||
<text class="tool-text">I</text> |
|||
</view> |
|||
<view class="tool-btn" @click="insertBulletList"> |
|||
<text class="tool-text">•</text> |
|||
</view> |
|||
<view class="tool-btn" @click="insertNumberList"> |
|||
<text class="tool-text">1.</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 文本输入区域 --> |
|||
<textarea |
|||
class="form-textarea" |
|||
v-model="editForm.service_remark" |
|||
placeholder="请输入服务结果内容,支持简单的格式化文本" |
|||
maxlength="1000" |
|||
:show-confirm-bar="false" |
|||
@focus="onTextareaFocus" |
|||
@blur="onTextareaBlur"> |
|||
</textarea> |
|||
|
|||
<!-- 字数统计 --> |
|||
<view class="char-count">{{ editForm.service_remark.length }}/1000</view> |
|||
|
|||
<!-- 提示信息 --> |
|||
<view class="editor-tips"> |
|||
<text class="tip-text">支持基础格式:粗体、斜体、列表等</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="modal-footer"> |
|||
<button class="modal-btn cancel" @click="closeEditModal">取消</button> |
|||
<button class="modal-btn confirm" @click="saveServiceRemark" :disabled="saving"> |
|||
{{ saving ? '保存中...' : '保存' }} |
|||
</button> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import apiRoute from '@/common/axios.js'; |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
loading: true, |
|||
serviceList: [], |
|||
currentPage: 1, |
|||
pageSize: 10, |
|||
hasMore: true, |
|||
loadMoreStatus: 'more', |
|||
showEditModal: false, |
|||
saving: false, |
|||
editForm: { |
|||
id: 0, |
|||
service_remark: '' |
|||
}, |
|||
// 富文本编辑状态 |
|||
bold: false, |
|||
italic: false, |
|||
textareaFocused: false |
|||
} |
|||
}, |
|||
onLoad() { |
|||
this.init(); |
|||
}, |
|||
onPullDownRefresh() { |
|||
this.refreshServiceList(); |
|||
}, |
|||
onReachBottom() { |
|||
if (this.hasMore && !this.loading) { |
|||
this.loadMore(); |
|||
} |
|||
}, |
|||
methods: { |
|||
async init() { |
|||
this.getServiceList(); |
|||
}, |
|||
|
|||
// 获取服务记录列表 |
|||
async getServiceList(refresh = false) { |
|||
if (refresh) { |
|||
this.currentPage = 1; |
|||
this.hasMore = true; |
|||
this.serviceList = []; |
|||
} |
|||
|
|||
this.loading = true; |
|||
this.loadMoreStatus = 'loading'; |
|||
|
|||
try { |
|||
const response = await apiRoute.get('/personnel/myServiceLogs', { |
|||
page: this.currentPage, |
|||
limit: this.pageSize, |
|||
demo: 1 // 添加演示数据标识 |
|||
}); |
|||
|
|||
if (response.code === 1) { |
|||
const newServices = response.data.data || []; |
|||
|
|||
if (refresh) { |
|||
this.serviceList = newServices; |
|||
} else { |
|||
this.serviceList = [...this.serviceList, ...newServices]; |
|||
} |
|||
|
|||
// 检查是否还有更多数据 |
|||
this.hasMore = newServices.length === this.pageSize; |
|||
this.loadMoreStatus = this.hasMore ? 'more' : 'noMore'; |
|||
} else { |
|||
uni.showToast({ |
|||
title: response.data.msg || '加载失败', |
|||
icon: 'none' |
|||
}); |
|||
} |
|||
} catch (error) { |
|||
console.error('获取服务记录失败:', error); |
|||
uni.showToast({ |
|||
title: '网络错误,请稍后重试', |
|||
icon: 'none' |
|||
}); |
|||
} finally { |
|||
this.loading = false; |
|||
if (refresh) { |
|||
uni.stopPullDownRefresh(); |
|||
} |
|||
} |
|||
}, |
|||
|
|||
// 刷新服务列表 |
|||
refreshServiceList() { |
|||
this.getServiceList(true); |
|||
}, |
|||
|
|||
// 加载更多 |
|||
loadMore() { |
|||
if (this.hasMore && !this.loading) { |
|||
this.currentPage++; |
|||
this.getServiceList(); |
|||
} |
|||
}, |
|||
|
|||
// 查看服务详情 |
|||
async viewServiceDetail(service) { |
|||
try { |
|||
const response = await apiRoute.get('/personnel/serviceLogDetail', { |
|||
id: service.id |
|||
}); |
|||
|
|||
if (response.code === 1) { |
|||
const detail = response.data; |
|||
this.showServiceDetailModal(detail); |
|||
} else { |
|||
uni.showToast({ |
|||
title: response.data.msg || '获取详情失败', |
|||
icon: 'none' |
|||
}); |
|||
} |
|||
} catch (error) { |
|||
console.error('获取服务详情失败:', error); |
|||
uni.showToast({ |
|||
title: '网络错误,请稍后重试', |
|||
icon: 'none' |
|||
}); |
|||
} |
|||
}, |
|||
|
|||
// 显示服务详情弹窗 |
|||
showServiceDetailModal(detail) { |
|||
let content = `服务名称:${detail.service_name || '-'}\n`; |
|||
content += `服务类型:${detail.service_type || '-'}\n`; |
|||
content += `状态:${detail.status === 1 ? '已完成' : (detail.status === 0 ? '待处理' : '未知状态')}\n`; |
|||
if (detail.description) { |
|||
content += `描述:${detail.description}\n`; |
|||
} |
|||
if (detail.service_remark) { |
|||
content += `服务结果:${detail.service_remark}\n`; |
|||
} |
|||
if (detail.feedback) { |
|||
content += `家长反馈:${detail.feedback}\n`; |
|||
} |
|||
if (detail.score) { |
|||
content += `家长评分:${detail.score}分`; |
|||
} |
|||
|
|||
uni.showModal({ |
|||
title: '服务详情', |
|||
content: content, |
|||
showCancel: false |
|||
}); |
|||
}, |
|||
|
|||
|
|||
// 获取图片URL |
|||
getImageUrl(url) { |
|||
if (!url) return ''; |
|||
if (url.startsWith('http')) { |
|||
return url; |
|||
} |
|||
return this.$baseUrl + '/' + url; |
|||
}, |
|||
|
|||
// 格式化日期 |
|||
formatDate(dateString) { |
|||
if (!dateString) return '-'; |
|||
const date = new Date(dateString); |
|||
const year = date.getFullYear(); |
|||
const month = String(date.getMonth() + 1).padStart(2, '0'); |
|||
const day = String(date.getDate()).padStart(2, '0'); |
|||
return `${year}-${month}-${day}`; |
|||
}, |
|||
|
|||
// 去除HTML标签 |
|||
stripHtml(html) { |
|||
if (!html) return ''; |
|||
return html.replace(/<[^>]*>/g, '').trim(); |
|||
}, |
|||
|
|||
// 格式化富文本内容 |
|||
formatRichText(text) { |
|||
if (!text) return ''; |
|||
|
|||
// 简单的markdown转换 |
|||
let formatted = text |
|||
// 粗体 |
|||
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>') |
|||
// 斜体 |
|||
.replace(/\*(.*?)\*/g, '<em>$1</em>') |
|||
// 无序列表 |
|||
.replace(/^\u2022\s(.+)$/gm, '<li>$1</li>') |
|||
// 有序列表 |
|||
.replace(/^\d+\.\s(.+)$/gm, '<li>$1</li>') |
|||
// 换行 |
|||
.replace(/\n/g, '<br/>'); |
|||
|
|||
// 如果有列表项,包装在ul标签中 |
|||
if (formatted.includes('<li>')) { |
|||
formatted = formatted.replace(/(<li>.*?<\/li>)/g, '<ul>$1</ul>'); |
|||
} |
|||
|
|||
return formatted; |
|||
}, |
|||
|
|||
// 编辑服务结果 |
|||
editServiceRemark(service) { |
|||
// 检查是否可以编辑 |
|||
if (service.status === 1) { |
|||
uni.showToast({ |
|||
title: '服务已完成,无法修改', |
|||
icon: 'none' |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
this.editForm.id = service.id; |
|||
this.editForm.service_remark = this.stripHtml(service.service_remark || ''); |
|||
this.showEditModal = true; |
|||
}, |
|||
|
|||
// 关闭编辑弹窗 |
|||
closeEditModal() { |
|||
this.showEditModal = false; |
|||
this.editForm = { |
|||
id: 0, |
|||
service_remark: '' |
|||
}; |
|||
}, |
|||
|
|||
// 保存服务结果 |
|||
async saveServiceRemark() { |
|||
if (!this.editForm.service_remark.trim()) { |
|||
uni.showToast({ |
|||
title: '请输入服务结果内容', |
|||
icon: 'none' |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
this.saving = true; |
|||
|
|||
try { |
|||
const response = await apiRoute.post('/personnel/updateServiceRemark', { |
|||
id: this.editForm.id, |
|||
service_remark: this.editForm.service_remark |
|||
}); |
|||
|
|||
if (response.data.code === 1) { |
|||
uni.showToast({ |
|||
title: '保存成功', |
|||
icon: 'success' |
|||
}); |
|||
|
|||
// 更新列表中的数据 |
|||
const index = this.serviceList.findIndex(item => item.id === this.editForm.id); |
|||
if (index !== -1) { |
|||
this.serviceList[index].service_remark = this.editForm.service_remark; |
|||
} |
|||
|
|||
this.closeEditModal(); |
|||
} else { |
|||
uni.showToast({ |
|||
title: response.data.msg || '保存失败', |
|||
icon: 'none' |
|||
}); |
|||
} |
|||
} catch (error) { |
|||
console.error('保存服务结果失败:', error); |
|||
uni.showToast({ |
|||
title: '网络错误,请稍后重试', |
|||
icon: 'none' |
|||
}); |
|||
} finally { |
|||
this.saving = false; |
|||
} |
|||
}, |
|||
|
|||
// 富文本编辑功能 |
|||
onTextareaFocus() { |
|||
this.textareaFocused = true; |
|||
}, |
|||
|
|||
onTextareaBlur() { |
|||
this.textareaFocused = false; |
|||
}, |
|||
|
|||
toggleBold() { |
|||
this.bold = !this.bold; |
|||
this.insertFormatText('**', '**'); |
|||
}, |
|||
|
|||
toggleItalic() { |
|||
this.italic = !this.italic; |
|||
this.insertFormatText('*', '*'); |
|||
}, |
|||
|
|||
insertBulletList() { |
|||
this.insertFormatText('\n• ', ''); |
|||
}, |
|||
|
|||
insertNumberList() { |
|||
this.insertFormatText('\n1. ', ''); |
|||
}, |
|||
|
|||
insertFormatText(before, after) { |
|||
const textarea = this.editForm.service_remark; |
|||
const newText = textarea + before + '请输入内容' + after; |
|||
this.editForm.service_remark = newText; |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.container { |
|||
background: #1a1a1a; |
|||
min-height: 100vh; |
|||
} |
|||
|
|||
.main-content { |
|||
padding: 20rpx; |
|||
} |
|||
|
|||
.service-cards { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 20rpx; |
|||
} |
|||
|
|||
.service-card { |
|||
background: #2a2a2a; |
|||
border-radius: 16rpx; |
|||
overflow: hidden; |
|||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.3); |
|||
border: 1rpx solid #444; |
|||
position: relative; |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 24rpx; |
|||
} |
|||
|
|||
.service-preview { |
|||
width: 120rpx; |
|||
height: 120rpx; |
|||
border-radius: 12rpx; |
|||
overflow: hidden; |
|||
margin-right: 24rpx; |
|||
flex-shrink: 0; |
|||
|
|||
.preview-image { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
} |
|||
|
|||
.card-content { |
|||
flex: 1; |
|||
} |
|||
|
|||
.card-header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 16rpx; |
|||
|
|||
.service-name { |
|||
font-size: 32rpx; |
|||
font-weight: 600; |
|||
color: #fff; |
|||
flex: 1; |
|||
margin-right: 16rpx; |
|||
} |
|||
|
|||
.service-status { |
|||
padding: 8rpx 16rpx; |
|||
border-radius: 20rpx; |
|||
font-size: 24rpx; |
|||
font-weight: 500; |
|||
|
|||
&.status-active { |
|||
background: rgba(41, 211, 180, 0.2); |
|||
color: #29d3b4; |
|||
border: 1rpx solid #29d3b4; |
|||
} |
|||
|
|||
&.status-pending { |
|||
background: rgba(255, 193, 7, 0.2); |
|||
color: #ffc107; |
|||
border: 1rpx solid #ffc107; |
|||
} |
|||
|
|||
&.status-inactive { |
|||
background: rgba(220, 53, 69, 0.2); |
|||
color: #dc3545; |
|||
border: 1rpx solid #dc3545; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.service-info { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 12rpx; |
|||
} |
|||
|
|||
.info-item { |
|||
display: flex; |
|||
align-items: flex-start; |
|||
|
|||
.label { |
|||
color: #999; |
|||
font-size: 26rpx; |
|||
min-width: 140rpx; |
|||
flex-shrink: 0; |
|||
} |
|||
|
|||
.value { |
|||
color: #ccc; |
|||
font-size: 26rpx; |
|||
flex: 1; |
|||
word-break: break-all; |
|||
|
|||
&.score { |
|||
color: #29d3b4; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
&.placeholder { |
|||
color: #666; |
|||
font-style: italic; |
|||
} |
|||
} |
|||
|
|||
.value-content { |
|||
flex: 1; |
|||
color: #ccc; |
|||
font-size: 26rpx; |
|||
line-height: 1.6; |
|||
|
|||
/* 富文本样式 */ |
|||
:deep(strong) { |
|||
font-weight: 600; |
|||
color: #fff; |
|||
} |
|||
|
|||
:deep(em) { |
|||
font-style: italic; |
|||
color: #29d3b4; |
|||
} |
|||
|
|||
:deep(ul) { |
|||
margin: 8rpx 0; |
|||
padding-left: 24rpx; |
|||
} |
|||
|
|||
:deep(li) { |
|||
margin: 4rpx 0; |
|||
list-style: disc; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.card-arrow { |
|||
margin-left: 16rpx; |
|||
width: 40rpx; |
|||
height: 40rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
flex-shrink: 0; |
|||
|
|||
.iconfont { |
|||
font-size: 24rpx; |
|||
color: #666; |
|||
} |
|||
} |
|||
|
|||
.card-actions { |
|||
margin-top: 20rpx; |
|||
padding-top: 20rpx; |
|||
border-top: 1rpx solid #444; |
|||
|
|||
.edit-btn { |
|||
background: #29d3b4; |
|||
color: #fff; |
|||
border: none; |
|||
border-radius: 8rpx; |
|||
padding: 12rpx 24rpx; |
|||
font-size: 26rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
gap: 8rpx; |
|||
|
|||
&:active { |
|||
background: #22b39a; |
|||
} |
|||
|
|||
.iconfont { |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.empty-state { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
padding: 120rpx 40rpx; |
|||
|
|||
.empty-icon { |
|||
font-size: 120rpx; |
|||
margin-bottom: 24rpx; |
|||
opacity: 0.3; |
|||
} |
|||
|
|||
.empty-text { |
|||
color: #666; |
|||
font-size: 28rpx; |
|||
} |
|||
} |
|||
|
|||
.loading-container { |
|||
padding: 120rpx 40rpx; |
|||
text-align: center; |
|||
} |
|||
|
|||
.load-more { |
|||
padding: 40rpx 0; |
|||
} |
|||
|
|||
/* 动画效果 */ |
|||
.service-card { |
|||
animation: slideIn 0.3s ease-out; |
|||
} |
|||
|
|||
@keyframes slideIn { |
|||
from { |
|||
opacity: 0; |
|||
transform: translateY(20rpx); |
|||
} |
|||
to { |
|||
opacity: 1; |
|||
transform: translateY(0); |
|||
} |
|||
} |
|||
|
|||
/* 编辑弹窗样式 */ |
|||
.edit-modal { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
background-color: rgba(0, 0, 0, 0.5); |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
z-index: 1000; |
|||
|
|||
.modal-content { |
|||
background-color: #2a2a2a; |
|||
border-radius: 20rpx; |
|||
width: 90%; |
|||
max-height: 80%; |
|||
overflow: hidden; |
|||
border: 1rpx solid #444; |
|||
|
|||
.modal-header { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
padding: 32rpx; |
|||
border-bottom: 1rpx solid #444; |
|||
|
|||
.modal-title { |
|||
font-size: 32rpx; |
|||
font-weight: 600; |
|||
color: #fff; |
|||
} |
|||
|
|||
.modal-close { |
|||
width: 48rpx; |
|||
height: 48rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
|
|||
.iconfont { |
|||
font-size: 32rpx; |
|||
color: #999; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.modal-body { |
|||
padding: 32rpx; |
|||
|
|||
.form-item { |
|||
.form-label { |
|||
font-size: 28rpx; |
|||
color: #ccc; |
|||
margin-bottom: 16rpx; |
|||
display: block; |
|||
} |
|||
|
|||
.editor-toolbar { |
|||
background-color: #1a1a1a; |
|||
border: 1rpx solid #444; |
|||
border-bottom: none; |
|||
border-radius: 12rpx 12rpx 0 0; |
|||
padding: 16rpx; |
|||
|
|||
.toolbar-group { |
|||
display: flex; |
|||
gap: 16rpx; |
|||
|
|||
.tool-btn { |
|||
width: 48rpx; |
|||
height: 48rpx; |
|||
background-color: #444; |
|||
border: 1rpx solid #666; |
|||
border-radius: 8rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
|
|||
&.active { |
|||
background-color: #29d3b4; |
|||
border-color: #29d3b4; |
|||
} |
|||
|
|||
.tool-text { |
|||
font-size: 24rpx; |
|||
color: #fff; |
|||
font-weight: 600; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.form-textarea { |
|||
width: 100%; |
|||
min-height: 300rpx; |
|||
background-color: #1a1a1a; |
|||
border: 1rpx solid #444; |
|||
border-radius: 0 0 12rpx 12rpx; |
|||
border-top: none; |
|||
padding: 20rpx; |
|||
font-size: 28rpx; |
|||
color: #fff; |
|||
line-height: 1.6; |
|||
box-sizing: border-box; |
|||
|
|||
&::placeholder { |
|||
color: #666; |
|||
} |
|||
} |
|||
|
|||
.char-count { |
|||
text-align: right; |
|||
margin-top: 8rpx; |
|||
font-size: 24rpx; |
|||
color: #666; |
|||
} |
|||
|
|||
.editor-tips { |
|||
margin-top: 12rpx; |
|||
|
|||
.tip-text { |
|||
font-size: 22rpx; |
|||
color: #666; |
|||
line-height: 1.4; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.modal-footer { |
|||
display: flex; |
|||
gap: 24rpx; |
|||
padding: 32rpx; |
|||
border-top: 1rpx solid #444; |
|||
|
|||
.modal-btn { |
|||
flex: 1; |
|||
height: 72rpx; |
|||
border-radius: 12rpx; |
|||
font-size: 28rpx; |
|||
font-weight: 600; |
|||
border: none; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
|
|||
&.cancel { |
|||
background-color: #444; |
|||
color: #ccc; |
|||
|
|||
&:active { |
|||
background-color: #555; |
|||
} |
|||
} |
|||
|
|||
&.confirm { |
|||
background-color: #29d3b4; |
|||
color: #fff; |
|||
|
|||
&:active:not(:disabled) { |
|||
background-color: #22b39a; |
|||
} |
|||
|
|||
&:disabled { |
|||
background-color: #666; |
|||
color: #999; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,565 +0,0 @@ |
|||
<!--服务列表页面--> |
|||
<template> |
|||
<view class="container dark-theme"> |
|||
<view class="header"> |
|||
<view class="search-bar"> |
|||
<view class="search-input"> |
|||
<input |
|||
placeholder="搜索服务..." |
|||
v-model="searchText" |
|||
@input="handleSearch" |
|||
/> |
|||
</view> |
|||
<view class="filter-btn" @click="showFilter"> |
|||
<text>筛选</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="service-list"> |
|||
<view class="service-item" |
|||
v-for="(service, index) in filteredServiceList" |
|||
:key="index" |
|||
@click="goToDetail(service)"> |
|||
<view class="service-header"> |
|||
<view class="service-title">{{ service.name }}</view> |
|||
<view class="service-badge" :class="[ |
|||
service.status === '正常' ? 'badge-success' : '', |
|||
service.status === '即将到期' ? 'badge-warning' : '', |
|||
service.status === '已过期' ? 'badge-danger' : '', |
|||
!['正常', '即将到期', '已过期'].includes(service.status) ? 'badge-default' : '' |
|||
]"> |
|||
{{ service.status }} |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="service-content"> |
|||
<view class="service-meta"> |
|||
<view class="meta-item"> |
|||
<text class="meta-label">类型:</text> |
|||
<text class="meta-value">{{ service.type }}</text> |
|||
</view> |
|||
<view class="meta-item"> |
|||
<text class="meta-label">时长:</text> |
|||
<text class="meta-value">{{ service.duration }}</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="service-desc">{{ service.description }}</view> |
|||
|
|||
<view class="service-footer"> |
|||
<view class="service-time"> |
|||
{{ service.startTime }} - {{ service.endTime }} |
|||
</view> |
|||
<view class="service-action"> |
|||
<text class="action-text">查看详情</text> |
|||
<text class="action-arrow">></text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="empty-state" v-if="filteredServiceList.length === 0"> |
|||
<image class="empty-icon" src="/static/icon-img/empty.png"></image> |
|||
<view class="empty-text">{{ searchText ? '未找到相关服务' : '暂无服务记录' }}</view> |
|||
</view> |
|||
|
|||
<!-- 筛选弹窗 --> |
|||
<fui-bottom-popup v-model="showFilterPopup" :zIndex="9999"> |
|||
<view class="filter-popup"> |
|||
<view class="popup-header"> |
|||
<view class="popup-title">筛选条件</view> |
|||
<view class="popup-close" @click="showFilterPopup = false">✕</view> |
|||
</view> |
|||
|
|||
<view class="filter-content"> |
|||
<view class="filter-group"> |
|||
<view class="filter-title">服务状态</view> |
|||
<view class="filter-options"> |
|||
<view |
|||
class="filter-option" |
|||
:class="{ active: selectedStatus === '' }" |
|||
@click="selectedStatus = ''" |
|||
> |
|||
全部 |
|||
</view> |
|||
<view |
|||
class="filter-option" |
|||
:class="{ active: selectedStatus === '正常' }" |
|||
@click="selectedStatus = '正常'" |
|||
> |
|||
正常 |
|||
</view> |
|||
<view |
|||
class="filter-option" |
|||
:class="{ active: selectedStatus === '即将到期' }" |
|||
@click="selectedStatus = '即将到期'" |
|||
> |
|||
即将到期 |
|||
</view> |
|||
<view |
|||
class="filter-option" |
|||
:class="{ active: selectedStatus === '已过期' }" |
|||
@click="selectedStatus = '已过期'" |
|||
> |
|||
已过期 |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="popup-actions"> |
|||
<view class="btn btn-reset" @click="resetFilter">重置</view> |
|||
<view class="btn btn-confirm" @click="applyFilter">确定</view> |
|||
</view> |
|||
</view> |
|||
</fui-bottom-popup> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import apiRoute from '@/api/apiRoute.js'; |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
serviceList: [], |
|||
filteredServiceList: [], |
|||
searchText: '', |
|||
showFilterPopup: false, |
|||
selectedStatus: '' |
|||
} |
|||
}, |
|||
onLoad() { |
|||
this.init(); |
|||
}, |
|||
methods: { |
|||
async init() { |
|||
this.getServiceList(); |
|||
}, |
|||
|
|||
// 获取服务列表 |
|||
async getServiceList() { |
|||
try { |
|||
// 模拟数据,实际应该调用API |
|||
this.serviceList = [ |
|||
{ |
|||
id: 1, |
|||
name: '专业体能训练服务', |
|||
type: '体能训练', |
|||
status: '正常', |
|||
duration: '3个月', |
|||
startTime: '2024-01-01', |
|||
endTime: '2024-03-31', |
|||
description: '专业的体能训练指导,包含有氧运动、力量训练等综合项目' |
|||
}, |
|||
{ |
|||
id: 2, |
|||
name: '基础动作指导服务', |
|||
type: '技术指导', |
|||
status: '即将到期', |
|||
duration: '1个月', |
|||
startTime: '2024-06-01', |
|||
endTime: '2024-06-30', |
|||
description: '针对基础动作的专业指导和纠正' |
|||
}, |
|||
{ |
|||
id: 3, |
|||
name: '营养咨询服务', |
|||
type: '营养指导', |
|||
status: '正常', |
|||
duration: '6个月', |
|||
startTime: '2024-01-15', |
|||
endTime: '2024-07-15', |
|||
description: '专业营养师提供个性化营养方案和饮食建议' |
|||
}, |
|||
{ |
|||
id: 4, |
|||
name: '康复训练服务', |
|||
type: '康复指导', |
|||
status: '已过期', |
|||
duration: '2个月', |
|||
startTime: '2023-10-01', |
|||
endTime: '2023-11-30', |
|||
description: '运动损伤康复和预防性训练指导' |
|||
} |
|||
]; |
|||
|
|||
this.filteredServiceList = [...this.serviceList]; |
|||
|
|||
// 实际API调用示例: |
|||
// let res = await apiRoute.getServiceList({}); |
|||
// if (res.code === 1) { |
|||
// this.serviceList = res.data; |
|||
// this.filteredServiceList = [...this.serviceList]; |
|||
// } |
|||
} catch (error) { |
|||
console.error('获取服务列表失败:', error); |
|||
uni.showToast({ |
|||
title: '获取数据失败', |
|||
icon: 'none' |
|||
}); |
|||
} |
|||
}, |
|||
|
|||
// 搜索处理 |
|||
handleSearch() { |
|||
this.filterServices(); |
|||
}, |
|||
|
|||
// 筛选服务 |
|||
filterServices() { |
|||
let filtered = [...this.serviceList]; |
|||
|
|||
// 按搜索文本筛选 |
|||
if (this.searchText) { |
|||
filtered = filtered.filter(service => |
|||
service.name.includes(this.searchText) || |
|||
service.type.includes(this.searchText) || |
|||
service.description.includes(this.searchText) |
|||
); |
|||
} |
|||
|
|||
// 按状态筛选 |
|||
if (this.selectedStatus) { |
|||
filtered = filtered.filter(service => service.status === this.selectedStatus); |
|||
} |
|||
|
|||
this.filteredServiceList = filtered; |
|||
}, |
|||
|
|||
// 显示筛选 |
|||
showFilter() { |
|||
this.showFilterPopup = true; |
|||
}, |
|||
|
|||
// 重置筛选 |
|||
resetFilter() { |
|||
this.selectedStatus = ''; |
|||
this.filterServices(); |
|||
}, |
|||
|
|||
// 应用筛选 |
|||
applyFilter() { |
|||
this.filterServices(); |
|||
this.showFilterPopup = false; |
|||
}, |
|||
|
|||
|
|||
// 跳转到详情页 |
|||
goToDetail(service) { |
|||
this.$navigateTo({ |
|||
url: `/pages/coach/my/service_detail?id=${service.id}` |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
// 通用样式 |
|||
.container { |
|||
min-height: 100vh; |
|||
} |
|||
|
|||
// 暗黑主题样式 |
|||
.dark-theme { |
|||
background-color: #121212; |
|||
color: #ffffff; |
|||
|
|||
.header { |
|||
background-color: #181818; |
|||
padding: 20rpx; |
|||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3); |
|||
} |
|||
|
|||
.search-input { |
|||
background-color: #1e1e1e; |
|||
border-radius: 25rpx; |
|||
padding: 15rpx 30rpx; |
|||
|
|||
input { |
|||
width: 100%; |
|||
font-size: 28rpx; |
|||
color: #ffffff; |
|||
} |
|||
} |
|||
|
|||
.filter-btn { |
|||
background-color: #00d18c; |
|||
color: #121212; |
|||
padding: 15rpx 30rpx; |
|||
border-radius: 25rpx; |
|||
font-size: 28rpx; |
|||
font-weight: bold; |
|||
} |
|||
|
|||
.service-item { |
|||
background-color: #1e1e1e; |
|||
border-radius: 16rpx; |
|||
padding: 30rpx; |
|||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.3); |
|||
margin-bottom: 20rpx; |
|||
} |
|||
|
|||
.service-title { |
|||
font-size: 32rpx; |
|||
font-weight: bold; |
|||
color: #ffffff; |
|||
flex: 1; |
|||
margin-right: 20rpx; |
|||
} |
|||
|
|||
.service-badge { |
|||
padding: 8rpx 16rpx; |
|||
border-radius: 20rpx; |
|||
font-size: 24rpx; |
|||
|
|||
&.badge-success { |
|||
background-color: rgba(82, 196, 26, 0.2); |
|||
color: #52c41a; |
|||
border: 1px solid #52c41a; |
|||
} |
|||
|
|||
&.badge-warning { |
|||
background-color: rgba(250, 140, 22, 0.2); |
|||
color: #fa8c16; |
|||
border: 1px solid #fa8c16; |
|||
} |
|||
|
|||
&.badge-danger { |
|||
background-color: rgba(255, 77, 79, 0.2); |
|||
color: #ff4d4f; |
|||
border: 1px solid #ff4d4f; |
|||
} |
|||
|
|||
&.badge-default { |
|||
background-color: rgba(102, 102, 102, 0.2); |
|||
color: #999; |
|||
border: 1px solid #666; |
|||
} |
|||
} |
|||
|
|||
.meta-item { |
|||
.meta-label { |
|||
color: #b0b0b0; |
|||
font-size: 26rpx; |
|||
} |
|||
|
|||
.meta-value { |
|||
color: #ffffff; |
|||
font-size: 26rpx; |
|||
} |
|||
} |
|||
|
|||
.service-desc { |
|||
color: #b0b0b0; |
|||
font-size: 26rpx; |
|||
line-height: 1.5; |
|||
} |
|||
|
|||
.service-footer { |
|||
padding-top: 15rpx; |
|||
border-top: 1px solid #333333; |
|||
} |
|||
|
|||
.service-time { |
|||
color: #999999; |
|||
font-size: 24rpx; |
|||
} |
|||
|
|||
.service-action { |
|||
color: #00d18c; |
|||
font-size: 26rpx; |
|||
} |
|||
|
|||
.empty-state { |
|||
.empty-icon { |
|||
opacity: 0.2; |
|||
} |
|||
|
|||
.empty-text { |
|||
color: #b0b0b0; |
|||
} |
|||
} |
|||
|
|||
// 筛选弹窗样式 |
|||
.filter-popup { |
|||
background-color: #1e1e1e; |
|||
border-radius: 20rpx 20rpx 0 0; |
|||
} |
|||
|
|||
.popup-header { |
|||
border-bottom: 1px solid #333333; |
|||
} |
|||
|
|||
.popup-title { |
|||
color: #ffffff; |
|||
} |
|||
|
|||
.popup-close { |
|||
color: #b0b0b0; |
|||
} |
|||
|
|||
.filter-title { |
|||
color: #ffffff; |
|||
} |
|||
|
|||
.filter-option { |
|||
background-color: #282828; |
|||
color: #b0b0b0; |
|||
|
|||
&.active { |
|||
background-color: #00d18c; |
|||
color: #121212; |
|||
} |
|||
} |
|||
|
|||
.popup-actions { |
|||
border-top: 1px solid #333333; |
|||
} |
|||
|
|||
.btn { |
|||
&.btn-reset { |
|||
background-color: #333333; |
|||
color: #ffffff; |
|||
} |
|||
|
|||
&.btn-confirm { |
|||
background-color: #00d18c; |
|||
color: #121212; |
|||
font-weight: bold; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 通用布局样式(不受主题影响的部分) |
|||
.search-bar { |
|||
display: flex; |
|||
gap: 20rpx; |
|||
align-items: center; |
|||
} |
|||
|
|||
.search-input { |
|||
flex: 1; |
|||
} |
|||
|
|||
.service-list { |
|||
padding: 20rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.service-header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 20rpx; |
|||
} |
|||
|
|||
.service-content { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 15rpx; |
|||
} |
|||
|
|||
.service-meta { |
|||
display: flex; |
|||
gap: 30rpx; |
|||
} |
|||
|
|||
.meta-item { |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.service-footer { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
} |
|||
|
|||
.service-action { |
|||
display: flex; |
|||
align-items: center; |
|||
|
|||
.action-arrow { |
|||
margin-left: 10rpx; |
|||
} |
|||
} |
|||
|
|||
.empty-state { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
padding: 100rpx 0; |
|||
|
|||
.empty-icon { |
|||
width: 120rpx; |
|||
height: 120rpx; |
|||
margin-bottom: 30rpx; |
|||
} |
|||
|
|||
.empty-text { |
|||
font-size: 28rpx; |
|||
} |
|||
} |
|||
|
|||
.popup-header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 30rpx; |
|||
} |
|||
|
|||
.popup-title { |
|||
font-size: 32rpx; |
|||
font-weight: bold; |
|||
} |
|||
|
|||
.popup-close { |
|||
font-size: 36rpx; |
|||
} |
|||
|
|||
.filter-content { |
|||
padding: 30rpx; |
|||
} |
|||
|
|||
.filter-group { |
|||
margin-bottom: 40rpx; |
|||
} |
|||
|
|||
.filter-title { |
|||
font-size: 28rpx; |
|||
font-weight: bold; |
|||
margin-bottom: 20rpx; |
|||
} |
|||
|
|||
.filter-options { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
gap: 20rpx; |
|||
} |
|||
|
|||
.filter-option { |
|||
padding: 15rpx 30rpx; |
|||
border-radius: 25rpx; |
|||
font-size: 26rpx; |
|||
} |
|||
|
|||
.popup-actions { |
|||
display: flex; |
|||
gap: 20rpx; |
|||
padding: 30rpx; |
|||
} |
|||
|
|||
.btn { |
|||
flex: 1; |
|||
padding: 20rpx; |
|||
border-radius: 12rpx; |
|||
text-align: center; |
|||
font-size: 28rpx; |
|||
} |
|||
</style> |
|||
@ -1,168 +0,0 @@ |
|||
<template> |
|||
<view style="height: 100vh;background-color: #fff;"> |
|||
<view class="title_style"> |
|||
{{arrayInfo.title}} |
|||
</view> |
|||
<view class="date_style"> |
|||
{{arrayInfo.update_time}} |
|||
</view> |
|||
|
|||
<view class="url_style" v-if="arrayInfo.type == 1 && arrayInfo.url"> |
|||
<video style="margin: auto;" :src="arrayInfo.url" :enable-progress-gesture="true" |
|||
:show-fullscreen-btn="true" :show-play-btn="true" @error="onVideoError" @play="onPlay" |
|||
@pause="onPause" /> |
|||
</view> |
|||
|
|||
<view class="url_image_style" v-if="arrayInfo.type == 3 && arrayInfo.url"> |
|||
<image :src="arrayInfo.url" mode="aspectFill" @click="clickPreviewImage(arrayInfo.url)" |
|||
style="width: 80%;margin: auto;"> |
|||
</image> |
|||
</view> |
|||
|
|||
<view class="url_file_style" v-if="arrayInfo.type == 2 && arrayInfo.url"> |
|||
<a style="cursor: pointer;color: blue;" @click="previewFile(arrayInfo.url)">素材文件</a> |
|||
</view> |
|||
|
|||
<!-- <view class="con_style" v-html="arrayInfo.content"></view> --> |
|||
<jyf-parser class="con_style" :html="arrayInfo.content" :tag-style="tagStyle"></jyf-parser> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import apiRoute from '@/api/apiRoute.js'; |
|||
import jyfParser from '@/components/jyf-parser/jyf-parser.vue'; |
|||
|
|||
export default { |
|||
components: { |
|||
jyfParser |
|||
}, |
|||
data() { |
|||
return { |
|||
articleId: undefined, |
|||
arrayInfo: [], |
|||
tagStyle: { |
|||
// 设置富文本样式 |
|||
p: 'margin:0;padding:0;color:#333333;', |
|||
span: 'color:#333333;', |
|||
h1: 'color:#333333;', |
|||
h2: 'color:#333333;', |
|||
h3: 'color:#333333;', |
|||
h4: 'color:#333333;', |
|||
h5: 'color:#333333;', |
|||
h6: 'color:#333333;', |
|||
li: 'color:#333333;', |
|||
div: 'color:#333333;' |
|||
} |
|||
} |
|||
}, |
|||
onLoad(options) { |
|||
this.articleId = options.id; |
|||
console.log(this.articleId, 888) |
|||
this.init() |
|||
}, |
|||
methods: { |
|||
init() { |
|||
apiRoute.teachingResearchInfo(this.articleId).then(res => { |
|||
if (res.code == 1) { |
|||
this.arrayInfo = res.data |
|||
} |
|||
}) |
|||
}, |
|||
clickPreviewImage(url) { |
|||
uni.previewImage({ |
|||
urls: [url], // 支持多张图预览 |
|||
current: url, // 当前显示的图片链接 |
|||
success: () => { |
|||
console.log('预览成功'); |
|||
}, |
|||
fail: (err) => { |
|||
console.error('预览失败', err); |
|||
} |
|||
}); |
|||
}, |
|||
async previewFile(url) { |
|||
|
|||
console.log(url) |
|||
|
|||
try { |
|||
// 1. 下载文件到本地 |
|||
const { |
|||
tempFilePath |
|||
} = await this.downloadFile(this.$util.img('public/'+url)); |
|||
console.log(tempFilePath) |
|||
// 2. 打开文件 |
|||
await uni.openDocument({ |
|||
filePath: this.$util.img(tempFilePath), |
|||
showMenu: true, |
|||
success: () => { |
|||
console.log('打开文档成功'); |
|||
} |
|||
}); |
|||
} catch (err) { |
|||
uni.showToast({ |
|||
title: '预览失败', |
|||
icon: 'none' |
|||
}); |
|||
console.error('预览失败:', err); |
|||
} |
|||
}, |
|||
|
|||
downloadFile(url) { |
|||
return new Promise((resolve, reject) => { |
|||
uni.downloadFile({ |
|||
url, |
|||
success: (res) => { |
|||
if (res.statusCode === 200) { |
|||
resolve(res); |
|||
} else { |
|||
reject(new Error('下载失败')); |
|||
} |
|||
}, |
|||
fail: (err) => { |
|||
reject(err); |
|||
} |
|||
}); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
.title_style { |
|||
width: 100%; |
|||
text-align: center; |
|||
font-size: 40rpx; |
|||
font-weight: bold; |
|||
padding-top: 10px; |
|||
} |
|||
|
|||
.date_style { |
|||
width: 100%; |
|||
text-align: right; |
|||
font-size: 20rpx; |
|||
color: #ccc; |
|||
padding-right: 16rpx; |
|||
margin-top: 10px; |
|||
} |
|||
|
|||
.con_style { |
|||
font-size: 30rpx; |
|||
padding: 18rpx; |
|||
margin-top: 20px; |
|||
} |
|||
|
|||
.url_style { |
|||
margin-top: 20px; |
|||
text-align: center; |
|||
} |
|||
|
|||
.url_image_style { |
|||
padding: 20rpx; |
|||
text-align: center; |
|||
} |
|||
|
|||
.url_file_style{ |
|||
padding: 20rpx; |
|||
} |
|||
</style> |
|||
@ -1,481 +0,0 @@ |
|||
<template> |
|||
<view class="schedule-detail-container"> |
|||
<!-- 页面加载状态 --> |
|||
<view class="loading-container" v-if="loading"> |
|||
<fui-loading></fui-loading> |
|||
<text class="loading-text">加载中...</text> |
|||
</view> |
|||
|
|||
<!-- 错误状态显示 --> |
|||
<view class="error-container" v-else-if="error"> |
|||
<text class="error-text">{{ errorMessage }}</text> |
|||
<view class="retry-btn" @click="fetchScheduleDetail"> |
|||
<text>重试</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="schedule-content" v-else> |
|||
<!-- 课程基本信息 --> |
|||
<view class="schedule-header"> |
|||
<view class="course-title"> |
|||
<text>{{ scheduleDetail.title || '暂无课程名称' }}</text> |
|||
<text class="status-tag" :class="statusClass">{{ statusText }}</text> |
|||
</view> |
|||
<view class="course-time">{{ scheduleDetail.course_date || '' }} {{ scheduleDetail.time_slot || '' }}</view> |
|||
</view> |
|||
|
|||
<!-- 课程详细信息 --> |
|||
<view class="info-card"> |
|||
<view class="info-item"> |
|||
<text class="info-label">授课教师:</text> |
|||
<text class="info-value">{{ scheduleDetail.coach?.name || '未设置' }}</text> |
|||
</view> |
|||
<view class="info-item"> |
|||
<text class="info-label">教室:</text> |
|||
<text class="info-value">{{ scheduleDetail.venue?.venue_name || '未设置' }}</text> |
|||
</view> |
|||
<view class="info-item"> |
|||
<text class="info-label">当前人数:</text> |
|||
<text class="info-value">{{ studentCount }}/{{ scheduleDetail.venue?.capacity || 0 }}</text> |
|||
</view> |
|||
<view class="info-item"> |
|||
<text class="info-label">课程内容:</text> |
|||
<text class="info-value">{{ scheduleDetail.content || '未设置上课内容' }}</text> |
|||
</view> |
|||
<view class="info-item" v-if="scheduleDetail.remark"> |
|||
<text class="info-label">备注:</text> |
|||
<text class="info-value">{{ scheduleDetail.remark }}</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 学员列表 --> |
|||
<view class="student-list-section"> |
|||
<view class="section-title"> |
|||
<text>学员列表</text> |
|||
</view> |
|||
<view class="student-list" v-if="scheduleDetail.student_courses && scheduleDetail.student_courses.length > 0"> |
|||
<view class="student-item" v-for="(student, index) in scheduleDetail.student_courses" :key="index"> |
|||
<view class="student-avatar"> |
|||
<image :src="$util.img(student.avatar)" mode="aspectFill"></image> |
|||
</view> |
|||
<view class="student-info"> |
|||
<text class="student-name">{{ student.name }}</text> |
|||
<text class="student-status" :class="{'signed': student.status === 'signed'}"> |
|||
{{ student.status === 'signed' ? '已签到' : '未签到' }} |
|||
</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="empty-list" v-else> |
|||
<text>暂无学员参与此课程</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 底部按钮区域 --> |
|||
<view class="footer-actions"> |
|||
<view class="action-btn adjust-btn" @click="handleAdjustClass"> |
|||
<text>调课</text> |
|||
</view> |
|||
<view class="action-btn sign-btn" @click="handleSignIn"> |
|||
<text>点名</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 引入课程详情组件 --> |
|||
<schedule-detail |
|||
:visible="showDetailPopup" |
|||
:scheduleId="scheduleId" |
|||
@update:visible="showDetailPopup = $event" |
|||
@sign-in="onSignIn" |
|||
@adjust-class="onAdjustClass" |
|||
></schedule-detail> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import apiRoute from '@/api/apiRoute.js' |
|||
import ScheduleDetail from '@/components/schedule/ScheduleDetail.vue' |
|||
|
|||
export default { |
|||
components: { |
|||
ScheduleDetail |
|||
}, |
|||
data() { |
|||
return { |
|||
scheduleId: '', // 课程安排ID |
|||
loading: false, |
|||
error: false, |
|||
errorMessage: '加载失败,请重试', |
|||
scheduleDetail: {}, |
|||
studentCount: 0, |
|||
showDetailPopup: false |
|||
} |
|||
}, |
|||
computed: { |
|||
// 课程状态文本和样式 |
|||
statusText() { |
|||
if (!this.scheduleDetail.student_courses || !this.scheduleDetail.student_courses[0]) { |
|||
return '未开始'; |
|||
} |
|||
|
|||
const now = new Date(); |
|||
const startDate = this.scheduleDetail.student_courses[0].start_date ? |
|||
new Date(this.scheduleDetail.student_courses[0].start_date) : null; |
|||
const endDate = this.scheduleDetail.student_courses[0].end_date ? |
|||
new Date(this.scheduleDetail.student_courses[0].end_date) : null; |
|||
|
|||
if (startDate && endDate) { |
|||
if (now >= startDate && now <= endDate) { |
|||
return '上课中'; |
|||
} else if (now > endDate) { |
|||
return '已结束'; |
|||
} else if (now < startDate) { |
|||
return '未开始'; |
|||
} |
|||
} |
|||
|
|||
return '未开始'; |
|||
}, |
|||
statusClass() { |
|||
switch (this.statusText) { |
|||
case '上课中': |
|||
return 'status-in-progress'; |
|||
case '已结束': |
|||
return 'status-ended'; |
|||
case '未开始': |
|||
default: |
|||
return 'status-not-started'; |
|||
} |
|||
} |
|||
}, |
|||
onLoad(options) { |
|||
if (options.id) { |
|||
this.scheduleId = options.id; |
|||
this.fetchScheduleDetail(); |
|||
} else { |
|||
this.error = true; |
|||
this.errorMessage = '未找到课程安排ID'; |
|||
} |
|||
}, |
|||
methods: { |
|||
// 获取课程详情 |
|||
async fetchScheduleDetail() { |
|||
if (!this.scheduleId) { |
|||
this.error = true; |
|||
this.errorMessage = '课程ID不能为空'; |
|||
return; |
|||
} |
|||
|
|||
this.loading = true; |
|||
this.error = false; |
|||
|
|||
try { |
|||
// 使用新接口获取课程安排详情 |
|||
const res = await apiRoute.getCourseScheduleInfo({ |
|||
id: this.scheduleId |
|||
}); |
|||
|
|||
if (res.code === 1 && res.data) { |
|||
this.scheduleDetail = res.data; |
|||
// 计算学生数量 |
|||
this.studentCount = this.scheduleDetail.student_courses ? |
|||
this.scheduleDetail.student_courses.length : 0; |
|||
} else { |
|||
// 如果新接口不可用,尝试使用旧接口 |
|||
const fallbackRes = await apiRoute.courseInfo({ |
|||
id: this.scheduleId |
|||
}); |
|||
|
|||
if (fallbackRes.code === 1 && fallbackRes.data) { |
|||
this.scheduleDetail = fallbackRes.data; |
|||
this.studentCount = this.scheduleDetail.student_courses ? |
|||
this.scheduleDetail.student_courses.length : 0; |
|||
} else { |
|||
throw new Error(res.msg || fallbackRes.msg || '获取课程详情失败'); |
|||
} |
|||
} |
|||
} catch (error) { |
|||
console.error('获取课程详情失败:', error); |
|||
this.error = true; |
|||
this.errorMessage = error.message || '获取课程详情失败,请重试'; |
|||
} finally { |
|||
this.loading = false; |
|||
} |
|||
}, |
|||
|
|||
// 点名功能 |
|||
handleSignIn() { |
|||
// 如果课程已结束,显示提示 |
|||
if (this.statusText === '已结束') { |
|||
uni.showToast({ |
|||
title: '课程已结束,无法点名', |
|||
icon: 'none' |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
// 如果没有学生,显示提示 |
|||
if (!this.scheduleDetail.student_courses || this.scheduleDetail.student_courses.length === 0) { |
|||
uni.showToast({ |
|||
title: '暂无学员,无法点名', |
|||
icon: 'none' |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
// 显示点名界面或跳转至点名页面 |
|||
uni.navigateTo({ |
|||
url: `/pages/coach/schedule/sign_in?id=${this.scheduleId}` |
|||
}); |
|||
}, |
|||
|
|||
// 调课功能 |
|||
handleAdjustClass() { |
|||
// 如果课程已结束,显示提示 |
|||
if (this.statusText === '已结束') { |
|||
uni.showToast({ |
|||
title: '课程已结束,无法调课', |
|||
icon: 'none' |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
// 跳转至调课页面 |
|||
uni.navigateTo({ |
|||
url: `/pages/coach/schedule/adjust_course?id=${this.scheduleId}` |
|||
}); |
|||
}, |
|||
|
|||
// 从弹窗组件中点名处理 |
|||
onSignIn(data) { |
|||
console.log('处理点名:', data); |
|||
uni.navigateTo({ |
|||
url: `/pages/coach/schedule/sign_in?id=${data.scheduleId}` |
|||
}); |
|||
}, |
|||
|
|||
// 从弹窗组件中调课处理 |
|||
onAdjustClass(data) { |
|||
console.log('处理调课:', data); |
|||
uni.navigateTo({ |
|||
url: `/pages/coach/schedule/adjust_course?id=${data.scheduleId}` |
|||
}); |
|||
}, |
|||
|
|||
// 显示弹窗 |
|||
showPopup() { |
|||
this.showDetailPopup = true; |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.schedule-detail-container { |
|||
background-color: #292929; |
|||
min-height: 100vh; |
|||
padding-bottom: 140rpx; // 为底部按钮留出空间 |
|||
} |
|||
|
|||
.loading-container, .error-container { |
|||
height: 100vh; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.loading-text, .error-text { |
|||
margin-top: 30rpx; |
|||
font-size: 28rpx; |
|||
color: #ccc; |
|||
} |
|||
|
|||
.retry-btn { |
|||
margin-top: 30rpx; |
|||
padding: 12rpx 30rpx; |
|||
background-color: #29d3b4; |
|||
border-radius: 8rpx; |
|||
color: #fff; |
|||
font-size: 24rpx; |
|||
} |
|||
|
|||
.schedule-content { |
|||
padding: 30rpx; |
|||
} |
|||
|
|||
.schedule-header { |
|||
margin-bottom: 30rpx; |
|||
} |
|||
|
|||
.course-title { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
font-size: 36rpx; |
|||
font-weight: bold; |
|||
color: #fff; |
|||
margin-bottom: 16rpx; |
|||
} |
|||
|
|||
.status-tag { |
|||
font-size: 24rpx; |
|||
padding: 4rpx 16rpx; |
|||
border-radius: 30rpx; |
|||
} |
|||
|
|||
.status-in-progress { |
|||
background-color: #FAD24E; |
|||
color: #333; |
|||
} |
|||
|
|||
.status-ended { |
|||
background-color: #e2e2e2; |
|||
color: #333; |
|||
} |
|||
|
|||
.status-not-started { |
|||
background-color: #1cd188; |
|||
color: #fff; |
|||
} |
|||
|
|||
.course-time { |
|||
font-size: 28rpx; |
|||
color: #FAD24E; |
|||
margin-bottom: 30rpx; |
|||
} |
|||
|
|||
.info-card { |
|||
background-color: #434544; |
|||
border-radius: 16rpx; |
|||
padding: 24rpx; |
|||
margin-bottom: 30rpx; |
|||
} |
|||
|
|||
.info-item { |
|||
display: flex; |
|||
margin-bottom: 20rpx; |
|||
} |
|||
|
|||
.info-label { |
|||
width: 160rpx; |
|||
font-size: 26rpx; |
|||
color: #ccc; |
|||
} |
|||
|
|||
.info-value { |
|||
flex: 1; |
|||
font-size: 26rpx; |
|||
color: #fff; |
|||
} |
|||
|
|||
.student-list-section { |
|||
background-color: #434544; |
|||
border-radius: 16rpx; |
|||
padding: 24rpx; |
|||
} |
|||
|
|||
.section-title { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding-bottom: 16rpx; |
|||
border-bottom: 1px solid #555; |
|||
margin-bottom: 20rpx; |
|||
} |
|||
|
|||
.section-title text { |
|||
font-size: 28rpx; |
|||
color: #fff; |
|||
} |
|||
|
|||
.student-list { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 20rpx; |
|||
} |
|||
|
|||
.student-item { |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.student-avatar { |
|||
width: 80rpx; |
|||
height: 80rpx; |
|||
border-radius: 50%; |
|||
overflow: hidden; |
|||
background-color: #555; |
|||
margin-right: 20rpx; |
|||
} |
|||
|
|||
.student-avatar image { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
|
|||
.student-info { |
|||
flex: 1; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
} |
|||
|
|||
.student-name { |
|||
font-size: 28rpx; |
|||
color: #fff; |
|||
} |
|||
|
|||
.student-status { |
|||
font-size: 24rpx; |
|||
color: #ff6b6b; |
|||
background: rgba(255, 107, 107, 0.1); |
|||
padding: 4rpx 12rpx; |
|||
border-radius: 20rpx; |
|||
} |
|||
|
|||
.student-status.signed { |
|||
color: #1cd188; |
|||
background: rgba(28, 209, 136, 0.1); |
|||
} |
|||
|
|||
.empty-list { |
|||
padding: 40rpx 0; |
|||
text-align: center; |
|||
color: #999; |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.footer-actions { |
|||
position: fixed; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
display: flex; |
|||
padding: 30rpx; |
|||
gap: 20rpx; |
|||
background-color: #292929; |
|||
border-top: 1px solid #434544; |
|||
} |
|||
|
|||
.action-btn { |
|||
flex: 1; |
|||
height: 80rpx; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
border-radius: 8rpx; |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.adjust-btn { |
|||
background-color: #555; |
|||
color: #fff; |
|||
} |
|||
|
|||
.sign-btn { |
|||
background-color: #29d3b4; |
|||
color: #fff; |
|||
} |
|||
</style> |
|||
@ -1,599 +0,0 @@ |
|||
<!--学员-详情--> |
|||
<template> |
|||
<view class="main_box"> |
|||
<!--学员信息--> |
|||
<view class="user_section"> |
|||
<view class="box"> |
|||
<view class="left"> |
|||
<image class="pic" :src="studentsInfo.customerResources.member.headimg"></image> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="item"> |
|||
<view class="name">{{ studentsInfo.name }}</view> |
|||
<view class="age"> |
|||
{{ studentsInfo.customerResources.age }}岁 |
|||
</view> |
|||
</view> |
|||
<view class="item"> |
|||
<view class="title">电话:{{ studentsInfo.customerResources.phone_number }}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="main_section"> |
|||
<view class="section_box"> |
|||
<view class="tag_box"> |
|||
<view :class="['item', tabType=='1' ? 'select':'']" @click="tabChange(1)">出勤记录</view> |
|||
<view :class="['item', tabType=='2' ? 'select':'']" @click="tabChange(2)">体侧报告</view> |
|||
</view> |
|||
|
|||
<!--作业列表--> |
|||
<view v-if="tabType=='1'" class="section_1"> |
|||
<view class="ul"> |
|||
<view class="li" |
|||
v-for="(v,k) in assignmentsList" |
|||
:key="k" |
|||
@click="opebViewWorkDetails(v)"> |
|||
<view class="left"> |
|||
<view class="title">{{ v.courses_name }}</view> |
|||
<view class="date">上课时间:{{ v.submit_time }}</view> |
|||
</view> |
|||
<view class="right"> |
|||
<view v-if="v.status==1" class="btn" style="background-color: #e2e2e2;">作业未提交</view> |
|||
<view v-else-if="v.status==2" class="btn" style="background-color: #a4adb3;">待批改</view> |
|||
<view v-else-if="v.status==3" class="btn" style="background-color: #29d3b4;">作业已完成</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
|
|||
<!--评测报告--> |
|||
<view v-if="tabType=='2'" class="section_2"> |
|||
<scroll-view |
|||
class="ul" |
|||
scroll-y="true" |
|||
:lower-threshold="lowerThreshold" |
|||
@scrolltolower="loadMoreData" |
|||
style="height: 65vh;" |
|||
> |
|||
<view |
|||
class="li" |
|||
v-for="(v,k) in surveyList" |
|||
:key="k" @click="openViewPhysicalExamination(v)" |
|||
> |
|||
<view class="top"> |
|||
<view class="title">综合评分:{{ v.calculateChildHealthScore }}</view> |
|||
<!-- <view class="hint">打败了99%学员</view>--> |
|||
</view> |
|||
<view class="bottom">测试时间:{{ $util.formatToDateTime(v.created_at, 'Y-m-d') }}</view> |
|||
</view> |
|||
</scroll-view> |
|||
</view> |
|||
|
|||
|
|||
</view> |
|||
|
|||
</view> |
|||
|
|||
<!-- 底部导航--> |
|||
<!-- <AQTabber/>--> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import memberApi from '@/api/member.js' |
|||
import AQTabber from '@/components/AQ/AQTabber.vue' |
|||
import apiRoute from '@/api/apiRoute.js' |
|||
|
|||
export default { |
|||
components: { |
|||
AQTabber, |
|||
}, |
|||
data() { |
|||
return { |
|||
tabType: '1',//1=班级成员,2=作业任务 |
|||
Atype: 1,//1=作业完成,2=作业未提交 |
|||
|
|||
students_id: '',//学生id |
|||
studentsInfo: {},// 学生详情 |
|||
assignmentsList: [],// 作业列表 |
|||
|
|||
loading: false,//加载状态 |
|||
lowerThreshold: 100,//距离底部多远触发 |
|||
isReachedBottom: false,//防止重复加载|true=不可加载|false=可加载 |
|||
|
|||
//筛选条件 |
|||
filteredData: { |
|||
page: 1,//当前页码 |
|||
limit: 10,//每页返回数据条数 |
|||
total: 10,//数据总条数 |
|||
user_id: '',//学员id |
|||
}, |
|||
surveyList: [],//体测报告列表 |
|||
} |
|||
}, |
|||
onLoad(options) { |
|||
this.students_id = options.students_id//学生id |
|||
}, |
|||
onShow() { |
|||
this.init()//初始化 |
|||
}, |
|||
methods: { |
|||
//初始化 |
|||
async init() { |
|||
//获取学生详情 |
|||
await this.getStudentsInfo() |
|||
await this.getSurveyList() |
|||
}, |
|||
formatAgeMonth(input) { |
|||
let str = String(input) |
|||
// 分割小数点前后部分 |
|||
let [yearPart, monthPart] = str.split('.') |
|||
// 如果没有小数部分,默认为 0 |
|||
if (!monthPart) { |
|||
monthPart = '00' |
|||
} |
|||
// 如果是 00,则显示为 0 |
|||
monthPart = monthPart === '00' ? '0' : monthPart |
|||
return `${yearPart}岁${monthPart}月` |
|||
}, |
|||
//获取学生详情 |
|||
async getStudentsInfo() { |
|||
let data = { |
|||
students_id: this.students_id, |
|||
} |
|||
let res = await apiRoute.jlStudentsInfo(data) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none', |
|||
}) |
|||
return |
|||
} |
|||
|
|||
this.studentsInfo = res.data//学生信息 |
|||
|
|||
this.assignmentsList = res.data.physical_test//作业列表 |
|||
this.filteredData.user_id = res.data.user_id |
|||
|
|||
}, |
|||
// 检查 expire_time 是否大于等于当前时间 5 天 |
|||
checkExpireTime(expireTime = '') { |
|||
if (!expireTime) { |
|||
return false |
|||
} |
|||
|
|||
const expireDate = new Date(expireTime) |
|||
const currentDate = new Date() |
|||
|
|||
// 计算天数差 |
|||
const timeDifference = expireDate - currentDate |
|||
const daysDifference = timeDifference / (1000 * 60 * 60 * 24) |
|||
|
|||
if (daysDifference >= 5) { |
|||
return true |
|||
} else { |
|||
return false |
|||
} |
|||
}, |
|||
|
|||
|
|||
//加载更多(下一页) |
|||
loadMoreData() { |
|||
//判断是否加载 |
|||
if (!this.isReachedBottom) { |
|||
this.isReachedBottom = true//设置为不可请求状态 |
|||
this.getSurveyList() |
|||
} |
|||
}, |
|||
//重置为第一页 |
|||
async resetFilteredData() { |
|||
this.isReachedBottom = false // 重置状态,以便下次触发加载更多 |
|||
|
|||
this.filteredData.page = 1//当前页码 |
|||
this.filteredData.limit = 10//每页返回数据条数 |
|||
this.filteredData.total = 10//数据总条数 |
|||
}, |
|||
//获取学生评测报告列表 |
|||
async getSurveyList() { |
|||
this.loading = true |
|||
|
|||
let data = { ...this.filteredData } |
|||
|
|||
//判断是否还有数据 |
|||
if ((this.filteredData.page - 1) * this.filteredData.limit >= this.filteredData.total) { |
|||
this.loading = false |
|||
uni.showToast({ |
|||
title: '暂无更多', |
|||
icon: 'none', |
|||
}) |
|||
return |
|||
} |
|||
|
|||
if (data.page == 1) { |
|||
this.surveyList = [] |
|||
} |
|||
|
|||
//学员-体测列表 |
|||
let res = await apiRoute.physicalTest(data) |
|||
this.loading = false |
|||
this.isReachedBottom = false |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none', |
|||
}) |
|||
return |
|||
} |
|||
|
|||
console.log(res, 111) |
|||
|
|||
this.surveyList = this.surveyList.concat(res.data.physical_test.data) // 使用 concat 方法 将新数据追加到数组中 |
|||
|
|||
console.log('列表', this.surveyList) |
|||
this.filteredData.total = res.data.total |
|||
this.filteredData.page++ |
|||
}, |
|||
|
|||
|
|||
//切换tab |
|||
tabChange(tabType) { |
|||
this.tabType = tabType |
|||
}, |
|||
|
|||
//打开课程详情 |
|||
openViewCourseInfo(item) { |
|||
this.$navigateTo({ |
|||
url: '/pages/coach/course/info', |
|||
}) |
|||
}, |
|||
//打开学员详情页 |
|||
openViewStudentInfo(item) { |
|||
this.$navigateTo({ |
|||
url: '/pages/coach/student/info', |
|||
}) |
|||
}, |
|||
|
|||
//打开体测报告 |
|||
openViewPhysicalExamination(item) { |
|||
let survey_id = item.id |
|||
this.$navigateTo({ |
|||
url: `/pages/coach/student/physical_examination?survey_id=${survey_id}`, |
|||
}) |
|||
}, |
|||
|
|||
//打开作业任务 |
|||
opebViewWorkDetails(item) { |
|||
this.$navigateTo({ |
|||
url: '/pages/coach/student/work_details', |
|||
}) |
|||
}, |
|||
}, |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
|
|||
.main_box { |
|||
background: #292929; |
|||
min-height: 100vh; |
|||
} |
|||
|
|||
//自定义导航栏 |
|||
.navbar_section { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
background: #292929; |
|||
|
|||
.title { |
|||
padding: 40rpx 0rpx; |
|||
|
|||
/* 小程序端样式 */ |
|||
// #ifdef MP-WEIXIN |
|||
padding: 80rpx 0rpx; |
|||
// #endif |
|||
|
|||
font-size: 30rpx; |
|||
color: #fff; |
|||
} |
|||
} |
|||
|
|||
//学员信息 |
|||
.user_section { |
|||
background-color: #29D3B4; |
|||
padding-top: 58rpx; |
|||
padding-bottom: 42rpx; |
|||
|
|||
.box { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
gap: 15rpx; |
|||
|
|||
.left { |
|||
position: relative; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
width: 120rpx; |
|||
|
|||
.pic { |
|||
width: 92rpx; |
|||
height: 92rpx; |
|||
border-radius: 50%; |
|||
} |
|||
|
|||
.btn_box { |
|||
position: absolute; |
|||
bottom: -18rpx; |
|||
|
|||
.btn { |
|||
width: 120rpx; |
|||
height: 38rpx; |
|||
line-height: 40rpx; |
|||
border-radius: 4rpx; |
|||
background-color: rgba(245, 154, 35, 1); |
|||
color: rgba(255, 255, 255, 1); |
|||
font-size: 20rpx; |
|||
text-align: center; |
|||
border: 0rpx solid rgba(121, 121, 121, 1); |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
.right { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 18rpx; |
|||
|
|||
.item { |
|||
color: #fff; |
|||
display: flex; |
|||
align-items: center; |
|||
|
|||
.name { |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.age { |
|||
margin-left: 20rpx; |
|||
width: 128rpx; |
|||
height: 42rpx; |
|||
line-height: 42rpx; |
|||
border-radius: 34rpx; |
|||
background-color: rgba(255, 255, 255, 1); |
|||
color: rgba(51, 51, 51, 1); |
|||
font-size: 28rpx; |
|||
text-align: center; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
//课程信息 |
|||
.course_section { |
|||
position: relative; |
|||
|
|||
.main { |
|||
position: relative; |
|||
z-index: 2; |
|||
padding: 0 24rpx; |
|||
display: flex; |
|||
justify-content: center; |
|||
|
|||
.course_box { |
|||
padding: 42rpx 28rpx; |
|||
width: 692rpx; |
|||
border-radius: 20rpx; |
|||
background-color: #fff; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 20rpx; |
|||
position: relative; |
|||
|
|||
.item { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 22rpx; |
|||
|
|||
.title { |
|||
font-size: 28rpx; |
|||
color: #333333; |
|||
} |
|||
|
|||
.pic { |
|||
width: 58rpx; |
|||
height: 58rpx; |
|||
border-radius: 50%; |
|||
} |
|||
|
|||
.name { |
|||
color: #333333; |
|||
font-size: 24rpx; |
|||
} |
|||
|
|||
.content { |
|||
color: #AAAAAA; |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
|
|||
.tag { |
|||
position: absolute; |
|||
right: 0; |
|||
top: 0; |
|||
width: 110rpx; |
|||
height: 60rpx; |
|||
line-height: 60rpx; |
|||
border-radius: 0rpx 24rpx 0rpx 24rpx; |
|||
background-color: rgba(236, 128, 141, 1); |
|||
color: rgba(255, 255, 255, 1); |
|||
font-size: 24rpx; |
|||
text-align: center; |
|||
} |
|||
|
|||
.btn { |
|||
position: absolute; |
|||
right: 30rpx; |
|||
bottom: 50rpx; |
|||
width: 130rpx; |
|||
height: 48rpx; |
|||
line-height: 48rpx; |
|||
border-radius: 10rpx; |
|||
background-color: rgba(41, 211, 180, 0); |
|||
color: rgba(50, 219, 224, 1); |
|||
font-size: 24rpx; |
|||
text-align: center; |
|||
font-family: -regular; |
|||
border: 2rpx solid rgba(50, 219, 224, 1); |
|||
} |
|||
} |
|||
} |
|||
|
|||
.bg_box { |
|||
z-index: 1; |
|||
width: 100%; |
|||
height: 150rpx; |
|||
} |
|||
|
|||
.bg_top { |
|||
position: absolute; |
|||
top: 0; |
|||
background-color: #29D3B4; |
|||
} |
|||
|
|||
.bg_bottom { |
|||
top: 50%; |
|||
position: absolute; |
|||
background-color: #292929; |
|||
} |
|||
} |
|||
|
|||
.main_section { |
|||
background: #292929 100%; |
|||
padding: 0 24rpx; |
|||
padding-top: 40rpx; |
|||
padding-bottom: 150rpx; |
|||
font-size: 24rpx; |
|||
color: #333333; |
|||
|
|||
.section_box { |
|||
background: #fff; |
|||
border-radius: 16rpx; |
|||
padding: 34rpx 24rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
gap: 38rpx; |
|||
|
|||
.tag_box { |
|||
width: 100%; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
gap: 112rpx; |
|||
|
|||
.item { |
|||
width: 112rpx; |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.select { |
|||
color: #29D3B4; |
|||
} |
|||
} |
|||
|
|||
//出勤记录 |
|||
.section_1 { |
|||
width: 100%; |
|||
|
|||
.ul { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 12rpx; |
|||
|
|||
.li { |
|||
padding: 30rpx 20rpx; |
|||
border: 1px solid #29D3B4; |
|||
border-radius: 18rpx; |
|||
background-color: rgba(41, 211, 180, 0.16); |
|||
font-size: 26rpx; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
|
|||
.left { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 15rpx; |
|||
} |
|||
|
|||
.right { |
|||
.btn { |
|||
width: 110rpx; |
|||
height: 44rpx; |
|||
line-height: 44rpx; |
|||
border-radius: 8rpx; |
|||
background-color: rgba(41, 211, 180, 1); |
|||
color: rgba(255, 255, 255, 1); |
|||
font-size: 20rpx; |
|||
text-align: center; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
//体测报告 |
|||
.section_2 { |
|||
width: 100%; |
|||
|
|||
.ul { |
|||
display: flex; |
|||
flex-direction: column; |
|||
|
|||
.li { |
|||
margin-bottom: 12rpx; |
|||
padding: 30rpx 20rpx; |
|||
border: 1px solid #29D3B4; |
|||
border-radius: 18rpx; |
|||
background-color: rgba(41, 211, 180, 0.16); |
|||
font-size: 26rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 20rpx; |
|||
|
|||
.top { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 40rpx; |
|||
|
|||
.title { |
|||
font-size: 34rpx; |
|||
} |
|||
|
|||
.hint { |
|||
color: #F59A23; |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
|
|||
.bottom { |
|||
} |
|||
|
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
|
|||
</style> |
|||
@ -1,499 +0,0 @@ |
|||
<template> |
|||
<view class="container"> |
|||
<uni-nav-bar fixed status-bar left-icon="left" title="学员详情" @clickLeft="navigateBack"></uni-nav-bar> |
|||
<view class="content" v-if="studentInfo"> |
|||
<view class="student-header"> |
|||
<view class="avatar-box"> |
|||
<image :src="studentInfo.avatar || '/static/icon-img/avatar.png'" mode="aspectFill" class="avatar-img"></image> |
|||
</view> |
|||
<view class="name-box"> |
|||
<text class="name">{{studentInfo.name}}</text> |
|||
<text class="id">ID: {{studentInfo.id}}</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="card-section"> |
|||
<view class="section-title">基本信息</view> |
|||
<view class="info-card"> |
|||
<view class="info-item"> |
|||
<text class="item-label">所属校区</text> |
|||
<text class="item-value">{{studentInfo.campus}}</text> |
|||
</view> |
|||
<view class="info-item"> |
|||
<text class="item-label">联系电话</text> |
|||
<text class="item-value">{{studentInfo.phone}}</text> |
|||
</view> |
|||
<view class="info-item"> |
|||
<text class="item-label">年龄</text> |
|||
<text class="item-value">{{studentInfo.age}}岁</text> |
|||
</view> |
|||
<view class="info-item"> |
|||
<text class="item-label">入学时间</text> |
|||
<text class="item-value">{{studentInfo.enrollmentDate}}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="card-section"> |
|||
<view class="section-title">课程信息</view> |
|||
<view class="info-card"> |
|||
<view class="info-item"> |
|||
<text class="item-label">剩余课程</text> |
|||
<text class="item-value highlight">{{studentInfo.remainingCourses}}节</text> |
|||
</view> |
|||
<view class="info-item"> |
|||
<text class="item-label">课程到期时间</text> |
|||
<text class="item-value highlight">{{studentInfo.expiryDate}}</text> |
|||
</view> |
|||
<view class="info-item"> |
|||
<text class="item-label">已消课程</text> |
|||
<text class="item-value">{{studentInfo.completedCourses}}节</text> |
|||
</view> |
|||
<view class="info-item"> |
|||
<text class="item-label">报名课程</text> |
|||
<text class="item-value">{{studentInfo.courseName}}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="card-section"> |
|||
<view class="section-title">最近上课记录</view> |
|||
<view class="info-card" v-if="studentInfo.recentClasses && studentInfo.recentClasses.length > 0"> |
|||
<view class="class-item" v-for="(item, index) in studentInfo.recentClasses" :key="index"> |
|||
<view class="class-date">{{item.date}}</view> |
|||
<view class="class-info"> |
|||
<text class="class-name">{{item.courseName}}</text> |
|||
<text class="class-time">{{item.timeSlot}}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="empty-class" v-else> |
|||
<text>暂无上课记录</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="btn-group"> |
|||
<button class="btn primary" @click="contactStudent">联系学员</button> |
|||
<button class="btn secondary" @click="viewSchedule">查看课表</button> |
|||
</view> |
|||
</view> |
|||
|
|||
<view v-else class="loading-box"> |
|||
<text>加载中...</text> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
id: null, |
|||
studentInfo: null |
|||
} |
|||
}, |
|||
onLoad(options) { |
|||
if (options.id) { |
|||
this.id = options.id; |
|||
this.getStudentDetail(); |
|||
} else { |
|||
uni.showToast({ |
|||
title: '参数错误', |
|||
icon: 'none' |
|||
}); |
|||
setTimeout(() => { |
|||
this.navigateBack(); |
|||
}, 1500); |
|||
} |
|||
}, |
|||
methods: { |
|||
navigateBack() { |
|||
uni.navigateBack(); |
|||
}, |
|||
getStudentDetail() { |
|||
// 模拟数据,实际开发中应该从API获取 |
|||
// try { |
|||
// const res = await memberApi.getStudentDetail({id: this.id}); |
|||
// if(res.code == 1) { |
|||
// this.studentInfo = res.data || null; |
|||
// } else { |
|||
// uni.showToast({ |
|||
// title: res.msg || '获取学员详情失败', |
|||
// icon: 'none' |
|||
// }); |
|||
// } |
|||
// } catch(error) { |
|||
// console.error('获取学员详情失败:', error); |
|||
// uni.showToast({ |
|||
// title: '获取学员详情失败', |
|||
// icon: 'none' |
|||
// }); |
|||
// } |
|||
|
|||
// 使用模拟数据 |
|||
setTimeout(() => { |
|||
// 定义一些模拟数据对象 |
|||
const studentData = { |
|||
'1': { |
|||
id: '1', |
|||
name: '张三', |
|||
avatar: '/static/icon-img/avatar.png', |
|||
campus: '总部校区', |
|||
phone: '13812341000', |
|||
age: 11, |
|||
enrollmentDate: '2023-01-11', |
|||
remainingCourses: 10, |
|||
expiryDate: '2023-12-31', |
|||
completedCourses: 20, |
|||
courseName: '少儿英语基础班', |
|||
recentClasses: [ |
|||
{ |
|||
date: '2023-09-15', |
|||
courseName: '少儿英语基础班', |
|||
timeSlot: '15:30-17:00' |
|||
}, |
|||
{ |
|||
date: '2023-09-08', |
|||
courseName: '少儿英语基础班', |
|||
timeSlot: '15:30-17:00' |
|||
}, |
|||
{ |
|||
date: '2023-09-01', |
|||
courseName: '少儿英语基础班', |
|||
timeSlot: '15:30-17:00' |
|||
} |
|||
] |
|||
}, |
|||
'2': { |
|||
id: '2', |
|||
name: '李四', |
|||
avatar: '/static/icon-img/avatar.png', |
|||
campus: '西区校区', |
|||
phone: '13812341001', |
|||
age: 12, |
|||
enrollmentDate: '2023-01-12', |
|||
remainingCourses: 5, |
|||
expiryDate: '2023-11-15', |
|||
completedCourses: 25, |
|||
courseName: '少儿英语进阶班', |
|||
recentClasses: [ |
|||
{ |
|||
date: '2023-09-14', |
|||
courseName: '少儿英语进阶班', |
|||
timeSlot: '14:00-15:30' |
|||
}, |
|||
{ |
|||
date: '2023-09-07', |
|||
courseName: '少儿英语进阶班', |
|||
timeSlot: '14:00-15:30' |
|||
} |
|||
] |
|||
}, |
|||
'3': { |
|||
id: '3', |
|||
name: '王五', |
|||
avatar: '/static/icon-img/avatar.png', |
|||
campus: '东区校区', |
|||
phone: '13812341002', |
|||
age: 13, |
|||
enrollmentDate: '2023-01-13', |
|||
remainingCourses: 15, |
|||
expiryDate: '2024-01-20', |
|||
completedCourses: 15, |
|||
courseName: '少儿英语口语班', |
|||
recentClasses: [ |
|||
{ |
|||
date: '2023-09-16', |
|||
courseName: '少儿英语口语班', |
|||
timeSlot: '10:00-11:30' |
|||
}, |
|||
{ |
|||
date: '2023-09-09', |
|||
courseName: '少儿英语口语班', |
|||
timeSlot: '10:00-11:30' |
|||
}, |
|||
{ |
|||
date: '2023-09-02', |
|||
courseName: '少儿英语口语班', |
|||
timeSlot: '10:00-11:30' |
|||
} |
|||
] |
|||
}, |
|||
'4': { |
|||
id: '4', |
|||
name: '赵六', |
|||
avatar: '/static/icon-img/avatar.png', |
|||
campus: '南区校区', |
|||
phone: '13812341003', |
|||
age: 10, |
|||
enrollmentDate: '2023-02-15', |
|||
remainingCourses: 8, |
|||
expiryDate: '2023-11-30', |
|||
completedCourses: 12, |
|||
courseName: '少儿英语基础班', |
|||
recentClasses: [ |
|||
{ |
|||
date: '2023-09-13', |
|||
courseName: '少儿英语基础班', |
|||
timeSlot: '16:00-17:30' |
|||
}, |
|||
{ |
|||
date: '2023-09-06', |
|||
courseName: '少儿英语基础班', |
|||
timeSlot: '16:00-17:30' |
|||
} |
|||
] |
|||
}, |
|||
'5': { |
|||
id: '5', |
|||
name: '刘七', |
|||
avatar: '/static/icon-img/avatar.png', |
|||
campus: '北区校区', |
|||
phone: '13812341004', |
|||
age: 14, |
|||
enrollmentDate: '2023-03-20', |
|||
remainingCourses: 20, |
|||
expiryDate: '2024-02-15', |
|||
completedCourses: 10, |
|||
courseName: '少儿英语进阶班', |
|||
recentClasses: [ |
|||
{ |
|||
date: '2023-09-12', |
|||
courseName: '少儿英语进阶班', |
|||
timeSlot: '17:00-18:30' |
|||
}, |
|||
{ |
|||
date: '2023-09-05', |
|||
courseName: '少儿英语进阶班', |
|||
timeSlot: '17:00-18:30' |
|||
} |
|||
] |
|||
}, |
|||
'6': { |
|||
id: '6', |
|||
name: '陈八', |
|||
avatar: '/static/icon-img/avatar.png', |
|||
campus: '总部校区', |
|||
phone: '13812341005', |
|||
age: 9, |
|||
enrollmentDate: '2023-04-05', |
|||
remainingCourses: 3, |
|||
expiryDate: '2023-10-30', |
|||
completedCourses: 27, |
|||
courseName: '少儿英语口语班', |
|||
recentClasses: [ |
|||
{ |
|||
date: '2023-09-11', |
|||
courseName: '少儿英语口语班', |
|||
timeSlot: '14:30-16:00' |
|||
}, |
|||
{ |
|||
date: '2023-09-04', |
|||
courseName: '少儿英语口语班', |
|||
timeSlot: '14:30-16:00' |
|||
} |
|||
] |
|||
} |
|||
}; |
|||
|
|||
// 根据ID获取对应的学员数据 |
|||
this.studentInfo = studentData[this.id] || { |
|||
id: this.id, |
|||
name: '未知学员', |
|||
avatar: '/static/icon-img/avatar.png', |
|||
campus: '未知校区', |
|||
phone: '暂无', |
|||
age: '暂无', |
|||
enrollmentDate: '暂无', |
|||
remainingCourses: 0, |
|||
expiryDate: '暂无', |
|||
completedCourses: 0, |
|||
courseName: '暂无', |
|||
recentClasses: [] |
|||
}; |
|||
}, 500); |
|||
}, |
|||
contactStudent() { |
|||
if (this.studentInfo && this.studentInfo.phone) { |
|||
uni.makePhoneCall({ |
|||
phoneNumber: this.studentInfo.phone.replace(/\*/g, '0') |
|||
}); |
|||
} |
|||
}, |
|||
viewSchedule() { |
|||
this.$navigateToPage(`/pages/coach/student/timetable`, { |
|||
id: this.id |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
.container { |
|||
min-height: 100vh; |
|||
background-color: #F5F5F5; |
|||
} |
|||
|
|||
.content { |
|||
padding: 20rpx; |
|||
} |
|||
|
|||
.loading-box { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
height: 80vh; |
|||
color: #999; |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.student-header { |
|||
display: flex; |
|||
align-items: center; |
|||
background-color: #FFFFFF; |
|||
border-radius: 12rpx; |
|||
padding: 40rpx; |
|||
margin-bottom: 20rpx; |
|||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
|||
|
|||
.avatar-box { |
|||
width: 150rpx; |
|||
height: 150rpx; |
|||
border-radius: 75rpx; |
|||
overflow: hidden; |
|||
margin-right: 30rpx; |
|||
|
|||
.avatar-img { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
} |
|||
|
|||
.name-box { |
|||
display: flex; |
|||
flex-direction: column; |
|||
|
|||
.name { |
|||
font-size: 36rpx; |
|||
font-weight: bold; |
|||
color: #333; |
|||
margin-bottom: 10rpx; |
|||
} |
|||
|
|||
.id { |
|||
font-size: 24rpx; |
|||
color: #999; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.card-section { |
|||
margin-bottom: 20rpx; |
|||
|
|||
.section-title { |
|||
font-size: 30rpx; |
|||
font-weight: bold; |
|||
color: #333; |
|||
margin: 30rpx 10rpx 20rpx; |
|||
} |
|||
|
|||
.info-card { |
|||
background-color: #FFFFFF; |
|||
border-radius: 12rpx; |
|||
padding: 20rpx 30rpx; |
|||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
|||
} |
|||
|
|||
.info-item { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
padding: 20rpx 0; |
|||
border-bottom: 1px solid #F5F5F5; |
|||
|
|||
&:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.item-label { |
|||
color: #666; |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.item-value { |
|||
color: #333; |
|||
font-size: 28rpx; |
|||
|
|||
&.highlight { |
|||
color: #FF6600; |
|||
font-weight: bold; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.class-item { |
|||
display: flex; |
|||
padding: 20rpx 0; |
|||
border-bottom: 1px solid #F5F5F5; |
|||
|
|||
&:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.class-date { |
|||
width: 180rpx; |
|||
font-size: 28rpx; |
|||
color: #666; |
|||
} |
|||
|
|||
.class-info { |
|||
flex: 1; |
|||
display: flex; |
|||
flex-direction: column; |
|||
|
|||
.class-name { |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
margin-bottom: 10rpx; |
|||
} |
|||
|
|||
.class-time { |
|||
font-size: 24rpx; |
|||
color: #999; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.empty-class { |
|||
padding: 40rpx 0; |
|||
text-align: center; |
|||
color: #999; |
|||
font-size: 28rpx; |
|||
} |
|||
} |
|||
|
|||
.btn-group { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
margin: 40rpx 0; |
|||
|
|||
.btn { |
|||
width: 48%; |
|||
height: 80rpx; |
|||
line-height: 80rpx; |
|||
border-radius: 40rpx; |
|||
font-size: 30rpx; |
|||
|
|||
&.primary { |
|||
background-color: #3B7CF9; |
|||
color: #FFFFFF; |
|||
} |
|||
|
|||
&.secondary { |
|||
background-color: #FFFFFF; |
|||
color: #3B7CF9; |
|||
border: 1px solid #3B7CF9; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,130 +0,0 @@ |
|||
<!--作业详情--> |
|||
<template> |
|||
<view class="dark-theme"> |
|||
<!-- 作业展示--> |
|||
<view class="top-style" v-if="infoData.content_text"> |
|||
<video v-if="infoData.content_type == 2" class="pic" style="width: 100%;border-radius: 15rpx;" :src="$util.img(infoData.content_text)"></video> |
|||
<image v-if="infoData.content_type == 1" style="width: 100%;border-radius: 15rpx;" :src="$util.img(infoData.content_text)" mode="aspectFit"></image> |
|||
|
|||
<view v-if="infoData.content_type == 3" class="multi-line-ellipsis" v-html="infoData.content_text"></view> |
|||
</view> |
|||
|
|||
<!-- 简练信息+作业描述--> |
|||
<view class="below-style"> |
|||
<view class="head-img"> |
|||
<!--教练头像--> |
|||
<fui-avatar width="80" :src="$util.img(infoData.coach_pic)"></fui-avatar> |
|||
<view class="head-text">{{infoData.coach_name}}</view> |
|||
</view> |
|||
<view class="multi-line-ellipsis" v-html="infoData.description"></view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
<script> |
|||
import memberApi from '@/api/member.js'; |
|||
|
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
//筛选条件 |
|||
filteredData: { |
|||
id: '',//作业id |
|||
}, |
|||
|
|||
infoData: {}, |
|||
} |
|||
}, |
|||
onLoad(options) { |
|||
this.filteredData.id = options.id || '1' // 默认ID为1 |
|||
// 使用模拟数据 |
|||
// this.mockData() |
|||
}, |
|||
onShow(){ |
|||
this.init() // 初始化数据 - 已注释 |
|||
}, |
|||
methods: { |
|||
//初始化 |
|||
async init(){ |
|||
this.getAssignmentsInfo() // 已注释 |
|||
}, |
|||
|
|||
// 模拟数据 |
|||
mockData() { |
|||
this.infoData = { |
|||
student_file: '/static/icon-img/empty.png', |
|||
student_file_type: 1, // 1-图片,2-视频 |
|||
coach_pic: '/static/icon-img/default_avatar.png', |
|||
coach_name: '张教练', |
|||
content_text: '<p>这是一份作业的详细说明,包含了作业的要求和注意事项。</p><p>1. 请按照要求完成动作练习</p><p>2. 注意动作的标准性和连贯性</p><p>3. 完成后请上传视频或图片记录</p>' |
|||
} |
|||
}, |
|||
|
|||
//获取作业详情 - 已注释 |
|||
|
|||
async getAssignmentsInfo() { |
|||
let params = {...this.filteredData} |
|||
let res = await memberApi.assignmentsInfo(params) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
this.infoData = res.data |
|||
}, |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.dark-theme { |
|||
background-color: #121212; |
|||
color: #ffffff; |
|||
min-height: 100vh; |
|||
padding-top: 0; |
|||
} |
|||
|
|||
.top-style{ |
|||
width: 92%; |
|||
height: 500rpx; |
|||
margin: auto; |
|||
margin-top: 0; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
background-color: #1e1e1e; |
|||
border-radius: 15rpx; |
|||
} |
|||
.top-style-img{ |
|||
width: 120rpx; |
|||
height: 120rpx; |
|||
} |
|||
.below-style{ |
|||
width: 92%; |
|||
margin: auto; |
|||
background-color: #1e1e1e; |
|||
border-radius: 15rpx; |
|||
margin-top: 20rpx; |
|||
padding: 20rpx 0; |
|||
} |
|||
.head-img { |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 10rpx 20rpx; |
|||
} |
|||
.head-text { |
|||
color: #ffffff; |
|||
font-size: 35rpx; |
|||
padding-left: 20rpx; |
|||
} |
|||
.multi-line-ellipsis { |
|||
color: #e0e0e0; |
|||
font-size: 29rpx; |
|||
padding: 20rpx 30rpx; |
|||
line-height: 1.6; |
|||
} |
|||
</style> |
|||
@ -1,765 +0,0 @@ |
|||
<!--订单列表-列表--> |
|||
<template> |
|||
<view class="main_box"> |
|||
|
|||
<view class="main_section"> |
|||
<scroll-view |
|||
class="section_1" |
|||
scroll-y="true" |
|||
:lower-threshold="lowerThreshold" |
|||
@scrolltolower="loadMoreData" |
|||
style="height: 83vh;" |
|||
> |
|||
<view |
|||
class="item" |
|||
v-for="(v,k) in tableList" |
|||
:key="k" |
|||
> |
|||
<view class="top"> |
|||
<view class="title">订单状态:{{v.order_status == 'pending' ? '待支付':'已支付' }}</view> |
|||
<!-- <view class="btn" @click="downloadFile($util.img(v.file_data))">下载合同 <fui-icon name="arrowright" color="#A4ADB3" size="35"></fui-icon></view>--> |
|||
</view> |
|||
<view class="bottom"> |
|||
<view class="box"> |
|||
<view class="title">客户姓名:</view> |
|||
<view class="content">{{ v.resource_id_name || ''}}</view> |
|||
</view> |
|||
|
|||
<view class="box"> |
|||
<view class="title">付款类型:</view> |
|||
<view class="content"> |
|||
{{ v.payment_type === 'cash' ? '现金支付' : v.payment_type === 'scan_code' ? '扫码支付' : '订阅支付' }} |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="box"> |
|||
<view class="title">订单金额:</view> |
|||
<view class="content">¥{{ v.order_amount || ''}}</view> |
|||
</view> |
|||
|
|||
<view class="box"> |
|||
<view class="title">课程:</view> |
|||
<view class="content">{{ v.course_id_name || ''}}</view> |
|||
</view> |
|||
|
|||
<view class="box"> |
|||
<view class="title">班级:</view> |
|||
<view class="content">{{ v.class_id_name }}</view> |
|||
</view> |
|||
|
|||
<view class="box"> |
|||
<view class="title">人员:</view> |
|||
<view class="content">{{ v.staff_id_name || ''}}</view> |
|||
</view> |
|||
|
|||
<view class="box"> |
|||
<view class="title">支付时间:</view> |
|||
<view class="content">{{ v.payment_time || '' }}</view> |
|||
</view> |
|||
|
|||
</view> |
|||
</view> |
|||
|
|||
</scroll-view> |
|||
<!-- <view class="btn_section">--> |
|||
<!-- <view class="btn" style="background-color:#29d3b4;" @click="openOrderShow()">创建订单</view>--> |
|||
<!-- </view>--> |
|||
</view> |
|||
|
|||
<!--创建订单弹出层--> |
|||
<fui-modal class="order_modal" :buttons="[]" width="600" :show="order_show"> |
|||
<text class="fui-title">创建订单</text> |
|||
<text class="fui-descr"></text> |
|||
<fui-form class="form-section" ref="form" top="0" :model="formData" :show="false"> |
|||
<view class="input-style"> |
|||
<!--客户名称--> |
|||
<fui-form-item |
|||
label="客户名称" |
|||
labelSize='26' |
|||
prop="" |
|||
background='#fff' |
|||
labelColor='#000' |
|||
:bottomBorder='true' |
|||
> |
|||
<view class="input-title" style="margin-right:14rpx;"> |
|||
<fui-input |
|||
:disabled="true" |
|||
:borderBottom="false" |
|||
:padding="[0]" |
|||
placeholder="请输入客户名称" |
|||
v-model="formData.resource_id_name" |
|||
backgroundColor="#fff" |
|||
size="26" |
|||
color="#000" |
|||
></fui-input> |
|||
</view> |
|||
</fui-form-item> |
|||
|
|||
<!--付款类型--> |
|||
<fui-form-item |
|||
label="选择付款类型" |
|||
asterisk |
|||
asteriskPosition="right" |
|||
labelSize='26' |
|||
prop="" |
|||
background='#fff' |
|||
labelColor='#000' |
|||
:bottomBorder='true' |
|||
> |
|||
<view class="input-title" style="margin-right:14rpx;"> |
|||
<view |
|||
class="input-title" |
|||
style="margin-right:14rpx;" |
|||
@click="openPaymentType()"> |
|||
{{ (formData.payment_type) ? formData.payment_type_name : '点击选择' }} |
|||
</view> |
|||
</view> |
|||
<fui-picker |
|||
:linkage='true' |
|||
:options="payment_type_options" |
|||
:layer="1" |
|||
:show="payment_type_show" |
|||
@change="changePaymentType" |
|||
@cancel="cancelPaymentType"> |
|||
</fui-picker> |
|||
</fui-form-item> |
|||
|
|||
<!--课程--> |
|||
<fui-form-item |
|||
label="选择课程" |
|||
asterisk |
|||
asteriskPosition="right" |
|||
labelSize='26' |
|||
prop="" |
|||
background='#fff' |
|||
labelColor='#000' |
|||
:bottomBorder='true' |
|||
> |
|||
<view class="input-title" style="margin-right:14rpx;"> |
|||
<view |
|||
class="input-title" |
|||
style="margin-right:14rpx;" |
|||
@click="openCourseId()"> |
|||
{{ (formData.course_id) ? formData.course_id_name : '点击选择' }} |
|||
</view> |
|||
</view> |
|||
<fui-picker |
|||
:linkage='true' |
|||
:options="course_id_options" |
|||
:layer="1" |
|||
:show="course_id_show" |
|||
@change="changeCourseId" |
|||
@cancel="cancelCourseId"> |
|||
</fui-picker> |
|||
</fui-form-item> |
|||
|
|||
<!--班级--> |
|||
<fui-form-item |
|||
label="选择班级" |
|||
asterisk |
|||
asteriskPosition="right" |
|||
labelSize='26' |
|||
prop="" |
|||
background='#fff' |
|||
labelColor='#000' |
|||
:bottomBorder='true' |
|||
> |
|||
<view class="input-title" style="margin-right:14rpx;"> |
|||
<view |
|||
class="input-title" |
|||
style="margin-right:14rpx;" |
|||
@click="openClassId()"> |
|||
{{ (formData.class_id) ? formData.class_id_name : '点击选择' }} |
|||
</view> |
|||
</view> |
|||
<fui-picker |
|||
:linkage='true' |
|||
:options="class_id_options" |
|||
:layer="1" |
|||
:show="class_id_show" |
|||
@change="changeClassId" |
|||
@cancel="cancelClassId"> |
|||
</fui-picker> |
|||
</fui-form-item> |
|||
|
|||
<!--订单金额--> |
|||
<fui-form-item |
|||
label="订单金额" |
|||
labelSize='26' |
|||
prop="" |
|||
background='#fff' |
|||
labelColor='#000' |
|||
:bottomBorder='true' |
|||
> |
|||
<view class="input-title" style="margin-right:14rpx;"> |
|||
<fui-input |
|||
:disabled="true" |
|||
:borderBottom="false" |
|||
:padding="[0]" |
|||
placeholder="订单金额" |
|||
v-model="formData.money" |
|||
backgroundColor="#fff" |
|||
size="26" |
|||
color="#000" |
|||
></fui-input> |
|||
</view> |
|||
</fui-form-item> |
|||
</view> |
|||
<view class="button_box"> |
|||
<fui-button background="#fff" color="#414141" borderColor="#465CFF" btnSize="small" @click="closeOrderShow">取消</fui-button> |
|||
<fui-button background="#fff" color="#465CFF" borderColor="#465CFF" btnSize="small" @click="clickOrder({index:1})">确定</fui-button> |
|||
|
|||
</view> |
|||
</fui-form> |
|||
<view class="fui-icon__close" @tap="closeOrderShow"> |
|||
<fui-icon name="close" color="#B2B2B2" :size="48"></fui-icon> |
|||
</view> |
|||
</fui-modal> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import apiRoute from '@/api/apiRoute.js'; |
|||
|
|||
export default { |
|||
components: { |
|||
}, |
|||
data() { |
|||
return { |
|||
loading:false,//加载状态 |
|||
lowerThreshold: 100,//距离底部多远触发 |
|||
isReachedBottom: false,//防止重复加载|true=不可加载|false=可加载 |
|||
|
|||
//筛选条件 |
|||
filteredData:{ |
|||
page:1,//当前页码 |
|||
limit:10,//每页返回数据条数 |
|||
total:10,//数据总条数 |
|||
resource_id:'',//客户资源表id |
|||
}, |
|||
tableList:[],//聊天数据列表 |
|||
|
|||
//订单表单 |
|||
formData:{ |
|||
payment_type:'',//付款类型必填验证 |
|||
payment_type_name:'',//付款类型必填验证 |
|||
|
|||
course_id:'',//课程ID必填验证 |
|||
course_id_name:'',//课程ID必填验证 |
|||
|
|||
class_id:'',//班级ID必填验证 |
|||
class_id_name:'',//班级ID必填验证 |
|||
|
|||
staff_id:'',//员工ID必填验证 |
|||
staff_id_name:'',//员工ID必填验证 |
|||
|
|||
resource_id:'',//客户资源表ID必填验证 |
|||
resource_id_name:'',//客户资源表ID必填验证 |
|||
|
|||
money:'',//金额|这个不入库就展示先 |
|||
}, |
|||
|
|||
order_show:false,//创建订单弹出层是否显示|true=显示,false=隐藏 |
|||
|
|||
//付款类型-下拉选择器相关 |
|||
payment_type_options:[ |
|||
// { |
|||
// text:'张三', |
|||
// value:'1' |
|||
// }, |
|||
],//可选值列表 |
|||
payment_type_show:false,//下拉选择器是否展示 |
|||
|
|||
//课程-下拉选择器相关 |
|||
course_id_options:[ |
|||
// { |
|||
// text:'张三', |
|||
// value:'1', |
|||
// price:'1'//课程价格 |
|||
// }, |
|||
],//可选值列表 |
|||
course_id_show:false,//下拉选择器是否展示 |
|||
|
|||
//班级-下拉选择器相关 |
|||
class_id_options:[ |
|||
// { |
|||
// text:'张三', |
|||
// value:'1' |
|||
// }, |
|||
],//可选值列表 |
|||
class_id_show:false,//下拉选择器是否展示 |
|||
} |
|||
}, |
|||
onLoad(options) { |
|||
this.filteredData.resource_id = options.resource_id//客户资源表id |
|||
|
|||
this.formData.resource_id = options.resource_id//客户资源表id |
|||
this.formData.resource_id_name = options.resource_name//客户资源表id姓名 |
|||
|
|||
|
|||
this.formData.staff_id = options.staff_id//员工资源表id姓名 |
|||
this.formData.staff_id_name = options.staff_id_name//员工资源表id姓名 |
|||
}, |
|||
onShow(){ |
|||
this.init() |
|||
}, |
|||
//下拉刷新 |
|||
async onPullDownRefresh() { |
|||
//重置为第一页 |
|||
await this.resetFilteredData() |
|||
await this.getList() |
|||
}, |
|||
methods: { |
|||
//初始化 |
|||
async init(){ |
|||
//获取付款类型 |
|||
await this.getPaymentTypeList() |
|||
//获取课程列表 |
|||
await this.getCourseList() |
|||
//获取班级列表 |
|||
await this.getClassList() |
|||
|
|||
//获取列表 |
|||
await this.getList(); |
|||
}, |
|||
|
|||
//加载更多(下一页) |
|||
loadMoreData() { |
|||
//判断是否加载 |
|||
if (!this.isReachedBottom) { |
|||
this.isReachedBottom = true;//设置为不可请求状态 |
|||
this.getList(); |
|||
} |
|||
}, |
|||
//重置为第一页 |
|||
async resetFilteredData() { |
|||
this.isReachedBottom = false; // 重置状态,以便下次触发加载更多 |
|||
|
|||
this.filteredData.page = 1//当前页码 |
|||
this.filteredData.limit = 10//每页返回数据条数 |
|||
this.filteredData.total = 10//数据总条数 |
|||
}, |
|||
|
|||
//获取合同列表 |
|||
async getList(){ |
|||
this.loading = true |
|||
|
|||
let params = {...this.filteredData} |
|||
|
|||
//判断是否还有数据 |
|||
if ((this.filteredData.page - 1) * this.filteredData.limit >= this.filteredData.total) { |
|||
this.loading = false |
|||
uni.showToast({ |
|||
title: '暂无更多', |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
if(params.page == 1){ |
|||
this.tableList = [] |
|||
} |
|||
|
|||
let res = await apiRoute.xy_orderTableList(params)//获取订单列表 |
|||
this.loading = false |
|||
this.isReachedBottom = false; |
|||
if (res.code != 1){ |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
this.tableList = this.tableList.concat(res.data.data); // 使用 concat 方法 将新数据追加到数组中 |
|||
// this.tableList.unshift(...res.data.data); // 将新数据插入到数组头部 |
|||
|
|||
console.log('列表',this.tableList) |
|||
this.filteredData.total = res.data.total |
|||
this.filteredData.page++ |
|||
}, |
|||
|
|||
//获取付款类型 |
|||
async getPaymentTypeList(){ |
|||
let res = await apiRoute.common_Dictionary({key:'payment_type'}) |
|||
if(res.code != 1){ |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
let dictionary = res.data.dictionary |
|||
let arr = [] |
|||
dictionary.forEach((v,k)=>{ |
|||
arr.push({ |
|||
text: v.name, |
|||
value: v.value, |
|||
}) |
|||
}) |
|||
this.payment_type_options = arr |
|||
console.log('付款类型',this.payment_type_options) |
|||
}, |
|||
//获取课程列表 |
|||
async getCourseList(){ |
|||
let params = {} |
|||
|
|||
let res = await apiRoute.common_getCourseAll(params) |
|||
if(res.code != 1){ |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
|
|||
let arr = [] |
|||
res.data.forEach((v,k)=>{ |
|||
arr.push({ |
|||
text: `${v.course_name}`, |
|||
value: v.id, |
|||
price: v.price, |
|||
}) |
|||
}) |
|||
this.course_id_options = arr |
|||
console.log('课程列表',this.course_id_options) |
|||
|
|||
}, |
|||
//获取班级列表 |
|||
async getClassList(){ |
|||
let params = { |
|||
status:1,//班级状态(1开启 2关闭) |
|||
} |
|||
|
|||
let res = await apiRoute.common_getClassAll(params) |
|||
if(res.code != 1){ |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
console.log('班级列表',res.data) |
|||
let arr = [] |
|||
res.data.forEach((v,k)=>{ |
|||
arr.push({ |
|||
text: `${v.campus_name}-${v.class_name}`, |
|||
value: v.id, |
|||
}) |
|||
}) |
|||
this.class_id_options = arr |
|||
}, |
|||
|
|||
|
|||
|
|||
|
|||
//创建订单相关 |
|||
//显示创建订单弹窗 |
|||
openOrderShow(){ |
|||
//重置的数据 |
|||
this.formData.payment_type = ''//付款类型必填验证 |
|||
this.formData.payment_type_name = ''//付款类型必填验证 |
|||
|
|||
this.formData.course_id = ''//课程ID必填验证 |
|||
this.formData.course_id_name = ''//课程ID必填验证 |
|||
|
|||
this.formData.class_id = ''//班级ID必填验证 |
|||
this.formData.class_id_name = ''//班级ID必填验证 |
|||
|
|||
this.formData.money = ''//金额|这个不入库就展示先 |
|||
|
|||
this.order_show = true//展示弹层 |
|||
}, |
|||
//关闭打卡弹窗 |
|||
closeOrderShow(){ |
|||
this.order_show = false |
|||
}, |
|||
//监听-打卡签到回调 |
|||
async clickOrder(e){ |
|||
if(e.index == 0){ |
|||
//取消按钮 |
|||
this.closeOrderShow() |
|||
}else{ |
|||
console.log('提交',this.formData) |
|||
await this.submitFormData() |
|||
} |
|||
}, |
|||
//提交表单 |
|||
async submitFormData() { |
|||
let param = {...this.formData} |
|||
//表单验证 |
|||
//... |
|||
if(!param.class_id){ |
|||
uni.showToast({ |
|||
title: '请选择班级', |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
if(!param.course_id){ |
|||
uni.showToast({ |
|||
title: '请选择课程', |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
if(!param.payment_type){ |
|||
uni.showToast({ |
|||
title: '请选择付款类型', |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
console.log('提交xxx',param) |
|||
this.closeOrderShow() |
|||
|
|||
let res = await apiRoute.xy_orderTableAdd(param) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
uni.showToast({ |
|||
title: '操作成功', |
|||
icon: 'success' |
|||
}) |
|||
|
|||
//延迟1s执行 |
|||
setTimeout(() => { |
|||
this.resetFilteredData()//重置表单 |
|||
this.getList();//刷新列表 |
|||
}, 1500) |
|||
}, |
|||
|
|||
|
|||
//下拉选择器相关-付款类型 |
|||
//监听-付款类型 |
|||
changePaymentType(e){ |
|||
this.formData.payment_type = e.value |
|||
this.formData.payment_type_name = e.text |
|||
this.cancelPaymentType() |
|||
}, |
|||
//打开选择器-付款类型 |
|||
openPaymentType(){ |
|||
this.payment_type_show = true |
|||
}, |
|||
//关闭选择器-付款类型 |
|||
cancelPaymentType(){ |
|||
this.payment_type_show = false |
|||
}, |
|||
|
|||
//下拉选择器相关-课程 |
|||
//监听-课程 |
|||
changeCourseId(e){ |
|||
console.log('课程',e) |
|||
this.formData.course_id = e.value |
|||
this.formData.course_id_name = e.text |
|||
|
|||
this.formData.money = this.course_id_options.find(v=>v.value == e.value).price |
|||
|
|||
// console.log('课程formData',this.formData) |
|||
this.cancelCourseId() |
|||
}, |
|||
//打开选择器-课程 |
|||
openCourseId(){ |
|||
this.course_id_show = true |
|||
}, |
|||
//关闭选择器-课程 |
|||
cancelCourseId(){ |
|||
this.course_id_show = false |
|||
}, |
|||
|
|||
//下拉选择器相关-班级 |
|||
//监听-班级 |
|||
changeClassId(e){ |
|||
this.formData.class_id = e.value |
|||
this.formData.class_id_name = e.text |
|||
this.cancelClassId() |
|||
}, |
|||
//打开选择器-班级 |
|||
openClassId(){ |
|||
this.class_id_show = true |
|||
}, |
|||
//关闭选择器-班级 |
|||
cancelClassId(){ |
|||
this.class_id_show = false |
|||
}, |
|||
|
|||
//下载文件 |
|||
async downloadFile(fileUrl) { |
|||
if (!fileUrl) { |
|||
this.$util.showToast({ |
|||
title: '暂无电子发票' |
|||
}); |
|||
return false; |
|||
} |
|||
|
|||
uni.downloadFile({ |
|||
url: fileUrl, |
|||
success: function (res) { |
|||
console.log('下载成功'); |
|||
// uni.openDocument({ |
|||
// filePath: res.tempFilePath, |
|||
// fileType: 'pdf', |
|||
// success: function (res) { |
|||
// console.log('打开文档成功'); |
|||
// } |
|||
// }); |
|||
} |
|||
}); |
|||
|
|||
} |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.main_box { |
|||
background: #292929; |
|||
} |
|||
|
|||
//自定义导航栏 |
|||
.navbar_section { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
background: #29d3b4; |
|||
|
|||
.title { |
|||
padding: 20rpx 0; |
|||
font-size: 30rpx; |
|||
color: #315d55; |
|||
} |
|||
} |
|||
|
|||
.main_section { |
|||
min-height: 100vh; |
|||
background: #292929 100%; |
|||
padding: 0 0rpx; |
|||
padding-top: 32rpx; |
|||
padding-bottom: 150rpx; |
|||
font-size: 28rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 20rpx; |
|||
|
|||
.section { |
|||
background-color: #434544; |
|||
padding: 40rpx 40rpx; |
|||
} |
|||
|
|||
.section_1{ |
|||
padding: 0 24rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
|
|||
.item{ |
|||
margin-bottom: 38rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
padding: 32rpx 24rpx; |
|||
border-radius: 14rpx; |
|||
background-color: #434544; |
|||
color: #fff; |
|||
.top{ |
|||
font-size: 28rpx; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
.title{ |
|||
font-size: 30rpx; |
|||
} |
|||
.btn{ |
|||
display: flex; |
|||
align-items: center; |
|||
color: #29D3B4; |
|||
} |
|||
} |
|||
.bottom{ |
|||
font-size: 26rpx; |
|||
margin-top: 25rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 15rpx; |
|||
.box{ |
|||
display: flex; |
|||
justify-content: space-between; |
|||
.title{ |
|||
width: 180rpx; |
|||
} |
|||
.content{ |
|||
width: 100%; |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
.btn_section{ |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
.btn{ |
|||
border-radius: 10rpx; |
|||
padding: 15rpx 0; |
|||
width: 70%; |
|||
color: #fff; |
|||
font-size: 30rpx; |
|||
text-align: center; |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
} |
|||
|
|||
.describe { |
|||
color: #999999; |
|||
padding-left: 30rpx; |
|||
} |
|||
|
|||
|
|||
//创建订单弹出层 |
|||
.order_modal{ |
|||
.fui-title { |
|||
font-size: 32rpx; |
|||
padding-top: 24rpx; |
|||
} |
|||
|
|||
.fui-descr { |
|||
font-size: 24rpx; |
|||
color: #B2B2B2; |
|||
padding-top: 12rpx; |
|||
padding-bottom: 48rpx; |
|||
} |
|||
|
|||
.fui-icon__close { |
|||
position: absolute; |
|||
right: 24rpx; |
|||
top: 20rpx; |
|||
} |
|||
|
|||
.form-section{ |
|||
|
|||
.input-style { |
|||
text-align: right !important; |
|||
.input-title{} |
|||
} |
|||
.button_box{ |
|||
margin-top: 30rpx; |
|||
padding: 20rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
gap: 20rpx; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,542 +0,0 @@ |
|||
<template> |
|||
<view class="container"> |
|||
<view class="header"> |
|||
<text class="title">字典获取优化演示</text> |
|||
<text class="subtitle">对比原方式和批量获取的性能差异</text> |
|||
</view> |
|||
|
|||
<!-- 性能对比 --> |
|||
<view class="performance-section"> |
|||
<view class="section-title">性能对比</view> |
|||
|
|||
<!-- 原有方式 --> |
|||
<view class="test-item"> |
|||
<view class="test-header"> |
|||
<text class="test-name">原方式(单个获取)</text> |
|||
<button |
|||
class="test-btn old-style" |
|||
@click="testOldMethod" |
|||
:disabled="oldTesting"> |
|||
{{ oldTesting ? '测试中...' : '开始测试' }} |
|||
</button> |
|||
</view> |
|||
<view class="test-result" v-if="oldResult"> |
|||
<text class="result-text">耗时: {{ oldResult.time }}ms</text> |
|||
<text class="result-text">请求次数: {{ oldResult.requests }}次</text> |
|||
<text class="result-text">获取数据: {{ oldResult.count }}个字典</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 新方式 --> |
|||
<view class="test-item"> |
|||
<view class="test-header"> |
|||
<text class="test-name">新方式(批量获取)</text> |
|||
<button |
|||
class="test-btn new-style" |
|||
@click="testNewMethod" |
|||
:disabled="newTesting"> |
|||
{{ newTesting ? '测试中...' : '开始测试' }} |
|||
</button> |
|||
</view> |
|||
<view class="test-result" v-if="newResult"> |
|||
<text class="result-text">耗时: {{ newResult.time }}ms</text> |
|||
<text class="result-text">请求次数: {{ newResult.requests }}次</text> |
|||
<text class="result-text">获取数据: {{ newResult.count }}个字典</text> |
|||
<text class="improvement"> |
|||
性能提升: {{ newResult.improvement }} |
|||
</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 缓存演示 --> |
|||
<view class="cache-section"> |
|||
<view class="section-title">缓存机制演示</view> |
|||
|
|||
<view class="cache-controls"> |
|||
<button class="cache-btn" @click="testCache">测试缓存效果</button> |
|||
<button class="cache-btn clear" @click="clearCache">清除缓存</button> |
|||
</view> |
|||
|
|||
<view class="cache-result" v-if="cacheResult"> |
|||
<text class="cache-text">第一次获取: {{ cacheResult.firstTime }}ms</text> |
|||
<text class="cache-text">缓存获取: {{ cacheResult.cacheTime }}ms</text> |
|||
<text class="cache-text">性能提升: {{ cacheResult.improvement }}</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 字典数据展示 --> |
|||
<view class="data-section"> |
|||
<view class="section-title">字典数据展示</view> |
|||
|
|||
<view class="dict-tabs"> |
|||
<view |
|||
class="tab-item" |
|||
:class="{ active: activeTab === key }" |
|||
v-for="(data, key) in dictData" |
|||
:key="key" |
|||
@click="activeTab = key"> |
|||
{{ getDictDisplayName(key) }} |
|||
</view> |
|||
</view> |
|||
|
|||
<scroll-view class="dict-content" scroll-y> |
|||
<view class="dict-items" v-if="dictData[activeTab]"> |
|||
<view |
|||
class="dict-item" |
|||
v-for="(item, index) in dictData[activeTab]" |
|||
:key="index"> |
|||
<text class="item-name">{{ item.name || item.text || '-' }}</text> |
|||
<text class="item-value">{{ item.value || '-' }}</text> |
|||
</view> |
|||
</view> |
|||
<view class="empty-state" v-else> |
|||
<text>暂无数据</text> |
|||
</view> |
|||
</scroll-view> |
|||
</view> |
|||
|
|||
<!-- 使用说明 --> |
|||
<view class="usage-section"> |
|||
<view class="section-title">使用说明</view> |
|||
<view class="usage-content"> |
|||
<text class="usage-text">1. 使用 dictUtil.getBatchDict() 批量获取字典</text> |
|||
<text class="usage-text">2. 支持自动缓存,30分钟有效期</text> |
|||
<text class="usage-text">3. 支持业务场景批量获取</text> |
|||
<text class="usage-text">4. 向后兼容原有 util.getDict() 方法</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import dictUtil from '@/common/dictUtil.js' |
|||
import util from '@/common/util.js' |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
// 测试状态 |
|||
oldTesting: false, |
|||
newTesting: false, |
|||
|
|||
// 测试结果 |
|||
oldResult: null, |
|||
newResult: null, |
|||
cacheResult: null, |
|||
|
|||
// 字典数据 |
|||
dictData: {}, |
|||
activeTab: '', |
|||
|
|||
// 测试用的字典keys |
|||
testKeys: [ |
|||
'SourceChannel', |
|||
'source', |
|||
'customer_purchasing_power', |
|||
'preliminarycustomerintention', |
|||
'cognitive_concept', |
|||
'kh_status', |
|||
'decision_maker', |
|||
'distance' |
|||
] |
|||
} |
|||
}, |
|||
onLoad() { |
|||
// 初始化时获取一次字典数据用于展示 |
|||
this.loadInitialData() |
|||
}, |
|||
methods: { |
|||
// 加载初始数据 |
|||
async loadInitialData() { |
|||
try { |
|||
const data = await dictUtil.getBatchDict(this.testKeys) |
|||
this.dictData = data |
|||
this.activeTab = Object.keys(data)[0] || '' |
|||
} catch (error) { |
|||
console.error('加载初始数据失败:', error) |
|||
} |
|||
}, |
|||
|
|||
// 测试原有方式(单个获取) |
|||
async testOldMethod() { |
|||
this.oldTesting = true |
|||
this.oldResult = null |
|||
|
|||
try { |
|||
const startTime = Date.now() |
|||
let successCount = 0 |
|||
|
|||
// 模拟原有的单个获取方式 |
|||
for (const key of this.testKeys) { |
|||
try { |
|||
await this.getOldDict(key) |
|||
successCount++ |
|||
} catch (error) { |
|||
console.warn(`获取字典 ${key} 失败:`, error) |
|||
} |
|||
} |
|||
|
|||
const endTime = Date.now() |
|||
const totalTime = endTime - startTime |
|||
|
|||
this.oldResult = { |
|||
time: totalTime, |
|||
requests: this.testKeys.length, |
|||
count: successCount |
|||
} |
|||
|
|||
uni.showToast({ |
|||
title: `原方式完成,耗时 ${totalTime}ms`, |
|||
icon: 'none' |
|||
}) |
|||
|
|||
} catch (error) { |
|||
console.error('测试原方式失败:', error) |
|||
uni.showToast({ |
|||
title: '测试失败', |
|||
icon: 'none' |
|||
}) |
|||
} finally { |
|||
this.oldTesting = false |
|||
} |
|||
}, |
|||
|
|||
// 测试新方式(批量获取) |
|||
async testNewMethod() { |
|||
this.newTesting = true |
|||
this.newResult = null |
|||
|
|||
try { |
|||
const startTime = Date.now() |
|||
|
|||
// 使用新的批量获取方式 |
|||
const data = await dictUtil.getBatchDict(this.testKeys, false) // 不使用缓存进行公平测试 |
|||
|
|||
const endTime = Date.now() |
|||
const totalTime = endTime - startTime |
|||
const successCount = Object.keys(data).length |
|||
|
|||
this.newResult = { |
|||
time: totalTime, |
|||
requests: 1, // 批量获取只需要1次请求 |
|||
count: successCount |
|||
} |
|||
|
|||
// 计算性能提升 |
|||
if (this.oldResult) { |
|||
const improvement = Math.round(((this.oldResult.time - totalTime) / this.oldResult.time) * 100) |
|||
this.newResult.improvement = `${improvement}%` |
|||
} |
|||
|
|||
// 更新展示数据 |
|||
this.dictData = data |
|||
|
|||
uni.showToast({ |
|||
title: `新方式完成,耗时 ${totalTime}ms`, |
|||
icon: 'none' |
|||
}) |
|||
|
|||
} catch (error) { |
|||
console.error('测试新方式失败:', error) |
|||
uni.showToast({ |
|||
title: '测试失败', |
|||
icon: 'none' |
|||
}) |
|||
} finally { |
|||
this.newTesting = false |
|||
} |
|||
}, |
|||
|
|||
// 模拟原有的单个字典获取 |
|||
async getOldDict(key) { |
|||
return new Promise((resolve, reject) => { |
|||
// 模拟单个接口请求的延迟 |
|||
setTimeout(async () => { |
|||
try { |
|||
// 这里可以调用原有的获取方法,或者模拟 |
|||
const result = await dictUtil.getDict(key, false) |
|||
resolve(result) |
|||
} catch (error) { |
|||
reject(error) |
|||
} |
|||
}, Math.random() * 200 + 100) // 模拟 100-300ms 的网络延迟 |
|||
}) |
|||
}, |
|||
|
|||
// 测试缓存效果 |
|||
async testCache() { |
|||
try { |
|||
// 清除缓存确保公平测试 |
|||
dictUtil.clearCache() |
|||
|
|||
// 第一次获取(无缓存) |
|||
const startTime1 = Date.now() |
|||
await dictUtil.getBatchDict(this.testKeys.slice(0, 3), true) |
|||
const firstTime = Date.now() - startTime1 |
|||
|
|||
// 第二次获取(有缓存) |
|||
const startTime2 = Date.now() |
|||
await dictUtil.getBatchDict(this.testKeys.slice(0, 3), true) |
|||
const cacheTime = Date.now() - startTime2 |
|||
|
|||
const improvement = Math.round(((firstTime - cacheTime) / firstTime) * 100) |
|||
|
|||
this.cacheResult = { |
|||
firstTime, |
|||
cacheTime, |
|||
improvement: `${improvement}%` |
|||
} |
|||
|
|||
uni.showToast({ |
|||
title: '缓存测试完成', |
|||
icon: 'success' |
|||
}) |
|||
|
|||
} catch (error) { |
|||
console.error('缓存测试失败:', error) |
|||
uni.showToast({ |
|||
title: '缓存测试失败', |
|||
icon: 'none' |
|||
}) |
|||
} |
|||
}, |
|||
|
|||
// 清除缓存 |
|||
clearCache() { |
|||
dictUtil.clearCache() |
|||
this.cacheResult = null |
|||
uni.showToast({ |
|||
title: '缓存已清除', |
|||
icon: 'success' |
|||
}) |
|||
}, |
|||
|
|||
// 获取字典显示名称 |
|||
getDictDisplayName(key) { |
|||
const nameMap = { |
|||
'SourceChannel': '来源渠道', |
|||
'source': '来源', |
|||
'customer_purchasing_power': '购买力', |
|||
'preliminarycustomerintention': '意向度', |
|||
'cognitive_concept': '认知理念', |
|||
'kh_status': '客户状态', |
|||
'decision_maker': '决策人', |
|||
'distance': '距离' |
|||
} |
|||
return nameMap[key] || key |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.container { |
|||
padding: 20rpx; |
|||
background: #f5f5f5; |
|||
min-height: 100vh; |
|||
} |
|||
|
|||
.header { |
|||
background: #fff; |
|||
padding: 30rpx; |
|||
border-radius: 12rpx; |
|||
margin-bottom: 20rpx; |
|||
text-align: center; |
|||
|
|||
.title { |
|||
font-size: 36rpx; |
|||
font-weight: 600; |
|||
color: #333; |
|||
display: block; |
|||
margin-bottom: 10rpx; |
|||
} |
|||
|
|||
.subtitle { |
|||
font-size: 26rpx; |
|||
color: #666; |
|||
display: block; |
|||
} |
|||
} |
|||
|
|||
.performance-section, .cache-section, .data-section, .usage-section { |
|||
background: #fff; |
|||
border-radius: 12rpx; |
|||
padding: 30rpx; |
|||
margin-bottom: 20rpx; |
|||
} |
|||
|
|||
.section-title { |
|||
font-size: 32rpx; |
|||
font-weight: 600; |
|||
color: #333; |
|||
margin-bottom: 20rpx; |
|||
border-left: 4rpx solid #29d3b4; |
|||
padding-left: 16rpx; |
|||
} |
|||
|
|||
.test-item { |
|||
margin-bottom: 30rpx; |
|||
padding: 20rpx; |
|||
background: #f8f9fa; |
|||
border-radius: 8rpx; |
|||
|
|||
&:last-child { |
|||
margin-bottom: 0; |
|||
} |
|||
} |
|||
|
|||
.test-header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 15rpx; |
|||
|
|||
.test-name { |
|||
font-size: 28rpx; |
|||
font-weight: 500; |
|||
color: #333; |
|||
} |
|||
|
|||
.test-btn { |
|||
padding: 12rpx 24rpx; |
|||
border-radius: 6rpx; |
|||
border: none; |
|||
font-size: 24rpx; |
|||
color: #fff; |
|||
|
|||
&.old-style { |
|||
background: #ff6b6b; |
|||
} |
|||
|
|||
&.new-style { |
|||
background: #29d3b4; |
|||
} |
|||
|
|||
&:disabled { |
|||
opacity: 0.6; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.test-result { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 8rpx; |
|||
|
|||
.result-text { |
|||
font-size: 24rpx; |
|||
color: #666; |
|||
} |
|||
|
|||
.improvement { |
|||
font-size: 26rpx; |
|||
color: #29d3b4; |
|||
font-weight: 600; |
|||
} |
|||
} |
|||
|
|||
.cache-controls { |
|||
display: flex; |
|||
gap: 20rpx; |
|||
margin-bottom: 20rpx; |
|||
|
|||
.cache-btn { |
|||
flex: 1; |
|||
padding: 16rpx; |
|||
border-radius: 8rpx; |
|||
border: none; |
|||
font-size: 26rpx; |
|||
color: #fff; |
|||
background: #29d3b4; |
|||
|
|||
&.clear { |
|||
background: #ff6b6b; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.cache-result { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 8rpx; |
|||
|
|||
.cache-text { |
|||
font-size: 24rpx; |
|||
color: #666; |
|||
} |
|||
} |
|||
|
|||
.dict-tabs { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
gap: 10rpx; |
|||
margin-bottom: 20rpx; |
|||
|
|||
.tab-item { |
|||
padding: 12rpx 20rpx; |
|||
background: #f0f0f0; |
|||
border-radius: 20rpx; |
|||
font-size: 24rpx; |
|||
color: #666; |
|||
|
|||
&.active { |
|||
background: #29d3b4; |
|||
color: #fff; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.dict-content { |
|||
height: 400rpx; |
|||
border: 1rpx solid #eee; |
|||
border-radius: 8rpx; |
|||
} |
|||
|
|||
.dict-items { |
|||
padding: 20rpx; |
|||
} |
|||
|
|||
.dict-item { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 16rpx 0; |
|||
border-bottom: 1rpx solid #f0f0f0; |
|||
|
|||
&:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.item-name { |
|||
font-size: 26rpx; |
|||
color: #333; |
|||
flex: 1; |
|||
} |
|||
|
|||
.item-value { |
|||
font-size: 24rpx; |
|||
color: #666; |
|||
margin-left: 20rpx; |
|||
} |
|||
} |
|||
|
|||
.empty-state { |
|||
padding: 60rpx; |
|||
text-align: center; |
|||
color: #999; |
|||
font-size: 26rpx; |
|||
} |
|||
|
|||
.usage-content { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 12rpx; |
|||
|
|||
.usage-text { |
|||
font-size: 26rpx; |
|||
color: #666; |
|||
line-height: 1.6; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,352 +0,0 @@ |
|||
<template> |
|||
<view class="mock-demo"> |
|||
<view class="header"> |
|||
<text class="title">Mock数据演示</text> |
|||
<view class="env-info"> |
|||
<text class="env-label">当前环境: {{ envInfo.env }}</text> |
|||
<text class="mock-status" :class="{ active: envInfo.mockEnabled }"> |
|||
Mock状态: {{ envInfo.mockEnabled ? '已开启' : '已关闭' }} |
|||
</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="content"> |
|||
<!-- 用户信息展示 --> |
|||
<view class="section"> |
|||
<view class="section-title">用户信息</view> |
|||
<view class="user-card" v-if="userInfo"> |
|||
<image class="avatar" :src="userInfo.avatar" mode="aspectFill"></image> |
|||
<view class="user-details"> |
|||
<text class="username">{{ userInfo.username }}</text> |
|||
<text class="phone">{{ userInfo.phone }}</text> |
|||
<text class="email">{{ userInfo.email }}</text> |
|||
</view> |
|||
</view> |
|||
<view class="loading" v-else> |
|||
<text>加载中...</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 课程表展示 --> |
|||
<view class="section"> |
|||
<view class="section-title">今日课程</view> |
|||
<view class="schedule-list"> |
|||
<view class="schedule-item" v-for="item in scheduleList" :key="item.id"> |
|||
<view class="time">{{ item.start_time }} - {{ item.end_time }}</view> |
|||
<view class="course-info"> |
|||
<text class="course-name">{{ item.course_name }}</text> |
|||
<text class="teacher">{{ item.teacher_name }}</text> |
|||
<text class="classroom">{{ item.classroom }}</text> |
|||
</view> |
|||
<view class="status" :class="item.status"> |
|||
{{ getStatusText(item.status) }} |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 操作按钮 --> |
|||
<view class="actions"> |
|||
<button class="btn primary" @click="refreshData">刷新数据</button> |
|||
<button class="btn secondary" @click="toggleMock"> |
|||
{{ envInfo.mockEnabled ? '关闭Mock' : '开启Mock' }} |
|||
</button> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { Api_url, isMockEnabled, isDebug, env } from '@/common/config.js' |
|||
import http from '@/common/axios.js' |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
userInfo: null, |
|||
scheduleList: [], |
|||
envInfo: { |
|||
env: env, |
|||
mockEnabled: isMockEnabled, |
|||
debug: isDebug |
|||
} |
|||
} |
|||
}, |
|||
|
|||
onLoad() { |
|||
this.loadData() |
|||
}, |
|||
|
|||
methods: { |
|||
async loadData() { |
|||
try { |
|||
// 加载用户信息 |
|||
await this.loadUserInfo() |
|||
// 加载课程表 |
|||
await this.loadSchedule() |
|||
} catch (error) { |
|||
console.error('数据加载失败:', error) |
|||
uni.showToast({ |
|||
title: '数据加载失败', |
|||
icon: 'none' |
|||
}) |
|||
} |
|||
}, |
|||
|
|||
async loadUserInfo() { |
|||
try { |
|||
const response = await http.get('/user/info') |
|||
this.userInfo = response.data |
|||
} catch (error) { |
|||
console.error('用户信息加载失败:', error) |
|||
} |
|||
}, |
|||
|
|||
async loadSchedule() { |
|||
try { |
|||
const response = await http.get('/student/schedule') |
|||
this.scheduleList = response.data || [] |
|||
} catch (error) { |
|||
console.error('课程表加载失败:', error) |
|||
} |
|||
}, |
|||
|
|||
async refreshData() { |
|||
uni.showLoading({ |
|||
title: '刷新中...' |
|||
}) |
|||
|
|||
try { |
|||
await this.loadData() |
|||
uni.showToast({ |
|||
title: '刷新成功', |
|||
icon: 'success' |
|||
}) |
|||
} catch (error) { |
|||
uni.showToast({ |
|||
title: '刷新失败', |
|||
icon: 'none' |
|||
}) |
|||
} finally { |
|||
uni.hideLoading() |
|||
} |
|||
}, |
|||
|
|||
toggleMock() { |
|||
// 这里只是演示,实际需要重新配置环境变量 |
|||
uni.showModal({ |
|||
title: '提示', |
|||
content: 'Mock开关需要在环境变量中配置,请修改.env文件中的VUE_APP_MOCK_ENABLED参数', |
|||
showCancel: false |
|||
}) |
|||
}, |
|||
|
|||
getStatusText(status) { |
|||
const statusMap = { |
|||
scheduled: '已安排', |
|||
completed: '已完成', |
|||
cancelled: '已取消' |
|||
} |
|||
return statusMap[status] || status |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.mock-demo { |
|||
padding: 20rpx; |
|||
background-color: #f8f9fa; |
|||
min-height: 100vh; |
|||
} |
|||
|
|||
.header { |
|||
background: white; |
|||
padding: 30rpx; |
|||
border-radius: 20rpx; |
|||
margin-bottom: 30rpx; |
|||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
.title { |
|||
font-size: 36rpx; |
|||
font-weight: bold; |
|||
color: #333; |
|||
display: block; |
|||
margin-bottom: 20rpx; |
|||
} |
|||
|
|||
.env-info { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
} |
|||
|
|||
.env-label { |
|||
font-size: 28rpx; |
|||
color: #666; |
|||
} |
|||
|
|||
.mock-status { |
|||
font-size: 28rpx; |
|||
color: #999; |
|||
padding: 10rpx 20rpx; |
|||
border-radius: 10rpx; |
|||
background: #f5f5f5; |
|||
} |
|||
|
|||
.mock-status.active { |
|||
color: #52c41a; |
|||
background: #f6ffed; |
|||
} |
|||
|
|||
.content { |
|||
flex: 1; |
|||
} |
|||
|
|||
.section { |
|||
background: white; |
|||
padding: 30rpx; |
|||
border-radius: 20rpx; |
|||
margin-bottom: 30rpx; |
|||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
.section-title { |
|||
font-size: 32rpx; |
|||
font-weight: bold; |
|||
color: #333; |
|||
margin-bottom: 30rpx; |
|||
} |
|||
|
|||
.user-card { |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.avatar { |
|||
width: 120rpx; |
|||
height: 120rpx; |
|||
border-radius: 60rpx; |
|||
margin-right: 30rpx; |
|||
} |
|||
|
|||
.user-details { |
|||
flex: 1; |
|||
} |
|||
|
|||
.username { |
|||
font-size: 32rpx; |
|||
font-weight: bold; |
|||
color: #333; |
|||
display: block; |
|||
margin-bottom: 10rpx; |
|||
} |
|||
|
|||
.phone, .email { |
|||
font-size: 28rpx; |
|||
color: #666; |
|||
display: block; |
|||
margin-bottom: 5rpx; |
|||
} |
|||
|
|||
.schedule-list { |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.schedule-item { |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 20rpx 0; |
|||
border-bottom: 1rpx solid #f0f0f0; |
|||
} |
|||
|
|||
.schedule-item:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.time { |
|||
width: 200rpx; |
|||
font-size: 28rpx; |
|||
color: #666; |
|||
} |
|||
|
|||
.course-info { |
|||
flex: 1; |
|||
margin-left: 20rpx; |
|||
} |
|||
|
|||
.course-name { |
|||
font-size: 30rpx; |
|||
font-weight: bold; |
|||
color: #333; |
|||
display: block; |
|||
margin-bottom: 10rpx; |
|||
} |
|||
|
|||
.teacher, .classroom { |
|||
font-size: 26rpx; |
|||
color: #666; |
|||
display: block; |
|||
margin-bottom: 5rpx; |
|||
} |
|||
|
|||
.status { |
|||
padding: 10rpx 20rpx; |
|||
border-radius: 10rpx; |
|||
font-size: 24rpx; |
|||
text-align: center; |
|||
min-width: 120rpx; |
|||
} |
|||
|
|||
.status.scheduled { |
|||
background: #e6f7ff; |
|||
color: #1890ff; |
|||
} |
|||
|
|||
.status.completed { |
|||
background: #f6ffed; |
|||
color: #52c41a; |
|||
} |
|||
|
|||
.status.cancelled { |
|||
background: #fff2e8; |
|||
color: #fa8c16; |
|||
} |
|||
|
|||
.loading { |
|||
text-align: center; |
|||
padding: 60rpx; |
|||
color: #666; |
|||
} |
|||
|
|||
.actions { |
|||
display: flex; |
|||
gap: 20rpx; |
|||
padding: 30rpx; |
|||
} |
|||
|
|||
.btn { |
|||
flex: 1; |
|||
padding: 24rpx; |
|||
border-radius: 12rpx; |
|||
font-size: 32rpx; |
|||
border: none; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.btn.primary { |
|||
background: #1890ff; |
|||
color: white; |
|||
} |
|||
|
|||
.btn.secondary { |
|||
background: #f5f5f5; |
|||
color: #666; |
|||
} |
|||
|
|||
.btn:active { |
|||
opacity: 0.8; |
|||
} |
|||
</style> |
|||
@ -1,633 +0,0 @@ |
|||
<template> |
|||
<div class="course-schedule"> |
|||
<!-- Header --> |
|||
<div class="header"> |
|||
<div class="back-btn" @click="goBack"> |
|||
<ChevronLeftIcon class="w-6 h-6" /> |
|||
</div> |
|||
<h1 class="title">课程安排详情</h1> |
|||
</div> |
|||
|
|||
<!-- Course Info --> |
|||
<div class="course-info"> |
|||
<h2 class="course-title">课程安排详情</h2> |
|||
<p class="course-time">日期:2025-07-24 08:30-09:30</p> |
|||
</div> |
|||
|
|||
<!-- Formal Students Section --> |
|||
<div class="section"> |
|||
<h3 class="section-title">正式学员</h3> |
|||
<div class="cards-grid"> |
|||
<!-- Student Card with Data --> |
|||
<div class="student-card filled"> |
|||
<div class="renewal-badge">待续费</div> |
|||
<div class="avatar">未</div> |
|||
<div class="student-info"> |
|||
<div class="student-name">张小明同学的名字很长需要省略</div> |
|||
<div class="student-age">年龄:8岁</div> |
|||
<div class="course-status">课程状态:正式课</div> |
|||
<div class="course-arrangement">课程安排:固定课</div> |
|||
<div class="remaining-hours">剩余课时:12节</div> |
|||
<div class="expiry-date">到期时间:2025-12-31</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Empty Slots --> |
|||
<div |
|||
v-for="n in 6" |
|||
:key="n" |
|||
class="student-card empty" |
|||
@click="openStudentModal('formal', n)" |
|||
> |
|||
<div class="add-icon"> |
|||
<PlusIcon class="w-8 h-8" /> |
|||
</div> |
|||
<div class="add-text"> |
|||
<div class="slot-title">空位</div> |
|||
<div class="slot-subtitle">点击添加学员</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Waiting List Section --> |
|||
<div class="section"> |
|||
<h3 class="section-title">等待位</h3> |
|||
<div class="cards-grid"> |
|||
<div |
|||
v-for="n in 2" |
|||
:key="n" |
|||
class="student-card waiting" |
|||
@click="openStudentModal('waiting', n)" |
|||
> |
|||
<div class="add-icon waiting-icon"> |
|||
<PlusIcon class="w-8 h-8" /> |
|||
</div> |
|||
<div class="add-text"> |
|||
<div class="slot-title">等待位</div> |
|||
<div class="slot-subtitle">点击添加学员</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Bottom Popup Modal --> |
|||
<div v-if="showModal" class="modal-overlay" @click="closeModal"> |
|||
<div class="modal-content" @click.stop> |
|||
<div class="modal-header"> |
|||
<h3>添加学员</h3> |
|||
</div> |
|||
|
|||
<div class="modal-body"> |
|||
<!-- Customer Selection --> |
|||
<div class="form-section"> |
|||
<label class="form-label">客户选择</label> |
|||
<div class="search-tabs"> |
|||
<button |
|||
:class="['tab-btn', { active: searchType === 'phone' }]" |
|||
@click="searchType = 'phone'" |
|||
> |
|||
手机号检索 |
|||
</button> |
|||
<button |
|||
:class="['tab-btn', { active: searchType === 'name' }]" |
|||
@click="searchType = 'name'" |
|||
> |
|||
姓名检索 |
|||
</button> |
|||
</div> |
|||
|
|||
<input |
|||
v-model="searchQuery" |
|||
:placeholder="searchType === 'phone' ? '请输入手机号' : '请输入姓名'" |
|||
class="search-input" |
|||
@input="searchStudents" |
|||
/> |
|||
|
|||
<!-- Search Results --> |
|||
<div v-if="searchResults.length > 0" class="search-results"> |
|||
<div |
|||
v-for="student in searchResults" |
|||
:key="student.id" |
|||
:class="['student-item', { selected: selectedStudent?.id === student.id }]" |
|||
@click="selectStudent(student)" |
|||
> |
|||
<div class="student-avatar">{{ student.name.charAt(0) }}</div> |
|||
<div class="student-details"> |
|||
<div class="student-name">{{ student.name }}</div> |
|||
<div class="student-phone">{{ student.phone }}</div> |
|||
</div> |
|||
<div v-if="selectedStudent?.id === student.id" class="check-icon"> |
|||
<CheckIcon class="w-5 h-5" /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Course Arrangement --> |
|||
<div class="form-section"> |
|||
<label class="form-label">课程安排</label> |
|||
<div class="radio-group"> |
|||
<label class="radio-item"> |
|||
<input |
|||
type="radio" |
|||
value="temporary" |
|||
v-model="courseArrangement" |
|||
/> |
|||
<span class="radio-text">临时课</span> |
|||
</label> |
|||
<label class="radio-item"> |
|||
<input |
|||
type="radio" |
|||
value="fixed" |
|||
v-model="courseArrangement" |
|||
/> |
|||
<span class="radio-text">固定课</span> |
|||
</label> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Remarks --> |
|||
<div class="form-section"> |
|||
<label class="form-label">备注</label> |
|||
<textarea |
|||
v-model="remarks" |
|||
placeholder="请输入备注信息" |
|||
class="remarks-textarea" |
|||
rows="3" |
|||
></textarea> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Modal Footer --> |
|||
<div class="modal-footer"> |
|||
<button class="btn btn-cancel" @click="closeModal">取消</button> |
|||
<button class="btn btn-confirm" @click="confirmSelection">确定</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { ChevronLeftIcon, PlusIcon, CheckIcon } from 'lucide-vue-next' |
|||
|
|||
export default { |
|||
name: 'CourseSchedule', |
|||
components: { |
|||
ChevronLeftIcon, |
|||
PlusIcon, |
|||
CheckIcon |
|||
}, |
|||
data() { |
|||
return { |
|||
showModal: false, |
|||
searchType: 'phone', |
|||
searchQuery: '', |
|||
courseArrangement: 'temporary', |
|||
remarks: '', |
|||
selectedStudent: null, |
|||
currentSlot: null, |
|||
searchResults: [], |
|||
// Mock student data |
|||
allStudents: [ |
|||
{ id: 1, name: '张小明', phone: '13800138001', age: 8 }, |
|||
{ id: 2, name: '李小红', phone: '13800138002', age: 9 }, |
|||
{ id: 3, name: '王小华', phone: '13800138003', age: 7 }, |
|||
{ id: 4, name: '赵小强', phone: '13800138004', age: 10 } |
|||
] |
|||
} |
|||
}, |
|||
methods: { |
|||
goBack() { |
|||
this.$router.go(-1) |
|||
}, |
|||
openStudentModal(type, index) { |
|||
this.showModal = true |
|||
this.currentSlot = { type, index } |
|||
this.resetForm() |
|||
}, |
|||
closeModal() { |
|||
this.showModal = false |
|||
this.resetForm() |
|||
}, |
|||
resetForm() { |
|||
this.searchQuery = '' |
|||
this.searchResults = [] |
|||
this.selectedStudent = null |
|||
this.courseArrangement = 'temporary' |
|||
this.remarks = '' |
|||
}, |
|||
searchStudents() { |
|||
if (!this.searchQuery.trim()) { |
|||
this.searchResults = [] |
|||
return |
|||
} |
|||
|
|||
this.searchResults = this.allStudents.filter(student => { |
|||
if (this.searchType === 'phone') { |
|||
return student.phone.includes(this.searchQuery) |
|||
} else { |
|||
return student.name.includes(this.searchQuery) |
|||
} |
|||
}) |
|||
}, |
|||
selectStudent(student) { |
|||
this.selectedStudent = student |
|||
}, |
|||
confirmSelection() { |
|||
if (!this.selectedStudent) { |
|||
alert('请选择学员') |
|||
return |
|||
} |
|||
|
|||
// Here you would typically save the selection |
|||
console.log('Selected:', { |
|||
student: this.selectedStudent, |
|||
slot: this.currentSlot, |
|||
arrangement: this.courseArrangement, |
|||
remarks: this.remarks |
|||
}) |
|||
|
|||
this.closeModal() |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.course-schedule { |
|||
min-height: 100vh; |
|||
background: #1a1a1a; |
|||
color: white; |
|||
padding: 0; |
|||
} |
|||
|
|||
.header { |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 16px 20px; |
|||
background: #2a2a2a; |
|||
} |
|||
|
|||
.back-btn { |
|||
margin-right: 16px; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.title { |
|||
font-size: 18px; |
|||
font-weight: 600; |
|||
margin: 0; |
|||
} |
|||
|
|||
.course-info { |
|||
padding: 24px 20px; |
|||
} |
|||
|
|||
.course-title { |
|||
font-size: 24px; |
|||
font-weight: 600; |
|||
margin: 0 0 12px 0; |
|||
} |
|||
|
|||
.course-time { |
|||
color: #4ade80; |
|||
font-size: 16px; |
|||
margin: 0; |
|||
} |
|||
|
|||
.section { |
|||
margin: 24px 20px; |
|||
} |
|||
|
|||
.section-title { |
|||
font-size: 18px; |
|||
font-weight: 600; |
|||
color: #fbbf24; |
|||
margin: 0 0 16px 0; |
|||
} |
|||
|
|||
.cards-grid { |
|||
display: grid; |
|||
grid-template-columns: 1fr 1fr; |
|||
gap: 12px; |
|||
} |
|||
|
|||
.student-card { |
|||
background: #2a2a2a; |
|||
border-radius: 12px; |
|||
padding: 16px; |
|||
min-height: 160px; |
|||
position: relative; |
|||
cursor: pointer; |
|||
transition: all 0.3s ease; |
|||
} |
|||
|
|||
.student-card.empty { |
|||
border: 2px dashed #fbbf24; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
text-align: center; |
|||
} |
|||
|
|||
.student-card.waiting { |
|||
border: 2px dashed #8b5cf6; |
|||
} |
|||
|
|||
.student-card.filled { |
|||
border: 1px solid #374151; |
|||
} |
|||
|
|||
.student-card:hover { |
|||
transform: translateY(-2px); |
|||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); |
|||
} |
|||
|
|||
.renewal-badge { |
|||
position: absolute; |
|||
top: 8px; |
|||
right: 8px; |
|||
background: #ef4444; |
|||
color: white; |
|||
font-size: 10px; |
|||
padding: 2px 6px; |
|||
border-radius: 8px; |
|||
} |
|||
|
|||
.avatar { |
|||
width: 32px; |
|||
height: 32px; |
|||
border-radius: 50%; |
|||
background: #4ade80; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
font-weight: 600; |
|||
margin-bottom: 8px; |
|||
} |
|||
|
|||
.student-info { |
|||
font-size: 12px; |
|||
line-height: 1.4; |
|||
} |
|||
|
|||
.student-name { |
|||
font-weight: 600; |
|||
margin-bottom: 4px; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
white-space: nowrap; |
|||
} |
|||
|
|||
.student-age, |
|||
.course-status, |
|||
.course-arrangement, |
|||
.remaining-hours, |
|||
.expiry-date { |
|||
color: #9ca3af; |
|||
margin-bottom: 2px; |
|||
} |
|||
|
|||
.add-icon { |
|||
color: #fbbf24; |
|||
margin-bottom: 8px; |
|||
} |
|||
|
|||
.waiting-icon { |
|||
color: #8b5cf6; |
|||
} |
|||
|
|||
.add-text { |
|||
text-align: center; |
|||
} |
|||
|
|||
.slot-title { |
|||
font-size: 16px; |
|||
font-weight: 600; |
|||
margin-bottom: 4px; |
|||
} |
|||
|
|||
.slot-subtitle { |
|||
font-size: 12px; |
|||
color: #9ca3af; |
|||
} |
|||
|
|||
/* Modal Styles */ |
|||
.modal-overlay { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
background: rgba(0, 0, 0, 0.5); |
|||
display: flex; |
|||
align-items: flex-end; |
|||
z-index: 1000; |
|||
} |
|||
|
|||
.modal-content { |
|||
background: white; |
|||
border-radius: 16px 16px 0 0; |
|||
width: 100%; |
|||
max-height: 80vh; |
|||
overflow-y: auto; |
|||
animation: slideUp 0.3s ease-out; |
|||
} |
|||
|
|||
@keyframes slideUp { |
|||
from { |
|||
transform: translateY(100%); |
|||
} |
|||
to { |
|||
transform: translateY(0); |
|||
} |
|||
} |
|||
|
|||
.modal-header { |
|||
padding: 20px; |
|||
border-bottom: 1px solid #e5e7eb; |
|||
text-align: center; |
|||
} |
|||
|
|||
.modal-header h3 { |
|||
margin: 0; |
|||
font-size: 18px; |
|||
font-weight: 600; |
|||
color: #1f2937; |
|||
} |
|||
|
|||
.modal-body { |
|||
padding: 20px; |
|||
color: #1f2937; |
|||
} |
|||
|
|||
.form-section { |
|||
margin-bottom: 24px; |
|||
} |
|||
|
|||
.form-label { |
|||
display: block; |
|||
font-weight: 600; |
|||
margin-bottom: 8px; |
|||
color: #374151; |
|||
} |
|||
|
|||
.search-tabs { |
|||
display: flex; |
|||
margin-bottom: 12px; |
|||
background: #f3f4f6; |
|||
border-radius: 8px; |
|||
padding: 4px; |
|||
} |
|||
|
|||
.tab-btn { |
|||
flex: 1; |
|||
padding: 8px 16px; |
|||
border: none; |
|||
background: transparent; |
|||
border-radius: 6px; |
|||
font-size: 14px; |
|||
cursor: pointer; |
|||
transition: all 0.2s; |
|||
} |
|||
|
|||
.tab-btn.active { |
|||
background: white; |
|||
color: #1f2937; |
|||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
.search-input { |
|||
width: 100%; |
|||
padding: 12px; |
|||
border: 1px solid #d1d5db; |
|||
border-radius: 8px; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.search-results { |
|||
max-height: 200px; |
|||
overflow-y: auto; |
|||
border: 1px solid #e5e7eb; |
|||
border-radius: 8px; |
|||
margin-top: 8px; |
|||
} |
|||
|
|||
.student-item { |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 12px; |
|||
border-bottom: 1px solid #f3f4f6; |
|||
cursor: pointer; |
|||
transition: background 0.2s; |
|||
} |
|||
|
|||
.student-item:hover { |
|||
background: #f9fafb; |
|||
} |
|||
|
|||
.student-item.selected { |
|||
background: #eff6ff; |
|||
border-color: #3b82f6; |
|||
} |
|||
|
|||
.student-avatar { |
|||
width: 40px; |
|||
height: 40px; |
|||
border-radius: 50%; |
|||
background: #3b82f6; |
|||
color: white; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
font-weight: 600; |
|||
margin-right: 12px; |
|||
} |
|||
|
|||
.student-details { |
|||
flex: 1; |
|||
} |
|||
|
|||
.student-details .student-name { |
|||
font-weight: 600; |
|||
margin-bottom: 4px; |
|||
} |
|||
|
|||
.student-details .student-phone { |
|||
color: #6b7280; |
|||
font-size: 14px; |
|||
} |
|||
|
|||
.check-icon { |
|||
color: #3b82f6; |
|||
} |
|||
|
|||
.radio-group { |
|||
display: flex; |
|||
gap: 16px; |
|||
} |
|||
|
|||
.radio-item { |
|||
display: flex; |
|||
align-items: center; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.radio-item input[type="radio"] { |
|||
margin-right: 8px; |
|||
} |
|||
|
|||
.radio-text { |
|||
font-size: 14px; |
|||
} |
|||
|
|||
.remarks-textarea { |
|||
width: 100%; |
|||
padding: 12px; |
|||
border: 1px solid #d1d5db; |
|||
border-radius: 8px; |
|||
font-size: 14px; |
|||
resize: vertical; |
|||
font-family: inherit; |
|||
} |
|||
|
|||
.modal-footer { |
|||
padding: 20px; |
|||
border-top: 1px solid #e5e7eb; |
|||
display: flex; |
|||
gap: 12px; |
|||
} |
|||
|
|||
.btn { |
|||
flex: 1; |
|||
padding: 12px 24px; |
|||
border-radius: 8px; |
|||
font-size: 16px; |
|||
font-weight: 600; |
|||
cursor: pointer; |
|||
transition: all 0.2s; |
|||
} |
|||
|
|||
.btn-cancel { |
|||
background: #f3f4f6; |
|||
color: #374151; |
|||
border: 1px solid #d1d5db; |
|||
} |
|||
|
|||
.btn-cancel:hover { |
|||
background: #e5e7eb; |
|||
} |
|||
|
|||
.btn-confirm { |
|||
background: #3b82f6; |
|||
color: white; |
|||
border: 1px solid #3b82f6; |
|||
} |
|||
|
|||
.btn-confirm:hover { |
|||
background: #2563eb; |
|||
} |
|||
</style> |
|||
@ -1,549 +0,0 @@ |
|||
<!--重构后的客户详情页面 - 使用组件化方式--> |
|||
<template> |
|||
<view class="assemble"> |
|||
<view class="main_box"> |
|||
<view style="height: 20rpx;background: #29D3B4;"></view> |
|||
|
|||
<!-- 头部信息区域 --> |
|||
<view class="count_section"> |
|||
<view class="main"> |
|||
<view class="course_box"> |
|||
<view class="course_box_top"> |
|||
<view class="course_box_top_top"> |
|||
<image class="pic" :src="$util.img('/uniapp_src/static/images/index/myk.png')"></image> |
|||
<view class="name">{{ $util.safeGet(clientInfo, 'customerResource.name', '未知客户') }}</view> |
|||
</view> |
|||
<view class="course_box_top_below"> |
|||
<view class="course_box_top_below-right"> |
|||
<!-- 操作按钮 --> |
|||
<view class="action-buttons"> |
|||
<view class="btn-item" @click="handleMakeCall"> |
|||
<image class="btn-icon" :src="$util.img('/uniapp_src/static/images/index/phone.png')"></image> |
|||
</view> |
|||
<view class="btn-item" @click="handleSendMessage" v-if="$util.safeGet(clientInfo, 'customerResource.member_id')"> |
|||
<image class="btn-icon" :src="$util.img('/uniapp_src/static/images/index/message.png')"></image> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 标签切换组件 --> |
|||
<TabSwitcher |
|||
:tabs="tabs" |
|||
:active-tab-id="switch_tags_type" |
|||
@tab-change="handleTabChange" |
|||
/> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="bg_box bg_top"></view> |
|||
<view class="bg_box bg_bottom"></view> |
|||
</view> |
|||
|
|||
<!-- 基本资料 --> |
|||
<view class="content-section" v-if="switch_tags_type == 1"> |
|||
<view class="integrated-info-section"> |
|||
<view class="basic-message"> |
|||
<view>客户和学生信息</view> |
|||
<view class="add-student-btn" @click="openAddStudentDialog"> |
|||
<view class="add-icon">+</view> |
|||
<view class="add-text">添加学生</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 使用客户信息卡片组件 --> |
|||
<ClientInfoCard |
|||
:client-info="clientInfo" |
|||
@call="handleMakeCall" |
|||
/> |
|||
|
|||
<!-- 学生信息列表 --> |
|||
<view class="student-list" v-if="studentList.length > 0"> |
|||
<StudentInfoCard |
|||
v-for="student in studentList" |
|||
:key="student.id" |
|||
:student="student" |
|||
:actions="studentActions" |
|||
@toggle-actions="toggleStudentActions" |
|||
@action="handleStudentAction" |
|||
/> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 课程信息 --> |
|||
<view class="content-section" v-else-if="switch_tags_type == 2"> |
|||
<view class="course-info-section"> |
|||
<text>课程信息内容...</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 通话记录 --> |
|||
<view class="content-section" v-else-if="switch_tags_type == 3"> |
|||
<view class="call-records-section"> |
|||
<CallRecordCard |
|||
v-for="record in listCallUp" |
|||
:key="record.id" |
|||
:record="record" |
|||
/> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 体测记录 --> |
|||
<view class="content-section" v-else-if="switch_tags_type == 4"> |
|||
<view class="fitness-records-section"> |
|||
<FitnessRecordCard |
|||
v-for="record in fitnessRecords" |
|||
:key="record.id" |
|||
:record="record" |
|||
@file-click="handleFitnessFileClick" |
|||
/> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 学习计划 --> |
|||
<view class="content-section" v-else-if="switch_tags_type == 5"> |
|||
<view class="study-plan-section"> |
|||
<text>学习计划内容...</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import apiRoute from '@/api/apiRoute.js' |
|||
import marketApi from '@/api/marketApi.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 FitnessRecordCard from '@/components/fitness-record-card/fitness-record-card.vue' |
|||
import CallRecordCard from '@/components/call-record-card/call-record-card.vue' |
|||
|
|||
export default { |
|||
name: 'ClueInfoRefactored', |
|||
components: { |
|||
ClientInfoCard, |
|||
StudentInfoCard, |
|||
TabSwitcher, |
|||
FitnessRecordCard, |
|||
CallRecordCard |
|||
}, |
|||
|
|||
data() { |
|||
return { |
|||
resource_sharing_id: '', |
|||
switch_tags_type: 1, // 默认显示基本资料 |
|||
|
|||
// 标签配置 |
|||
tabs: [ |
|||
{ id: 1, name: '基本资料' }, |
|||
{ id: 2, name: '课程信息' }, |
|||
{ id: 3, name: '通话记录' }, |
|||
{ id: 4, name: '体测记录' }, |
|||
{ id: 5, name: '学习计划' } |
|||
], |
|||
|
|||
// 学生操作按钮配置 |
|||
studentActions: [ |
|||
{ key: 'edit', text: '编辑学生' }, |
|||
{ key: 'order', text: '查看订单' }, |
|||
{ key: 'course', text: '课程安排' }, |
|||
{ key: 'fitness', text: '体测记录' } |
|||
], |
|||
|
|||
// 数据 |
|||
clientInfo: {}, |
|||
userInfo: {}, |
|||
studentList: [], |
|||
listCallUp: [], |
|||
fitnessRecords: [], |
|||
followList: [], |
|||
courseInfo: [], |
|||
coachList: [], |
|||
educationList: [], |
|||
assistantList: [] |
|||
} |
|||
}, |
|||
|
|||
onLoad(option) { |
|||
console.log('页面加载参数:', option) |
|||
this.resource_sharing_id = option.resource_sharing_id || '' |
|||
this.init() |
|||
}, |
|||
|
|||
methods: { |
|||
async init() { |
|||
console.log('开始初始化数据...') |
|||
try { |
|||
await this.getInfo() |
|||
await Promise.all([ |
|||
this.getUserInfo(), |
|||
this.getListCallUp(), |
|||
this.getStudentList(), |
|||
this.getFitnessRecords() |
|||
]) |
|||
console.log('数据初始化完成') |
|||
} catch (error) { |
|||
console.error('初始化失败:', error) |
|||
} |
|||
}, |
|||
|
|||
// 获取客户详情 |
|||
async getInfo() { |
|||
if (!this.resource_sharing_id) { |
|||
uni.showToast({ title: '缺少必要参数', icon: 'none' }) |
|||
return false |
|||
} |
|||
|
|||
try { |
|||
const res = await apiRoute.xs_resourceSharingInfo({ |
|||
resource_sharing_id: this.resource_sharing_id |
|||
}) |
|||
|
|||
if (res.code === 1) { |
|||
this.clientInfo = res.data |
|||
return true |
|||
} else { |
|||
uni.showToast({ title: res.msg, icon: 'none' }) |
|||
return false |
|||
} |
|||
} catch (error) { |
|||
console.error('获取客户详情失败:', error) |
|||
return false |
|||
} |
|||
}, |
|||
|
|||
// 获取员工信息 |
|||
async getUserInfo() { |
|||
try { |
|||
const res = await apiRoute.getPersonnelInfo({}) |
|||
if (res.code === 1) { |
|||
this.userInfo = res.data |
|||
return true |
|||
} |
|||
return false |
|||
} catch (error) { |
|||
console.error('获取员工信息失败:', error) |
|||
return false |
|||
} |
|||
}, |
|||
|
|||
// 获取通话记录 |
|||
async getListCallUp() { |
|||
if (!this.clientInfo.resource_id) return false |
|||
|
|||
try { |
|||
const res = await apiRoute.listCallUp({ |
|||
resource_id: this.clientInfo.resource_id |
|||
}) |
|||
|
|||
if (res.code === 1) { |
|||
this.listCallUp = res.data || [] |
|||
return true |
|||
} |
|||
return false |
|||
} catch (error) { |
|||
console.error('获取通话记录失败:', error) |
|||
return false |
|||
} |
|||
}, |
|||
|
|||
// 获取学生列表 |
|||
async getStudentList() { |
|||
try { |
|||
if (!this.clientInfo.resource_id) { |
|||
// 使用Mock数据 |
|||
this.studentList = this.getMockStudentList() |
|||
return true |
|||
} |
|||
|
|||
const res = await apiRoute.xs_getStudentList({ |
|||
parent_resource_id: this.clientInfo.resource_id |
|||
}) |
|||
|
|||
if (res.code === 1) { |
|||
this.studentList = res.data || [] |
|||
} else { |
|||
this.studentList = this.getMockStudentList() |
|||
} |
|||
return true |
|||
} catch (error) { |
|||
console.error('获取学生列表失败:', error) |
|||
this.studentList = this.getMockStudentList() |
|||
return true |
|||
} |
|||
}, |
|||
|
|||
// 获取体测记录 |
|||
async getFitnessRecords() { |
|||
try { |
|||
// 使用Mock数据 |
|||
this.fitnessRecords = this.getMockFitnessRecords() |
|||
return true |
|||
} catch (error) { |
|||
console.error('获取体测记录失败:', error) |
|||
return false |
|||
} |
|||
}, |
|||
|
|||
// Mock数据方法 |
|||
getMockStudentList() { |
|||
return [ |
|||
{ |
|||
id: 1, |
|||
name: '张小明', |
|||
gender: 1, |
|||
age: 9.05, |
|||
birthday: '2015-05-10', |
|||
emergency_contact: '张妈妈', |
|||
contact_phone: '13800138001', |
|||
member_label: '新学员', |
|||
note: '活泼好动,喜欢运动', |
|||
actionsExpanded: false |
|||
} |
|||
] |
|||
}, |
|||
|
|||
getMockFitnessRecords() { |
|||
return [ |
|||
{ |
|||
id: 1, |
|||
test_date: '2024-01-15', |
|||
height: '165', |
|||
weight: '55', |
|||
pdf_files: [ |
|||
{ |
|||
id: 1, |
|||
name: '体测报告_2024-01-15.pdf', |
|||
size: 1024000, |
|||
url: '/static/mock/fitness_report_1.pdf' |
|||
} |
|||
] |
|||
} |
|||
] |
|||
}, |
|||
|
|||
// 事件处理方法 |
|||
handleTabChange({ tabId }) { |
|||
this.switch_tags_type = tabId |
|||
}, |
|||
|
|||
handleMakeCall() { |
|||
const phoneNumber = this.$util.safeGet(this.clientInfo, 'customerResource.phone_number', '') |
|||
this.$util.makePhoneCall(phoneNumber) |
|||
}, |
|||
|
|||
handleSendMessage() { |
|||
uni.showToast({ |
|||
title: '发送消息功能待实现', |
|||
icon: 'none' |
|||
}) |
|||
}, |
|||
|
|||
toggleStudentActions(student) { |
|||
const index = this.studentList.findIndex(s => s.id === student.id) |
|||
if (index !== -1) { |
|||
this.$set(this.studentList[index], 'actionsExpanded', !student.actionsExpanded) |
|||
} |
|||
}, |
|||
|
|||
handleStudentAction({ action, student }) { |
|||
console.log('学生操作:', action, student) |
|||
|
|||
switch (action.key) { |
|||
case 'edit': |
|||
this.editStudent(student) |
|||
break |
|||
case 'order': |
|||
this.viewStudentOrders(student) |
|||
break |
|||
case 'course': |
|||
this.viewStudentCourse(student) |
|||
break |
|||
case 'fitness': |
|||
this.viewStudentFitness(student) |
|||
break |
|||
} |
|||
}, |
|||
|
|||
handleFitnessFileClick({ file, record }) { |
|||
console.log('点击体测文件:', file, record) |
|||
// 实现文件查看逻辑 |
|||
}, |
|||
|
|||
openAddStudentDialog() { |
|||
console.log('打开添加学生对话框') |
|||
// 实现添加学生逻辑 |
|||
}, |
|||
|
|||
// 学生操作相关方法 |
|||
editStudent(student) { |
|||
this.$util.navigateToPage('/pages/student/edit', { |
|||
student_id: student.id |
|||
}) |
|||
}, |
|||
|
|||
viewStudentOrders(student) { |
|||
this.$util.navigateToPage('/pages/market/clue/order_list', { |
|||
resource_id: this.clientInfo.resource_id, |
|||
student_id: student.id, |
|||
student_name: student.name |
|||
}) |
|||
}, |
|||
|
|||
viewStudentCourse(student) { |
|||
this.$util.navigateToPage('/pages/market/clue/course_arrange', { |
|||
resource_id: this.clientInfo.resource_id, |
|||
student_id: student.id, |
|||
student_name: student.name |
|||
}) |
|||
}, |
|||
|
|||
viewStudentFitness(student) { |
|||
this.$util.navigateToPage('/pages/fitness/records', { |
|||
student_id: student.id |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.assemble { |
|||
width: 100%; |
|||
height: 100vh; |
|||
overflow: auto; |
|||
background-color: #292929; |
|||
} |
|||
|
|||
.main_box { |
|||
background: #292929; |
|||
min-height: 20vh; |
|||
} |
|||
|
|||
.action-buttons { |
|||
display: flex; |
|||
align-items: center; |
|||
|
|||
.btn-item { |
|||
width: 60rpx; |
|||
height: 60rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
margin-left: 20rpx; |
|||
|
|||
.btn-icon { |
|||
width: 40rpx; |
|||
height: 40rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.count_section { |
|||
width: 100%; |
|||
position: relative; |
|||
|
|||
.main { |
|||
width: 100%; |
|||
position: absolute; |
|||
z-index: 2; |
|||
padding: 0rpx 24rpx; |
|||
display: flex; |
|||
justify-content: center; |
|||
|
|||
.course_box { |
|||
padding: 26rpx 22rpx 0 22rpx; |
|||
width: 95%; |
|||
height: 250rpx; |
|||
border-radius: 20rpx; |
|||
background-color: #fff; |
|||
} |
|||
} |
|||
|
|||
.bg_top { |
|||
height: 180rpx; |
|||
background-color: #29D3B4; |
|||
} |
|||
|
|||
.bg_bottom { |
|||
height: 80rpx; |
|||
background-color: #292929; |
|||
} |
|||
} |
|||
|
|||
.course_box_top { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
|
|||
.course_box_top_top { |
|||
display: flex; |
|||
align-items: center; |
|||
|
|||
.pic { |
|||
width: 60rpx; |
|||
height: 60rpx; |
|||
margin-right: 20rpx; |
|||
} |
|||
|
|||
.name { |
|||
font-size: 32rpx; |
|||
font-weight: bold; |
|||
color: #333; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.content-section { |
|||
background-color: #292929; |
|||
min-height: 60vh; |
|||
padding: 20rpx; |
|||
} |
|||
|
|||
.integrated-info-section { |
|||
.basic-message { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 30rpx 20rpx; |
|||
color: white; |
|||
font-size: 28rpx; |
|||
font-weight: bold; |
|||
|
|||
.add-student-btn { |
|||
display: flex; |
|||
align-items: center; |
|||
background-color: #29d3b4; |
|||
padding: 15rpx 25rpx; |
|||
border-radius: 25rpx; |
|||
|
|||
.add-icon { |
|||
color: white; |
|||
font-size: 24rpx; |
|||
margin-right: 10rpx; |
|||
} |
|||
|
|||
.add-text { |
|||
color: white; |
|||
font-size: 22rpx; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.student-list, |
|||
.call-records-section, |
|||
.fitness-records-section { |
|||
padding: 20rpx 0; |
|||
} |
|||
|
|||
.course-info-section, |
|||
.study-plan-section { |
|||
padding: 40rpx 20rpx; |
|||
color: white; |
|||
text-align: center; |
|||
} |
|||
</style> |
|||
@ -1,425 +0,0 @@ |
|||
<template> |
|||
<view class="assemble"> |
|||
<view class="title">跟进任务</view> |
|||
<view class="form-style"> |
|||
<fui-form class="input-style" ref="form" top="0" :model="formData" :show="false"> |
|||
<!--基础表单--> |
|||
<!--下拉--> |
|||
<fui-form-item |
|||
asterisk |
|||
label="跟进类型" |
|||
asteriskPosition="right" |
|||
labelSize='26' |
|||
prop="" |
|||
background='#434544' |
|||
labelColor='#fff' |
|||
:bottomBorder='false' |
|||
> |
|||
<view class="input-title" style="margin-right:14rpx;"> |
|||
<view v-if="!formData.entry_type" class="input-title" style="margin-right:14rpx;" @click="selectCon(`entry_type`)">点击选择 |
|||
</view> |
|||
<view v-else class="input-title" style="margin-right:14rpx;" @click="selectCon(`entry_type`)"> |
|||
{{ str_entry_type }} |
|||
</view> |
|||
</view> |
|||
</fui-form-item> |
|||
|
|||
<!--下拉--> |
|||
<fui-form-item |
|||
asterisk |
|||
label="跟进人员" |
|||
asteriskPosition="right" |
|||
labelSize='26' |
|||
prop="" |
|||
background='#434544' |
|||
labelColor='#fff' |
|||
:bottomBorder='false' |
|||
> |
|||
<view class="input-title" style="margin-right:14rpx;"> |
|||
<view v-if="!formData.follow_staff_id" class="input-title" style="margin-right:14rpx;" @click="selectCon(`follow_staff_id`)">点击选择 |
|||
</view> |
|||
<view v-else class="input-title" style="margin-right:14rpx;" @click="selectCon(`follow_staff_id`)"> |
|||
{{ str_follow_staff_id }} |
|||
</view> |
|||
</view> |
|||
</fui-form-item> |
|||
|
|||
<!--下拉--> |
|||
<fui-form-item |
|||
asterisk |
|||
label="跟进时间" |
|||
asteriskPosition="right" |
|||
labelSize='26' |
|||
prop="" |
|||
background='#434544' |
|||
labelColor='#fff' |
|||
:bottomBorder='false' |
|||
> |
|||
<view class="input-title" style="margin-right:14rpx;"> |
|||
<view v-if="!formData.reminder_time" class="input-title" style="margin-right:14rpx;" @click="selectCon(`reminder_time`)">点击选择 |
|||
</view> |
|||
<view v-else class="input-title" style="margin-right:14rpx;" @click="selectCon(`reminder_time`)"> |
|||
{{ formData.reminder_time }} |
|||
</view> |
|||
</view> |
|||
</fui-form-item> |
|||
|
|||
<!--手写--> |
|||
<fui-form-item |
|||
label="备注" |
|||
asteriskPosition="right" |
|||
labelSize='26' |
|||
prop="" |
|||
background='#434544' |
|||
labelColor='#fff' |
|||
:bottomBorder='false' |
|||
> |
|||
<view class="input-title" style="margin-right:14rpx;"> |
|||
<fui-input :borderBottom="false" :padding="[0]" placeholder="点击填写" v-model="formData.follow_content" |
|||
backgroundColor="#434544" size="26" color="#fff"></fui-input> |
|||
</view> |
|||
</fui-form-item> |
|||
</fui-form> |
|||
</view> |
|||
<view class="fui-btn__box"> |
|||
<fui-button background="#434544" color="#24BA9F" borderColor="#24BA9F" @click="submit">保存</fui-button> |
|||
</view> |
|||
|
|||
<!-- 年月日-选择时间 --> |
|||
<fui-date-picker :show="show_date" type="5" @change="change_date" @cancel="cancel_date"></fui-date-picker> |
|||
|
|||
<!-- 下拉选择器 --> |
|||
<fui-picker :linkage='linkage' :options="options" :layer="1" :show="show" @change="changeOptions" |
|||
@cancel="cancel"></fui-picker> |
|||
|
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import marketApi from '@/api/market.js'; |
|||
import memberApi from '@/api/member.js'; |
|||
|
|||
const rules = [{ |
|||
name: "mobile", |
|||
rule: ["required", "isMobile"], |
|||
msg: ["请输入手机号", "请输入正确的手机号"] |
|||
}]; |
|||
export default { |
|||
data() { |
|||
return { |
|||
rules, |
|||
|
|||
is_submit: true,//是否提交(防止重复提交)|true=可提交,false=不可提交 |
|||
|
|||
//表单数据 |
|||
formData:{ |
|||
//##### 基础表单 ##### |
|||
entry_type:'',//跟进类型(1=市场人员录入的,2=销售人员录入) |
|||
follow_staff_id:'',//跟进人员 |
|||
reminder_time:'',//跟进时间 |
|||
follow_content:'',//备注 |
|||
}, |
|||
|
|||
//下拉选择器组件 |
|||
options_type: undefined,//选择器标识 |
|||
show: false,//是否显示下拉选择器 |
|||
linkage: true,//是否联动选择 |
|||
options: [ |
|||
// { |
|||
// 'value': 1, |
|||
// 'text': '类型1' |
|||
// } |
|||
],//下拉选择器可选值列表 |
|||
|
|||
//时间选择器相关 |
|||
show_date: false,//是否显示时间选择器|true=是,false=否 |
|||
|
|||
//跟进类型-相关 |
|||
//字典-跟进类型 |
|||
options_entry_type:[ |
|||
{ |
|||
value: 1, |
|||
text: '市场人员' |
|||
}, |
|||
{ |
|||
value: 2, |
|||
text: '销售人员' |
|||
}, |
|||
], |
|||
//文本展示-跟进类型 |
|||
str_entry_type:'', |
|||
|
|||
//跟进人员-相关 |
|||
//字典-跟进人员 |
|||
options_follow_staff_id_sc:[],//(市场-跟进人员) |
|||
options_follow_staff_id_xs:[],//(销售-跟进人员) |
|||
//文本展示-跟进人员 |
|||
str_follow_staff_id:'', |
|||
|
|||
|
|||
} |
|||
}, |
|||
onShow() { |
|||
this.init() |
|||
}, |
|||
methods: { |
|||
|
|||
//初始化 |
|||
async init() { |
|||
this.getUserInfo() |
|||
//获取字典-跟进人员(市场) |
|||
this.getDic_staff_id('5') |
|||
//获取字典-跟进人员(销售) |
|||
this.getDic_staff_id('6') |
|||
}, |
|||
|
|||
//获取当前登陆用户信息 |
|||
async getUserInfo(){ |
|||
let res = await marketApi.member({}) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
console.log(111,res.data) |
|||
this.formData.staff_id = res.data.staff_id//基础表单->跟进人员 |
|||
this.str_staff_id = res.data.name//基础表单->跟进人员名字 |
|||
}, |
|||
|
|||
//获取字典-跟进人员(全部) |
|||
//获取人员列表 role_id|5=市场,6=销售 |
|||
async getDic_staff_id(role_id){ |
|||
let res = await memberApi.staffList({ |
|||
type: 2, |
|||
role_id:role_id |
|||
}) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
let arr = [] |
|||
res.data.forEach((v,k)=>{ |
|||
arr.push({ |
|||
text: v.name, |
|||
value: v.id, |
|||
}) |
|||
}) |
|||
|
|||
if(role_id == 5){ |
|||
this.options_follow_staff_id_sc = arr |
|||
console.log('市场',arr) |
|||
}else if(role_id == 6){ |
|||
this.options_follow_staff_id_xs = arr |
|||
console.log('销售',arr) |
|||
}else{ |
|||
//全部 |
|||
this.options_staff_id = arr |
|||
console.log('全部',arr) |
|||
} |
|||
}, |
|||
|
|||
//表单验证 |
|||
async validatorForm(data) { |
|||
//跟进类型 |
|||
if(!data.entry_type){ |
|||
uni.showToast({ |
|||
title: '跟进类型必填', |
|||
icon: 'none' |
|||
}) |
|||
return false |
|||
} |
|||
//跟进人员 |
|||
if(!data.follow_staff_id){ |
|||
uni.showToast({ |
|||
title: '跟进人员必填', |
|||
icon: 'none' |
|||
}) |
|||
return false |
|||
} |
|||
//跟进时间 |
|||
if(!data.reminder_time){ |
|||
uni.showToast({ |
|||
title: '跟进时间必填', |
|||
icon: 'none' |
|||
}) |
|||
return false |
|||
} |
|||
return true |
|||
}, |
|||
//提交 |
|||
async submit() { |
|||
console.log('提交',this.formData) |
|||
let data = {...this.formData} |
|||
//表单验证 |
|||
let validatorForm = await this.validatorForm(data) |
|||
console.log('验证结果',validatorForm) |
|||
if(!validatorForm){ |
|||
return |
|||
} |
|||
|
|||
//防止重复提交 |
|||
if (!this.is_submit) { |
|||
return |
|||
} |
|||
this.is_submit = false |
|||
|
|||
let res = await marketApi.createTask(data)//转移跟进任务 |
|||
|
|||
this.is_submit = true |
|||
|
|||
if(res.code != 1){ |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'success' |
|||
}) |
|||
//延迟1s执行 |
|||
setTimeout(() => { |
|||
//跳转页面-线索列表 |
|||
//关闭当前页跳转新页面 |
|||
uni.redirectTo({ |
|||
url: `/pages/market/clue/index` |
|||
}) |
|||
}, 1000) |
|||
}, |
|||
//选择弹窗 |
|||
selectCon(type) { |
|||
this.options_type = type |
|||
switch (type) { |
|||
//跟进类型 |
|||
case 'entry_type': |
|||
this.options = this.options_entry_type |
|||
this.show = true |
|||
this.linkage = true |
|||
//清空跟进任务->跟进人员 |
|||
this.formData.follow_staff_id = '' |
|||
break; |
|||
//跟进任务->跟进人员 |
|||
case 'follow_staff_id': |
|||
if(!this.formData.entry_type){ |
|||
uni.showToast({ |
|||
title: '请先选择跟进类型', |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
if(this.formData.entry_type == 1){ |
|||
//市场人员列表 |
|||
this.options = this.options_follow_staff_id_sc |
|||
}else{ |
|||
//销售人员列表 |
|||
this.options = this.options_follow_staff_id_xs |
|||
} |
|||
|
|||
this.show = true |
|||
this.linkage = true |
|||
break; |
|||
//跟进时间 |
|||
case 'reminder_time': |
|||
this.show_date = true |
|||
break; |
|||
} |
|||
}, |
|||
//监听-下拉选择框 |
|||
changeOptions(e) { |
|||
console.log('选择器选中',e) |
|||
this.show = false |
|||
let type = this.options_type |
|||
switch (type) { |
|||
//跟进类型 |
|||
case 'entry_type': |
|||
this.str_entry_type = e.text//选中的text值 |
|||
this.formData.entry_type = e.value//选中value值 |
|||
break; |
|||
//跟进人员 |
|||
case 'follow_staff_id': |
|||
this.str_follow_staff_id = e.text//选中的text值 |
|||
this.formData.follow_staff_id = e.value//选中value值 |
|||
break; |
|||
} |
|||
}, |
|||
|
|||
//关闭选择框 |
|||
cancel() { |
|||
this.show = false |
|||
}, |
|||
|
|||
//监听-时间选择器 |
|||
change_date(e) { |
|||
|
|||
this.show_date = false |
|||
//跟进时间 |
|||
let type = this.options_type |
|||
console.log('时间选择器',type,e) |
|||
let val = (e.result ?? '') |
|||
if(val){ |
|||
val = val + ':00' |
|||
} |
|||
|
|||
switch (type) { |
|||
//跟进任务->跟进时间 |
|||
case 'reminder_time': |
|||
this.formData.reminder_time = val |
|||
break; |
|||
} |
|||
}, |
|||
//关闭时间选择器 |
|||
cancel_date() { |
|||
this.show_date = false |
|||
}, |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.assemble { |
|||
width: 100%; |
|||
height: 100vh; |
|||
background: #292929; |
|||
} |
|||
|
|||
.title { |
|||
font-size: 26rpx; |
|||
color: #fff; |
|||
padding: 26rpx 0 26rpx 32rpx; |
|||
} |
|||
|
|||
.input-title { |
|||
font-size: 26rpx; |
|||
color: #fff; |
|||
} |
|||
|
|||
.form-style { |
|||
width: 100%; |
|||
background: #434544; |
|||
} |
|||
|
|||
.form-style-vid { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
padding: 12rpx 0; |
|||
} |
|||
|
|||
.input-style { |
|||
text-align: right !important; |
|||
} |
|||
|
|||
.fui-btn__box { |
|||
margin: 20rpx auto; |
|||
width: 92%; |
|||
|
|||
} |
|||
</style> |
|||
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -1,514 +0,0 @@ |
|||
<template> |
|||
<view class="course-detail-container"> |
|||
<!-- 课程基本信息 --> |
|||
<view class="course-info-card"> |
|||
<view class="course-header"> |
|||
<text class="course-title">{{ courseInfo.course_name || '课程详情' }}</text> |
|||
<view :class="['course-status',getStatusClass(courseInfo.status)]"> |
|||
{{ getStatusText(courseInfo.status) }} |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="course-stats"> |
|||
<view class="stat-item"> |
|||
<text class="stat-label">总课时</text> |
|||
<text class="stat-value">{{ courseInfo.total_hours || 0 }}</text> |
|||
</view> |
|||
<view class="stat-item"> |
|||
<text class="stat-label">赠送课时</text> |
|||
<text class="stat-value">{{ courseInfo.gift_hours || 0 }}</text> |
|||
</view> |
|||
<view class="stat-item"> |
|||
<text class="stat-label">已用课时</text> |
|||
<text class="stat-value">{{ (courseInfo.use_total_hours || 0) + (courseInfo.use_gift_hours || 0) }}</text> |
|||
</view> |
|||
<view class="stat-item"> |
|||
<text class="stat-label">剩余课时</text> |
|||
<text class="stat-value remaining">{{ getRemainingHours() }}</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="course-dates"> |
|||
<text class="date-item">开始日期:{{ courseInfo.start_date || '--' }}</text> |
|||
<text class="date-item">结束日期:{{ courseInfo.end_date || '--' }}</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 课程安排列表 --> |
|||
<view class="section-title"> |
|||
<text class="title-text">课程安排</text> |
|||
<text class="title-count">({{ scheduleList.length }})</text> |
|||
</view> |
|||
|
|||
<view class="schedule-list"> |
|||
<view |
|||
v-for="(item, index) in scheduleList" |
|||
:key="item.id" |
|||
class="schedule-item" |
|||
@tap="showScheduleDetail(item)" |
|||
> |
|||
<view class="schedule-date"> |
|||
<text class="date-text">{{ formatDate(item.course_date) }}</text> |
|||
<text class="time-text">{{ item.time_slot }}</text> |
|||
</view> |
|||
|
|||
<view class="schedule-info"> |
|||
<view class="schedule-type"> |
|||
<text :class="['type-tag',getScheduleTypeClass(item.schedule_type)]"> |
|||
{{ getScheduleTypeText(item.schedule_type) }} |
|||
</text> |
|||
<text :class="['type-tag',getCourseTypeClass(item.course_type)]"> |
|||
{{ getCourseTypeText(item.course_type) }} |
|||
</text> |
|||
</view> |
|||
|
|||
<view class="schedule-status"> |
|||
<text :class="['status-tag',getScheduleStatusClass(item.status)]"> |
|||
{{ getScheduleStatusText(item.status) }} |
|||
</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="schedule-arrow"> |
|||
<text class="arrow-icon">></text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 课程使用记录 --> |
|||
<view class="section-title"> |
|||
<text class="title-text">使用记录</text> |
|||
<text class="title-count">({{ usageList.length }})</text> |
|||
</view> |
|||
|
|||
<view class="usage-list"> |
|||
<view |
|||
v-for="(item, index) in usageList" |
|||
:key="item.id" |
|||
class="usage-item" |
|||
> |
|||
<view class="usage-date"> |
|||
<text class="date-text">{{ formatDate(item.usage_date) }}</text> |
|||
<text class="time-text">{{ item.time_slot || '--' }}</text> |
|||
</view> |
|||
|
|||
<view class="usage-info"> |
|||
<text class="usage-hours">消耗课时:{{ item.hours_used || 0 }}</text> |
|||
<text class="usage-type">{{ item.usage_type || '正常上课' }}</text> |
|||
</view> |
|||
|
|||
<view class="usage-status"> |
|||
<text class="status-text confirmed">已确认</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 无数据提示 --> |
|||
<view v-if="scheduleList.length === 0 && usageList.length === 0" class="no-data"> |
|||
<text class="no-data-text">暂无课程安排和使用记录</text> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
courseId: '', |
|||
courseInfo: {}, |
|||
scheduleList: [], |
|||
usageList: [] |
|||
} |
|||
}, |
|||
|
|||
onLoad(options) { |
|||
this.courseId = options.courseId || '' |
|||
if (this.courseId) { |
|||
this.loadCourseDetail() |
|||
} |
|||
}, |
|||
|
|||
methods: { |
|||
// 加载课程详情 |
|||
async loadCourseDetail() { |
|||
try { |
|||
uni.showLoading({ title: '加载中...' }) |
|||
|
|||
const res = await this.$http.get('/xy/course/detail', { |
|||
course_id: this.courseId |
|||
}) |
|||
|
|||
if (res.data.code === 1) { |
|||
this.courseInfo = res.data.data.course_info || {} |
|||
this.scheduleList = res.data.data.schedule_list || [] |
|||
this.usageList = res.data.data.usage_list || [] |
|||
} else { |
|||
uni.showToast({ |
|||
title: res.data.msg || '加载失败', |
|||
icon: 'none' |
|||
}) |
|||
} |
|||
} catch (error) { |
|||
console.error('加载课程详情失败:', error) |
|||
uni.showToast({ |
|||
title: '加载失败', |
|||
icon: 'none' |
|||
}) |
|||
} finally { |
|||
uni.hideLoading() |
|||
} |
|||
}, |
|||
|
|||
// 计算剩余课时 |
|||
getRemainingHours() { |
|||
const total = (this.courseInfo.total_hours || 0) + (this.courseInfo.gift_hours || 0) |
|||
const used = (this.courseInfo.use_total_hours || 0) + (this.courseInfo.use_gift_hours || 0) |
|||
return Math.max(0, total - used) |
|||
}, |
|||
|
|||
// 获取课程状态文本 |
|||
getStatusText(status) { |
|||
const statusMap = { |
|||
1: '有效', |
|||
2: '过期', |
|||
3: '等待期', |
|||
4: '延期' |
|||
} |
|||
return statusMap[status] || '未知' |
|||
}, |
|||
|
|||
// 获取课程状态样式 |
|||
getStatusClass(status) { |
|||
const classMap = { |
|||
1: 'status-active', |
|||
2: 'status-expired', |
|||
3: 'status-waiting', |
|||
4: 'status-delayed' |
|||
} |
|||
return classMap[status] || 'status-unknown' |
|||
}, |
|||
|
|||
// 获取课程安排类型文本 |
|||
getScheduleTypeText(type) { |
|||
const typeMap = { |
|||
1: '临时课', |
|||
2: '固定课' |
|||
} |
|||
return typeMap[type] || '未知' |
|||
}, |
|||
|
|||
// 获取课程安排类型样式 |
|||
getScheduleTypeClass(type) { |
|||
const classMap = { |
|||
1: 'type-temp', |
|||
2: 'type-fixed' |
|||
} |
|||
return classMap[type] || 'type-unknown' |
|||
}, |
|||
|
|||
// 获取课程类型文本 |
|||
getCourseTypeText(type) { |
|||
const typeMap = { |
|||
1: '加课', |
|||
2: '补课', |
|||
3: '等待位' |
|||
} |
|||
return typeMap[type] || '正常课' |
|||
}, |
|||
|
|||
// 获取课程类型样式 |
|||
getCourseTypeClass(type) { |
|||
const classMap = { |
|||
1: 'course-add', |
|||
2: 'course-makeup', |
|||
3: 'course-waiting' |
|||
} |
|||
return classMap[type] || 'course-normal' |
|||
}, |
|||
|
|||
// 获取课程安排状态文本 |
|||
getScheduleStatusText(status) { |
|||
const statusMap = { |
|||
0: '待上课', |
|||
1: '已上课', |
|||
2: '请假' |
|||
} |
|||
return statusMap[status] || '未知' |
|||
}, |
|||
|
|||
// 获取课程安排状态样式 |
|||
getScheduleStatusClass(status) { |
|||
const classMap = { |
|||
0: 'schedule-pending', |
|||
1: 'schedule-completed', |
|||
2: 'schedule-leave' |
|||
} |
|||
return classMap[status] || 'schedule-unknown' |
|||
}, |
|||
|
|||
// 格式化日期 |
|||
formatDate(dateStr) { |
|||
if (!dateStr) return '--' |
|||
const date = new Date(dateStr) |
|||
const month = (date.getMonth() + 1).toString().padStart(2, '0') |
|||
const day = date.getDate().toString().padStart(2, '0') |
|||
return `${month}-${day}` |
|||
}, |
|||
|
|||
// 显示课程安排详情 |
|||
showScheduleDetail(item) { |
|||
// 可以跳转到课程安排详情页面 |
|||
console.log('查看课程安排详情:', item) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.course-detail-container { |
|||
padding: 20rpx; |
|||
background-color: #f5f5f5; |
|||
min-height: 100vh; |
|||
} |
|||
|
|||
.course-info-card { |
|||
background: white; |
|||
border-radius: 16rpx; |
|||
padding: 24rpx; |
|||
margin-bottom: 20rpx; |
|||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
.course-header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 20rpx; |
|||
} |
|||
|
|||
.course-title { |
|||
font-size: 32rpx; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.course-status { |
|||
padding: 8rpx 16rpx; |
|||
border-radius: 20rpx; |
|||
font-size: 24rpx; |
|||
font-weight: 500; |
|||
|
|||
&.status-active { |
|||
background: #e8f5e8; |
|||
color: #52c41a; |
|||
} |
|||
|
|||
&.status-expired { |
|||
background: #fff2f0; |
|||
color: #ff4d4f; |
|||
} |
|||
|
|||
&.status-waiting { |
|||
background: #f6ffed; |
|||
color: #faad14; |
|||
} |
|||
|
|||
&.status-delayed { |
|||
background: #f0f5ff; |
|||
color: #1890ff; |
|||
} |
|||
} |
|||
|
|||
.course-stats { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
margin-bottom: 20rpx; |
|||
} |
|||
|
|||
.stat-item { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
flex: 1; |
|||
} |
|||
|
|||
.stat-label { |
|||
font-size: 24rpx; |
|||
color: #666; |
|||
margin-bottom: 8rpx; |
|||
} |
|||
|
|||
.stat-value { |
|||
font-size: 28rpx; |
|||
font-weight: 600; |
|||
color: #333; |
|||
|
|||
&.remaining { |
|||
color: #1890ff; |
|||
} |
|||
} |
|||
|
|||
.course-dates { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
padding-top: 20rpx; |
|||
border-top: 1rpx solid #f0f0f0; |
|||
} |
|||
|
|||
.date-item { |
|||
font-size: 24rpx; |
|||
color: #666; |
|||
} |
|||
|
|||
.section-title { |
|||
display: flex; |
|||
align-items: center; |
|||
margin: 30rpx 0 16rpx; |
|||
} |
|||
|
|||
.title-text { |
|||
font-size: 28rpx; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.title-count { |
|||
font-size: 24rpx; |
|||
color: #666; |
|||
margin-left: 8rpx; |
|||
} |
|||
|
|||
.schedule-list, .usage-list { |
|||
background: white; |
|||
border-radius: 16rpx; |
|||
overflow: hidden; |
|||
margin-bottom: 20rpx; |
|||
} |
|||
|
|||
.schedule-item, .usage-item { |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 24rpx; |
|||
border-bottom: 1rpx solid #f0f0f0; |
|||
|
|||
&:last-child { |
|||
border-bottom: none; |
|||
} |
|||
} |
|||
|
|||
.schedule-date, .usage-date { |
|||
display: flex; |
|||
flex-direction: column; |
|||
width: 140rpx; |
|||
margin-right: 20rpx; |
|||
} |
|||
|
|||
.date-text { |
|||
font-size: 28rpx; |
|||
font-weight: 600; |
|||
color: #333; |
|||
margin-bottom: 4rpx; |
|||
} |
|||
|
|||
.time-text { |
|||
font-size: 24rpx; |
|||
color: #666; |
|||
} |
|||
|
|||
.schedule-info, .usage-info { |
|||
flex: 1; |
|||
} |
|||
|
|||
.schedule-type { |
|||
display: flex; |
|||
gap: 8rpx; |
|||
margin-bottom: 8rpx; |
|||
} |
|||
|
|||
.type-tag, .course-type-tag { |
|||
padding: 4rpx 8rpx; |
|||
border-radius: 8rpx; |
|||
font-size: 20rpx; |
|||
|
|||
&.type-temp { |
|||
background: #fff7e6; |
|||
color: #fa8c16; |
|||
} |
|||
|
|||
&.type-fixed { |
|||
background: #f6ffed; |
|||
color: #52c41a; |
|||
} |
|||
|
|||
&.course-add { |
|||
background: #e6f7ff; |
|||
color: #1890ff; |
|||
} |
|||
|
|||
&.course-makeup { |
|||
background: #f9f0ff; |
|||
color: #722ed1; |
|||
} |
|||
|
|||
&.course-waiting { |
|||
background: #fff2f0; |
|||
color: #ff4d4f; |
|||
} |
|||
} |
|||
|
|||
.schedule-status, .usage-status { |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.status-text { |
|||
font-size: 24rpx; |
|||
font-weight: 500; |
|||
|
|||
&.schedule-pending { |
|||
color: #faad14; |
|||
} |
|||
|
|||
&.schedule-completed { |
|||
color: #52c41a; |
|||
} |
|||
|
|||
&.schedule-leave { |
|||
color: #ff4d4f; |
|||
} |
|||
|
|||
&.confirmed { |
|||
color: #52c41a; |
|||
} |
|||
} |
|||
|
|||
.schedule-arrow { |
|||
margin-left: 16rpx; |
|||
} |
|||
|
|||
.arrow-icon { |
|||
font-size: 24rpx; |
|||
color: #ccc; |
|||
} |
|||
|
|||
.usage-hours { |
|||
font-size: 26rpx; |
|||
color: #333; |
|||
margin-bottom: 4rpx; |
|||
} |
|||
|
|||
.usage-type { |
|||
font-size: 24rpx; |
|||
color: #666; |
|||
} |
|||
|
|||
.no-data { |
|||
text-align: center; |
|||
padding: 100rpx 0; |
|||
} |
|||
|
|||
.no-data-text { |
|||
font-size: 24rpx; |
|||
color: #999; |
|||
} |
|||
</style> |
|||
@ -1,836 +0,0 @@ |
|||
<!--数据-首页--> |
|||
<template> |
|||
<view class="main_box"> |
|||
<!--自定义导航栏--> |
|||
<view class="navbar_section"> |
|||
<view class="title">数据</view> |
|||
</view> |
|||
|
|||
<!-- 市场人员展示--> |
|||
<view v-if="infoData.role_type == 'market_type'"> |
|||
<view class="count_section"> |
|||
<view class="title_box">业绩统计</view> |
|||
<view class="box_1"> |
|||
<view class="left"> |
|||
<view class="charts-box"> |
|||
<qiun-data-charts |
|||
type="ring" |
|||
:opts="opts" |
|||
:chartData="chartData" |
|||
/> |
|||
</view> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="title">本周已分配</view> |
|||
<view class="content"> |
|||
<text class="strong">{{infoData.num_1}}人</text> |
|||
</view> |
|||
<view class="title">本周未分配</view> |
|||
<view class="content"> |
|||
<text class="strong">{{infoData.num_2}}人</text> |
|||
<!-- <text>较上月</text>--> |
|||
</view> |
|||
|
|||
<view class="legeng"> |
|||
<view class="item"> |
|||
<view class="piece" style="background-color: #45c59f;"></view> |
|||
<view class="lable">已分配</view> |
|||
|
|||
<view class="item"> |
|||
<view class="piece" style="background-color:#02a7f0;"></view> |
|||
<view class="lable">未分配</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="title_box" v-show="box_2_show">新客签到</view> |
|||
<view class="box_2" v-show="box_2_show"> |
|||
<view class="progress-container"> |
|||
<view :style="{ width: progress + '%' }" class="progress-bar"> |
|||
</view> |
|||
<view class="dian" :style="{ left: (progress - 2) + '%' }"></view> |
|||
</view> |
|||
<view class="progress-text"> |
|||
<text>0</text> |
|||
<text>50人</text> |
|||
<text>100人</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="main_section"> |
|||
<view class="tag_section"> |
|||
<view :class="['left',tagType=='1'?'select':'']" @click="changeTag('1')">统计分析</view> |
|||
<view :class="['right',tagType=='2'?'select':'']" @click="changeTag('2')">统计排名</view> |
|||
</view> |
|||
|
|||
<!-- 销售分析--> |
|||
<view class="section_box_1" v-if="tagType=='1'"> |
|||
<view class="left"> |
|||
<qiun-data-charts |
|||
type="funnel" |
|||
:opts="opts_2" |
|||
:chartData="chartData_2" |
|||
/> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="item"> |
|||
<view class="title" style="color: #12E7E8;"> |
|||
已分配<text>({{infoData.num_1_rate}}%)</text> |
|||
</view> |
|||
<view class="title" style="color: #12E7E8;"> |
|||
{{infoData.num_1}}<text>人</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="item"> |
|||
<view class="title" style="color: #4DA3FF;"> |
|||
未分配<text>({{infoData.num_2_rate}}%)</text> |
|||
</view> |
|||
<view class="title" style="color: #4DA3FF;"> |
|||
{{infoData.num_2}}<text>人</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="item"> |
|||
<view class="title" style="color: #FFCB31;"> |
|||
本周拉新<text>({{infoData.num_3_rate}}%)</text> |
|||
</view> |
|||
<view class="title" style="color: #FFCB31;"> |
|||
{{infoData.total_1}}<text>人</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 销售排名--> |
|||
<view class="section_box_2" v-else> |
|||
<view class="itme" v-for="(v,k) in infoData.staff_list" :key="k"> |
|||
<view class="title">{{k+1}} {{v.name}}</view> |
|||
<view class="money">{{v.goal}}人</view> |
|||
<view class="plan"> |
|||
<fui-progress :percent="getPercent(v.wx_yj,v.goal)" height="15" radius="100" background="#e4e4e4" activeColor="#4bced0"></fui-progress> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 销售人员展示--> |
|||
<view v-else> |
|||
<view class="count_section"> |
|||
<view class="title_box">业绩统计</view> |
|||
<view class="box_1"> |
|||
<view class="left"> |
|||
<view class="charts-box"> |
|||
<qiun-data-charts |
|||
type="ring" |
|||
:opts="opts" |
|||
:chartData="chartData" |
|||
/> |
|||
</view> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="title">已成交</view> |
|||
<view class="content"> |
|||
<text class="strong">{{infoData.num_1}}人</text> |
|||
</view> |
|||
<view class="title">未成交</view> |
|||
<view class="content"> |
|||
<text class="strong">{{infoData.num_2}}人</text> |
|||
<!-- <text>较上月</text>--> |
|||
</view> |
|||
|
|||
<view class="legeng"> |
|||
<view class="item"> |
|||
<view class="piece" style="background-color: #45c59f;"></view> |
|||
<view class="lable">已成交</view> |
|||
|
|||
<view class="item"> |
|||
<view class="piece" style="background-color:#02a7f0;"></view> |
|||
<view class="lable">未成交</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="main_section"> |
|||
<view class="tag_section"> |
|||
<view :class="['left',tagType=='1'?'select':'']" @click="changeTag('1')">统计分析</view> |
|||
<view :class="['right',tagType=='2'?'select':'']" @click="changeTag('2')">统计排名</view> |
|||
</view> |
|||
|
|||
<!-- 销售分析--> |
|||
<view class="section_box_1" v-if="tagType=='1'"> |
|||
<view class="left"> |
|||
<qiun-data-charts |
|||
type="funnel" |
|||
:opts="opts_2" |
|||
:chartData="chartData_2" |
|||
/> |
|||
</view> |
|||
<view class="right"> |
|||
<view class="item"> |
|||
<view class="title" style="color: #12E7E8;"> |
|||
已成交<text>({{infoData.num_1_rate}}%)</text> |
|||
</view> |
|||
<view class="title" style="color: #12E7E8;"> |
|||
{{infoData.num_1}}<text>人</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="item"> |
|||
<view class="title" style="color: #4DA3FF;"> |
|||
未成交<text>({{infoData.num_2_rate}}%)</text> |
|||
</view> |
|||
<view class="title" style="color: #4DA3FF;"> |
|||
{{infoData.num_2}}<text>人</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="item"> |
|||
<view class="title" style="color: #FFCB31;"> |
|||
本周分配<text>({{infoData.num_3_rate}}%)</text> |
|||
</view> |
|||
<view class="title" style="color: #FFCB31;"> |
|||
{{infoData.total_1}}<text>人</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 销售排名--> |
|||
<view class="section_box_2" v-else> |
|||
<view class="itme" v-for="(v,k) in infoData.staff_list" :key="k"> |
|||
<view class="title">{{k+1}} {{v.name}}</view> |
|||
<view class="money">{{v.goal}}人</view> |
|||
<view class="plan"> |
|||
<fui-progress :percent="getPercent(v.wx_yj,v.goal)" height="15" radius="100" background="#e4e4e4" activeColor="#4bced0"></fui-progress> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
|
|||
<!-- 底部导航--> |
|||
<AQTabber/> |
|||
</view> |
|||
</template> |
|||
|
|||
|
|||
|
|||
<script> |
|||
import apiRoute from '@/api/apiRoute.js'; |
|||
// import marketApi from '@/api/market.js'; |
|||
import AQTabber from "@/components/AQ/AQTabber.vue" |
|||
|
|||
|
|||
export default { |
|||
components: { |
|||
AQTabber, |
|||
}, |
|||
data() { |
|||
return { |
|||
|
|||
infoData:{ |
|||
staff_list:[],//销售排行 |
|||
},//详情数据 |
|||
|
|||
//统计图相关 |
|||
chartData: {}, |
|||
opts: { |
|||
rotate: false, // 是否旋转图表 |
|||
rotateLock: false, // 是否锁定旋转 |
|||
color: [ |
|||
"#e9e9e9", // 颜色1:未完成 |
|||
"#02a7f0", // 颜色2:续费 |
|||
"#45c59f", // 颜色3:新签 |
|||
], |
|||
padding: [0, 0, 0, 0], // 图表内边距 [上, 右, 下, 左] |
|||
dataLabel: true, // 是否显示数据标签 |
|||
enableScroll: false, // 是否启用滚动 |
|||
legend: { |
|||
show: false, // 是否显示图例 |
|||
// position: "right", // 图例位置 |
|||
// lineHeight: 25 // 图例行高 |
|||
}, |
|||
title: { |
|||
name: "本周分析", // 主标题文本 |
|||
fontSize: 16, // 主标题字体大小 |
|||
color: "#666666" // 主标题颜色 |
|||
}, |
|||
subtitle: { |
|||
name: "0%", // 副标题文本 |
|||
fontSize: 18, // 副标题字体大小 |
|||
color: "#7cb5ec" // 副标题颜色 |
|||
}, |
|||
extra: { |
|||
ring: { |
|||
ringWidth: 17, // 环形图宽度 |
|||
activeOpacity: 0.5, // 激活状态透明度 |
|||
activeRadius: 5, // 启用Tooltip点击时,突出部分的宽度(最大值不得超过labelWidth) |
|||
offsetAngle: 0, // 起始角度偏移 |
|||
labelWidth: 1, // 标签宽度 |
|||
border: true, // 是否显示边框 |
|||
customRadius:68,//自定义半径(一般不需要传值,饼图会自动计算半径,自定义半径可能会导致显示图表显示不全) |
|||
borderWidth: 2, // 分割线的宽度 |
|||
borderColor: "#fff" // 边框颜色 |
|||
} |
|||
} |
|||
}, |
|||
|
|||
//新客签到进度条统计 |
|||
progress: 50, // 初始进度为50% |
|||
box_2_show: false,//新客签到进度条统计|true=显示,false=隐藏 |
|||
|
|||
tagType:'1',//1=销售分析,2=销售排名 |
|||
|
|||
//销售分析统计图 |
|||
chartData_2: {}, |
|||
opts_2: { |
|||
// 颜色数组,用于图表的系列颜色 |
|||
// color: ["#12E7E8","#4DA3FF","#FFCB31"], |
|||
// 内边距,顺序为上、右、下、左 |
|||
padding: [0,0,0,0], |
|||
// 是否启用滚动,false 表示不启用 |
|||
enableScroll: false, |
|||
legend:{ |
|||
show:true// 是否显示图例标识 |
|||
}, |
|||
// 额外配置项 |
|||
extra: { |
|||
// 漏斗图配置 |
|||
funnel: { |
|||
// 激活状态下的透明度 |
|||
activeOpacity: 0.3, |
|||
// 激活状态下的宽度 |
|||
activeWidth: 10, |
|||
// 是否显示边框 |
|||
border: true, |
|||
// 边框宽度 |
|||
borderWidth: 2, |
|||
// 边框颜色 |
|||
borderColor: "#FFFFFF", |
|||
// 填充透明度 |
|||
fillOpacity: 1, |
|||
// 标签对齐方式,left 表示左对齐 |
|||
labelAlign: "right", |
|||
// 漏斗图类型,pyramid 表示金字塔型 |
|||
type: "pyramid" |
|||
} |
|||
} |
|||
}, |
|||
|
|||
userInfo: {},//当前登录的用户信息 |
|||
} |
|||
}, |
|||
onLoad() {}, |
|||
onShow() { |
|||
this.init() |
|||
}, |
|||
methods: { |
|||
|
|||
async init(){ |
|||
await this.getUserInfo() |
|||
await this.getPerformance() |
|||
}, |
|||
|
|||
//获取用户信息 |
|||
async getUserInfo(){ |
|||
let res = await apiRoute.getPersonnelInfo({}) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
this.userInfo = res.data |
|||
}, |
|||
|
|||
//获取统计信息 |
|||
async getPerformance(){ |
|||
let role_key_arr = this.userInfo.role_key_arr.join(',') |
|||
let params = { |
|||
personnel_id:this.userInfo.id,//员工表id |
|||
role_key_arr: role_key_arr, // 角色key 转换数组为字符串,若为空则赋予空字符串 |
|||
} |
|||
let res= await apiRoute.xs_statisticsMarketData(params) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}); |
|||
return |
|||
} |
|||
// console.log('xx',res) |
|||
this.infoData = res.data |
|||
|
|||
if(this.infoData.role_type == 'market_type'){ |
|||
//市场人员 |
|||
//环形统计图相关 |
|||
let chartData_1 = { |
|||
series: [ |
|||
{ |
|||
data: [ |
|||
{ |
|||
"name": "已分配", |
|||
"value": this.infoData.num_1_rate, |
|||
"labelShow": false |
|||
}, |
|||
{ |
|||
"name": "未分配", |
|||
"value": this.infoData.num_2_rate, |
|||
"labelShow": false |
|||
}, |
|||
{ |
|||
"name": "总人数", |
|||
"value": this.infoData.num_3_rate, |
|||
"labelShow": false |
|||
}, |
|||
] |
|||
} |
|||
] |
|||
}; |
|||
this.chartData = JSON.parse(JSON.stringify(chartData_1)); |
|||
this.opts.subtitle = { |
|||
name: `${this.infoData.num_4_rate}%`, // 副标题文本 |
|||
fontSize: 18, // 副标题字体大小 |
|||
color: "#7cb5ec" // 副标题颜色 |
|||
} |
|||
|
|||
//销售分析统计图相关 |
|||
let chartDataB = { |
|||
series: [ |
|||
{ |
|||
data: [ |
|||
{ |
|||
"name": "本周拉新", // 数据项的名称,表示当前数据的分类为“跟进中” |
|||
"centerText": this.infoData.total_1, // 中心显示的文本内容,这里为空字符串,表示不显示中心文本 |
|||
"value": this.infoData.num_3_rate, // 数据项的值,表示“跟进中”的数量为50 |
|||
// "labelText":'跟进中' |
|||
"labelShow":false, |
|||
"color": "#FFCB31", // 自定义颜色 |
|||
}, |
|||
{ |
|||
"name": "未分配", |
|||
"centerText": this.infoData.num_2, |
|||
"value": this.infoData.num_2_rate, |
|||
// "labelText":"试听" |
|||
"labelShow":false, |
|||
"color": "#4DA3FF", // 自定义颜色 |
|||
}, |
|||
{ |
|||
"name": "已分配", |
|||
"centerText": this.infoData.num_1, |
|||
"value": this.infoData.num_1_rate, |
|||
// "labelText":"已成交" |
|||
"labelShow":false, |
|||
"color": "#12E7E8", // 自定义颜色 |
|||
} |
|||
] |
|||
} |
|||
] |
|||
}; |
|||
this.chartData_2 = JSON.parse(JSON.stringify(chartDataB)); |
|||
}else{ |
|||
//环形统计图相关 |
|||
let chartData_1 = { |
|||
series: [ |
|||
{ |
|||
data: [ |
|||
{ |
|||
"name": "已成交", |
|||
"value": this.infoData.num_1_rate, |
|||
"labelShow": false |
|||
}, |
|||
{ |
|||
"name": "未成交", |
|||
"value": this.infoData.num_2_rate, |
|||
"labelShow": false |
|||
}, |
|||
{ |
|||
"name": "总人数", |
|||
"value": this.infoData.num_3_rate, |
|||
"labelShow": false |
|||
}, |
|||
] |
|||
} |
|||
] |
|||
}; |
|||
this.chartData = JSON.parse(JSON.stringify(chartData_1)); |
|||
this.opts.subtitle = { |
|||
name: `${this.infoData.num_4_rate}%`, // 副标题文本 |
|||
fontSize: 18, // 副标题字体大小 |
|||
color: "#7cb5ec" // 副标题颜色 |
|||
} |
|||
|
|||
//销售分析统计图相关 |
|||
let chartDataB = { |
|||
series: [ |
|||
{ |
|||
data: [ |
|||
{ |
|||
"name": "本周成交", // 数据项的名称,表示当前数据的分类为“跟进中” |
|||
"centerText": this.infoData.total_1, // 中心显示的文本内容,这里为空字符串,表示不显示中心文本 |
|||
"value": this.infoData.num_3_rate, // 数据项的值,表示“跟进中”的数量为50 |
|||
// "labelText":'跟进中' |
|||
"labelShow":false, |
|||
"color": "#FFCB31", // 自定义颜色 |
|||
}, |
|||
{ |
|||
"name": "未成交", |
|||
"centerText": this.infoData.num_2, |
|||
"value": this.infoData.num_2_rate, |
|||
// "labelText":"试听" |
|||
"labelShow":false, |
|||
"color": "#4DA3FF", // 自定义颜色 |
|||
}, |
|||
{ |
|||
"name": "已成交", |
|||
"centerText": this.infoData.num_1, |
|||
"value": this.infoData.num_1_rate, |
|||
// "labelText":"已成交" |
|||
"labelShow":false, |
|||
"color": "#12E7E8", // 自定义颜色 |
|||
} |
|||
] |
|||
} |
|||
] |
|||
}; |
|||
this.chartData_2 = JSON.parse(JSON.stringify(chartDataB)); |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
}, |
|||
|
|||
//计算百分比取整数 |
|||
getPercent(num1,total){ |
|||
// 计算百分比并取整数 |
|||
if(!total){ |
|||
return 0 |
|||
} |
|||
|
|||
let num_percent = (num1 / total) * 100; |
|||
if(num_percent <= 0){ |
|||
num_percent = 0 |
|||
}else{ |
|||
num_percent = Math.ceil((num1 / total) * 100); |
|||
} |
|||
// console.log('qqq',[num_percent,num1,total]) |
|||
return num_percent |
|||
}, |
|||
|
|||
|
|||
|
|||
//切换tag |
|||
changeTag(type){ |
|||
this.tagType = type |
|||
}, |
|||
|
|||
//打开到课率统计 |
|||
openViewArrivalStatistics(){ |
|||
this.$navigateTo({ |
|||
url: '/pages/market/my/arrival_statistics' |
|||
}) |
|||
}, |
|||
|
|||
//打开即将到期 |
|||
openViewDueSoon(){ |
|||
this.$navigateTo({ |
|||
url: '/pages/market/my/due_soon' |
|||
}) |
|||
}, |
|||
|
|||
//打开授课统计 |
|||
openViewSchoolingStatistics(){ |
|||
this.$navigateTo({ |
|||
url: '/pages/market/my/schooling_statistics' |
|||
}) |
|||
}, |
|||
|
|||
//打开意见反馈 |
|||
openViewFeedback(){ |
|||
this.$navigateTo({ |
|||
url: '/pages/common/feedback' |
|||
}) |
|||
}, |
|||
|
|||
//打开个人资料 |
|||
openViewMyInfo(){ |
|||
this.$navigateTo({ |
|||
url: '/pages/market/my/info' |
|||
}) |
|||
}, |
|||
|
|||
//打开企业信息 |
|||
openViewFirmInfo(){ |
|||
this.$navigateTo({ |
|||
url: '/pages/market/my/firm_info' |
|||
}) |
|||
}, |
|||
|
|||
|
|||
//打开设置 |
|||
openViewSetUp(){ |
|||
this.$navigateTo({ |
|||
url: '/pages/market/my/set_up' |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
|
|||
|
|||
.main_box{ |
|||
background: #292929; |
|||
min-height: 100%; |
|||
} |
|||
|
|||
//自定义导航栏 |
|||
.navbar_section{ |
|||
border: 1px solid #292929; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
background: #292929; |
|||
position: relative; |
|||
.title{ |
|||
padding: 40rpx 0rpx; |
|||
|
|||
/* 小程序端样式 */ |
|||
// #ifdef MP-WEIXIN |
|||
padding: 80rpx 0rpx; |
|||
// #endif |
|||
|
|||
font-size: 30rpx; |
|||
color: #fff; |
|||
} |
|||
|
|||
.statistics-btn { |
|||
position: absolute; |
|||
right: 20rpx; |
|||
background-color: #29D3B4; |
|||
padding: 10rpx 20rpx; |
|||
border-radius: 30rpx; |
|||
font-size: 24rpx; |
|||
color: #fff; |
|||
} |
|||
} |
|||
|
|||
|
|||
//统计信息 |
|||
.count_section{ |
|||
padding: 20rpx 46rpx; |
|||
padding-bottom: 60rpx; |
|||
background-color: #434544; |
|||
color: #fff; |
|||
.title_box{ |
|||
font-size: 26rpx; |
|||
} |
|||
.box_1{ |
|||
margin-top: 25rpx; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
gap: 30rpx; |
|||
.left{ |
|||
width: 280rpx; /* 设置宽度为 280rpx */ |
|||
height: 280rpx; /* 设置高度为 280rpx */ |
|||
.charts-box { |
|||
width: 280rpx; /* 设置宽度为 280rpx */ |
|||
height: 280rpx; /* 设置高度为 280rpx */ |
|||
} |
|||
} |
|||
.right{ |
|||
font-size: 24rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 20rpx; |
|||
.title{} |
|||
.content{ |
|||
display: flex; |
|||
gap: 40rpx; |
|||
.strong{ |
|||
font-size: 30rpx; |
|||
} |
|||
.text{ |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
.legeng{ |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 50rpx; |
|||
.item{ |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 20rpx; |
|||
.piece{ |
|||
|
|||
width: 20rpx; |
|||
height: 20rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
|||
// 其他样式省略 |
|||
.box_2 { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
margin-top: 20rpx; |
|||
|
|||
.progress-container { |
|||
position: relative; |
|||
width: 80%; |
|||
height: 4rpx; |
|||
background-color: #ccc; |
|||
border-radius: 2rpx; |
|||
//overflow: hidden; |
|||
margin-bottom: 10rpx; |
|||
|
|||
.progress-bar { |
|||
height: 100%; |
|||
background-color: #45c59f; |
|||
border-radius: 2rpx; |
|||
} |
|||
.dian{ |
|||
position: absolute; |
|||
top: -9rpx; |
|||
left: 0rpx; |
|||
width: 18rpx; |
|||
height: 18rpx; |
|||
border-radius: 50%; |
|||
background-color: #fff; |
|||
|
|||
} |
|||
} |
|||
|
|||
.progress-text { |
|||
margin-left: 5%; |
|||
width: 85%; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
text { |
|||
font-size: 26rpx; |
|||
color: #fff; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.main_section{ |
|||
background: #292929 100%; |
|||
padding: 0 24rpx; |
|||
padding-top: 40rpx; |
|||
padding-bottom: 150rpx; |
|||
font-size: 24rpx; |
|||
color: #333333; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 22rpx; |
|||
|
|||
.tag_section{ |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
view{ |
|||
border: 1px solid #969696; |
|||
width: 258rpx; |
|||
height: 72rpx; |
|||
line-height: 72rpx; |
|||
background-color: #292929; |
|||
text-align: center; |
|||
font-size: 26rpx; |
|||
color: #fff; |
|||
} |
|||
.left{ |
|||
border-radius: 22rpx 0rpx 0rpx 22rpx; |
|||
} |
|||
.right{ |
|||
border-radius: 0rpx 22rpx 22rpx 0rpx; |
|||
} |
|||
.select{ |
|||
background-color: #fff; |
|||
color: #29D3B4; |
|||
} |
|||
} |
|||
|
|||
.section_box_1{ |
|||
margin-top: 38rpx; |
|||
padding: 66rpx 14rpx; |
|||
border-radius: 12rpx; |
|||
background-color: #434544FF; |
|||
color: #d9dada; |
|||
font-size: 26rpx; |
|||
text-align: center; |
|||
height: 600rpx; |
|||
|
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
.left{ |
|||
width: 70%; |
|||
} |
|||
.right{ |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 20rpx; |
|||
.item{ |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 10rpx; |
|||
.title{ |
|||
font-size: 26rpx; |
|||
text-align: left; |
|||
text{ |
|||
margin-left: 5rpx; |
|||
color: #d9dada; |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
.section_box_2{ |
|||
color: #fff; |
|||
margin-top: 38rpx; |
|||
padding: 20rpx 42rpx; |
|||
background-color: #434544; |
|||
border-radius: 12rpx; |
|||
font-size: 26rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 20rpx; |
|||
.itme{ |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 15rpx; |
|||
.money{ |
|||
display: flex; |
|||
justify-content: flex-end; |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
} |
|||
|
|||
|
|||
</style> |
|||
@ -1,390 +0,0 @@ |
|||
<template> |
|||
<view class="assemble"> |
|||
<view style="height: 20rpx;"></view> |
|||
<!-- 市场人员展示--> |
|||
<view class="div-style"> |
|||
<view style="height: 38vh;"> |
|||
<view style="display: flex;align-items: center;padding: 20rpx 0 0 20rpx;"> |
|||
<view> |
|||
<image :src="$util.img('/uniapp_src/static/images/index/danlan.png')" class="drop-image"> |
|||
</image> |
|||
</view> |
|||
<view class="title">本月业绩</view> |
|||
</view> |
|||
<view class="coach-message"> |
|||
<view class="left1"> |
|||
<view style="padding: 20rpx 0;"> |
|||
<view style="display: flex;align-items: center;"> |
|||
<view style="padding: 12rpx;"> |
|||
<image :src="$util.img('/uniapp_src/static/images/index/huang.png')" |
|||
class="drop-image-x"></image> |
|||
</view> |
|||
<view class="title-x">资源总数</view> |
|||
</view> |
|||
<view class="title-x1">{{infoData.month.new_total}}人</view> |
|||
</view> |
|||
|
|||
<view> |
|||
<view style="display: flex;align-items: center;"> |
|||
<view style="padding: 12rpx;"> |
|||
<image :src="$util.img('/uniapp_src/static/images/index/lvs.png')" |
|||
class="drop-image-x"></image> |
|||
</view> |
|||
<view class="title-x">已分配</view> |
|||
</view> |
|||
<view class="title-x1">{{infoData.month.new_total}}人</view> |
|||
</view> |
|||
|
|||
<view> |
|||
<view style="display: flex;align-items: center;"> |
|||
<view style="padding: 12rpx;"> |
|||
<image :src="$util.img('/uniapp_src/static/images/index/shenlan.png')" |
|||
class="drop-image-x"></image> |
|||
</view> |
|||
<view class="title-x">昨日新增</view> |
|||
</view> |
|||
<view class="title-x1">{{infoData.month.yesterday_new}}人</view> |
|||
</view> |
|||
|
|||
<view> |
|||
<view style="display: flex;align-items: center;"> |
|||
<view style="padding: 12rpx;"> |
|||
<image :src="$util.img('/uniapp_src/static/images/index/lan.png')" |
|||
class="drop-image-x"></image> |
|||
</view> |
|||
<view class="title-x">今日新增</view> |
|||
</view> |
|||
<view class="title-x1">{{infoData.month.today_new}}人</view> |
|||
</view> |
|||
</view> |
|||
<!-- 统计图--> |
|||
<view class="right1"> |
|||
<view style="text-align: center;">{{infoData.date_range}}</view> |
|||
<view class="statistics_box"> |
|||
|
|||
<view class="item"> |
|||
<view class="box"> |
|||
<view class="progress-bar" |
|||
:style="{ height: `${infoData.month.yesterday_new_rate}%`, background: '#f59a23' }"> |
|||
</view> |
|||
<view class="ratio" |
|||
:style="{ color: infoData.month.yesterday_new_rate <= 0 ? '#333333' : '#000' }"> |
|||
{{ infoData.month.yesterday_new_rate }}% |
|||
</view> |
|||
</view> |
|||
<view class="title">昨日</view> |
|||
</view> |
|||
|
|||
<view class="item"> |
|||
<view class="box"> |
|||
<view class="progress-bar" |
|||
:style="{ height: `${infoData.month.assigned_sales_rate}%`, background: '#039f64' }"> |
|||
</view> |
|||
<view class="ratio" |
|||
:style="{ color: infoData.month.assigned_sales_rate <= 0 ? '#333333' : '#000' }"> |
|||
{{ infoData.month.assigned_sales_rate }}% |
|||
</view> |
|||
</view> |
|||
<view class="title">分配</view> |
|||
</view> |
|||
|
|||
<view class="item"> |
|||
<view class="box"> |
|||
<view class="progress-bar" |
|||
:style="{ height: `${infoData.month.today_new_rate}%`, background: '#4066f2' }"> |
|||
</view> |
|||
<view class="ratio" |
|||
:style="{ color: infoData.month.today_new_rate <= 0 ? '#333333' : '#000' }"> |
|||
{{ infoData.month.today_new_rate }}% |
|||
</view> |
|||
</view> |
|||
<view class="title">今日</view> |
|||
</view> |
|||
|
|||
</view> |
|||
</view> |
|||
|
|||
</view> |
|||
</view> |
|||
|
|||
<view style="width: 90%;background: #EFF3F8;height: 4rpx;margin: auto;"></view> |
|||
|
|||
<view style="height: 38vh;"> |
|||
<view style="display: flex;align-items: center;padding: 20rpx 0 0 20rpx;"> |
|||
<view> |
|||
<image :src="$util.img('/uniapp_src/static/images/index/danlv.png')" class="drop-image"></image> |
|||
</view> |
|||
<view class="title">个人业绩</view> |
|||
</view> |
|||
|
|||
<view class="coach-message"> |
|||
<view class="this_month"> |
|||
<view style="padding: 20rpx 0;display: flex;justify-content: space-between;"> |
|||
<view style="width: 48%;"> |
|||
<view style="display: flex;align-items: center;"> |
|||
<view style="padding: 12rpx;"> |
|||
<image :src="$util.img('/uniapp_src/static/images/index/danlv.png')" |
|||
class="drop-image-x"></image> |
|||
</view> |
|||
<view class="title-x">今日新增资源</view> |
|||
</view> |
|||
<view class="title-x1">{{infoData.last_month.xzzy}}人</view> |
|||
</view> |
|||
|
|||
<view style="width: 48%;"> |
|||
<view style="display: flex;align-items: center;"> |
|||
<view style="padding: 12rpx;"> |
|||
<image :src="$util.img('/uniapp_src/static/images/index/danlv.png')" |
|||
class="drop-image-x"></image> |
|||
</view> |
|||
<view class="title-x">今日业绩收入</view> |
|||
</view> |
|||
<view class="title-x1">{{infoData.last_month.yjsr}}元</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view style="padding: 20rpx 0;display: flex;justify-content: space-between;"> |
|||
<view style="width: 48%;"> |
|||
<view style="display: flex;align-items: center;"> |
|||
<view style="padding: 12rpx;"> |
|||
<image :src="$util.img('/uniapp_src/static/images/index/danlv.png')" |
|||
class="drop-image-x"></image> |
|||
</view> |
|||
<view class="title-x">历史关单数量</view> |
|||
</view> |
|||
<view class="title-x1">{{infoData.last_month.gdsl}}人</view> |
|||
</view> |
|||
|
|||
<view style="width: 48%;"> |
|||
<view style="display: flex;align-items: center;"> |
|||
<view style="padding: 12rpx;"> |
|||
<image :src="$util.img('/uniapp_src/static/images/index/danlv.png')" |
|||
class="drop-image-x"></image> |
|||
</view> |
|||
<view class="title-x">其他奖励</view> |
|||
</view> |
|||
<view class="title-x1">{{infoData.last_month.qtjl}}元</view> |
|||
</view> |
|||
|
|||
|
|||
</view> |
|||
<view style="padding: 20rpx 0;display: flex;justify-content: space-between;"> |
|||
<view style="width: 48%;"> |
|||
<view style="display: flex;align-items: center;"> |
|||
<view style="padding: 12rpx;"> |
|||
<image :src="$util.img('/uniapp_src/static/images/index/danlv.png')" |
|||
class="drop-image-x"></image> |
|||
</view> |
|||
<view class="title-x">本月提成</view> |
|||
</view> |
|||
<view class="title-x1">{{infoData.last_month.bytc}}元</view> |
|||
</view> |
|||
|
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<AQTabber /> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import apiRoute from '@/api/apiRoute.js'; |
|||
|
|||
import AQTabber from "@/components/AQ/AQTabber.vue" |
|||
|
|||
export default { |
|||
components: { |
|||
AQTabber, |
|||
}, |
|||
data() { |
|||
return { |
|||
infoData: {}, //详情 |
|||
|
|||
userInfo: {}, //当前登录的用户信息 |
|||
} |
|||
}, |
|||
onShow() { |
|||
this.init() |
|||
}, |
|||
methods: { |
|||
async init() { |
|||
await this.getUserInfo() |
|||
await this.getXsIndex() |
|||
}, |
|||
|
|||
//获取用户信息 |
|||
async getUserInfo() { |
|||
let res = await apiRoute.getPersonnelInfo({}) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
this.userInfo = res.data |
|||
}, |
|||
|
|||
//获取销售首页详情 |
|||
async getXsIndex() { |
|||
let role_key_arr = this.userInfo.role_key_arr.join(',') |
|||
let params = { |
|||
personnel_id: this.userInfo.id, //员工表id |
|||
role_key_arr: role_key_arr, // 角色key 转换数组为字符串,若为空则赋予空字符串 |
|||
} |
|||
let res = await apiRoute.xs_statisticsMarketHome(params) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
this.infoData = res.data |
|||
console.log('统计', this.infoData) |
|||
}, |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
//自定义导航栏 |
|||
.navbar_section { |
|||
border: 1px solid #fff; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
background: #fff; |
|||
|
|||
.title { |
|||
padding: 40rpx 0rpx; |
|||
|
|||
/* 小程序端样式 */ |
|||
// #ifdef MP-WEIXIN |
|||
padding: 80rpx 0rpx; |
|||
// #endif |
|||
|
|||
font-size: 30rpx; |
|||
color: #858585; |
|||
} |
|||
} |
|||
|
|||
.assemble { |
|||
width: 100%; |
|||
height: 100vh; |
|||
background: #292929; |
|||
} |
|||
|
|||
.div-style { |
|||
width: 92%; |
|||
height: 85vh; |
|||
background: #fff; |
|||
border-radius: 16rpx; |
|||
margin: auto; |
|||
} |
|||
|
|||
.coach-message { |
|||
width: 92%; |
|||
margin: 10rpx auto; |
|||
display: flex; |
|||
align-items: center; |
|||
padding-top: 20rpx; |
|||
} |
|||
|
|||
.drop-image { |
|||
width: 50rpx; |
|||
height: 50rpx; |
|||
} |
|||
|
|||
.title { |
|||
font-size: 30rpx; |
|||
color: #7F7F7F; |
|||
padding-left: 20rpx; |
|||
} |
|||
|
|||
.left1 { |
|||
width: 48%; |
|||
height: 95%; |
|||
margin: auto; |
|||
} |
|||
|
|||
.right1 { |
|||
width: 48%; |
|||
height: 95%; |
|||
margin: auto; |
|||
|
|||
.statistics_box { |
|||
margin: auto; |
|||
margin-top: 10rpx; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
|
|||
.item { |
|||
width: 90rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
|
|||
.box { |
|||
width: 100%; |
|||
height: 328rpx; |
|||
border: 1px solid #ddd; |
|||
border-radius: 6rpx; |
|||
background: #f5f5f5; |
|||
position: relative; |
|||
|
|||
.progress-bar { |
|||
width: 100%; |
|||
height: 0; |
|||
transition: height 0.3s ease; |
|||
position: absolute; |
|||
bottom: 0; |
|||
} |
|||
|
|||
.ratio { |
|||
width: 100%; |
|||
position: absolute; |
|||
bottom: -0rpx; |
|||
font-size: 26rpx; |
|||
text-align: center; |
|||
} |
|||
} |
|||
|
|||
.title { |
|||
margin-top: 5rpx; |
|||
padding: 0; |
|||
font-size: 26rpx; |
|||
color: #999999; |
|||
; |
|||
text-align: center; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.this_month { |
|||
width: 100%; |
|||
height: 95%; |
|||
margin: auto; |
|||
} |
|||
|
|||
.drop-image-x { |
|||
width: 20rpx; |
|||
height: 20rpx; |
|||
} |
|||
|
|||
.title-x { |
|||
font-size: 28rpx; |
|||
color: #7F7F7F; |
|||
padding-left: 20rpx; |
|||
} |
|||
|
|||
.title-x1 { |
|||
font-size: 28rpx; |
|||
color: #333333; |
|||
padding-left: 60rpx; |
|||
} |
|||
</style> |
|||
@ -1,207 +0,0 @@ |
|||
<!--企业信息--> |
|||
<template> |
|||
<view class="assemble"> |
|||
<view style="height: 30rpx;"></view> |
|||
|
|||
<scroll-view |
|||
class="ul" |
|||
scroll-y="true" |
|||
:lower-threshold="lowerThreshold" |
|||
@scrolltolower="loadMoreData_1" |
|||
style="height: 80vh;" |
|||
> |
|||
<view class="li" v-for="(v,k) in tableList" :key="k"> |
|||
<!--企业图--> |
|||
<view class="section_1"> |
|||
<image class="pic" v-if="v.campus_preview_image" :src="v.campus_preview_image" mode="aspectFit"></image> |
|||
</view> |
|||
|
|||
<view class="title_section">基本信息</view> |
|||
<view class="section_2"> |
|||
<view class="item"> |
|||
<view class="title">企业名称</view> |
|||
<view class="content">{{v.campus_name}}</view> |
|||
</view> |
|||
|
|||
<view class="item"> |
|||
<view class="title">企业地址</view> |
|||
<view class="content">{{v.campus_address}}</view> |
|||
</view> |
|||
</view> |
|||
|
|||
|
|||
<view class="title_section">企业地图</view> |
|||
<view class="section_3"> |
|||
<view class="map_box"> |
|||
<map |
|||
:id="`shopMap_${k}`" |
|||
:latitude="v.campus_coordinates_arr.lat" |
|||
:longitude="v.campus_coordinates_arr.lng" |
|||
:markers="getMarkers(k,v)" |
|||
:scale="15" |
|||
:show-location="false" |
|||
style="width: 90%; height: 400rpx;" |
|||
></map> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="title_section">企业介绍</view> |
|||
<view class="section_4"> |
|||
<view class="html" v-html="v. |
|||
campus_introduction"></view> |
|||
</view> |
|||
</view> |
|||
</scroll-view> |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import apiRoute from '@/api/apiRoute.js'; |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
dataInfo:{},//企业信息 |
|||
|
|||
loading:false,//加载状态 |
|||
lowerThreshold: 100,//距离底部多远触发 |
|||
isReachedBottom: false,//防止重复加载|true=不可加载|false=可加载 |
|||
//筛选条件 |
|||
filteredData:{ |
|||
personnel_id:'', |
|||
}, |
|||
//数据列表 |
|||
tableList:[], |
|||
|
|||
//地图相关 |
|||
//地图控件 |
|||
mapControls:{ |
|||
position:{ |
|||
|
|||
}, |
|||
} |
|||
} |
|||
}, |
|||
onShow(){ |
|||
this.init() |
|||
}, |
|||
methods: { |
|||
//初始化 |
|||
async init(){ |
|||
await this.getUserInfo() |
|||
await this.getPersonnelCampus() |
|||
}, |
|||
|
|||
//获取用户信息 |
|||
async getUserInfo(){ |
|||
let res = await apiRoute.getPersonnelInfo({}) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
this.filteredData.personnel_id = res.data.id//员工id |
|||
|
|||
}, |
|||
|
|||
//获取校区信息 |
|||
async getPersonnelCampus(){ |
|||
let params = {...this.filteredData} |
|||
let res = await apiRoute.common_getPersonnelCampus(params) |
|||
if(res.code != 1){ |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
this.tableList = res.data |
|||
console.log(123,this.tableList) |
|||
}, |
|||
|
|||
// 获取标记点 |
|||
getMarkers(id,item) { |
|||
return [{ |
|||
id: id, |
|||
latitude: item.campus_coordinates_arr.lat, |
|||
longitude: item.campus_coordinates_arr.lng, |
|||
name: item.campus_address, |
|||
iconPath: '/static/icon-img/ding_wei.png' |
|||
}]; |
|||
}, |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.assemble{ |
|||
width: 100%; |
|||
min-height: 100vh; |
|||
background: #333333; |
|||
color: #fff; |
|||
} |
|||
|
|||
.ul{ |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 40rpx; |
|||
.li{ |
|||
border-top: 1px solid #434544; |
|||
.section_1{ |
|||
.pic{ |
|||
width: 100%; |
|||
height: 300rpx; |
|||
} |
|||
} |
|||
.title_section{ |
|||
padding: 20rpx 40rpx; |
|||
color: #fff; |
|||
font-size: 24rpx; |
|||
} |
|||
.section_2{ |
|||
background-color: #434544; |
|||
display: flex; |
|||
flex-direction: column; |
|||
.item{ |
|||
padding: 40rpx; |
|||
padding-left: 40rpx; |
|||
display: flex; |
|||
gap: 30rpx; |
|||
} |
|||
} |
|||
.section_3{ |
|||
padding: 20rpx 22rpx; |
|||
.html{ |
|||
color: #fff; |
|||
} |
|||
.map_box{ |
|||
color: #fff; |
|||
display: flex; |
|||
justify-content: center; |
|||
} |
|||
} |
|||
.section_4{ |
|||
padding: 20rpx 22rpx; |
|||
padding-bottom: 250rpx; |
|||
.html{ |
|||
color: #fff; |
|||
} |
|||
} |
|||
} |
|||
.li:nth-child(1){ |
|||
border: 0px solid #434544; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,177 +0,0 @@ |
|||
<!--合同详情页面--> |
|||
<template> |
|||
<view class="main_box"> |
|||
<!-- 合同基本信息 --> |
|||
<view class="contract_info_card" v-if="contractInfo"> |
|||
<view class="contract_header"> |
|||
<view class="contract_title">{{ contractInfo.title }}</view> |
|||
<view class="contract_status" :class="contractInfo.status"> |
|||
{{ contractInfo.status_text }} |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="contract_details"> |
|||
<view class="detail_item"> |
|||
<view class="detail_label">合同金额</view> |
|||
<view class="detail_value amount">¥{{ contractInfo.amount }}</view> |
|||
</view> |
|||
<view class="detail_item"> |
|||
<view class="detail_label">签订日期</view> |
|||
<view class="detail_value">{{ contractInfo.sign_date }}</view> |
|||
</view> |
|||
<view class="detail_item"> |
|||
<view class="detail_label">有效期</view> |
|||
<view class="detail_value">{{ contractInfo.valid_date }}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 空状态 --> |
|||
<view class="empty_state" v-if="!loading && !contractInfo"> |
|||
<image src="/static/icon-img/empty.png" class="empty_icon"></image> |
|||
<view class="empty_text">暂无合同信息</view> |
|||
</view> |
|||
|
|||
<!-- 加载状态 --> |
|||
<view class="loading_state" v-if="loading"> |
|||
<view class="loading_text">加载中...</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
contractInfo: null, |
|||
loading: false, |
|||
contractId: null, |
|||
childId: null |
|||
} |
|||
}, |
|||
onLoad(options) { |
|||
this.contractId = options.contractId |
|||
this.childId = options.childId |
|||
this.loadContractInfo() |
|||
}, |
|||
methods: { |
|||
async loadContractInfo() { |
|||
// 模拟合同详情数据 |
|||
this.contractInfo = { |
|||
title: '少儿篮球培训合同', |
|||
status: 'active', |
|||
status_text: '有效', |
|||
amount: '2880.00', |
|||
sign_date: '2024-01-01', |
|||
valid_date: '2024-01-01 至 2024-12-31' |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.main_box { |
|||
background: #f8f9fa; |
|||
min-height: 100vh; |
|||
padding: 20rpx; |
|||
} |
|||
|
|||
.contract_info_card { |
|||
background: #fff; |
|||
border-radius: 16rpx; |
|||
padding: 32rpx; |
|||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1); |
|||
|
|||
.contract_header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 32rpx; |
|||
padding-bottom: 24rpx; |
|||
border-bottom: 1px solid #f0f0f0; |
|||
|
|||
.contract_title { |
|||
font-size: 36rpx; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.contract_status { |
|||
font-size: 24rpx; |
|||
padding: 8rpx 16rpx; |
|||
border-radius: 12rpx; |
|||
|
|||
&.active { |
|||
background: rgba(40, 167, 69, 0.1); |
|||
color: #28a745; |
|||
} |
|||
|
|||
&.expired { |
|||
background: rgba(220, 53, 69, 0.1); |
|||
color: #dc3545; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.contract_details { |
|||
.detail_item { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 20rpx 0; |
|||
border-bottom: 1px solid #f8f9fa; |
|||
|
|||
.detail_label { |
|||
font-size: 28rpx; |
|||
color: #666; |
|||
min-width: 160rpx; |
|||
} |
|||
|
|||
.detail_value { |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
flex: 1; |
|||
text-align: right; |
|||
|
|||
&.amount { |
|||
color: #e67e22; |
|||
font-weight: 600; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.empty_state { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
padding: 120rpx 0; |
|||
|
|||
.empty_icon { |
|||
width: 160rpx; |
|||
height: 160rpx; |
|||
margin-bottom: 32rpx; |
|||
opacity: 0.3; |
|||
} |
|||
|
|||
.empty_text { |
|||
font-size: 28rpx; |
|||
color: #999; |
|||
} |
|||
} |
|||
|
|||
.loading_state { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
padding: 60rpx 0; |
|||
|
|||
.loading_text { |
|||
font-size: 28rpx; |
|||
color: #666; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,187 +0,0 @@ |
|||
<!--课程详情页面--> |
|||
<template> |
|||
<view class="main_box"> |
|||
<!-- 课程基本信息 --> |
|||
<view class="course_info_card" v-if="courseInfo"> |
|||
<view class="course_header"> |
|||
<view class="course_name">{{ courseInfo.course_name }}</view> |
|||
<view class="course_status" :class="courseInfo.status"> |
|||
{{ courseInfo.status === 'active' ? '进行中' : '已结束' }} |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="course_details"> |
|||
<view class="detail_item"> |
|||
<view class="detail_label">授课教师</view> |
|||
<view class="detail_value">{{ courseInfo.teacher_name }}</view> |
|||
</view> |
|||
<view class="detail_item"> |
|||
<view class="detail_label">上课校区</view> |
|||
<view class="detail_value">{{ courseInfo.campus_name }}</view> |
|||
</view> |
|||
<view class="detail_item"> |
|||
<view class="detail_label">上课时间</view> |
|||
<view class="detail_value">{{ courseInfo.schedule_time }}</view> |
|||
</view> |
|||
<view class="detail_item"> |
|||
<view class="detail_label">课程进度</view> |
|||
<view class="detail_value">{{ courseInfo.progress }}</view> |
|||
</view> |
|||
<view class="detail_item" v-if="courseInfo.next_class"> |
|||
<view class="detail_label">下节课时间</view> |
|||
<view class="detail_value next_class">{{ courseInfo.next_class }}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 空状态 --> |
|||
<view class="empty_state" v-if="!loading && !courseInfo"> |
|||
<image src="/static/icon-img/empty.png" class="empty_icon"></image> |
|||
<view class="empty_text">暂无课程信息</view> |
|||
</view> |
|||
|
|||
<!-- 加载状态 --> |
|||
<view class="loading_state" v-if="loading"> |
|||
<view class="loading_text">加载中...</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
courseInfo: null, |
|||
loading: false, |
|||
courseId: null, |
|||
childId: null |
|||
} |
|||
}, |
|||
onLoad(options) { |
|||
this.courseId = options.courseId |
|||
this.childId = options.childId |
|||
this.loadCourseInfo() |
|||
}, |
|||
methods: { |
|||
async loadCourseInfo() { |
|||
// 这里可以添加具体的课程详情获取逻辑 |
|||
// 暂时使用模拟数据 |
|||
this.courseInfo = { |
|||
course_name: '少儿篮球训练', |
|||
teacher_name: '王教练', |
|||
campus_name: '总部校区', |
|||
schedule_time: '周六 09:00-10:30', |
|||
progress: '8/12节', |
|||
status: 'active', |
|||
next_class: '2024-01-20 09:00' |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.main_box { |
|||
background: #f8f9fa; |
|||
min-height: 100vh; |
|||
padding: 20rpx; |
|||
} |
|||
|
|||
.course_info_card { |
|||
background: #fff; |
|||
border-radius: 16rpx; |
|||
padding: 32rpx; |
|||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1); |
|||
|
|||
.course_header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 32rpx; |
|||
padding-bottom: 24rpx; |
|||
border-bottom: 1px solid #f0f0f0; |
|||
|
|||
.course_name { |
|||
font-size: 36rpx; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.course_status { |
|||
font-size: 24rpx; |
|||
padding: 8rpx 16rpx; |
|||
border-radius: 12rpx; |
|||
|
|||
&.active { |
|||
background: rgba(41, 211, 180, 0.1); |
|||
color: #29d3b4; |
|||
} |
|||
|
|||
&.inactive { |
|||
background: #f0f0f0; |
|||
color: #999; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.course_details { |
|||
.detail_item { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 20rpx 0; |
|||
border-bottom: 1px solid #f8f9fa; |
|||
|
|||
.detail_label { |
|||
font-size: 28rpx; |
|||
color: #666; |
|||
min-width: 160rpx; |
|||
} |
|||
|
|||
.detail_value { |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
flex: 1; |
|||
text-align: right; |
|||
|
|||
&.next_class { |
|||
color: #29d3b4; |
|||
font-weight: 600; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.empty_state { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
padding: 120rpx 0; |
|||
|
|||
.empty_icon { |
|||
width: 160rpx; |
|||
height: 160rpx; |
|||
margin-bottom: 32rpx; |
|||
opacity: 0.3; |
|||
} |
|||
|
|||
.empty_text { |
|||
font-size: 28rpx; |
|||
color: #999; |
|||
} |
|||
} |
|||
|
|||
.loading_state { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
padding: 60rpx 0; |
|||
|
|||
.loading_text { |
|||
font-size: 28rpx; |
|||
color: #666; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,181 +0,0 @@ |
|||
<!--教学资料详情页面--> |
|||
<template> |
|||
<view class="main_box"> |
|||
<!-- 资料基本信息 --> |
|||
<view class="material_info_card" v-if="materialInfo"> |
|||
<view class="material_header"> |
|||
<view class="material_title">{{ materialInfo.title }}</view> |
|||
<view class="material_type">{{ materialInfo.type }}</view> |
|||
</view> |
|||
|
|||
<view class="material_details"> |
|||
<view class="detail_item"> |
|||
<view class="detail_label">发布时间</view> |
|||
<view class="detail_value">{{ materialInfo.created_at }}</view> |
|||
</view> |
|||
<view class="detail_item"> |
|||
<view class="detail_label">资料类型</view> |
|||
<view class="detail_value">{{ materialInfo.type }}</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="material_content"> |
|||
<view class="content_title">资料内容</view> |
|||
<view class="content_text">{{ materialInfo.content }}</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 空状态 --> |
|||
<view class="empty_state" v-if="!loading && !materialInfo"> |
|||
<image src="/static/icon-img/empty.png" class="empty_icon"></image> |
|||
<view class="empty_text">暂无资料信息</view> |
|||
</view> |
|||
|
|||
<!-- 加载状态 --> |
|||
<view class="loading_state" v-if="loading"> |
|||
<view class="loading_text">加载中...</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
materialInfo: null, |
|||
loading: false, |
|||
materialId: null, |
|||
childId: null |
|||
} |
|||
}, |
|||
onLoad(options) { |
|||
this.materialId = options.materialId |
|||
this.childId = options.childId |
|||
this.loadMaterialInfo() |
|||
}, |
|||
methods: { |
|||
async loadMaterialInfo() { |
|||
// 模拟教学资料详情数据 |
|||
this.materialInfo = { |
|||
title: '篮球基础训练视频', |
|||
type: '视频资料', |
|||
created_at: '2024-01-15 14:30:00', |
|||
content: '这是一套专门为少儿设计的篮球基础训练视频,包含运球、投篮、传球等基本技能的教学内容。' |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.main_box { |
|||
background: #f8f9fa; |
|||
min-height: 100vh; |
|||
padding: 20rpx; |
|||
} |
|||
|
|||
.material_info_card { |
|||
background: #fff; |
|||
border-radius: 16rpx; |
|||
padding: 32rpx; |
|||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1); |
|||
|
|||
.material_header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 32rpx; |
|||
padding-bottom: 24rpx; |
|||
border-bottom: 1px solid #f0f0f0; |
|||
|
|||
.material_title { |
|||
font-size: 36rpx; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.material_type { |
|||
font-size: 24rpx; |
|||
padding: 8rpx 16rpx; |
|||
border-radius: 12rpx; |
|||
background: rgba(41, 211, 180, 0.1); |
|||
color: #29d3b4; |
|||
} |
|||
} |
|||
|
|||
.material_details { |
|||
margin-bottom: 32rpx; |
|||
|
|||
.detail_item { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 20rpx 0; |
|||
border-bottom: 1px solid #f8f9fa; |
|||
|
|||
.detail_label { |
|||
font-size: 28rpx; |
|||
color: #666; |
|||
min-width: 160rpx; |
|||
} |
|||
|
|||
.detail_value { |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
flex: 1; |
|||
text-align: right; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.material_content { |
|||
.content_title { |
|||
font-size: 28rpx; |
|||
font-weight: 600; |
|||
color: #333; |
|||
margin-bottom: 16rpx; |
|||
} |
|||
|
|||
.content_text { |
|||
font-size: 26rpx; |
|||
color: #666; |
|||
line-height: 1.6; |
|||
padding: 16rpx; |
|||
background: #f8f9fa; |
|||
border-radius: 8rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.empty_state { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
padding: 120rpx 0; |
|||
|
|||
.empty_icon { |
|||
width: 160rpx; |
|||
height: 160rpx; |
|||
margin-bottom: 32rpx; |
|||
opacity: 0.3; |
|||
} |
|||
|
|||
.empty_text { |
|||
font-size: 28rpx; |
|||
color: #999; |
|||
} |
|||
} |
|||
|
|||
.loading_state { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
padding: 60rpx 0; |
|||
|
|||
.loading_text { |
|||
font-size: 28rpx; |
|||
color: #666; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,174 +0,0 @@ |
|||
<!--消息详情页面--> |
|||
<template> |
|||
<view class="main_box"> |
|||
<!-- 消息基本信息 --> |
|||
<view class="message_info_card" v-if="messageInfo"> |
|||
<view class="message_header"> |
|||
<view class="message_title">{{ messageInfo.title }}</view> |
|||
<view class="message_time">{{ messageInfo.created_at }}</view> |
|||
</view> |
|||
|
|||
<view class="message_details"> |
|||
<view class="detail_item"> |
|||
<view class="detail_label">发送者</view> |
|||
<view class="detail_value">{{ messageInfo.sender }}</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="message_content"> |
|||
<view class="content_title">消息内容</view> |
|||
<view class="content_text">{{ messageInfo.content }}</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 空状态 --> |
|||
<view class="empty_state" v-if="!loading && !messageInfo"> |
|||
<image src="/static/icon-img/empty.png" class="empty_icon"></image> |
|||
<view class="empty_text">暂无消息信息</view> |
|||
</view> |
|||
|
|||
<!-- 加载状态 --> |
|||
<view class="loading_state" v-if="loading"> |
|||
<view class="loading_text">加载中...</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
messageInfo: null, |
|||
loading: false, |
|||
messageId: null, |
|||
childId: null |
|||
} |
|||
}, |
|||
onLoad(options) { |
|||
this.messageId = options.messageId |
|||
this.childId = options.childId |
|||
this.loadMessageInfo() |
|||
}, |
|||
methods: { |
|||
async loadMessageInfo() { |
|||
// 模拟消息详情数据 |
|||
this.messageInfo = { |
|||
title: '课程提醒', |
|||
sender: '王教练', |
|||
created_at: '2024-01-15 09:30:00', |
|||
content: '提醒您的孩子明天有篮球课,请准时参加。上课时间:10:00-11:30,地点:篮球馆A。' |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.main_box { |
|||
background: #f8f9fa; |
|||
min-height: 100vh; |
|||
padding: 20rpx; |
|||
} |
|||
|
|||
.message_info_card { |
|||
background: #fff; |
|||
border-radius: 16rpx; |
|||
padding: 32rpx; |
|||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1); |
|||
|
|||
.message_header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 32rpx; |
|||
padding-bottom: 24rpx; |
|||
border-bottom: 1px solid #f0f0f0; |
|||
|
|||
.message_title { |
|||
font-size: 36rpx; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.message_time { |
|||
font-size: 24rpx; |
|||
color: #999; |
|||
} |
|||
} |
|||
|
|||
.message_details { |
|||
margin-bottom: 32rpx; |
|||
|
|||
.detail_item { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 20rpx 0; |
|||
border-bottom: 1px solid #f8f9fa; |
|||
|
|||
.detail_label { |
|||
font-size: 28rpx; |
|||
color: #666; |
|||
min-width: 160rpx; |
|||
} |
|||
|
|||
.detail_value { |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
flex: 1; |
|||
text-align: right; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.message_content { |
|||
.content_title { |
|||
font-size: 28rpx; |
|||
font-weight: 600; |
|||
color: #333; |
|||
margin-bottom: 16rpx; |
|||
} |
|||
|
|||
.content_text { |
|||
font-size: 26rpx; |
|||
color: #666; |
|||
line-height: 1.6; |
|||
padding: 16rpx; |
|||
background: #f8f9fa; |
|||
border-radius: 8rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.empty_state { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
padding: 120rpx 0; |
|||
|
|||
.empty_icon { |
|||
width: 160rpx; |
|||
height: 160rpx; |
|||
margin-bottom: 32rpx; |
|||
opacity: 0.3; |
|||
} |
|||
|
|||
.empty_text { |
|||
font-size: 28rpx; |
|||
color: #999; |
|||
} |
|||
} |
|||
|
|||
.loading_state { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
padding: 60rpx 0; |
|||
|
|||
.loading_text { |
|||
font-size: 28rpx; |
|||
color: #666; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,182 +0,0 @@ |
|||
<!--订单详情页面--> |
|||
<template> |
|||
<view class="main_box"> |
|||
<!-- 订单基本信息 --> |
|||
<view class="order_info_card" v-if="orderInfo"> |
|||
<view class="order_header"> |
|||
<view class="order_no">订单号:{{ orderInfo.order_no }}</view> |
|||
<view class="order_status" :class="orderInfo.status"> |
|||
{{ orderInfo.status_text }} |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="order_details"> |
|||
<view class="detail_item"> |
|||
<view class="detail_label">课程名称</view> |
|||
<view class="detail_value">{{ orderInfo.course_name }}</view> |
|||
</view> |
|||
<view class="detail_item"> |
|||
<view class="detail_label">订单金额</view> |
|||
<view class="detail_value amount">¥{{ orderInfo.amount }}</view> |
|||
</view> |
|||
<view class="detail_item"> |
|||
<view class="detail_label">下单时间</view> |
|||
<view class="detail_value">{{ orderInfo.created_at }}</view> |
|||
</view> |
|||
<view class="detail_item" v-if="orderInfo.pay_time"> |
|||
<view class="detail_label">支付时间</view> |
|||
<view class="detail_value">{{ orderInfo.pay_time }}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 空状态 --> |
|||
<view class="empty_state" v-if="!loading && !orderInfo"> |
|||
<image src="/static/icon-img/empty.png" class="empty_icon"></image> |
|||
<view class="empty_text">暂无订单信息</view> |
|||
</view> |
|||
|
|||
<!-- 加载状态 --> |
|||
<view class="loading_state" v-if="loading"> |
|||
<view class="loading_text">加载中...</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
orderInfo: null, |
|||
loading: false, |
|||
orderId: null, |
|||
childId: null |
|||
} |
|||
}, |
|||
onLoad(options) { |
|||
this.orderId = options.orderId |
|||
this.childId = options.childId |
|||
this.loadOrderInfo() |
|||
}, |
|||
methods: { |
|||
async loadOrderInfo() { |
|||
// 模拟订单详情数据 |
|||
this.orderInfo = { |
|||
order_no: 'ORD202401001', |
|||
course_name: '少儿篮球课程包', |
|||
amount: '2880.00', |
|||
status: 'paid', |
|||
status_text: '已支付', |
|||
created_at: '2024-01-01 10:00:00', |
|||
pay_time: '2024-01-01 10:05:00' |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.main_box { |
|||
background: #f8f9fa; |
|||
min-height: 100vh; |
|||
padding: 20rpx; |
|||
} |
|||
|
|||
.order_info_card { |
|||
background: #fff; |
|||
border-radius: 16rpx; |
|||
padding: 32rpx; |
|||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1); |
|||
|
|||
.order_header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 32rpx; |
|||
padding-bottom: 24rpx; |
|||
border-bottom: 1px solid #f0f0f0; |
|||
|
|||
.order_no { |
|||
font-size: 32rpx; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.order_status { |
|||
font-size: 24rpx; |
|||
padding: 8rpx 16rpx; |
|||
border-radius: 12rpx; |
|||
|
|||
&.paid { |
|||
background: rgba(40, 167, 69, 0.1); |
|||
color: #28a745; |
|||
} |
|||
|
|||
&.unpaid { |
|||
background: rgba(220, 53, 69, 0.1); |
|||
color: #dc3545; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.order_details { |
|||
.detail_item { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 20rpx 0; |
|||
border-bottom: 1px solid #f8f9fa; |
|||
|
|||
.detail_label { |
|||
font-size: 28rpx; |
|||
color: #666; |
|||
min-width: 160rpx; |
|||
} |
|||
|
|||
.detail_value { |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
flex: 1; |
|||
text-align: right; |
|||
|
|||
&.amount { |
|||
color: #e67e22; |
|||
font-weight: 600; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.empty_state { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
padding: 120rpx 0; |
|||
|
|||
.empty_icon { |
|||
width: 160rpx; |
|||
height: 160rpx; |
|||
margin-bottom: 32rpx; |
|||
opacity: 0.3; |
|||
} |
|||
|
|||
.empty_text { |
|||
font-size: 28rpx; |
|||
color: #999; |
|||
} |
|||
} |
|||
|
|||
.loading_state { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
padding: 60rpx 0; |
|||
|
|||
.loading_text { |
|||
font-size: 28rpx; |
|||
color: #666; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,159 +0,0 @@ |
|||
<!--服务详情页面--> |
|||
<template> |
|||
<view class="main_box"> |
|||
<!-- 服务基本信息 --> |
|||
<view class="service_info_card" v-if="serviceInfo"> |
|||
<view class="service_header"> |
|||
<view class="service_title">{{ serviceInfo.title }}</view> |
|||
<view class="service_status" :class="serviceInfo.status"> |
|||
{{ serviceInfo.status_text }} |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="service_details"> |
|||
<view class="detail_item"> |
|||
<view class="detail_label">服务时间</view> |
|||
<view class="detail_value">{{ serviceInfo.service_time }}</view> |
|||
</view> |
|||
<view class="detail_item"> |
|||
<view class="detail_label">服务内容</view> |
|||
<view class="detail_value">{{ serviceInfo.content }}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 空状态 --> |
|||
<view class="empty_state" v-if="!loading && !serviceInfo"> |
|||
<image src="/static/icon-img/empty.png" class="empty_icon"></image> |
|||
<view class="empty_text">暂无服务信息</view> |
|||
</view> |
|||
|
|||
<!-- 加载状态 --> |
|||
<view class="loading_state" v-if="loading"> |
|||
<view class="loading_text">加载中...</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
serviceInfo: null, |
|||
loading: false, |
|||
serviceId: null, |
|||
childId: null |
|||
} |
|||
}, |
|||
onLoad(options) { |
|||
this.serviceId = options.serviceId |
|||
this.childId = options.childId |
|||
this.loadServiceInfo() |
|||
}, |
|||
methods: { |
|||
async loadServiceInfo() { |
|||
// 模拟服务详情数据 |
|||
this.serviceInfo = { |
|||
title: '课程跟踪服务', |
|||
status: 'completed', |
|||
status_text: '已完成', |
|||
service_time: '2024-01-15 10:00:00', |
|||
content: '针对学员的课程进度进行跟踪辅导,提供个性化建议。' |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.main_box { |
|||
background: #f8f9fa; |
|||
min-height: 100vh; |
|||
padding: 20rpx; |
|||
} |
|||
|
|||
.service_info_card { |
|||
background: #fff; |
|||
border-radius: 16rpx; |
|||
padding: 32rpx; |
|||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1); |
|||
|
|||
.service_header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 32rpx; |
|||
padding-bottom: 24rpx; |
|||
border-bottom: 1px solid #f0f0f0; |
|||
|
|||
.service_title { |
|||
font-size: 36rpx; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.service_status { |
|||
font-size: 24rpx; |
|||
padding: 8rpx 16rpx; |
|||
border-radius: 12rpx; |
|||
background: rgba(41, 211, 180, 0.1); |
|||
color: #29d3b4; |
|||
} |
|||
} |
|||
|
|||
.service_details { |
|||
.detail_item { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 20rpx 0; |
|||
border-bottom: 1px solid #f8f9fa; |
|||
|
|||
.detail_label { |
|||
font-size: 28rpx; |
|||
color: #666; |
|||
min-width: 160rpx; |
|||
} |
|||
|
|||
.detail_value { |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
flex: 1; |
|||
text-align: right; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.empty_state { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
padding: 120rpx 0; |
|||
|
|||
.empty_icon { |
|||
width: 160rpx; |
|||
height: 160rpx; |
|||
margin-bottom: 32rpx; |
|||
opacity: 0.3; |
|||
} |
|||
|
|||
.empty_text { |
|||
font-size: 28rpx; |
|||
color: #999; |
|||
} |
|||
} |
|||
|
|||
.loading_state { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
padding: 60rpx 0; |
|||
|
|||
.loading_text { |
|||
font-size: 28rpx; |
|||
color: #666; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,272 +0,0 @@ |
|||
<template> |
|||
<view class="main_box"> |
|||
<view class="after-class-title"> |
|||
<view class="after-class-title-left">课后作业</view> |
|||
</view> |
|||
|
|||
<scroll-view |
|||
class="table_list" |
|||
scroll-y="true" |
|||
:lower-threshold="lowerThreshold" |
|||
@scrolltolower="loadMoreData" |
|||
style="height: 100vh;" |
|||
> |
|||
|
|||
<view class="con-list" v-for="(v,k) in tableList" :key="k" @click="openViewWorkDetails(v)"> |
|||
<view class="con-list-img" v-if="v.content_text"> |
|||
<video v-if="v.content_type == 2" class="pic" style="width: 100%;border-radius: 15rpx;" :src="$util.img(v.content_text)"></video> |
|||
<image v-else-if="v.content_type == 1" style="width: 100%;border-radius: 15rpx;" :src="$util.img(v.content_text)" mode="aspectFit"></image> |
|||
<view class="text" v-else>{{v.content_text}}</view> |
|||
</view> |
|||
|
|||
<view class="date_box"> |
|||
<view class="describe" style="margin-top: 20rpx;"> |
|||
时间:{{v.created_at}} |
|||
</view> |
|||
<!--是否已经完成作业--> |
|||
<view class="mark" v-if="v.status == 3"> |
|||
<image class="check_mark" :src="$util.img('/uniapp_src/static/images/index/check_mark.png')"></image> |
|||
</view> |
|||
</view> |
|||
|
|||
|
|||
<!--作业描述--> |
|||
<view class="con" style="margin-bottom: 20rpx; color:#fff;" v-html="v.description"></view> |
|||
|
|||
<view class="assignment"> |
|||
<view>{{v.type == 1 ? '班级作业' : '个人作业'}}</view> |
|||
</view> |
|||
</view> |
|||
|
|||
</scroll-view> |
|||
|
|||
|
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import apiRoute from '@/api/apiRoute.js'; |
|||
import memberApi from '@/api/member.js'; |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
loading:false,//加载状态 |
|||
lowerThreshold: 100,//距离底部多远触发 |
|||
isReachedBottom: false,//防止重复加载|true=不可加载|false=可加载 |
|||
|
|||
//筛选条件 |
|||
filteredData:{ |
|||
page:1,//当前页码 |
|||
limit:10,//每页返回数据条数 |
|||
total:10,//数据总条数 |
|||
resources_id: '',//学生资源id |
|||
status: '',//状态 1待批改 2未提交 3已提交 |
|||
}, |
|||
|
|||
tableList:[],//表格数据 |
|||
|
|||
member_info:{},//学生信息 |
|||
|
|||
} |
|||
}, |
|||
onShow(){ |
|||
this.init()//初始化 |
|||
}, |
|||
//下拉刷新 |
|||
async onPullDownRefresh() { |
|||
//重置为第一页 |
|||
await this.resetFilteredData() |
|||
await this.getList() |
|||
}, |
|||
methods: { |
|||
//初始化 |
|||
async init(){ |
|||
await this.memberInit() |
|||
await this.getList(); |
|||
}, |
|||
|
|||
//获取学员信息 |
|||
async memberInit() { |
|||
let res = await apiRoute.xy_memberInfo({}) |
|||
if(res.code != 1){ |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
this.member_info = res.data |
|||
this.filteredData.resources_id = this.member_info.id,//学生资源id |
|||
console.log('xxxx',this.member_info) |
|||
}, |
|||
|
|||
//加载更多(下一页) |
|||
loadMoreData() { |
|||
//判断是否加载 |
|||
if (!this.isReachedBottom) { |
|||
this.isReachedBottom = true;//设置为不可请求状态 |
|||
this.getList(); |
|||
} |
|||
}, |
|||
//重置为第一页 |
|||
async resetFilteredData() { |
|||
this.isReachedBottom = false; // 重置状态,以便下次触发加载更多 |
|||
|
|||
this.filteredData.page = 1//当前页码 |
|||
this.filteredData.limit = 10//每页返回数据条数 |
|||
this.filteredData.total = 10//数据总条数 |
|||
}, |
|||
|
|||
//获取作业列表 |
|||
async getList(){ |
|||
this.loading = true |
|||
|
|||
let data = {...this.filteredData} |
|||
|
|||
//判断是否还有数据 |
|||
if ((this.filteredData.page - 1) * this.filteredData.limit >= this.filteredData.total) { |
|||
this.loading = false |
|||
uni.showToast({ |
|||
title: '暂无更多', |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
if(data.page == 1){ |
|||
this.tableList = [] |
|||
} |
|||
|
|||
let res = await apiRoute.xy_assignment(data) |
|||
this.loading = false |
|||
this.isReachedBottom = false; |
|||
if (res.code != 1){ |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
this.tableList = this.tableList.concat(res.data.data); // 使用 concat 方法 将新数据追加到数组中 |
|||
|
|||
console.log('列表',this.tableList) |
|||
this.filteredData.total = res.data.total |
|||
this.filteredData.page++ |
|||
}, |
|||
|
|||
//跳转页面-打开作业详情 |
|||
openViewWorkDetails(item) { |
|||
let id = item.id |
|||
this.$navigateTo({ |
|||
url: `/pages/student/index/work_details?id=${id}` |
|||
}) |
|||
}, |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
}, |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.main_box{ |
|||
width: 100%; |
|||
height: 100vh; |
|||
background: #292929; |
|||
overflow: auto; |
|||
|
|||
.table_list{ |
|||
padding-bottom: 150rpx; |
|||
} |
|||
} |
|||
.after-class-title { |
|||
width: 92%; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
margin: auto; |
|||
padding-top: 30rpx; |
|||
} |
|||
.after-class-title-left { |
|||
color: #fff; |
|||
font-size: 35rpx; |
|||
border-bottom: 4rpx #29d3b4 solid; |
|||
} |
|||
.con-list{ |
|||
width: 100%; |
|||
padding: 30rpx; |
|||
margin-top: 20rpx; |
|||
border-bottom: 2rpx #fff solid; |
|||
.date_box{ |
|||
padding-top: 30rpx; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
.describe{ |
|||
width: 75%; |
|||
color: #fff; |
|||
} |
|||
} |
|||
} |
|||
.con-list-img{ |
|||
width: 100%; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
|
|||
video{ |
|||
width: 100%; |
|||
height: 280rpx; |
|||
} |
|||
image{ |
|||
width: 100%; |
|||
height: 280rpx; |
|||
} |
|||
.text{ |
|||
width: 100%; |
|||
font-size: 28rpx; |
|||
color:#fff; |
|||
white-space: pre-wrap; |
|||
word-wrap: break-word; |
|||
} |
|||
|
|||
} |
|||
.pic{ |
|||
width: 85%; |
|||
height: 100%; |
|||
} |
|||
.con{ |
|||
width: 75%; |
|||
color: #fff; |
|||
padding-top: 30rpx; |
|||
} |
|||
.mark{ |
|||
width: 70rpx; |
|||
height: 70rpx; |
|||
border-radius: 100%; |
|||
background: #29d3b4; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
.check_mark{ |
|||
width: 80%; |
|||
height: 80%; |
|||
} |
|||
.assignment{ |
|||
display: flex; |
|||
justify-content: flex-end; |
|||
align-items: center; |
|||
view{ |
|||
padding: 6rpx 12rpx; |
|||
color: #6b9d53; |
|||
border: 2rpx #6b9d53 solid; |
|||
border-radius: 10rpx; |
|||
width: 150rpx; |
|||
text-align: center; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,114 +0,0 @@ |
|||
<!--作业详情--> |
|||
<template> |
|||
<view class="main_box"> |
|||
<!-- 作业展示--> |
|||
<view class="top-style" v-if="infoData.content_text"> |
|||
<video v-if="infoData.content_type == 2" class="pic" style="width: 100%;border-radius: 15rpx;" :src="$util.img(infoData.content_text)"></video> |
|||
<image v-else-if="infoData.content_type == 1" style="width: 100%;border-radius: 15rpx;" :src="$util.img(infoData.content_text)" mode="aspectFit"></image> |
|||
</view> |
|||
|
|||
<!-- 简练信息+作业描述--> |
|||
<view class="below-style"> |
|||
<view class="head-img"> |
|||
<!--学生头像--> |
|||
<fui-avatar width="80" :src="infoData.student.customerResources.member.headimg ? infoData.student.customerResources.member.headimg : $util.img('/uniapp_src/static/images/common/yong_hu.png')"></fui-avatar> |
|||
<view class="head-text">{{infoData .student.name}}</view> |
|||
</view> |
|||
<view class="multi-line-ellipsis"> |
|||
状态:{{ infoData.status == 1 ? '待批改' : infoData.status == 2 ? '未提交' : infoData.status == 3 ? '已提交' :''}} </view> |
|||
<view class="multi-line-ellipsis" v-html="infoData.description"></view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
<script> |
|||
import apiRoute from '@/api/apiRoute.js'; |
|||
|
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
//筛选条件 |
|||
filteredData: { |
|||
id: '',//作业id |
|||
}, |
|||
|
|||
infoData:{}, |
|||
} |
|||
}, |
|||
onLoad(options) { |
|||
this.filteredData.id = options.id//作业id |
|||
}, |
|||
onShow(){ |
|||
this.init()//初始化数据 |
|||
}, |
|||
methods: { |
|||
//初始化 |
|||
async init(){ |
|||
this.getAssignmentsInfo() |
|||
}, |
|||
|
|||
//获取作业详情 |
|||
async getAssignmentsInfo() { |
|||
let params = {...this.filteredData} |
|||
let res = await apiRoute.xy_assignmentsInfo(params) |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
this.infoData = res.data |
|||
}, |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.main_box{ |
|||
width: 100%; |
|||
height: 100%; |
|||
background: #292929; |
|||
padding-top: 45rpx; |
|||
} |
|||
.top-style{ |
|||
width: 92%; |
|||
height: 700rpx; |
|||
margin: auto; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
.top-style-img{ |
|||
width: 120rpx; |
|||
height: 120rpx; |
|||
} |
|||
.below-style{ |
|||
width: 92%; |
|||
margin: auto; |
|||
.head-img { |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 10rpx 20rpx; |
|||
} |
|||
.head-text { |
|||
color: #fff; |
|||
font-size: 35rpx; |
|||
padding-left: 20rpx; |
|||
} |
|||
} |
|||
|
|||
|
|||
.multi-line-ellipsis { |
|||
margin-top: 20rpx; |
|||
color: #fff; |
|||
font-size: 29rpx; |
|||
padding: 5rpx 10rpx; |
|||
// display: -webkit-box; |
|||
// -webkit-box-orient: vertical; |
|||
// -webkit-line-clamp: 2; |
|||
// overflow: hidden; |
|||
// text-overflow: ellipsis; |
|||
} |
|||
</style> |
|||
@ -1,379 +0,0 @@ |
|||
<!--我的-首页--> |
|||
<template> |
|||
<view class="main_box"> |
|||
<view class="navbar_section"> |
|||
<view class="title">我的</view> |
|||
</view> |
|||
<view style="background:#29D3B4;"> |
|||
<!--用户信息--> |
|||
<view class="user_section"> |
|||
<view class="box"> |
|||
<view class="left" @click="personal_data"> |
|||
<image class="pic" :src="member_info.memberHasOne ? member_info.memberHasOne.headimg : $util.img('/uniapp_src/static/images/common/yong_hu.png')"></image> |
|||
<view class="name">{{member_info.name}}</view> |
|||
</view> |
|||
<view class="right" @click="setup"> |
|||
<image :src="$util.img('/uniapp_src/static/images/index/setup.png')" style="width: 50rpx;height: 50rpx;"></image> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!--统计信息--> |
|||
<view class="count_section"> |
|||
<view class="main"> |
|||
<view class="course_box"> |
|||
<view class="top"> |
|||
<view class="item"> |
|||
<view class="num">{{member_info.classes_count}}</view> |
|||
<view class="intro">我的课程</view> |
|||
</view> |
|||
<view class="item"> |
|||
<view class="num">{{member_info.sign_count}}</view> |
|||
<view class="intro">已上课时</view> |
|||
</view> |
|||
<view class="item"> |
|||
<view class="num">{{member_info.stay_sign_count}}</view> |
|||
<view class="intro">待上课时 |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="bottom"></view> |
|||
<view class="bg_box bg_top"></view> |
|||
<view class="bg_box bg_bottom"></view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="main_section"> |
|||
<view class="section_box"> |
|||
<view class="item" style="border-radius: 16rpx 16rpx 0 0;" @click="lesson_consumption"> |
|||
<view>课时消耗</view> |
|||
<image :src="$util.img('/uniapp_src/static/images/index/right_arrow.png')" class="arrow-icon"></image> |
|||
</view> |
|||
|
|||
<view class="item" @click="openViewOrder()"> |
|||
<view>我的订单</view> |
|||
<image :src="$util.img('/uniapp_src/static/images/index/right_arrow.png')" class="arrow-icon"></image> |
|||
</view> |
|||
|
|||
<view class="item" @click="navigateToTimetable()"> |
|||
<view>我的课表</view> |
|||
<image :src="$util.img('/uniapp_src/static/images/index/right_arrow.png')" class="arrow-icon"></image> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="section_box"> |
|||
<view class="item" @click="openViewMyCoach()"> |
|||
<view>我的教练</view> |
|||
<image :src="$util.img('/uniapp_src/static/images/index/right_arrow.png')" class="arrow-icon"></image> |
|||
</view> |
|||
|
|||
<view class="item" @click="navigateToHomework()"> |
|||
<view>作业管理</view> |
|||
<image :src="$util.img('/uniapp_src/static/images/index/right_arrow.png')" class="arrow-icon"></image> |
|||
</view> |
|||
|
|||
<view class="item" @click="feedback"> |
|||
<view>意见反馈</view> |
|||
<image :src="$util.img('/uniapp_src/static/images/index/right_arrow.png')" class="arrow-icon"></image> |
|||
</view> |
|||
|
|||
<view class="item" @click="openViewMyMessage({user_id:1})"> |
|||
<view>我的消息</view> |
|||
<image :src="$util.img('/uniapp_src/static/images/index/right_arrow.png')" class="arrow-icon"></image> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 底部导航--> |
|||
<AQTabber /> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import AQTabber from "@/components/AQ/AQTabber.vue" |
|||
import apiRoute from '@/api/apiRoute.js'; |
|||
import member from '@/api/member.js'; |
|||
export default { |
|||
components: { |
|||
AQTabber, |
|||
}, |
|||
data() { |
|||
return { |
|||
member_info: [], |
|||
} |
|||
}, |
|||
onLoad() { |
|||
this.member_init(); |
|||
}, |
|||
methods: { |
|||
//获取学员信息 |
|||
async member_init() { |
|||
let res = await apiRoute.xy_memberInfo({}) |
|||
if(res.code != 1){ |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
this.member_info = res.data |
|||
}, |
|||
//打开设置 |
|||
setup(item) { |
|||
this.$navigateTo({ |
|||
url: '/pages/student/my/set_up' |
|||
}) |
|||
}, |
|||
//意见反馈 |
|||
feedback() { |
|||
this.$navigateTo({ |
|||
url: '/pages/common/feedback' |
|||
}) |
|||
}, |
|||
//课时消耗 |
|||
lesson_consumption() { |
|||
this.$navigateTo({ |
|||
url: '/pages/student/my/lesson_consumption' |
|||
}) |
|||
}, |
|||
//我的成员 |
|||
my_members() { |
|||
this.$navigateTo({ |
|||
url: '/pages/student/my/my_members' |
|||
}) |
|||
}, |
|||
//人人资料 |
|||
personal_data() { |
|||
this.$navigateTo({ |
|||
url: '/pages/student/my/personal_data' |
|||
}) |
|||
}, |
|||
|
|||
//跳转页面-订单列表 |
|||
openViewOrder() { |
|||
let resource_id = this.member_info.id//客户资源id |
|||
let resource_name = this.member_info.name || ''//客户资源id姓名 |
|||
|
|||
// let staff_id = this.userInfo.id//员工id |
|||
// let staff_id_name = this.userInfo.name || ''//员工姓名 |
|||
|
|||
let staff_id = ''//员工id |
|||
let staff_id_name = ''//员工姓名 |
|||
|
|||
this.$navigateTo({ |
|||
url: `/pages/common/contract_list?resource_id=${resource_id}&resource_name=${resource_name}&staff_id=${staff_id}&staff_id_name=${staff_id_name}` |
|||
}) |
|||
}, |
|||
|
|||
//跳转页面-我的消息 |
|||
openViewMyMessage(item) { |
|||
this.$navigateTo({ |
|||
url: `/pages/common/my_message` |
|||
}) |
|||
}, |
|||
|
|||
//跳转页面-我的教练 |
|||
openViewMyCoach(){ |
|||
this.$navigateTo({ |
|||
url: `/pages/student/my/my_coach` |
|||
}) |
|||
}, |
|||
|
|||
//跳转页面-课表 |
|||
navigateToTimetable(){ |
|||
this.$navigateTo({ |
|||
url: `/pages/student/timetable/index` |
|||
}) |
|||
}, |
|||
|
|||
//跳转页面-作业管理 |
|||
navigateToHomework(){ |
|||
this.$navigateTo({ |
|||
url: `/pages/student/index/job_list` |
|||
}) |
|||
}, |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.main_box { |
|||
background: #292929; |
|||
height: 100%; |
|||
} |
|||
|
|||
//自定义导航栏 |
|||
.navbar_section { |
|||
border: 1px solid #29D3B4; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
background: #29D3B4; |
|||
|
|||
.title { |
|||
padding: 40rpx 20rpx; |
|||
|
|||
/* 小程序端样式 */ |
|||
// #ifdef MP-WEIXIN |
|||
padding: 80rpx 0 20rpx; |
|||
// #endif |
|||
|
|||
|
|||
font-size: 30rpx; |
|||
color: #fff; |
|||
} |
|||
} |
|||
|
|||
//用户信息 |
|||
.user_section { |
|||
background-color: #29D3B4; |
|||
padding-top: 58rpx; |
|||
padding-bottom: 42rpx; |
|||
color: #fff; |
|||
font-size: 28rpx; |
|||
|
|||
.box { |
|||
padding-left: 19rpx; |
|||
padding-right: 29rpx; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
gap: 15rpx; |
|||
|
|||
.left { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 20rpx; |
|||
|
|||
.pic { |
|||
width: 144rpx; |
|||
height: 144rpx; |
|||
border-radius: 50%; |
|||
} |
|||
|
|||
.name { |
|||
font-size: 28rpx; |
|||
} |
|||
} |
|||
|
|||
.right { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 20rpx; |
|||
|
|||
.btn { |
|||
min-height: 28rpx; |
|||
font-size: 28rpx; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
//统计信息 |
|||
.count_section { |
|||
position: relative; |
|||
|
|||
.main { |
|||
position: relative; |
|||
z-index: 2; |
|||
padding: 0rpx 24rpx; |
|||
display: flex; |
|||
justify-content: center; |
|||
|
|||
.course_box { |
|||
padding: 42rpx 28rpx; |
|||
width: 692rpx; |
|||
border-radius: 20rpx; |
|||
background-color: #fff; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 32rpx; |
|||
|
|||
.top { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
|
|||
.item { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
gap: 12rpx; |
|||
|
|||
.num { |
|||
color: #29D3B4; |
|||
font-size: 56rpx; |
|||
} |
|||
|
|||
.intro { |
|||
color: #AAAAAA; |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.bg_box { |
|||
z-index: 1; |
|||
width: 100%; |
|||
height: 150rpx; |
|||
} |
|||
|
|||
.bg_top { |
|||
position: absolute; |
|||
top: 0; |
|||
background-color: #29D3B4; |
|||
} |
|||
|
|||
.bg_bottom { |
|||
top: 50%; |
|||
position: absolute; |
|||
background-color: #292929; |
|||
} |
|||
} |
|||
|
|||
.main_section { |
|||
margin-top: 20rpx; |
|||
background: #292929 100%; |
|||
padding: 0 24rpx; |
|||
padding-top: 40rpx; |
|||
padding-bottom: 150rpx; |
|||
font-size: 24rpx; |
|||
color: #333333; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 22rpx; |
|||
|
|||
.section_box { |
|||
margin-bottom: 10rpx; |
|||
background: #fff; |
|||
border-radius: 16rpx; |
|||
padding: 6rpx 24rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
|
|||
.item { |
|||
padding: 35rpx 78rpx; |
|||
border-top: 1px solid #F2F2F2; |
|||
font-size: 28rpx; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
} |
|||
|
|||
.item:nth-child(1) { |
|||
border-top: 0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 箭头图标样式 |
|||
.arrow-icon { |
|||
width: 24rpx; |
|||
height: 24rpx; |
|||
opacity: 0.6; |
|||
|
|||
} |
|||
</style> |
|||
@ -1,607 +0,0 @@ |
|||
<!--课程-列表--> |
|||
<template> |
|||
<view class="main_box"> |
|||
<!--自定义导航栏--> |
|||
<view class="navbar_section"> |
|||
<view class="title">课表</view> |
|||
</view> |
|||
|
|||
<view class="main_section"> |
|||
<view class="section_1"> |
|||
<view class="ul"> |
|||
<view class="li" v-for="(v,k) in dateList" :key="k" @click="selectDate(v.date)"> |
|||
<text>{{v.week}}</text> |
|||
|
|||
<text :class="[filteredData.course_date == v.date ? 'today':'']">{{today == v.date ? '今':v.today}}</text> |
|||
|
|||
<text :class="[v.is_sign == 1 ? 'select_plan':'']"></text> |
|||
</view> |
|||
</view> |
|||
<view class="btn" @click="show_calendar=true"> |
|||
查看更多 <fui-icon name="arrowdown" color="#A4ADB3" size="45"></fui-icon> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="section_2"> |
|||
<view class="item_box"> |
|||
<text v-if="(venuesInfo.id || '')">{{venuesInfo.venue_name}}</text> |
|||
</view> |
|||
<view class="item_box" style="text-align: right;color: #F59A23;" @click="more"> |
|||
更多场馆 |
|||
</view> |
|||
|
|||
</view> |
|||
|
|||
<scroll-view |
|||
class="section_3" |
|||
scroll-y="true" |
|||
:lower-threshold="lowerThreshold" |
|||
@scrolltolower="loadMoreData" |
|||
style="height: 100vh;" |
|||
> |
|||
<view class="ul"> |
|||
<view v-for="(v,k) in tableList" :key="k" class="li" @click="openViewCourseInfo(v)"> |
|||
<view class="top_box"> |
|||
<view class="center_box"> |
|||
<view>教练:{{v.courseScheduleHasOne.coach.name}}</view> |
|||
<view>课程:{{v.courseScheduleHasOne.course.course_name}}</view> |
|||
<view>时间:{{v.course_date}}</view> |
|||
<view>课室:{{v.courseScheduleHasOne.campus_name}} {{v.courseScheduleHasOne.venue.venue_name}}</view> |
|||
</view> |
|||
<view class="right_box"> |
|||
<!-- v.status|1=未开始,2=进行中,3=已结束--> |
|||
<view class="tag" |
|||
v-if="v.status != null" |
|||
:style="{background: v.status == 1 ? '#1cd188' : v.status == 2 ? '#fad24e' : '#ff4d4f'}"> |
|||
{{ v.status == 0 ? '待上课' : v.status == 1 ? '已上课' : '请假' }} |
|||
</view> |
|||
<!-- <view class="tag" style="background:#1cd188;">待上课</view>--> |
|||
</view> |
|||
</view> |
|||
<view class="bottom_box"> |
|||
<view class="hint"> |
|||
<!-- 已签到学生 ({{v.sign_list.length }}/{{v.max_students.split(',').length }})--> |
|||
</view> |
|||
<view class="list_box"> |
|||
<!-- <view class="list">--> |
|||
<!-- <view class="itme" v-for="(item,index) in v.sign_list || 0" :key="index">--> |
|||
<!-- <image :src="$util.img(item.header)"></image>--> |
|||
<!-- </view>--> |
|||
<!-- </view>--> |
|||
<view class="btn"> |
|||
详情 |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</scroll-view> |
|||
<!-- 加载状态--> |
|||
<!-- <fui-loading :isFixed="true" srcCol="/static/icon-img/loading_white.png" text="正在加载..." v-if="loading"></fui-loading>--> |
|||
|
|||
</view> |
|||
|
|||
<!-- 日历选择--> |
|||
<fui-bottom-popup :show="show_calendar" @close="show_calendar=false"> |
|||
<view class="fui-custom__wrap"> |
|||
<uni-calendar |
|||
:insert="true" |
|||
:lunar="false" |
|||
:selected="calendarSelected" |
|||
:startDate="startDate" |
|||
:endDate="endDate" |
|||
@change="changeCalendar" |
|||
/> |
|||
</view> |
|||
</fui-bottom-popup> |
|||
|
|||
<!-- 底部导航--> |
|||
<AQTabber/> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import apiRoute from '@/api/apiRoute.js'; |
|||
import memberApi from '@/api/member.js'; |
|||
import commonApi from '@/api/common.js'; |
|||
import AQTabber from "@/components/AQ/AQTabber.vue" |
|||
|
|||
|
|||
export default { |
|||
components: { |
|||
AQTabber, |
|||
}, |
|||
data() { |
|||
return { |
|||
loading: false,//加载状态 |
|||
lowerThreshold: 100,//距离底部多远触发 |
|||
isReachedBottom: false,//防止重复加载|true=不可加载|false=可加载 |
|||
|
|||
memberInfo:{},//当前登录的学生详情 |
|||
|
|||
//筛选条件 |
|||
filteredData: { |
|||
page: 1,//当前页码 |
|||
limit: 10,//每页返回数据条数 |
|||
total: 10,//数据总条数 |
|||
resources_id:'',//客户资源表id |
|||
course_date: '',//上课日期 |
|||
venue_id: '',//场地id |
|||
}, |
|||
tableList: [],//表格数据 |
|||
|
|||
venuesInfo: {id:''},//场地信息 |
|||
|
|||
//今日日期 |
|||
today: '', |
|||
dateList: [],//日期列表 |
|||
|
|||
//日历选择相关 |
|||
show_calendar:false,//是否展示日期 |
|||
startDate:'',//开始日期 |
|||
endDate:'',//结束日期 |
|||
calendarSelected: [ |
|||
// { |
|||
// date: '2025-04-07',//需要上课的日期 |
|||
// }, |
|||
// { |
|||
// date: '2025-04-09',//需要上课的日期 |
|||
// }, |
|||
],//日历打点(有课的日期) |
|||
|
|||
|
|||
} |
|||
}, |
|||
onLoad(options) { |
|||
if (options.venue_id) { |
|||
this.filteredData.venue_id = options.venue_id |
|||
} |
|||
}, |
|||
onShow() { |
|||
this.init()//初始化 |
|||
}, |
|||
//下拉刷新 |
|||
async onPullDownRefresh() { |
|||
//重置为第一页 |
|||
let course_date = this.filteredData.course_date |
|||
await this.loadData() |
|||
this.filteredData.course_date = course_date |
|||
await this.getList() |
|||
}, |
|||
|
|||
methods: { |
|||
//初始化 |
|||
async init() { |
|||
await this.getMemberInfo()//获取当前登录的学生信息 |
|||
await this.getThisDate()//获取当前日期 |
|||
await this.getList()//获取列表 |
|||
await this.getHeadDate()//获取课程头日期 |
|||
|
|||
this.getDateRange()//获取日期范围 |
|||
this.setCalendarSelected()//设置日期打点 |
|||
|
|||
}, |
|||
|
|||
|
|||
//获取当前登录的学生信息 |
|||
async getMemberInfo() { |
|||
let res = await apiRoute.xy_memberInfo({}) |
|||
if(res.code != 1){ |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
this.memberInfo = res.data |
|||
this.filteredData.resources_id = res.data.id |
|||
}, |
|||
|
|||
//获取课程头日期 |
|||
async getHeadDate() { |
|||
// 计算开始日期:从今天往前推2天 |
|||
let startDate = new Date(); |
|||
startDate.setDate(startDate.getDate() - 2); |
|||
let start_date = startDate.toISOString().split('T')[0]; |
|||
|
|||
// 计算结束日期:从今天往后推4天 |
|||
let endDate = new Date(); |
|||
endDate.setDate(endDate.getDate() + 4); |
|||
let end_date = endDate.toISOString().split('T')[0]; |
|||
|
|||
let params = { |
|||
resources_id: this.memberInfo.id, // 客户资源ID |
|||
start_date: start_date, // 开始日期(Y-m-d) |
|||
end_date: end_date, // 结束日期(Y-m-d) |
|||
} |
|||
let res = await apiRoute.xy_personCourseScheduleGetCalendar(params) |
|||
if (res.code != 1) { |
|||
//提示 |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none', |
|||
}) |
|||
return |
|||
} |
|||
|
|||
this.dateList = [] |
|||
res.data.forEach((v, k) => { |
|||
this.dateList.push({ |
|||
date: v.date, |
|||
status: v.status,//1是正常 2请假 |
|||
week: v.week, |
|||
today: v.today, |
|||
is_sign: v.is_sign, |
|||
}) |
|||
}) |
|||
|
|||
|
|||
console.log('xxx', res) |
|||
|
|||
}, |
|||
|
|||
//获取当前日期 |
|||
async getThisDate() { |
|||
let date = new Date(); |
|||
let year = date.getFullYear(); |
|||
let month = String(date.getMonth() + 1).padStart(2, '0'); // 月份前补零 |
|||
let day = String(date.getDate()).padStart(2, '0'); // 日期前补零 |
|||
let hour = date.getHours(); |
|||
let minute = date.getMinutes(); |
|||
let second = date.getSeconds(); |
|||
|
|||
let res = `${year}-${month}-${day}`; // 格式化日期 |
|||
this.today = res; |
|||
this.filteredData.course_date = res; |
|||
}, |
|||
|
|||
//加载更过(下一页) |
|||
async loadMoreData() { |
|||
//判断是否加载 |
|||
if (!this.isReachedBottom) { |
|||
this.isReachedBottom = true;//设置为不可请求状态 |
|||
await this.getList(); |
|||
} |
|||
}, |
|||
//重置为第一页 |
|||
async loadData() { |
|||
this.isReachedBottom = false; // 重置状态,以便下次触发加载更多 |
|||
|
|||
this.filteredData.page = 1//当前页码 |
|||
this.filteredData.limit = 10//每页返回数据条数 |
|||
this.filteredData.total = 10//数据总条数 |
|||
}, |
|||
//获取列表 |
|||
async getList() { |
|||
this.loading = true |
|||
|
|||
let data = {...this.filteredData} |
|||
if(this.filteredData.page == 1){ |
|||
this.tableList = [] |
|||
} |
|||
|
|||
//判断是否还有数据 |
|||
if ((this.filteredData.page - 1) * this.filteredData.limit >= this.filteredData.total) { |
|||
this.loading = false |
|||
uni.showToast({ |
|||
title: '暂无更多', |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
let res = await apiRoute.xy_personCourseSchedule(data) |
|||
this.loading = false |
|||
this.isReachedBottom = false; |
|||
if (res.code != 1) { |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
this.tableList = this.tableList.concat(res.data.data); // 使用 concat 方法 将新数据追加到数组中 |
|||
|
|||
//场地信息 |
|||
this.venuesInfo = res.data.venues_info |
|||
|
|||
this.filteredData.total = res.data.total |
|||
this.filteredData.page++ |
|||
}, |
|||
|
|||
//选择日期 |
|||
async selectDate(date) { |
|||
this.loadData() |
|||
this.filteredData.course_date = date |
|||
this.getList() |
|||
}, |
|||
|
|||
//日历选择相关 |
|||
// 获取日期范围 |
|||
getDateRange() { |
|||
const today = new Date(); // 获取今天的日期 |
|||
const startDate = new Date(today); // 复制今天的日期 |
|||
const endDate = new Date(today); // 复制今天的日期 |
|||
|
|||
// 计算 startDate:往前推 1 个月 |
|||
startDate.setMonth(today.getMonth() - 1); |
|||
|
|||
// 计算 endDate:往后推 1 个月 |
|||
endDate.setMonth(today.getMonth() + 2); |
|||
|
|||
// 将日期格式化为 YYYY-MM-DD |
|||
const formatDate = (date) => { |
|||
const year = date.getFullYear(); |
|||
const month = String(date.getMonth() + 1).padStart(2, '0'); |
|||
const day = String(date.getDate()).padStart(2, '0'); |
|||
return `${year}-${month}-${day}`; |
|||
}; |
|||
|
|||
// 更新 data 中的 startDate 和 endDate |
|||
this.startDate = formatDate(startDate); |
|||
this.endDate = formatDate(endDate); |
|||
console.log([this.startDate,this.endDate]) |
|||
}, |
|||
//设置日期打点 |
|||
async setCalendarSelected(){ |
|||
//获取当前月份 |
|||
const today = new Date(); // 获取当前日期 |
|||
const year = today.getFullYear(); // 获取年份 |
|||
const month = today.getMonth(); // 获取月份(0-11) |
|||
|
|||
// 计算本月第一天 |
|||
const firstDay = new Date(year, month, 1); |
|||
// 计算本月最后一天(下个月的第一天减去1天) |
|||
const lastDay = new Date(year, month + 1, 0); |
|||
|
|||
// 格式化日期为 YYYY-MM-DD |
|||
const formatDate = (date) => { |
|||
const y = date.getFullYear(); |
|||
const m = String(date.getMonth() + 1).padStart(2, '0'); // 月份补零 |
|||
const d = String(date.getDate()).padStart(2, '0'); // 日期补零 |
|||
return `${y}-${m}-${d}`; |
|||
}; |
|||
|
|||
let start_date = formatDate(firstDay); // 本月第一天 |
|||
let end_date = formatDate(lastDay); // 本月最后一天 |
|||
|
|||
let params = { |
|||
resources_id: this.memberInfo.id, // 客户资源ID |
|||
start_date: start_date, // 开始日期(Y-m-d) |
|||
end_date: end_date, // 结束日期(Y-m-d) |
|||
} |
|||
let res = await apiRoute.xy_personCourseScheduleGetCalendar(params) |
|||
|
|||
this.calendarSelected = [] |
|||
res.data.forEach((v,k)=>{ |
|||
if(v.is_sign == 1){ |
|||
this.calendarSelected.push({ |
|||
date: v.date, |
|||
}) |
|||
} |
|||
}) |
|||
|
|||
|
|||
// this.calendarSelected = [ |
|||
// { |
|||
// date: '2025-04-07', |
|||
// }, |
|||
// { |
|||
// date: '2025-04-08', |
|||
// }, |
|||
// { |
|||
// date: '2025-04-09', |
|||
// } |
|||
// ] |
|||
}, |
|||
//日历选择 |
|||
changeCalendar(e){ |
|||
console.log('日历',e) |
|||
this.show_calendar = false |
|||
console.log('日历',e) |
|||
this.show_calendar = false |
|||
this.loadData() |
|||
this.filteredData.course_date = e.fulldate |
|||
this.getList() |
|||
}, |
|||
|
|||
|
|||
//打开课表详情页 |
|||
openViewCourseInfo(item) { |
|||
let person_course_schedule_id = item.id |
|||
this.$navigateTo({ |
|||
url: `/pages/student/timetable/info?person_course_schedule_id=${person_course_schedule_id}` |
|||
}) |
|||
}, |
|||
//体育馆列表 |
|||
more() { |
|||
let course_date = this.filteredData.course_date |
|||
let venue_id = this.venuesInfo.id || ''//当前场馆id |
|||
this.$navigateTo({ |
|||
url: `/pages/student/timetable/list?course_date=${course_date}&venue_id=${venue_id}` |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
|
|||
.main_box{ |
|||
background: #292929 ; |
|||
} |
|||
|
|||
//自定义导航栏 |
|||
.navbar_section{ |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
background: #292929; |
|||
.title{ |
|||
padding: 40rpx 0rpx; |
|||
|
|||
/* 小程序端样式 */ |
|||
// #ifdef MP-WEIXIN |
|||
padding: 80rpx 0rpx; |
|||
// #endif |
|||
|
|||
font-size: 30rpx; |
|||
color: #fff; |
|||
} |
|||
} |
|||
|
|||
.main_section{ |
|||
min-height: 100vh; |
|||
background: #292929 100%; |
|||
padding-top: 40rpx; |
|||
padding-bottom: 150rpx; |
|||
font-size: 24rpx; |
|||
color: #FFFFFF; |
|||
|
|||
.section_1{ |
|||
background: #333333 100%; |
|||
width: 100%; |
|||
padding: 30rpx 28rpx; |
|||
.ul{ |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
.li{ |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
align-items: center; |
|||
gap: 10rpx; |
|||
text{ |
|||
font-size: 24rpx; |
|||
color: #FFFFFF; |
|||
text-align: center; |
|||
} |
|||
text:nth-child(2){ |
|||
width: 44rpx; |
|||
height: 44rpx; |
|||
} |
|||
text:nth-child(3){ |
|||
width: 8rpx; |
|||
height: 8rpx; |
|||
} |
|||
.today{ |
|||
border-radius: 50%; |
|||
background: #29D3B4; |
|||
text-align: center; |
|||
line-height: 42rpx; |
|||
} |
|||
.select_plan{ |
|||
background: #F59A23; |
|||
border-radius: 50%; |
|||
} |
|||
} |
|||
} |
|||
.btn{ |
|||
margin-top: 20rpx; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
color: #A4ADB3; |
|||
} |
|||
} |
|||
|
|||
.section_2{ |
|||
margin-top: 30rpx; |
|||
padding: 0 20rpx ; |
|||
color: #fff; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
.item_box { |
|||
width: 45%; |
|||
.fui-filter__item { |
|||
display: flex; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.section_3{ |
|||
margin-top: 36rpx; |
|||
color: #fff; |
|||
font-size: 24rpx; |
|||
.ul{ |
|||
padding: 0 26rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 30rpx; |
|||
.li{ |
|||
position: relative; |
|||
border-radius: 22rpx; |
|||
background: #434544 100%; |
|||
padding: 14rpx 0; |
|||
display: flex; |
|||
flex-direction: column; |
|||
.top_box{ |
|||
padding: 20rpx 30rpx; |
|||
.center_box{ |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 10rpx; |
|||
view{} |
|||
} |
|||
.right_box{ |
|||
.tag{ |
|||
position:absolute; |
|||
top: 0rpx; |
|||
right: 0rpx; |
|||
padding: 10rpx; |
|||
width: 102rpx; |
|||
text-align: center; |
|||
font-size: 24rpx; |
|||
border-bottom-left-radius: 20rpx; |
|||
border-top-right-radius: 20rpx; |
|||
} |
|||
} |
|||
} |
|||
.bottom_box{ |
|||
border-top: 1px dashed #F2F2F2; |
|||
padding: 26rpx 16rpx 0 26rpx; |
|||
.hint{ |
|||
color:#D7D7D7; |
|||
} |
|||
.list_box{ |
|||
margin-top: 22rpx; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
.list{ |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 14rpx; |
|||
.itme{ |
|||
image{ |
|||
width: 48rpx; |
|||
height: 48rpx; |
|||
border-radius: 50%; |
|||
} |
|||
} |
|||
} |
|||
.btn{ |
|||
border: 1px solid #FAD04D; |
|||
border-radius: 10rpx; |
|||
background: #434544; |
|||
color: #FAD04D; |
|||
width: 110rpx; |
|||
height: 60rpx; |
|||
line-height: 55rpx; |
|||
text-align: center; |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
|
|||
</style> |
|||
@ -1,254 +0,0 @@ |
|||
<!--课程-详情--> |
|||
<template> |
|||
<view class="main_box"> |
|||
<scroll-view scroll-y="true" :lower-threshold="lowerThreshold" |
|||
@scrolltolower="loadMoreData" style="height: 100vh;"> |
|||
|
|||
<view class="data_hint" v-if="!this.tableList.length">暂无更多数据</view> |
|||
|
|||
<view class="main_section" v-for="(v,k) in tableList" :key="k" @click="opebViewTimetable(v)"> |
|||
<view class="title">{{v.campus.campus_name}} </view> |
|||
<view class="con">{{v.campus.campus_address}} {{v.venue_name}}</view> |
|||
<!-- <view class="con" v-if="v.distance === null ">无法获取定位</view>--> |
|||
<!-- <view class="con" v-else-if="v.distance">距您{{v.distance}}km</view>--> |
|||
<view class="current-venue" v-if="venue_id == v.id"> |
|||
当前场馆 |
|||
</view> |
|||
</view> |
|||
</scroll-view> |
|||
<!-- 加载状态--> |
|||
<!-- <fui-loading :isFixed="true" srcCol="/static/icon-img/loading_white.png" text="正在加载..." v-if="loading"></fui-loading>--> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import apiRoute from '@/api/apiRoute.js'; |
|||
import memberApi from '@/api/member.js'; |
|||
import AQTabber from "@/components/AQ/AQTabber.vue" |
|||
|
|||
|
|||
export default { |
|||
components: { |
|||
AQTabber, |
|||
}, |
|||
data() { |
|||
return { |
|||
loading:false,//加载状态 |
|||
lowerThreshold: 100,//距离底部多远触发 |
|||
isReachedBottom: false,//防止重复加载|true=不可加载|false=可加载 |
|||
|
|||
memberInfo:{id:''},//客户资源信息 |
|||
|
|||
//筛选条件 |
|||
filteredData:{ |
|||
// page:1,//当前页码 |
|||
// limit:10,//每页返回数据条数 |
|||
// total:10,//数据总条数 |
|||
course_date:'',//日期 |
|||
resources_id:'',//客户资源ID |
|||
}, |
|||
|
|||
tableList:[],//表格数据 |
|||
|
|||
longitude:'',//当前用户经度 |
|||
latitude:'',//当前用户纬度 |
|||
venue_id:'',//当前场馆id |
|||
} |
|||
}, |
|||
onLoad(options) { |
|||
this.filteredData.course_date = options.course_date//上课日期 |
|||
//场馆id |
|||
this.venue_id = options.venue_id || ''//场地ID |
|||
}, |
|||
onShow() { |
|||
this.init()//初始化 |
|||
}, |
|||
methods: { |
|||
//初始化 |
|||
async init() { |
|||
// await this.getUserLocation(); |
|||
|
|||
await this.getMemberInfo(); |
|||
await this.getList(); |
|||
}, |
|||
|
|||
//获取当前登录的学生信息 |
|||
async getMemberInfo() { |
|||
let res = await apiRoute.xy_memberInfo({}) |
|||
if(res.code != 1){ |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
this.memberInfo = res.data |
|||
this.filteredData.resources_id = res.data.id |
|||
}, |
|||
|
|||
|
|||
// 获取用户当前位置(支持多端) |
|||
async getUserLocation() { |
|||
try { |
|||
const location = await this.getLocation(); |
|||
this.longitude = location.longitude; |
|||
this.latitude = location.latitude; |
|||
} catch (error) { |
|||
console.log(error); |
|||
uni.showToast({ |
|||
title: '获取位置失败', |
|||
icon: 'none' |
|||
}); |
|||
// throw error; // 重新抛出错误,以便在 init 方法中捕获 |
|||
} |
|||
}, |
|||
|
|||
// 封装 uni.getLocation 为一个返回 Promise 的函数 |
|||
getLocation() { |
|||
return new Promise((resolve, reject) => { |
|||
uni.getLocation({ |
|||
type: 'wgs84', |
|||
success: (res) => { |
|||
console.log('当前位置的经度:' + res.longitude); |
|||
console.log('当前位置的纬度:' + res.latitude); |
|||
resolve(res); |
|||
}, |
|||
fail: (err) => { |
|||
console.log(err); |
|||
reject(err); |
|||
} |
|||
}); |
|||
}); |
|||
}, |
|||
|
|||
//计算距离 |
|||
getDistance(lat1, lng1, lat2, lng2) { |
|||
const R = 6371; // 地球半径,单位为公里 |
|||
const dLat = this.deg2rad(lat2 - lat1); |
|||
const dLon = this.deg2rad(lng2 - lng1); |
|||
const a = |
|||
Math.sin(dLat / 2) * Math.sin(dLat / 2) + |
|||
Math.cos(this.deg2rad(lat1)) * Math.cos(this.deg2rad(lat2)) * |
|||
Math.sin(dLon / 2) * Math.sin(dLon / 2); |
|||
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); |
|||
const distance = R * c; // 距离,单位为公里 |
|||
|
|||
return distance.toFixed(2); // 保留两位小数 |
|||
}, |
|||
// 将角度转换为弧度 |
|||
deg2rad(deg) { |
|||
return deg * (Math.PI / 180); |
|||
}, |
|||
|
|||
|
|||
//加载更多(下一页) |
|||
loadMoreData() { |
|||
return //本页面无需下一页 |
|||
//判断是否加载 |
|||
if (!this.isReachedBottom) { |
|||
this.isReachedBottom = true;//设置为不可请求状态 |
|||
this.getList(); |
|||
} |
|||
}, |
|||
//重置为第一页 |
|||
loadData() { |
|||
setTimeout(() => { |
|||
this.isReachedBottom = false; // 重置状态,以便下次触发加载更多 |
|||
}, 1000); |
|||
}, |
|||
|
|||
//获取场地列表 |
|||
async getList(){ |
|||
this.loading = true |
|||
|
|||
let data = {...this.filteredData} |
|||
|
|||
//判断是否还有数据 |
|||
// if(this.filteredData.page * this.filteredData.limit > this.total){ |
|||
// this.loading = false |
|||
// uni.showToast({ |
|||
// title: '暂无更多', |
|||
// icon: 'none' |
|||
// }) |
|||
// return |
|||
// } |
|||
|
|||
let res = await apiRoute.xy_personCourseScheduleGetVenueListAll(data) |
|||
this.loading = false |
|||
this.isReachedBottom = false; |
|||
if (res.code != 1){ |
|||
uni.showToast({ |
|||
title: res.msg, |
|||
icon: 'none' |
|||
}) |
|||
return |
|||
} |
|||
|
|||
this.tableList = res.data |
|||
|
|||
|
|||
this.tableList.forEach((v,k)=>{ |
|||
if(this.longitude && this.latitude && (v.longitude || '') && (v.latitude || '')){ |
|||
//计算距离 |
|||
v.distance = this.getDistance(this.latitude, this.longitude, v.latitude, v.longitude) |
|||
}else{ |
|||
v.distance = null |
|||
} |
|||
}) |
|||
|
|||
console.log('列表',this.tableList) |
|||
}, |
|||
|
|||
//跳转页面-课程列表 |
|||
opebViewTimetable(item) { |
|||
let venue_id = item.id |
|||
this.$navigateTo({ |
|||
url: `/pages/student/timetable/index?venue_id=${venue_id}` |
|||
}) |
|||
}, |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.main_box { |
|||
width: 100%; |
|||
height: 100vh; |
|||
overflow: auto; |
|||
background: #292929; |
|||
} |
|||
.data_hint{ |
|||
margin-top: 100rpx; |
|||
font-size: 30rpx; |
|||
text-align: center; |
|||
color: #fff; |
|||
} |
|||
.main_section{ |
|||
width: 92%; |
|||
border-radius: 15rpx; |
|||
background-color: #404045; |
|||
margin: 20rpx auto; |
|||
padding: 40rpx 0 40rpx 80rpx; |
|||
color: #fff; |
|||
position: relative; |
|||
} |
|||
.title{ |
|||
font-size: 32rpx; |
|||
} |
|||
.con{ |
|||
color: #D7D7D7; |
|||
font-size: 26rpx; |
|||
margin-top: 20rpx; |
|||
} |
|||
.current-venue{ |
|||
border-radius: 8rpx; |
|||
border: 2rpx #F59A23 solid; |
|||
width: 120rpx; |
|||
text-align: center; |
|||
color: #F59A23; |
|||
position: absolute; |
|||
top: 10%; |
|||
right: 3%; |
|||
} |
|||
</style> |
|||
Loading…
Reference in new issue