img

一、案例介绍

本案例将展示Select组件在实际业务场景中的综合应用,通过实现一个在线课程选择系统,展示如何在复杂业务场景中灵活运用Select组件的各种特性。

二、代码实现

@Entry
@Component
struct CourseSelectionExample {
  @State selectedSemester: string = ''
  @State selectedDepartment: string = ''
  @State selectedMajor: string = ''
  @State selectedCourse: string = ''
  @State selectedTeacher: string = ''
  @State selectedTime: string = ''

  @State semesterIndex: number = -1
  @State departmentIndex: number = -1
  @State majorIndex: number = -1
  @State courseIndex: number = -1
  @State teacherIndex: number = -1
  @State timeIndex: number = -1

  @State departments: string[] = []
  @State majors: string[] = []
  @State courses: string[] = []
  @State teachers: string[] = []
  @State times: string[] = []

  @State selectedCourses: Array<{
    semester: string,
    course: string,
    teacher: string,
    time: string,
    credits: number
  }> = []

  private readonly semesters: string[] = ['2024春季学期', '2024秋季学期']
  private readonly departmentMap: Map<string, string[]> = new Map([
    ['2024春季学期', ['计算机学院', '经济学院', '外国语学院']],
    ['2024秋季学期', ['计算机学院', '经济学院', '外国语学院']]
  ])
  private readonly majorMap: Map<string, string[]> = new Map([
    ['计算机学院', ['计算机科学', '软件工程', '人工智能']],
    ['经济学院', ['经济学', '金融学', '国际贸易']],
    ['外国语学院', ['英语', '日语', '法语']]
  ])
  private readonly courseMap: Map<string, Array<{
    name: string,
    credits: number
  }>> = new Map([
    ['计算机科学', [
      { name: '数据结构', credits: 4 },
      { name: '操作系统', credits: 4 },
      { name: '计算机网络', credits: 3 }
    ]],
    ['软件工程', [
      { name: '软件工程导论', credits: 3 },
      { name: '需求分析', credits: 3 },
      { name: '软件测试', credits: 4 }
    ]]
  ])
  private readonly teacherMap: Map<string, string[]> = new Map([
    ['数据结构', ['王教授', '李教授', '张教授']],
    ['操作系统', ['刘教授', '陈教授', '孙教授']],
    ['计算机网络', ['赵教授', '钱教授', '孙教授']]
  ])
  private readonly timeMap: Map<string, string[]> = new Map([
    ['王教授', ['周一 1-2节', '周三 3-4节', '周五 5-6节']],
    ['李教授', ['周二 1-2节', '周四 3-4节', '周五 7-8节']],
    ['张教授', ['周一 3-4节', '周三 5-6节', '周五 1-2节']]
  ])

  build() {
    Column() {
      Text('在线选课系统')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 20 })

      // 学期选择
      this.SelectItem(
        '学期:',
        this.selectedSemester || '请选择学期',
        this.semesters,
        this.semesterIndex,
        (index: number) => {
          this.semesterIndex = index
          this.selectedSemester = this.semesters[index]
          this.departments = this.departmentMap.get(this.selectedSemester) || []
          this.resetDepartmentAndBelow()
        }
      )

      // 院系选择
      if (this.departments.length > 0) {
        this.SelectItem(
          '院系:',
          this.selectedDepartment || '请选择院系',
          this.departments,
          this.departmentIndex,
          (index: number) => {
            this.departmentIndex = index
            this.selectedDepartment = this.departments[index]
            this.majors = this.majorMap.get(this.selectedDepartment) || []
            this.resetMajorAndBelow()
          }
        )
      }

      // 专业选择
      if (this.majors.length > 0) {
        this.SelectItem(
          '专业:',
          this.selectedMajor || '请选择专业',
          this.majors,
          this.majorIndex,
          (index: number) => {
            this.majorIndex = index
            this.selectedMajor = this.majors[index]
            this.courses = (this.courseMap.get(this.selectedMajor) || []).map(course => course.name)
            this.resetCourseAndBelow()
          }
        )
      }

      // 课程选择
      if (this.courses.length > 0) {
        this.SelectItem(
          '课程:',
          this.selectedCourse || '请选择课程',
          this.courses,
          this.courseIndex,
          (index: number) => {
            this.courseIndex = index
            this.selectedCourse = this.courses[index]
            this.teachers = this.teacherMap.get(this.selectedCourse) || []
            this.resetTeacherAndBelow()
          }
        )
      }

      // 教师选择
      if (this.teachers.length > 0) {
        this.SelectItem(
          '教师:',
          this.selectedTeacher || '请选择教师',
          this.teachers,
          this.teacherIndex,
          (index: number) => {
            this.teacherIndex = index
            this.selectedTeacher = this.teachers[index]
            this.times = this.timeMap.get(this.selectedTeacher) || []
            this.resetTime()
          }
        )
      }

      // 时间选择
      if (this.times.length > 0) {
        this.SelectItem(
          '时间:',
          this.selectedTime || '请选择时间',
          this.times,
          this.timeIndex,
          (index: number) => {
            this.timeIndex = index
            this.selectedTime = this.times[index]
          }
        )
      }

      // 已选课程列表
      if (this.selectedCourses.length > 0) {
        Column() {
          Text('已选课程')
            .fontSize(18)
            .fontWeight(FontWeight.Bold)
            .margin({ top: 30, bottom: 10 })

          List() {
            ForEach(this.selectedCourses, (course, index) => {
              ListItem() {
                Row() {
                  Column() {
                    Text(course.course)
                      .fontSize(16)
                      .fontWeight(FontWeight.Medium)
                      .margin({ bottom: 4 })
                    Row() {
                      Text(`${course.teacher} | ${course.time}`)
                        .fontSize(14)
                        .fontColor('#666666')
                      Text(`学分:${course.credits}`)
                        .fontSize(14)
                        .fontColor('#666666')
                        .margin({ left: 16 })
                    }
                  }
                  .alignItems(HorizontalAlign.Start)
                  .layoutWeight(1)

                  Button({ type: ButtonType.Circle }) {
                    Image($r('app.media.ic_delete'))
                      .width(20)
                      .height(20)
                  }
                  .backgroundColor('#FFE8E8')
                  .onClick(() => {
                    this.removeCourse(index)
                  })
                }
                .width('100%')
                .padding(16)
                .backgroundColor(Color.White)
                .borderRadius(8)
                .margin({ bottom: 8 })
              }
            })
          }
        }
        .width('100%')
        .padding(16)
        .backgroundColor('#F5F5F5')
        .borderRadius(8)
      }

      // 选课按钮
      Button('添加课程')
        .width('100%')
        .height(50)
        .backgroundColor('#007DFF')
        .borderRadius(8)
        .fontSize(18)
        .fontColor(Color.White)
        .margin({ top: 20 })
        .enabled(this.canAddCourse())
        .opacity(this.canAddCourse() ? 1 : 0.5)
        .onClick(() => {
          this.addCourse()
        })
    }
    .width('100%')
    .height('100%')
    .padding(16)
  }

  @Builder
  SelectItem(label: string, value: string, options: string[], selectedIndex: number, onSelectCallback: (index: number) => void) {
    Row() {
      Text(label)
        .fontSize(16)
        .width(80)
      Select({
        value: value,
        selected: selectedIndex,
        options: options
      })
        .width('70%')
        .height(40)
        .backgroundColor(selectedIndex === -1 ? '#F5F5F5' : '#E6F2FF')
        .borderRadius(8)
        .fontColor(selectedIndex === -1 ? '#999999' : '#007DFF')
        .onSelect((index: number) => {
          onSelectCallback(index)
        })
    }
    .width('100%')
    .margin({ bottom: 20 })
  }

  private resetDepartmentAndBelow() {
    this.selectedDepartment = ''
    this.selectedMajor = ''
    this.selectedCourse = ''
    this.selectedTeacher = ''
    this.selectedTime = ''
    this.departmentIndex = -1
    this.majorIndex = -1
    this.courseIndex = -1
    this.teacherIndex = -1
    this.timeIndex = -1
    this.majors = []
    this.courses = []
    this.teachers = []
    this.times = []
  }

  private resetMajorAndBelow() {
    this.selectedMajor = ''
    this.selectedCourse = ''
    this.selectedTeacher = ''
    this.selectedTime = ''
    this.majorIndex = -1
    this.courseIndex = -1
    this.teacherIndex = -1
    this.timeIndex = -1
    this.courses = []
    this.teachers = []
    this.times = []
  }

  private resetCourseAndBelow() {
    this.selectedCourse = ''
    this.selectedTeacher = ''
    this.selectedTime = ''
    this.courseIndex = -1
    this.teacherIndex = -1
    this.timeIndex = -1
    this.teachers = []
    this.times = []
  }

  private resetTeacherAndBelow() {
    this.selectedTeacher = ''
    this.selectedTime = ''
    this.teacherIndex = -1
    this.timeIndex = -1
    this.times = []
  }

  private resetTime() {
    this.selectedTime = ''
    this.timeIndex = -1
  }

  private canAddCourse(): boolean {
    return this.selectedSemester !== '' &&
      this.selectedDepartment !== '' &&
      this.selectedMajor !== '' &&
      this.selectedCourse !== '' &&
      this.selectedTeacher !== '' &&
      this.selectedTime !== ''
  }

  private addCourse() {
    const courseInfo = this.courseMap.get(this.selectedMajor)?.find(course => course.name === this.selectedCourse)
    if (courseInfo) {
      // 检查时间冲突
      if (this.checkTimeConflict(this.selectedTime)) {
        AlertDialog.show({
          title: '提示',
          message: '所选时间与已选课程时间冲突',
          confirm: {
            value: '确定',
            action: () => {}
          }
        })
        return
      }

      this.selectedCourses.push({
        semester: this.selectedSemester,
        course: this.selectedCourse,
        teacher: this.selectedTeacher,
        time: this.selectedTime,
        credits: courseInfo.credits
      })

      // 重置选择
      this.resetCourseAndBelow()
    }
  }

  private removeCourse(index: number) {
    this.selectedCourses.splice(index, 1)
  }

  private checkTimeConflict(newTime: string): boolean {
    return this.selectedCourses.some(course => course.time === newTime)
  }
}

三、总结

本案例通过一个在线课程选择系统,展示了 Select 组件在实际业务场景中的综合应用。通过多级选择(学期、院系、专业、课程、教师、时间),实现了复杂的课程选择逻辑。通过状态管理(如 @State 管理选中值和索引),确保了用户选择的实时更新。通过已选课程列表和选课按钮,提供了用户友好的交互体验。这种设计不仅展示了 Select 组件的灵活性和易用性,还提供了丰富的交互效果,开发者可以参考此案例,快速实现类似的在线课程选择系统。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐