Files
akmon/pages/sport/teacher/create-assignment.uvue
2026-01-20 08:04:15 +08:00

1188 lines
34 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<scroll-view class="create-assignment-container">
<!-- 标题栏 -->
<view class="page-header">
<text class="page-title">{{ isEditMode ? '编辑作业' : '创建作业' }}</text>
</view>
<!-- 可滚动内容区域 -->
<scroll-view class="scroll-container" direction="vertical" :show-scrollbar="false">
<view class="content-wrapper" :class="{ 'large-screen': isLargeScreen }">
<!-- 训练项目数据 -->
<supadb collection="ak_training_projects" :filter="projectsFilter" @process-data="handleProjectsData"
#default="{ data, loading: projectsLoading }">
<view style="display: none;"></view>
</supadb>
<!-- 班级数据 -->
<supadb collection="ak_classes" @process-data="handleClassesData"
#default="{ data, loading: classesLoading }">
<view style="display: none;"></view>
</supadb>
<form @submit.prevent="submitAssignment">
<!-- 基本信息 -->
<view class="form-section">
<view class="section-title">基本信息</view>
<view class="form-item">
<view class="form-label">
<text class="label-text">作业标题</text>
<text class="required-mark">*</text>
</view>
<input :value="formData.title" @input="onTitleInput" placeholder="请输入作业标题" maxlength="50" class="text-input" />
<view class="word-count">{{ formData.title.length }}/50</view>
</view>
<view class="form-item">
<view class="form-label">
<text class="label-text">作业描述</text>
</view> <textarea :value="formData.description" @input="onDescriptionInput" placeholder="请输入作业描述(可选)" maxlength="200"
class="textarea-input" />
<view class="word-count">{{ formData.description.length }}/200</view>
</view> <!-- 训练项目选择 -->
<view class="form-item">
<view class="form-label">
<text class="label-text">训练项目</text>
<text class="required-mark">*</text>
</view>
<view v-if="projectsLoading==false" class="picker-field"
@click="showProjectPickerActionSheet">
<text class="picker-text">{{ getSelectedProjectText() ?? '请选择训练项目' }}</text>
<text class="picker-arrow">▼</text>
</view>
<view v-else class="loading-picker">
<text>加载项目中..</text>
</view>
</view>
<!-- 项目详情预览 -->
<view v-if="selectedProject != null" class="project-preview">
<view class="preview-header">
<text class="preview-title">项目详情</text>
</view>
<view class="project-info">
<view class="info-row">
<text class="info-label">项目名称:</text>
<text class="info-value">{{ getProjectDisplayName(selectedProject) }}</text>
</view>
<view class="info-row">
<text class="info-label">难度等级:</text>
<text class="info-value difficulty" :class="getDifficultyClass(selectedProject)">
{{ getProjectDifficulty(selectedProject) }}
</text>
</view>
<view class="info-row">
<text class="info-label">类别:</text>
<text class="info-value">{{ getProjectCategory(selectedProject) }}</text>
</view>
</view>
</view>
</view>
<!-- 时间设置 -->
<view class="form-section">
<view class="section-title">时间设置</view>
<view class="form-item">
<view class="form-label">
<text class="label-text">截止日期</text>
<text class="required-mark">*</text>
</view>
<picker-date :value="formData.dueDate" placeholder="请选择截止日期" class="date-picker"
@change="onDatePickerChange" />
</view>
<view class="form-item">
<view class="form-label">
<text class="label-text">截止时间</text>
</view> <picker-time :value="convertTimeStringToArray(formData.dueTime)"
@change="onTimePickerChange" placeholder="请选择截止时间" class="time-picker" />
</view>
<view class="form-item">
<view class="form-label">
<text class="label-text">预计用时</text>
</view>
<view class="duration-input"> <input :value="formData.estimatedMinutes" @input="onEstimatedMinutesInput" type="number" placeholder="30"
class="number-input" />
<text class="unit-text">分钟</text>
</view>
</view>
</view>
<!-- 目标设置 -->
<view class="form-section">
<view class="section-title">目标设置</view>
<view class="form-item">
<view class="form-label">
<text class="label-text">目标描述</text>
</view> <textarea :value="formData.targetDescription" @input="onTargetDescriptionInput" placeholder="请描述本次作业的训练目标(可选)"
maxlength="300" class="textarea-input" />
<view class="word-count">{{ formData.targetDescription.length }}/300</view>
</view>
<view class="form-item">
<view class="form-label">
<text class="label-text">最低完成要求</text>
</view> <textarea :value="formData.minimumRequirement" @input="onMinimumRequirementInput" placeholder="请描述最低完成标准(可选)" maxlength="200"
class="textarea-input" />
<view class="word-count">{{ formData.minimumRequirement.length }}/200</view>
</view>
</view>
<!-- 评分设置 -->
<view class="form-section">
<view class="section-title">评分设置</view>
<view class="form-item">
<view class="form-label">
<text class="label-text">总分</text>
</view>
<view class="score-input"> <input :value="formData.totalScore" @input="onTotalScoreInput" type="number" placeholder="100"
class="number-input" />
<text class="unit-text">分</text>
</view>
</view>
<view class="form-item">
<view class="form-label">
<text class="label-text">及格分数</text>
</view>
<view class="score-input"> <input :value="formData.passingScore" @input="onPassingScoreInput" type="number" placeholder="60"
class="number-input" />
<text class="unit-text">分</text>
</view>
</view>
<view class="form-item checkbox-item">
<switch :value="formData.allowRetake" @change="onAllowRetakeChange" class="switch-input" />
<text class="checkbox-label">允许重新提交</text>
</view>
</view>
<!-- 高级设置 -->
<view class="form-section">
<view class="section-title">高级设置</view> <!-- 班级选择 -->
<view class="form-item">
<view class="form-label">
<text class="label-text">指定班级</text>
</view>
<view v-if="classesLoading==false" class="picker-field" @click="showClassPickerActionSheet">
<text class="picker-text">{{ formData.selectedClassName ?? '请选择班级(可选)' }}</text>
<text class="picker-arrow">▼</text>
</view>
<view v-else class="loading-picker">
<text>加载班级中..</text>
</view>
<text class="help-text">不选择则对所有班级开放</text>
</view>
<!-- 提交设置 -->
<view class="form-item">
<view class="form-label">
<text class="label-text">提交要求</text>
</view>
<view class="checkbox-group">
<view class="checkbox-item">
<switch :value="formData.requireVideo" @change="onRequireVideoChange" class="switch-input" />
<text class="checkbox-label">要求提交视频</text>
</view>
<view class="checkbox-item">
<switch :value="formData.requirePhoto" @change="onRequirePhotoChange" class="switch-input" />
<text class="checkbox-label">要求提交照片</text>
</view>
<view class="checkbox-item">
<switch :value="formData.requireText" @change="onRequireTextChange" class="switch-input" />
<text class="checkbox-label">要求文字说明</text>
</view>
</view>
</view>
<!-- 通知设置 -->
<view class="form-item">
<view class="form-label">
<text class="label-text">通知设置</text>
</view>
<view class="checkbox-group">
<view class="checkbox-item">
<switch :value="formData.sendNotification" @change="onSendNotificationChange" class="switch-input" />
<text class="checkbox-label">发布时通知学生</text>
</view>
<view class="checkbox-item">
<switch :value="formData.remindBeforeDeadline" @change="onRemindBeforeDeadlineChange" class="switch-input" />
<text class="checkbox-label">截止前提醒</text>
</view>
</view>
</view>
<!-- 评分细则 -->
<view class="form-item">
<view class="form-label">
<text class="label-text">评分细则</text>
</view> <textarea :value="formData.gradingCriteria" @input="onGradingCriteriaInput" placeholder="请详细描述评分标准和要求(可选)" maxlength="500"
class="textarea-input large" />
<view class="word-count">{{ formData.gradingCriteria.length }}/500</view>
</view>
<!-- 备注信息 -->
<view class="form-item">
<view class="form-label">
<text class="label-text">备注信息</text>
</view> <textarea :value="formData.notes" @input="onNotesInput" placeholder="其他需要说明的信息(可选)" maxlength="300"
class="textarea-input" />
<view class="word-count">{{ formData.notes.length }}/300</view>
</view>
</view>
<!-- 提交按钮 -->
<view class="submit-section">
<button @click="saveDraft" class="draft-btn" :disabled="submitting">
<text>保存草稿</text>
</button>
<button @click="submitAssignment" class="submit-btn" :disabled="submitting || !isFormValid">
<text>{{ isEditMode ? '更新作业' : '发布作业' }}</text>
</button>
</view>
</form>
</view>
</scroll-view>
</scroll-view>
</template>
<script lang="uts">
import supa from '@/components/supadb/aksupainstance.uts'
import { getCurrentUserId } from '@/utils/store.uts'
import {
getProjectId,
getProjectDisplayName,
getProjectCategory,
getProjectDifficulty,
getDifficultyClass
} from '@/pages/sport/types.uts'
type AssignmentFormData = {
title : string
description : string
projectId : string
classId : string
dueDate : string
dueTime : string
estimatedMinutes : string
targetDescription : string
minimumRequirement : string
totalScore : string
passingScore : string
allowRetake : boolean
// 高级设置
selectedClassName : string
requireVideo : boolean
requirePhoto : boolean
requireText : boolean
sendNotification : boolean
remindBeforeDeadline : boolean
gradingCriteria : string
notes : string
}
export default {
data() {
return {
screenWidth: uni.getSystemInfoSync().windowWidth,
isEditMode: false,
submitting: false,
assignmentId: '', // Store assignment ID for edit mode// Form data
formData: {
title: '',
description: '',
projectId: '',
classId: '', // Store class ID instead of class name
dueDate: '',
dueTime: '23:59',
estimatedMinutes: '30',
targetDescription: '',
minimumRequirement: '',
totalScore: '100',
passingScore: '60',
allowRetake: true,
selectedClassName: '', // Keep for display purposes
requireVideo: false,
requirePhoto: false,
requireText: false,
sendNotification: false,
remindBeforeDeadline: false,
gradingCriteria: '',
notes: ''
} as AssignmentFormData,
// Projects data
availableProjects: [] as UTSJSONObject[],
selectedProject: null as UTSJSONObject | null,
projectsLoading: true,
// Classes data
availableClasses: [] as UTSJSONObject[],
classesLoading: true,// Filters
projectsFilter: {
is_active: true // 只获取已激活的项目
}
}
},
computed: {
isFormValid() : boolean {
console.log(this.formData)
return this.formData.title.trim().length > 0 &&
this.formData.dueDate.length > 0
},
isLargeScreen() : boolean {
return (this.screenWidth as number) >= 768
}
},
onLoad(options : UTSJSONObject) {
const id = options.getString('id')
if (id != null && id.length > 0) {
this.isEditMode = true
this.assignmentId = id
this.loadAssignmentData(id)
}
},
onMounted() {
// Initialize screen width
this.screenWidth = uni.getSystemInfoSync().windowWidth
},
onResize(size : OnResizeOptions) {
this.screenWidth = size.size.windowWidth
},
methods: {
// Form input handlers
onTitleInput(event : InputEvent) {
this.formData.title = event.detail.value
},
onDescriptionInput(event : InputEvent) {
this.formData.description = event.detail.value
},
onEstimatedMinutesInput(event : InputEvent) {
this.formData.estimatedMinutes = event.detail.value
},
onTargetDescriptionInput(event : InputEvent) {
this.formData.targetDescription = event.detail.value
},
onMinimumRequirementInput(event : InputEvent) {
this.formData.minimumRequirement = event.detail.value
},
onTotalScoreInput(event : InputEvent) {
this.formData.totalScore = event.detail.value
},
onPassingScoreInput(event : InputEvent) {
this.formData.passingScore = event.detail.value
},
onGradingCriteriaInput(event : InputEvent) {
this.formData.gradingCriteria = event.detail.value
},
onNotesInput(event : InputEvent) {
this.formData.notes = event.detail.value
},
// Switch handlers
onAllowRetakeChange(event : SwitchChangeEvent) {
this.formData.allowRetake = event.detail.value
},
onRequireVideoChange(event : SwitchChangeEvent) {
this.formData.requireVideo = event.detail.value
},
onRequirePhotoChange(event : SwitchChangeEvent) {
this.formData.requirePhoto = event.detail.value
},
onRequireTextChange(event : SwitchChangeEvent) {
this.formData.requireText = event.detail.value
},
onSendNotificationChange(event : SwitchChangeEvent) {
this.formData.sendNotification = event.detail.value
},
onRemindBeforeDeadlineChange(event : SwitchChangeEvent) {
this.formData.remindBeforeDeadline = event.detail.value
}, // 获取当前教师ID全局实现替换本地实现
getCurrentTeacherId(): string {
const teacherId = getCurrentUserId()
if (teacherId == null || teacherId.length == 0) {
uni.navigateTo({ url: '/pages/user/login' })
return ''
}
return teacherId
}, // Time picker conversion methods
convertTimeStringToArray(timeString : string) : number[] {
if (timeString == null || timeString.length == 0) {
return [23, 59] // Default to 23:59
}
const parts = timeString.split(':')
if (parts.length >= 2) {
const hour = parseInt(parts[0]) ?? 0
const minute = parseInt(parts[1]) ?? 0
return [hour, minute]
}
return [23, 59] // Default fallback
}, convertTimeArrayToString(timeArray : number[]) : string {
if (timeArray == null || timeArray.length < 2) {
return '23:59' // Default fallback
} const hour = timeArray[0] ?? 0
const minute = timeArray[1] ?? 0
const hourStr = hour < 10 ? '0' + hour : hour.toString()
const minuteStr = minute < 10 ? '0' + minute : minute.toString()
return hourStr + ':' + minuteStr
}, onTimePickerChange(timeArray : number[]) {
this.formData.dueTime = this.convertTimeArrayToString(timeArray)
},
onDatePickerChange(dateString : string) {
this.formData.dueDate = dateString
}, handleProjectsData(data : UTSJSONObject) {
const dataArray = data.get("data")
if (dataArray != null && Array.isArray(dataArray)) {
this.availableProjects = dataArray as Array<UTSJSONObject>
} else {
this.availableProjects = []
}
console.log('DEBUG: Projects data received:', this.availableProjects)
console.log(this.availableProjects)
this.projectsLoading = false // 如果是编辑模式且已有项目ID设置选中的项目
if (this.isEditMode && this.formData.projectId.length > 0) {
this.setSelectedProjectById(this.formData.projectId)
}
}, handleClassesData(data : UTSJSONObject) {
console.log('DEBUG: Classes data processing started')
const dataArray = data.get("data")
if (dataArray != null && Array.isArray(dataArray)) {
this.availableClasses = dataArray as Array<UTSJSONObject>
} else {
this.availableClasses = []
}
console.log('DEBUG: Classes data received:', this.availableClasses)
this.classesLoading = false },async loadAssignmentData(assignmentId : string) { try {
console.log('加载作业数据:', assignmentId)
// 从 Supabase 加载作业数据
const result = await supa.from('ak_assignments').select('*', null).eq('id', assignmentId).execute()
if (result.status >= 200 && result.status < 300 && result.data != null && Array.isArray(result.data) && (result.data as Array<any>).length > 0) {
const dataArray = result.data as Array<any>
const assignment = dataArray[0] as UTSJSONObject // 填充表单数据
this.formData.title = assignment.getString('title') ?? ''
this.formData.description = assignment.getString('description') ?? '' // 解析截止时间
const dueDate = assignment.getString('due_date') ?? ''
if (dueDate != null && dueDate.length > 0) {
const date = new Date(dueDate)
this.formData.dueDate = date.toISOString().split('T')[0] // YYYY-MM-DD
this.formData.dueTime = date.toTimeString().substring(0, 5) // HH:MM
}
// 班级信息
const classId = assignment.getString('class_id') ?? ''
if (classId != null && classId.length > 0) {
this.formData.classId = classId // 尝试从可用班级中找到匹配的班级名称
const matchedClass = this.availableClasses.find((c : UTSJSONObject) : boolean => c.getString('id') === classId)
if (matchedClass != null) {
this.formData.selectedClassName = matchedClass?.getString('name') ?? ''
}
}
// 项目相关信息
const projectName = assignment.getString('project_name') ?? ''
if (projectName != null && projectName.length > 0) { // 尝试从可用项目中找到匹配的项目
const matchedProject = this.availableProjects.find((p : UTSJSONObject) : boolean => p.getString('name') === projectName)
if (matchedProject != null) {
this.selectProject(matchedProject)
}
}
console.log('作业数据加载成功:', this.formData)
} else {
console.error('加载作业数据失败:', result.error)
uni.showToast({ title: '加载作业数据失败', icon: 'none' })
}
} catch (error) {
console.error('加载作业数据异常:', error)
uni.showToast({ title: '网络错误,请重试', icon: 'none' })
}
},
showProjectPickerActionSheet() {
console.log('DEBUG: Available projects count:', this.availableProjects.length)
if (this.availableProjects.length === 0) {
uni.showToast({
title: '暂无可用项目',
icon: 'none'
})
return
}
const itemList : string[] = []
for (let i = 0; i < this.availableProjects.length; i++) {
const project = this.availableProjects[i]
console.log(project)
itemList.push(getProjectDisplayName(project))
}
console.log('DEBUG: ActionSheet itemList:', itemList)
uni.showActionSheet({
itemList,
success: (res) => {
if (typeof res.tapIndex === 'number') {
const selectedProject = this.availableProjects[res.tapIndex]
this.selectProject(selectedProject)
}
}
})
}, showClassPickerActionSheet() {
console.log('DEBUG: Available classes count:', this.availableClasses.length)
if (this.classesLoading) {
uni.showToast({
title: '班级数据加载中...',
icon: 'none'
})
return
}
if (this.availableClasses.length === 0) {
uni.showToast({
title: '暂无可用班级',
icon: 'none'
})
return
} // 构建班级选择列表,添加"全部班级"选项
const itemList = ['全部班级']
for (let i = 0; i < this.availableClasses.length; i++) {
const classData = this.availableClasses[i]
const className = classData.getString('name') ?? '未知班级'
itemList.push(className)
}
console.log('DEBUG: Class ActionSheet itemList:', itemList)
uni.showActionSheet({
itemList,
success: (res) => {
if (typeof res.tapIndex === 'number') {
if (res.tapIndex === 0) {
// 选择了"全部班级"
this.formData.selectedClassName = ''
this.formData.classId = '' } else {
// 选择了具体班级
const selectedClass = this.availableClasses[res.tapIndex - 1]
this.formData.selectedClassName = selectedClass.getString('name') ?? '未知班级'
this.formData.classId = selectedClass.getString('id') ?? ''
console.log('DEBUG: Selected class:', {
name: this.formData.selectedClassName,
id: this.formData.classId
})
}
}
}
})
}, selectProject(project : UTSJSONObject) {
this.selectedProject = project
this.formData.projectId = getProjectId(project) as string
},setSelectedProjectById(projectId : string) {
const project = this.availableProjects.find((p : UTSJSONObject) : boolean => getProjectId(p) === projectId)
if (project != null) {
this.selectedProject = project
}
},
getSelectedProjectText() : string | null {
if (this.selectedProject != null) {
const selectedProject = this.selectedProject
return getProjectDisplayName(selectedProject!!)
}
return null
},
async saveDraft() {
this.submitting = true
try {
const teacherId = this.getCurrentTeacherId()
if (teacherId == null || teacherId.length == 0) {
uni.showToast({ title: '用户未登录,请重新登录', icon: 'none' })
this.submitting = false
return
} // 构建草稿数据
const draftData = {
teacher_id: teacherId,
title: this.formData.title ?? '未命名草稿',
description: this.formData.description,
project_name: this.selectedProject?.getString('name') ?? '',
class_id: this.formData.classId ?? null, // 使用实际的班级ID due_date: (this.formData.dueDate != null && this.formData.dueDate.length > 0) ? `${this.formData.dueDate}T${this.formData.dueTime}:00.000Z` : null,
start_time: new Date().toISOString(),
end_time: (this.formData.dueDate != null && this.formData.dueDate.length > 0) ? `${this.formData.dueDate}T${this.formData.dueTime}:00.000Z` : null,
status: 'draft',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
} as UTSJSONObject
console.log('保存草稿数据:', draftData)
// 使用 Supabase 插入数据
const result = await supa.from('ak_assignments').insert(draftData).execute()
console.log('保存草稿结果:', result)
if (result.status >= 200 && result.status < 300) {
uni.showToast({
title: '草稿已保存',
icon: 'success'
})
} else {
console.error('保存草稿失败:', result.error)
uni.showToast({
title: '保存失败: ' + (result.error?.message ?? '未知错误'),
icon: 'none'
})
}
} catch (error) {
console.error('保存草稿失败:', error)
uni.showToast({
title: '网络错误,请重试',
icon: 'none'
})
} finally {
this.submitting = false
}
}, async submitAssignment() {
console.log('submitAssignment 0')
if (!this.isFormValid) {
uni.showToast({
title: '请完善必填信息',
icon: 'error',
duration: 4000
}
)
return
}
console.log('submitAssignment')
this.submitting = true
try {
// 获取当前教师ID
const teacherId = this.getCurrentTeacherId()
if (teacherId == null || teacherId.length == 0) {
uni.showToast({ title: '用户未登录,请重新登录', icon: 'none' })
this.submitting = false
return
}
if (this.isEditMode && this.assignmentId != null && this.assignmentId.length > 0) {
// 编辑模式 - 更新现有作业
const updateData = {
title: this.formData.title,
description: this.formData.description,
project_name: this.selectedProject?.getString('name') ?? '',
due_date: `${this.formData.dueDate}T${this.formData.dueTime}:00.000Z`,
end_time: `${this.formData.dueDate}T${this.formData.dueTime}:00.000Z`,
status: 'active',
updated_at: new Date().toISOString()
} as UTSJSONObject
console.log('更新作业数据:', updateData)
const result = await supa.from('ak_assignments').update(updateData).eq('id', this.assignmentId).execute()
console.log('更新结果:', result)
if (result.status >= 200 && result.status < 300) {
uni.showToast({
title: '作业已更新',
icon: 'success'
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
} else {
console.error('更新失败:', result.error)
uni.showToast({
title: '更新失败: ' + (result.error?.message ?? '未知错误'),
icon: 'none'
})
}
} else {
// 创建模式 - 新建作业
const assignmentData = {
teacher_id: teacherId,
title: this.formData.title,
description: this.formData.description,
project_name: this.selectedProject?.getString('name') ?? '',
class_id: this.formData.classId ?? null, // 使用实际的班级ID
due_date: `${this.formData.dueDate}T${this.formData.dueTime}:00.000Z`,
start_time: new Date().toISOString(), // 当前时间作为开始时间
end_time: `${this.formData.dueDate}T${this.formData.dueTime}:00.000Z`,
status: 'active',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
} as UTSJSONObject
console.log('创建作业数据:', assignmentData)
const result = await supa.from('ak_assignments').insert(assignmentData).execute()
console.log('创建结果:', result)
if (result.status >= 200 && result.status < 300) {
uni.showToast({
title: '作业已发布',
icon: 'success'
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
} else {
console.error('创建失败:', result.error)
uni.showToast({
title: '发布失败: ' + (result.error?.message ?? '未知错误'),
icon: 'none'
})
}
}
} catch (error) {
console.error('提交作业失败:', error)
uni.showToast({
title: '网络错误,请重试',
icon: 'none'
})
} finally {
this.submitting = false
}
}, debugProjectsData() {
console.log('=== MANUAL DEBUG ===')
console.log('availableProjects.length:', this.availableProjects.length)
console.log('availableProjects:', this.availableProjects)
console.log('projectsLoading:', this.projectsLoading)
console.log('projectsFilter:', this.projectsFilter)
// 显示具体的项目信息
for (let i = 0; i < this.availableProjects.length; i++) {
const project = this.availableProjects[i]
console.log(`Project ${i}:`, project)
try {
console.log(` - ID: ${getProjectId(project)}`)
console.log(` - DisplayName: ${getProjectDisplayName(project)}`)
console.log(` - Category: ${getProjectCategory(project)}`)
console.log(` - Difficulty: ${getProjectDifficulty(project)}`)
} catch (e) {
console.log(` - Error processing project:`, e)
}
}
uni.showToast({
title: `找到 ${this.availableProjects.length} 个项目`,
icon: 'none'
})
},
debugClassesData() {
console.log('=== CLASSES DEBUG ===')
console.log('availableClasses.length:', this.availableClasses.length)
console.log('availableClasses:', this.availableClasses)
console.log('classesLoading:', this.classesLoading) // 显示具体的班级信息
for (let i = 0; i < this.availableClasses.length; i++) {
const classData = this.availableClasses[i]
console.log(`Class ${i}:`, classData)
console.log(` - ID: ${classData.getString('id')}`)
console.log(` - Name: ${classData.getString('name')}`)
console.log(` - Grade ID: ${classData.getString('grade_id')}`)
}
uni.showToast({
title: `找到 ${this.availableClasses.length} 个班级`,
icon: 'none'
}) },
// Template helper wrapper methods
getProjectDisplayName(project : UTSJSONObject | null) : string {
if (project == null) return ''
return getProjectDisplayName(project)
},
getProjectDifficulty(project : UTSJSONObject | null) : number {
if (project == null) return 1
return getProjectDifficulty(project)
},
getProjectCategory(project : UTSJSONObject | null) : string {
if (project == null) return ''
return getProjectCategory(project)
},
getDifficultyClass(project : UTSJSONObject | null) : string {
if (project == null) return ''
return getDifficultyClass(project)
}
}
}
</script>
<style scoped>
.create-assignment-container {
flex: 1;
background-image: linear-gradient(to bottom right, #667eea, #764ba2);
min-height: 100vh;
display: flex;
flex-direction: column;
}
.page-header {
padding: 40rpx 30rpx 30rpx;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
flex-shrink: 0;
}
.page-title {
font-size: 48rpx;
font-weight: bold;
color: #FFFFFF;
}
.scroll-container {
flex: 1;
height: 0;
/* 确保滚动容器能正确工作 */
}
.content-wrapper {
padding: 30rpx;
background: #F8FAFC;
border-radius: 30rpx 30rpx 0 0;
margin-top: 20rpx;
min-height: calc(100vh - 160rpx);
/* 确保内容至少填满屏幕 */
}
.content-wrapper.large-screen {
padding: 40rpx;
max-width: 800rpx;
margin: 20rpx auto 0;
border-radius: 30rpx;
}
.form-section {
background: #FFFFFF;
padding: 30rpx;
border-radius: 20rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
margin-bottom: 30rpx;
}
.section-title {
font-size: 36rpx;
font-weight: bold;
color: #1E293B;
margin-bottom: 30rpx;
padding-bottom: 15rpx;
border-bottom: 2rpx solid #E2E8F0;
}
.form-item {
margin-bottom: 30rpx;
}
.form-item:last-child {
margin-bottom: 0;
}
.form-label {
flex-direction: row;
align-items: center;
margin-bottom: 15rpx;
}
.label-text {
font-size: 28rpx;
color: #374151;
font-weight: 400;
}
.required-mark {
color: #EF4444;
font-size: 28rpx;
margin-left: 5rpx;
}
.text-input,
.textarea-input {
width: 100%;
padding: 20rpx;
border: 2rpx solid #E5E7EB;
border-radius: 15rpx;
font-size: 28rpx;
color: #374151;
background: #FFFFFF;
}
.text-input:focus,
.textarea-input:focus {
border-color: #6366F1;
outline: none;
}
.textarea-input {
height: 150rpx;
text-align: top;
}
.word-count {
text-align: right;
font-size: 24rpx;
color: #9CA3AF;
margin-top: 10rpx;
}
.picker-field {
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 20rpx;
border: 2rpx solid #E5E7EB;
border-radius: 15rpx;
background: #FFFFFF;
min-height: 80rpx;
}
.picker-text {
font-size: 28rpx;
color: #374151;
flex: 1;
}
.picker-arrow {
font-size: 24rpx;
color: #9CA3AF;
}
.loading-picker {
padding: 20rpx;
border: 2rpx solid #E5E7EB;
border-radius: 15rpx;
background: #F9FAFB;
align-items: center;
justify-content: center;
min-height: 80rpx;
}
.date-picker,
.time-picker {
width: 100%;
height: 80rpx;
padding: 0 20rpx;
border: 2rpx solid #E5E7EB;
border-radius: 15rpx;
background: #FFFFFF;
font-size: 28rpx;
color: #374151;
}
.duration-input,
.score-input {
flex-direction: row;
align-items: center;
}
.duration-input .number-input,
.score-input .number-input {
margin-right: 15rpx;
}
.duration-input .unit-text,
.score-input .unit-text {
margin-left: 0;
}
.number-input {
flex: 1;
padding: 20rpx;
border: 2rpx solid #E5E7EB;
border-radius: 15rpx;
font-size: 28rpx;
color: #374151;
background: #FFFFFF;
text-align: center;
}
.unit-text {
font-size: 28rpx;
color: #6B7280;
}
.checkbox-item {
flex-direction: row;
align-items: center;
}
.checkbox-item .switch-input {
margin-right: 20rpx;
}
.switch-input {
transform: scale(0.8);
}
.checkbox-label {
font-size: 28rpx;
color: #374151;
}
/* Project Preview */
.project-preview {
background: #F8FAFC;
border: 2rpx solid #E2E8F0;
border-radius: 15rpx;
overflow: hidden;
margin-top: 20rpx;
}
.preview-header {
background: #EDE9FE;
padding: 20rpx;
}
.preview-title {
font-size: 28rpx;
color: #7C3AED;
font-weight: 400;
}
.project-info {
padding: 20rpx;
}
.project-info .info-row {
margin-bottom: 15rpx;
}
.project-info .info-row:last-child {
margin-bottom: 0;
}
.info-row {
flex-direction: row;
align-items: center;
}
.info-row .info-label {
margin-right: 15rpx;
}
.info-label {
font-size: 26rpx;
color: #6B7280;
width: 120rpx;
}
.info-value {
font-size: 26rpx;
color: #374151;
flex: 1;
}
.info-value.difficulty {
font-weight: 400;
}
.info-value.difficulty.beginner {
color: #10B981;
}
.info-value.difficulty.intermediate {
color: #F59E0B;
}
.info-value.difficulty.advanced {
color: #EF4444;
}
/* Advanced Settings */
.help-text {
font-size: 24rpx;
color: #9CA3AF;
margin-top: 8rpx;
}
.checkbox-group {}
.checkbox-group .checkbox-item {
margin-bottom: 20rpx;
}
.checkbox-group .checkbox-item:last-child {
margin-bottom: 0;
}
.checkbox-group .checkbox-item {
margin-bottom: 20rpx;
}
.checkbox-group .checkbox-item:last-child {
margin-bottom: 0;
}
.textarea-input.large {
height: 200rpx;
}
/* Submit Section */
.submit-section {
flex-direction: row;
margin-top: 40rpx;
padding: 0 30rpx 40rpx;
}
.submit-section .draft-btn,
.submit-section .submit-btn {
margin-right: 20rpx;
}
.submit-section .submit-btn:last-child {
margin-right: 0;
}
.draft-btn,
.submit-btn {
flex: 1;
height: 90rpx;
border-radius: 20rpx;
font-size: 32rpx;
font-weight: 400;
border: none;
}
.draft-btn {
background: #F3F4F6;
color: #6B7280;
}
.draft-btn:active {
background: #E5E7EB;
}
.submit-btn {
background-image: linear-gradient(to bottom right, #6366F1, #8B5CF6);
color: #FFFFFF;
}
.submit-btn:active {
opacity: 0.8;
}
.submit-btn:disabled,
.draft-btn:disabled {
opacity: 0.5;
}
</style>