Files
2026-09-24 16:25:22 +08:00

331 lines
7.8 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>
<hr-page page-bg="#FFFFFF" status-bg="#FFFFFF" nav-title="课程库" :no-scroll="true" @right-click="goCert">
<!-- ============ 搜索行(xSearch ============ -->
<view class="cl-search">
<view class="hr-flex1">
<x-search v-model="keyword" placeholder="搜索课题,如 成人 CPR / AED" round="20rpx" height="72rpx"
input-bg-color="#F3F4F6" icon-color="#9CA3AF" font-color="#1F2937"
:show-cancel="false"></x-search>
</view>
</view>
<!-- ============ 一级侧栏 + 三级内容 ============ -->
<view class="cl-split">
<scroll-view class="cl-side" :scroll-y="true" :show-scrollbar="false">
<view v-for="(c, i) in catalogs" :key="c.id"
:class="activeCatalog == i ? 'cl-side-item cl-side-item-on' : 'cl-side-item'" @click="onCatalog(i)">
<view class="cl-side-ic" :style="{ backgroundColor: c.iconBg }">
<text class="cl-side-ic-t" :style="{ color: c.iconColor }">{{ c.icon }}</text>
</view>
<text :class="activeCatalog == i ? 'cl-side-b cl-side-b-on' : 'cl-side-b'">{{ c.name }}</text>
<text class="cl-side-s">{{ c.count }} 课题</text>
</view>
</scroll-view>
<scroll-view class="cl-main" :scroll-y="true" :show-scrollbar="false">
<!-- 搜索过滤结果 -->
<view v-if="keyword != ''">
<view v-for="(r, i) in searchResult" :key="i" class="cl-l3" @click="openSubject(r)">
<view class="cl-l3-no">
<text class="cl-l3-no-t">{{ r.no }}</text>
</view>
<view class="hr-flex1">
<text class="cl-l3-b">{{ r.name }}</text>
<text class="cl-l3-s">{{ r.meta }}</text>
</view>
<text class="cl-l3-go"></text>
</view>
<hr-empty v-if="searchResult.length == 0" icon="⌕" title="没有匹配的课题"
sub="换个关键词试试,例如「CPR」「AED」「气道」"></hr-empty>
</view>
<!-- 二级组标题 + 三级条目 -->
<view v-else-if="activeCatalog == 0">
<view v-for="(g, gi) in groups" :key="gi">
<view class="cl-group">
<view class="cl-group-bar"></view>
<text class="cl-group-b">{{ g.name }}</text>
<view class="cl-group-cnt">
<text class="cl-group-cnt-t">{{ g.count }} 课题</text>
</view>
<view class="cl-group-line"></view>
</view>
<view v-for="(it, ii) in g.items" :key="ii" class="cl-l3" @click="openSubject(it)">
<view class="cl-l3-no">
<text class="cl-l3-no-t">{{ it.no }}</text>
</view>
<view class="hr-flex1">
<text class="cl-l3-b">{{ it.name }}</text>
<text class="cl-l3-s">{{ it.meta }}</text>
</view>
<text class="cl-l3-go"></text>
</view>
</view>
<view style="margin:6px 13px 14px 13px">
<hr-tip theme="info" icon=""
:text="'共 ' + catalogs.length + ' 个一级分类 · 49 个课题。其余分类的课题内容正在建设,敬请期待。'"></hr-tip>
</view>
</view>
<hr-empty v-else icon="▦" :title="catalogName + ' · 内容建设中'" sub="该分类的课题与题库正在录入,可先学习「急救基础」"></hr-empty>
<view style="height:24px"></view>
</scroll-view>
</view>
</hr-page>
</template>
<script lang="uts" setup>
import { ref, computed } from 'vue'
import { catalogList, courseGroups } from '@/mock/index.uts'
import { HrCatalog, HrGroup, HrSubject } from '@/mock/types.uts'
import { navTo } from '@/utils/nav.uts'
/**
* s10 课程库(三级导航)
* 一级侧栏分类 + 二级组标题(不可点,仅作分组)+ 三级课题条目(唯一可点)。
*/
const catalogs = ref<HrCatalog[]>(catalogList)
const groups = ref<HrGroup[]>(courseGroups)
const activeCatalog = ref(0)
const keyword = ref('')
const catalogName = computed(() : string => {
return catalogs.value[activeCatalog.value].name
})
/** 全量课题(用于搜索) */
const allSubjects = computed(() : HrSubject[] => {
const list : HrSubject[] = []
for (let gi = 0; gi < groups.value.length; gi++) {
const g = groups.value[gi]
for (let ii = 0; ii < g.items.length; ii++) {
list.push(g.items[ii])
}
}
return list
})
const searchResult = computed(() : HrSubject[] => {
if (keyword.value == '') { return [] as HrSubject[] }
const kw = keyword.value.toLowerCase()
const list : HrSubject[] = []
for (let i = 0; i < allSubjects.value.length; i++) {
const s = allSubjects.value[i]
if (s.name.toLowerCase().indexOf(kw) > -1) { list.push(s) }
}
return list
})
function onCatalog(i : number) : void {
activeCatalog.value = i
keyword.value = ''
}
function openSubject(s : HrSubject) : void {
navTo('/pages/course/subject?name=' + s.name)
}
function goCert() : void {
navTo('/pages/study/certificates')
}
function onScanSearch() : void {
uni.showToast({ title: '扫码搜索课题', icon: 'none' })
}
</script>
<style>
.cl-search {
display: flex;
flex-direction: row;
align-items: center;
background-color: #FFFFFF;
border-bottom: 2rpx solid #F3F4F6;
padding: 16rpx 28rpx 16rpx 28rpx;
}
.cl-search-scan {
margin-left: 16rpx;
width: 72rpx;
height: 72rpx;
border-radius: 20rpx;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.cl-split {
flex: 1;
display: flex;
flex-direction: row;
}
/* ---------- 左侧一级分类 ---------- */
.cl-side {
width: 184rpx;
background-color: #FAFBFC;
border-right: 2rpx solid #F3F4F6;
}
.cl-side-item {
flex-direction: column;
align-items: center;
padding: 22rpx 12rpx 22rpx 12rpx;
border-left: 6rpx solid transparent;
}
.cl-side-item-on {
background-color: #FFFFFF;
border-left: 6rpx solid #2563EB;
}
.cl-side-ic {
width: 72rpx;
height: 72rpx;
border-radius: 22rpx;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
margin-bottom: 12rpx;
}
.cl-side-ic-t {
font-size: 33.6rpx;
font-weight: bold;
}
.cl-side-b {
font-size: 25.8rpx;
color: #1F2937;
}
.cl-side-b-on {
color: #2563EB;
font-weight: bold;
}
.cl-side-s {
font-size: 20.2rpx;
color: #9CA3AF;
margin-top: 4rpx;
}
/* ---------- 右侧内容 ---------- */
.cl-main {
flex: 1;
background-color: #F3F4F6;
}
.cl-hint {
display: flex;
flex-direction: row;
align-items: center;
padding: 20rpx 26rpx 8rpx 26rpx;
}
.cl-hint-i {
font-size: 23.6rpx;
color: #2563EB;
font-weight: bold;
margin-right: 12rpx;
}
.cl-hint-t {
font-size: 23.6rpx;
color: #9CA3AF;
}
.cl-group {
display: flex;
flex-direction: row;
align-items: center;
padding: 26rpx 26rpx 16rpx 26rpx;
}
.cl-group-bar {
width: 6rpx;
height: 24rpx;
border-radius: 4rpx;
background-color: #2563EB;
margin-right: 14rpx;
}
.cl-group-b {
font-size: 29.2rpx;
font-weight: bold;
color: #1F2937;
}
.cl-group-cnt {
margin-left: 14rpx;
background-color: #EFF6FF;
border-radius: 12rpx;
padding: 2rpx 12rpx 2rpx 12rpx;
}
.cl-group-cnt-t {
font-size: 21.2rpx;
font-weight: bold;
color: #2563EB;
}
.cl-group-line {
flex: 1;
height: 2rpx;
background-color: #F3F4F6;
margin-left: 14rpx;
}
.cl-l3 {
display: flex;
flex-direction: row;
align-items: center;
margin: 0rpx 26rpx 16rpx 26rpx;
background-color: #FFFFFF;
border: 2rpx solid #F3F4F6;
border-radius: 22rpx;
padding: 22rpx 24rpx 22rpx 24rpx;
}
.cl-l3-no {
width: 48rpx;
height: 48rpx;
border-radius: 16rpx;
background-color: #EFF6FF;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
margin-right: 20rpx;
}
.cl-l3-no-t {
font-size: 23.6rpx;
font-weight: bold;
color: #2563EB;
}
.cl-l3-b {
font-size: 29.2rpx;
color: #1F2937;
lines: 1;
}
.cl-l3-s {
font-size: 23.6rpx;
color: #9CA3AF;
margin-top: 4rpx;
}
.cl-l3-go {
font-size: 33.6rpx;
color: #9CA3AF;
margin-left: 16rpx;
}
</style>