331 lines
7.8 KiB
Plaintext
331 lines
7.8 KiB
Plaintext
<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> |