保存数据

This commit is contained in:
Ls
2026-04-11 17:47:28 +08:00
parent f682c0316b
commit c9aeba0949
35 changed files with 5658 additions and 3544 deletions

View File

@@ -41,38 +41,14 @@
</view>
</view>
<!-- 泳道设置 -->
<view class="form-card">
<view class="form-title">泳道设置</view>
<view class="radio-group">
<view class="radio-item" :class="{ active: courseData.laneType === 'single' }"
@click="selectSingleLane">
<view class="radio-icon">
<view v-if="courseData.laneType === 'single'" class="radio-inner"></view>
</view>
<text>一个泳道</text>
</view>
<view class="radio-item" :class="{ active: courseData.laneType === 'multi' }"
@click="selectMultiLane">
<view class="radio-icon">
<view v-if="courseData.laneType === 'multi'" class="radio-inner"></view>
</view>
<text>多个泳道</text>
</view>
</view>
<view v-if="courseData.laneType === 'multi'" class="multi-lane-options">
<view class="lane-input-wrapper">
<text class="lane-label">泳道个数</text>
<view class="lane-input">
<input class="number-input" v-model="courseData.laneCount" type="number"
placeholder="请输入泳道个数" />
<text class="unit-text"></text>
</view>
</view>
<!-- 组别设置 -->
<view v-if="type==1" class="form-card">
<view class="form-title">组别设置</view>
<view class="group-options">
<view class="person-input-wrapper">
<text class="person-label">一个泳道人数</text>
<text class="person-label">每组人数</text>
<view class="person-input">
<input class="number-input" v-model="courseData.lanePersonCount" type="number"
<input class="number-input" v-model="courseData.groupPersonCount" type="number"
placeholder="请输入人数" />
<text class="unit-text"></text>
</view>
@@ -80,11 +56,34 @@
</view>
</view>
<!-- 分段设置 -->
<view v-if="type==2" class="form-card">
<view class="form-title">分段设置</view>
<view class="segment-options">
<view class="segment-input-wrapper">
<text class="segment-label">分段距离</text>
<view class="segment-input">
<input class="number-input" v-model="courseData.segmentDistance" type="number"
placeholder="请输入距离" />
<text class="unit-text"></text>
</view>
</view>
<view class="segment-count-wrapper">
<text class="segment-count-label">分段数</text>
<view class="segment-count-input">
<input class="number-input" v-model="courseData.segmentCount" type="number"
placeholder="请输入段数" />
<text class="unit-text"></text>
</view>
</view>
</view>
</view>
<!-- 学生列表 -->
<view class="form-card">
<view class="student-header">
<view class="header-left">
<text class="form-title">选择学生</text>
<text class="form-title" style="margin-bottom: 0;">选择学生</text>
<text class="student-count">已选({{ selectedStudentIds.length }}/{{ allStudents.length }})</text>
</view>
<view class="header-actions">
@@ -111,11 +110,12 @@
</view>
<view v-else class="student-list">
<view v-for="student in allStudents" :key="student.id" class="student-item"
:class="{ checked: selectedStudentIds.includes(student.id) }"
@click="toggleStudentSelect(student.id)">
<view class="student-checkbox" :class="{ checked: selectedStudentIds.includes(student.id) }">
<u-icon v-if="selectedStudentIds.includes(student.id)" name="checkmark" size="14"
<view v-for="student in allStudents" :key="student.studentId" class="student-item"
:class="{ checked: selectedStudentIds.includes(student.studentId) }"
@click="toggleStudentSelect(student.studentId)">
<view class="student-checkbox"
:class="{ checked: selectedStudentIds.includes(student.studentId) }">
<u-icon v-if="selectedStudentIds.includes(student.studentId)" name="checkmark" size="14"
color="#fff"></u-icon>
</view>
<view class="student-avatar">
@@ -123,12 +123,6 @@
</view>
<view class="student-info">
<view class="student-name">{{ student.name }}</view>
<view class="student-meta">
<text class="gender-badge" :class="student.gender === '男' ? 'male' : 'female'">
{{ student.gender }}
</text>
<text class="age-text">{{ student.age }}</text>
</view>
</view>
</view>
</view>
@@ -139,10 +133,10 @@
<text class="preview-title">已选学生</text>
</view>
<view class="preview-list">
<view v-for="(student, index) in selectedStudents" :key="student.id" class="preview-item">
<view v-for="(student, index) in selectedStudents" :key="student.studentId" class="preview-item">
<text class="preview-index">{{ index + 1 }}</text>
<text class="preview-name">{{ student.name }}</text>
<view class="preview-remove" @click.stop="removeSelectedStudent(student.id)">
<view class="preview-remove" @click.stop="removeSelectedStudent(student.studentId)">
<u-icon name="close" size="14" color="#ff4d4f"></u-icon>
</view>
</view>
@@ -150,7 +144,9 @@
</view>
</view>
</view>
<view class="" style="width: 100%; height: 80rpx;">
</view>
<!-- 底部按钮区域 -->
<view class="bottom-actions">
<view class="action-buttons">
@@ -164,29 +160,24 @@
import { ref, computed } from 'vue'
import { Service } from '@/Service/Service'
import { onLoad } from '@dcloudio/uni-app'
import { PlanService } from '@/Service/swimming/PlanService'
import { studentService } from '@/Service/swimming/studentService'
// 学生类型
interface Student {
id : string
name : string
gender : string
age : string
school ?: string
address ?: string
}
// 课程数据
const courseData = ref({
projectName: '',
startType: 'together', // together | interval
intervalSeconds: '',
laneType: 'single', // single | multi
laneCount: '',
lanePersonCount: ''
groupPersonCount: '',
segmentDistance: '',
segmentCount: ''
})
// 所有学生列表
const allStudents = ref<Student[]>([])
const allStudents = ref<Array<any>>([])
// 已选学生ID列表
const selectedStudentIds = ref<string[]>([])
@@ -194,60 +185,62 @@
// 加载状态
const loading = ref(false)
onLoad(() => {
let type = ref('')
let planId=ref('')
onLoad((data : any) => {
type.value = data.type
if(data.id){
planId.value=data.id
getPlanInfo()
}
getStudentList()
})
// 获取计划详情
const getPlanInfo = () => {
PlanService.GetPlanInfo(planId.value).then(res => {
if (res.code == 0) {
selectedStudentIds.value=res.data.plan.users.map((item:any)=>{
return item.studentId
})
courseData.value.groupPersonCount=res.data.plan.groupInt
courseData.value.segmentDistance=res.data.plan.subsectionDistance
courseData.value.segmentCount=res.data.plan.subsectionInt
courseData.value.projectName=res.data.plan.name
courseData.value.startType = res.data.plan.departType == '间隔出发' ? 'interval' : 'together'
courseData.value.intervalSeconds = res.data.plan.interval
} else {
Service.Msg(res.msg)
}
})
}
// 是否全选
const allSelected = computed(() => {
return allStudents.value.length > 0 && allStudents.value.every(s => selectedStudentIds.value.includes(s.id))
return allStudents.value.length > 0 && allStudents.value.every(s => selectedStudentIds.value.includes(s.studentId))
})
// 已选学生列表(按选择顺序排序)
const selectedStudents = computed(() => {
return selectedStudentIds.value
.map(id => allStudents.value.find(s => s.id === id))
.map(id => allStudents.value.find(s => s.studentId === id))
.filter((s) : s is Student => s !== undefined)
})
// 选择单泳道
const selectSingleLane = () => {
courseData.value.laneType = 'single'
}
// 选择多泳道
const selectMultiLane = () => {
courseData.value.laneType = 'multi'
}
// 获取学生列表(模拟接口)
const getStudentList = async () => {
loading.value = true
try {
// TODO: 实际项目中应从接口获取
// const res = await Service.Request('/api/students', 'GET', {})
// allStudents.value = res.data
// 模拟接口延迟
await new Promise(resolve => setTimeout(resolve, 500))
// 假数据
allStudents.value = [
{ id: '001', name: '张三', gender: '男', age: '12', school: '第一小学' },
{ id: '002', name: '李四', gender: '女', age: '13', school: '第二小学' },
{ id: '003', name: '王五', gender: '男', age: '11', school: '第一小学' },
{ id: '004', name: '赵六', gender: '女', age: '12', school: '第三小学' },
{ id: '005', name: '钱七', gender: '男', age: '14', school: '第二小学' },
{ id: '006', name: '孙八', gender: '女', age: '10', school: '第一小学' },
{ id: '007', name: '周九', gender: '男', age: '13', school: '第四小学' },
{ id: '008', name: '吴十', gender: '女', age: '12', school: '第二小学' }
]
} catch (error) {
Service.Msg('获取学生列表失败')
console.error(error)
} finally {
loading.value = false
}
studentService.GetStudentList().then(res => {
if (res.code == 0) {
allStudents.value = res.data
loading.value = false
} else {
Service.Msg(res.msg)
}
})
}
// 切换学生选中状态
@@ -267,7 +260,7 @@
selectedStudentIds.value = []
} else {
// 全选
selectedStudentIds.value = allStudents.value.map(s => s.id)
selectedStudentIds.value = allStudents.value.map(s => s.studentId)
}
}
@@ -279,11 +272,70 @@
}
}
// 保存项目
const confirmCreate = () => {
if (!courseData.value.projectName) {
Service.Msg('请输入项目名称!')
return
}
if (courseData.value.startType == 'interval' && !courseData.value.intervalSeconds) {
Service.Msg('请输入正确时间间隔!')
return
}
if (!courseData.value.groupPersonCount && type.value=='1') {
Service.Msg('请输入每组人数!')
return
}
if (!courseData.value.segmentDistance && type.value=='2') {
Service.Msg('请输入分段距离')
return
}
if (!courseData.value.segmentCount && type.value=='2') {
Service.Msg('请输入分段数')
return
}
let users=[]
selectedStudents.value.map((item:any)=>{
users.push({
studentId:item.studentId,
name:item.name
})
})
const data = {
planId: planId.value,
name: courseData.value.projectName,
planType:type.value=='1'?'计时项目':'分段项目',
departType: courseData.value.startType=='together'?'一起出发':'间隔出发',
interval: courseData.value.startType=='together'?0:courseData.value.intervalSeconds,
groupInt: courseData.value.groupPersonCount?courseData.value.groupPersonCount:'',
subsectionDistance: courseData.value.segmentDistance?courseData.value.segmentDistance:'',
subsectionInt: courseData.value.segmentCount?courseData.value.segmentCount:'',
users: JSON.stringify(users),
project: '',
group: '',
}
console.log(data);
PlanService.AddPlan(data).then(res=>{
if(res.code==0){
Service.Msg('添加成功!')
setTimeout(()=>{
Service.GoPageBack()
},1000)
}else{
Service.Msg(res.msg)
}
})
}
</script>
@@ -446,15 +498,14 @@
}
}
/* 多泳道选项 */
.multi-lane-options {
padding-top: 20rpx;
/* 组别选项 */
.group-options {
display: flex;
flex-direction: column;
gap: 16rpx;
}
.lane-input-wrapper,
.group-input-wrapper,
.person-input-wrapper {
background-color: #f5f5f5;
border-radius: 16rpx;
@@ -463,7 +514,7 @@
align-items: center;
justify-content: space-between;
.lane-label,
.group-label,
.person-label {
font-size: 28rpx;
font-weight: 600;
@@ -471,7 +522,7 @@
}
}
.lane-input,
.group-input,
.person-input {
flex: 1;
margin-left: 24rpx;
@@ -495,6 +546,54 @@
}
}
/* 分段设置选项 */
.segment-options {
display: flex;
flex-direction: column;
gap: 16rpx;
}
.segment-input-wrapper,
.segment-count-wrapper {
background-color: #f5f5f5;
border-radius: 16rpx;
padding: 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
.segment-label,
.segment-count-label {
font-size: 28rpx;
font-weight: 600;
color: #333;
}
}
.segment-input,
.segment-count-input {
flex: 1;
margin-left: 24rpx;
display: flex;
align-items: center;
background-color: #fff;
border-radius: 12rpx;
padding: 0 20rpx;
height: 72rpx;
.number-input {
flex: 1;
font-size: 28rpx;
color: #333;
}
.unit-text {
font-size: 24rpx;
color: #999;
margin-left: 12rpx;
}
}
/* 学生列表头部 */
.student-header {
display: flex;
@@ -785,7 +884,7 @@
.cancel-btn,
.confirm-btn {
flex: 1;
flex: 1;
height: 88rpx;
border-radius: 16rpx;
border: none;