1
This commit is contained in:
@@ -0,0 +1,361 @@
|
||||
<template>
|
||||
<hr-page page-bg="#F3F4F6" status-bg="#FFFFFF" nav-title="课题详情" :xloading="true" @right-click="onMore">
|
||||
<template v-slot:right>
|
||||
<x-icon name="more-fill" color="#6B7280" font-size="18"></x-icon>
|
||||
</template>
|
||||
|
||||
<!-- ============ 课题 hero ============ -->
|
||||
<view class="subj-bar">
|
||||
<view class="subj-c1"></view>
|
||||
<view class="subj-info">
|
||||
<view class="subj-nav" @click="prevSubject">
|
||||
<x-icon name="arrow-left-s-line" color="#FFFFFF" font-size="18"></x-icon>
|
||||
</view>
|
||||
<view class="subj-mid">
|
||||
<view class="hr-flex1">
|
||||
<text class="subj-name">{{ subject }}</text>
|
||||
<text class="subj-sub">急救基础 · 心肺复苏 · 资料 6 份 · 题库 50</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="subj-nav" @click="nextSubject">
|
||||
<x-icon name="arrow-right-s-line" color="#FFFFFF" font-size="18"></x-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="hr-body">
|
||||
|
||||
<!-- ============ 学习进度 ============ -->
|
||||
<hr-card>
|
||||
<view class="hr-row-between" style="margin-bottom:9px">
|
||||
<text class="sj-lb">学习进度</text>
|
||||
<text class="sj-pct">{{ progress }}%</text>
|
||||
</view>
|
||||
<hr-progress :percent="progress"></hr-progress>
|
||||
<view class="hr-row" style="margin-top:11px">
|
||||
<text class="sj-meta">已学资料 <text class="sj-meta-v">4/6</text></text>
|
||||
<text class="sj-meta sj-meta-gap">已练题 <text class="sj-meta-v">32/50</text></text>
|
||||
<text class="sj-meta sj-meta-gap">正确率 <text class="sj-meta-ok">{{ rate }}%</text></text>
|
||||
</view>
|
||||
</hr-card>
|
||||
|
||||
<!-- ============ 功能入口 ============ -->
|
||||
<hr-sec title="功能入口"></hr-sec>
|
||||
<view class="sj-entries">
|
||||
<view v-for="(e, i) in entries" :key="i" class="sj-entry"
|
||||
:class="i == entries.length - 1 ? 'sj-entry-last' : ''" @click="onEntry(i)">
|
||||
<view class="sj-entry-ic" :style="{ backgroundColor: e.bg }">
|
||||
<x-icon :name="entryIcon(e.icon)" :color="e.color" font-size="40rpx"></x-icon>
|
||||
</view>
|
||||
<text class="sj-entry-b">{{ e.name }}</text>
|
||||
<text class="sj-entry-s">{{ e.sub }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- ============ 文档资料 ============ -->
|
||||
<hr-sec title="文档资料" more="共 6 份 ›" @more-click="onMore"></hr-sec>
|
||||
<hr-card variant="list">
|
||||
<view v-for="(m, i) in materials" :key="m.id" class="doc-row"
|
||||
:class="i == materials.length - 1 ? 'doc-row-last' : ''" @click="openMaterial(m)">
|
||||
<view class="doc-ic" :style="{ backgroundColor: m.badgeColor }">
|
||||
<x-icon v-if="m.kind == 'video'" name="play-fill" color="#FFFFFF" font-size="32rpx"></x-icon>
|
||||
<text v-else class="doc-ic-tx">{{ m.icon }}</text>
|
||||
</view>
|
||||
<view class="hr-flex1">
|
||||
<text class="doc-b">{{ m.title }}</text>
|
||||
<text class="doc-s">{{ m.meta }}</text>
|
||||
</view>
|
||||
<view class="doc-go">
|
||||
<x-icon name="arrow-right-s-line" color="#9CA3AF" font-size="34rpx"></x-icon>
|
||||
</view>
|
||||
</view>
|
||||
</hr-card>
|
||||
<view class="doc-hint">
|
||||
<text class="doc-hint-t">✦ 点击任意资料查看详情(视频与文档共用同一详情页)</text>
|
||||
</view>
|
||||
|
||||
<view style="height:14px"></view>
|
||||
</view>
|
||||
</hr-page>
|
||||
</template>
|
||||
|
||||
<script lang="uts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { subjectMaterials, courseGroups } from '@/mock/index.uts'
|
||||
import { HrMaterial, HrSubject } from '@/mock/types.uts'
|
||||
import { navTo } from '@/utils/nav.uts'
|
||||
import { toRemixIcon } from '@/utils/icon.uts'
|
||||
|
||||
/**
|
||||
* s35 课题详情
|
||||
* 不再设章节目录与章节学习;改为「学习进度 + 错题/收藏/顺序练习 三入口 + 文档资料列表」。
|
||||
*/
|
||||
type Entry = { icon : string, name : string, sub : string, bg : string, color : string }
|
||||
|
||||
/*
|
||||
* ⚠ 模板里不能直接调用「import 进来的函数」:
|
||||
* uvue 编译器会把 `<x-icon :name="toRemixIcon(e.icon)">` 编译成 `unref(toRemixIcon)(e.icon)`,
|
||||
* UTS/Kotlin 侧报 `找不到名称"invoke"` / `Function invocation 'toRemixIcon(...)' expected`。
|
||||
* 必须包一层本文件内定义的函数(模板对 script 内定义的函数会走 _ctx.xxx,正常)。
|
||||
*/
|
||||
function entryIcon(glyph : string) : string {
|
||||
return toRemixIcon(glyph)
|
||||
}
|
||||
|
||||
const subject = ref('成人 CPR(高级生命支持)')
|
||||
const progress = ref(68)
|
||||
const rate = ref(78)
|
||||
const materials = ref<HrMaterial[]>(subjectMaterials)
|
||||
|
||||
const entries : Entry[] = [
|
||||
{ icon: '✗', name: '我的错题', sub: '12 道', bg: '#FEF2F2', color: '#DC2626' } as Entry,
|
||||
{ icon: '★', name: '我的收藏', sub: '8 道', bg: '#FEF3C7', color: '#B45309' } as Entry,
|
||||
{ icon: '▸', name: '顺序练习', sub: '50 题 · 约 30 分钟', bg: '#ECFDF5', color: '#059669' } as Entry
|
||||
]
|
||||
|
||||
/** 全部三级课题,用于上一个 / 下一个切换 */
|
||||
const allSubjects = computed(() : HrSubject[] => {
|
||||
const list : HrSubject[] = []
|
||||
for (let gi = 0; gi < courseGroups.length; gi++) {
|
||||
const g = courseGroups[gi]
|
||||
for (let ii = 0; ii < g.items.length; ii++) {
|
||||
list.push(g.items[ii])
|
||||
}
|
||||
}
|
||||
return list
|
||||
})
|
||||
|
||||
function indexOfSubject() : number {
|
||||
for (let i = 0; i < allSubjects.value.length; i++) {
|
||||
if (allSubjects.value[i].name == subject.value) { return i }
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
function prevSubject() : void {
|
||||
let i = indexOfSubject() - 1
|
||||
if (i < 0) { i = allSubjects.value.length - 1 }
|
||||
subject.value = allSubjects.value[i].name
|
||||
}
|
||||
|
||||
function nextSubject() : void {
|
||||
let i = indexOfSubject() + 1
|
||||
if (i >= allSubjects.value.length) { i = 0 }
|
||||
subject.value = allSubjects.value[i].name
|
||||
}
|
||||
|
||||
function onEntry(i : number) : void {
|
||||
if (i == 0) { navTo('/pages/study/wrong-book'); return }
|
||||
if (i == 1) { uni.showToast({ title: '我的收藏 · 8 道题', icon: 'none' }); return }
|
||||
navTo('/pages/course/practice')
|
||||
}
|
||||
|
||||
function openMaterial(m : HrMaterial) : void {
|
||||
navTo('/pages/course/media?id=' + m.id)
|
||||
}
|
||||
|
||||
function onMore() : void {
|
||||
uni.showToast({ title: '资料管理 / 下载全部', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* ---------- hero ---------- */
|
||||
.subj-bar {
|
||||
background-image: linear-gradient(to bottom right, #2563EB, #1D4ED8);
|
||||
padding: 24rpx 28rpx 24rpx 28rpx;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.subj-c1 {
|
||||
position: absolute;
|
||||
right: -72rpx;
|
||||
top: -92rpx;
|
||||
width: 260rpx;
|
||||
height: 260rpx;
|
||||
border-radius: 130rpx;
|
||||
background-color: rgba(255, 255, 255, 0.09);
|
||||
}
|
||||
|
||||
.subj-info {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.subj-nav {
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
border-radius: 16rpx;
|
||||
background-color: rgba(255, 255, 255, 0.18);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.subj-mid {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-left: 18rpx;
|
||||
margin-right: 18rpx;
|
||||
}
|
||||
|
||||
.subj-name {
|
||||
font-size: 31.4rpx;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
lines: 1;
|
||||
}
|
||||
|
||||
.subj-sub {
|
||||
font-size: 23.6rpx;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
margin-top: 4rpx;
|
||||
lines: 1;
|
||||
}
|
||||
|
||||
/* ---------- 学习进度 ---------- */
|
||||
.sj-lb {
|
||||
font-size: 29.2rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
}
|
||||
|
||||
.sj-pct {
|
||||
font-size: 25.8rpx;
|
||||
font-weight: bold;
|
||||
color: #2563EB;
|
||||
}
|
||||
|
||||
.sj-meta {
|
||||
font-size: 24.6rpx;
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
.sj-meta-gap {
|
||||
margin-left: 28rpx;
|
||||
}
|
||||
|
||||
.sj-meta-v {
|
||||
font-size: 24.6rpx;
|
||||
color: #1F2937;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.sj-meta-ok {
|
||||
font-size: 24.6rpx;
|
||||
color: #059669;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* ---------- 功能入口 ---------- */
|
||||
.sj-entries {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.sj-entry {
|
||||
flex: 1;
|
||||
background-color: #FFFFFF;
|
||||
border: 2rpx solid #E5E7EB;
|
||||
border-radius: 26rpx;
|
||||
padding: 26rpx 12rpx 22rpx 12rpx;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-right: 18rpx;
|
||||
}
|
||||
|
||||
.sj-entry-last {
|
||||
margin-right: 0rpx;
|
||||
}
|
||||
|
||||
.sj-entry-ic {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 26rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 14rpx;
|
||||
}
|
||||
|
||||
.sj-entry-b {
|
||||
font-size: 25.8rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
}
|
||||
|
||||
.sj-entry-s {
|
||||
font-size: 21.2rpx;
|
||||
color: #9CA3AF;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
/* ---------- 资料行 ---------- */
|
||||
.doc-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding-top: 24rpx;
|
||||
padding-bottom: 24rpx;
|
||||
border-bottom: 2rpx solid #F3F4F6;
|
||||
}
|
||||
|
||||
.doc-row-last {
|
||||
border-bottom-width: 0rpx;
|
||||
}
|
||||
|
||||
.doc-ic {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 20rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 22rpx;
|
||||
}
|
||||
|
||||
.doc-ic-tx {
|
||||
font-size: 21.2rpx;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.doc-b {
|
||||
font-size: 29.2rpx;
|
||||
color: #1F2937;
|
||||
lines: 1;
|
||||
}
|
||||
|
||||
.doc-s {
|
||||
font-size: 23.6rpx;
|
||||
color: #9CA3AF;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.doc-go {
|
||||
margin-left: 16rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.doc-hint {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 16rpx 0rpx 4rpx 0rpx;
|
||||
}
|
||||
|
||||
.doc-hint-t {
|
||||
font-size: 23.6rpx;
|
||||
color: #9CA3AF;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user