1
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
<template>
|
||||
<hr-page page-bg="#F3F4F6" status-bg="#FFFFFF" nav-title="答题卡" @right-click="submit">
|
||||
<template v-slot:right>
|
||||
<text class="ac-nav-submit">交卷</text>
|
||||
</template>
|
||||
|
||||
<view class="hr-body">
|
||||
|
||||
<!-- ============ 图例 ============ -->
|
||||
<hr-card>
|
||||
<view class="hr-row hr-wrap">
|
||||
<view class="ac-lg">
|
||||
<view class="ac-lg-s" style="background-color:#EFF6FF;border:1px solid #BFDBFE"></view>
|
||||
<text class="ac-lg-t">已答 {{ doneCount }}</text>
|
||||
</view>
|
||||
<view class="ac-lg">
|
||||
<view class="ac-lg-s" style="background-color:#FFFFFF;border:1px solid #E5E7EB"></view>
|
||||
<text class="ac-lg-t">未答 {{ total - doneCount }}</text>
|
||||
</view>
|
||||
<view class="ac-lg">
|
||||
<view class="ac-lg-s" style="background-color:#FEF3C7;border:1px solid #FDE68A"></view>
|
||||
<text class="ac-lg-t">标记 {{ markCount }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</hr-card>
|
||||
|
||||
<!-- ============ 题号九宫格 ============ -->
|
||||
<hr-card style="margin-top:10px">
|
||||
<view class="ac-grid">
|
||||
<view v-for="(q, i) in questions" :key="i" :class="cellClass(i)" :style="cellStyle" @click="jump(i)">
|
||||
<text :class="cellTextClass(i)">{{ i + 1 }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</hr-card>
|
||||
|
||||
<hr-tip style="margin-top:10px" :theme="answeredAll ? 'ok' : 'warn'"
|
||||
:icon="answeredAll ? '✓' : '⚑'"
|
||||
:text="answeredAll ? '全部题目已作答,可以交卷了。' : ('仍有 ' + (total - doneCount) + ' 题未作答,交卷后将无法返回修改。')"></hr-tip>
|
||||
|
||||
<view style="height:14px"></view>
|
||||
</view>
|
||||
|
||||
<template v-slot:footer>
|
||||
<view class="hr-fixedbar">
|
||||
<view class="hr-btn hr-btn-ghost ac-foot-prev" @click="resume">
|
||||
<text class="ac-foot-t">继续答题</text>
|
||||
</view>
|
||||
<view class="hr-btn hr-btn-primary" style="flex:1" @click="submit">
|
||||
<text class="ac-foot-t2">交卷并查看成绩</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</hr-page>
|
||||
</template>
|
||||
|
||||
<script lang="uts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { quizQuestions } from '@/mock/index.uts'
|
||||
import { quizState, answeredCount, markedCount } from '@/utils/quiz.uts'
|
||||
import { navBack, relaunchTo } from '@/utils/nav.uts'
|
||||
|
||||
/** s18 答题卡 */
|
||||
const questions = quizQuestions
|
||||
const total = questions.length
|
||||
const refreshKey = ref(0)
|
||||
const cellSize = ref(92)
|
||||
|
||||
const doneCount = computed(() : number => {
|
||||
const k = refreshKey.value
|
||||
return answeredCount()
|
||||
})
|
||||
|
||||
const markCount = computed(() : number => {
|
||||
const k = refreshKey.value
|
||||
return markedCount()
|
||||
})
|
||||
|
||||
const answeredAll = computed(() : boolean => {
|
||||
return doneCount.value == total
|
||||
})
|
||||
|
||||
const cellStyle = computed(() : string => {
|
||||
return `width:${cellSize.value}rpx;height:${cellSize.value}rpx;`
|
||||
})
|
||||
|
||||
onLoad(() => {
|
||||
// 6 列均分:内容宽 750rpx - 页面左右 64 - 卡片左右 52 - 5 个 16rpx 间隙 80
|
||||
cellSize.value = Math.floor((750 - 64 - 52 - 80) / 6)
|
||||
})
|
||||
|
||||
onPageShow(() => {
|
||||
refreshKey.value = refreshKey.value + 1
|
||||
})
|
||||
|
||||
function cellClass(i : number) : string {
|
||||
const k = refreshKey.value
|
||||
if (quizState.current == i) { return 'ac-cell ac-cell-cur' }
|
||||
if (quizState.marked[i]) { return 'ac-cell ac-cell-mark' }
|
||||
if (quizState.answers[i] >= 0) { return 'ac-cell ac-cell-done' }
|
||||
return 'ac-cell'
|
||||
}
|
||||
|
||||
function cellTextClass(i : number) : string {
|
||||
const k = refreshKey.value
|
||||
if (quizState.current == i) { return 'ac-cell-t ac-cell-t-cur' }
|
||||
return 'ac-cell-t'
|
||||
}
|
||||
|
||||
function jump(i : number) : void {
|
||||
quizState.current = i
|
||||
navBack()
|
||||
}
|
||||
|
||||
function resume() : void {
|
||||
navBack()
|
||||
}
|
||||
|
||||
function submit() : void {
|
||||
uni.showModal({
|
||||
title: '交卷确认',
|
||||
content: `已作答 ${doneCount.value} / ${total} 题。交卷后无法修改。`,
|
||||
cancelText: '继续答题',
|
||||
confirmText: '交卷',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
quizState.submitted = true
|
||||
uni.showToast({ title: '已交卷 · 得分 92', icon: 'success' })
|
||||
setTimeout(() => {
|
||||
relaunchTo('/pages/study/exams')
|
||||
}, 700)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.ac-nav-submit {
|
||||
font-size: 31.4rpx;
|
||||
color: #2563EB;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.ac-lg {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-right: 28rpx;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.ac-lg-s {
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
border-radius: 8rpx;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.ac-lg-t {
|
||||
font-size: 25.8rpx;
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
.ac-grid {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.ac-cell {
|
||||
border-radius: 18rpx;
|
||||
background-color: #FFFFFF;
|
||||
border: 2rpx solid #E5E7EB;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 16rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.ac-cell-done {
|
||||
background-color: #EFF6FF;
|
||||
border: 2rpx solid #BFDBFE;
|
||||
}
|
||||
|
||||
.ac-cell-mark {
|
||||
background-color: #FEF3C7;
|
||||
border: 2rpx solid #FDE68A;
|
||||
}
|
||||
|
||||
.ac-cell-cur {
|
||||
background-color: #2563EB;
|
||||
border: 2rpx solid #2563EB;
|
||||
}
|
||||
|
||||
.ac-cell-t {
|
||||
font-size: 26.8rpx;
|
||||
font-weight: bold;
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
.ac-cell-t-cur {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.ac-foot-prev {
|
||||
flex: 0 0 220rpx;
|
||||
margin-right: 18rpx;
|
||||
}
|
||||
|
||||
.ac-foot-t {
|
||||
font-size: 31.4rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
}
|
||||
|
||||
.ac-foot-t2 {
|
||||
font-size: 32.4rpx;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,331 @@
|
||||
<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>
|
||||
@@ -0,0 +1,490 @@
|
||||
<template>
|
||||
<hr-page page-bg="#F3F4F6" status-bg="#FFFFFF" :nav-title="material.title" @right-click="onStar">
|
||||
<template v-slot:right>
|
||||
<x-icon :name="starred ? 'star-fill' : 'star-line'" :color="starred ? '#F59E0B' : '#6B7280'"
|
||||
font-size="19"></x-icon>
|
||||
</template>
|
||||
|
||||
<view class="hr-body" style="padding-bottom:22px">
|
||||
|
||||
<!-- ============ 视频资料 ============ -->
|
||||
<view v-if="isVideo">
|
||||
<view class="vd" :style="{ height: videoH + 'rpx' }">
|
||||
<!-- 播放/暂停 -->
|
||||
<view class="vd-play" @click="togglePlay">
|
||||
<x-icon :name="playing ? 'pause-fill' : 'play-fill'" :color="playing ? '#FFFFFF' : '#1D4ED8'"
|
||||
font-size="20"></x-icon>
|
||||
</view>
|
||||
<!-- 进度条 -->
|
||||
<view class="vd-bar">
|
||||
<view class="vd-track">
|
||||
<view class="vd-track-i" :style="{ width: played + '%' }"></view>
|
||||
</view>
|
||||
<view class="vd-row">
|
||||
<text class="vd-time">{{ curTime }} / {{ totalTime }}</text>
|
||||
<view class="vd-acts">
|
||||
<view @click="togglePlay">
|
||||
<x-icon :name="playing ? 'pause-line' : 'play-line'" color="#FFFFFF"
|
||||
font-size="16"></x-icon>
|
||||
</view>
|
||||
<view style="margin-left:14px" @click="onFullscreen">
|
||||
<x-icon name="fullscreen-line" color="#FFFFFF" font-size="16"></x-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<hr-card style="margin-top:10px">
|
||||
<view class="hr-row-top">
|
||||
<text class="md-title">{{ material.title }}</text>
|
||||
<view class="md-badge" :style="{ backgroundColor: material.badgeColor }">
|
||||
<text class="md-badge-t">{{ material.badge }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<text class="md-meta">{{ material.meta }}</text>
|
||||
<text class="md-from">来自 {{ material.from }}</text>
|
||||
<view class="hr-row" style="margin-top:12px">
|
||||
<view style="flex:1">
|
||||
<hr-progress :percent="played"></hr-progress>
|
||||
</view>
|
||||
<text class="md-seen">已看 {{ played }}%</text>
|
||||
</view>
|
||||
</hr-card>
|
||||
</view>
|
||||
|
||||
<!-- ============ 文档资料 ============ -->
|
||||
<view v-else>
|
||||
<view class="dv">
|
||||
<view class="dv-sheet">
|
||||
<view class="dv-t"></view>
|
||||
<view class="dv-l dv-l-s"></view>
|
||||
<view class="dv-l"></view>
|
||||
<view class="dv-l dv-l-m"></view>
|
||||
<view class="dv-img"></view>
|
||||
<view class="dv-l dv-l-s"></view>
|
||||
<view class="dv-l dv-l-m"></view>
|
||||
<text class="dv-pg">{{ page }} / 12</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="dv-pager">
|
||||
<view class="dv-pager-b" @click="prevPage">
|
||||
<x-icon name="arrow-left-s-line" color="#6B7280" font-size="16"></x-icon>
|
||||
</view>
|
||||
<text class="dv-pager-t">第 {{ page }} 页 / 共 12 页</text>
|
||||
<view class="dv-pager-b" @click="nextPage">
|
||||
<x-icon name="arrow-right-s-line" color="#6B7280" font-size="16"></x-icon>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<hr-card style="margin-top:10px">
|
||||
<view class="hr-row-top">
|
||||
<text class="md-title">{{ material.title }}</text>
|
||||
<view class="md-badge" :style="{ backgroundColor: material.badgeColor }">
|
||||
<text class="md-badge-t">{{ material.badge }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<text class="md-meta">{{ material.meta }}</text>
|
||||
<text class="md-from">来自 {{ material.from }}</text>
|
||||
</hr-card>
|
||||
</view>
|
||||
|
||||
<!-- ============ 资料简介 ============ -->
|
||||
<hr-sec title="资料简介" :first="false"></hr-sec>
|
||||
<hr-card>
|
||||
<text class="md-desc">{{ material.summary }}</text>
|
||||
</hr-card>
|
||||
|
||||
<!-- ============ 学习笔记(仅视频) ============ -->
|
||||
<view v-if="isVideo">
|
||||
<hr-sec title="学习笔记" more="编辑 ›" @more-click="onEditNote"></hr-sec>
|
||||
<hr-card>
|
||||
<text class="md-desc">{{ note }}</text>
|
||||
<text class="md-note-time">最后编辑:昨天 21:32</text>
|
||||
</hr-card>
|
||||
</view>
|
||||
|
||||
<!-- ============ 离线下载 ============ -->
|
||||
<hr-sec title="离线下载" :more="downloaded ? '⇅ 管理 ›' : '⇅ 下载 ›'" @more-click="onDownload"></hr-sec>
|
||||
<hr-card variant="list">
|
||||
<hr-lrow :icon="downloaded ? '✓' : '⇅'" :theme="downloaded ? 'grn' : 'pri'"
|
||||
:title="downloaded ? '已下载到本机' : '尚未下载'" :sub="downloaded ? '2.4 MB · 无网络时仍可查阅' : '点击下载后可离线查阅'"
|
||||
:value="downloaded ? '已存' : '下载'" :value-theme="downloaded ? 'grn' : 'pri'" :value-bold="true"
|
||||
:is-last="true" @click="onDownload"></hr-lrow>
|
||||
</hr-card>
|
||||
|
||||
<view style="height:8px"></view>
|
||||
</view>
|
||||
|
||||
<template v-slot:footer>
|
||||
<view class="hr-fixedbar">
|
||||
<view class="hr-btn hr-btn-ghost md-fav" @click="onStar">
|
||||
<x-icon :name="starred ? 'star-fill' : 'star-line'" :color="starred ? '#F59E0B' : '#1F2937'"
|
||||
font-size="17"></x-icon>
|
||||
<text class="md-fav-t">{{ starred ? '已收藏' : '收藏' }}</text>
|
||||
</view>
|
||||
<view class="hr-btn hr-btn-primary md-main" @click="onMainAction">
|
||||
<text class="md-main-t">{{ isVideo ? (downloaded ? '已下载离线观看' : '下载离线观看') : '在线查看' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</hr-page>
|
||||
</template>
|
||||
|
||||
<script lang="uts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { subjectMaterials } from '@/mock/index.uts'
|
||||
import { HrMaterial } from '@/mock/types.uts'
|
||||
|
||||
/**
|
||||
* s02 / s41 资料详情(视频与文档共用同一页)
|
||||
* 标题即资料名称;不再有章节目录与章节学习。
|
||||
*/
|
||||
const material = ref<HrMaterial>(subjectMaterials[1])
|
||||
const starred = ref(false)
|
||||
const downloaded = ref(false)
|
||||
const page = ref(1)
|
||||
const playing = ref(false)
|
||||
const played = ref(62)
|
||||
const videoH = ref(386)
|
||||
const totalSeconds = 504
|
||||
let timer : number = 0
|
||||
|
||||
const note = '按压深度 5~6 cm,频率 100~120 次/分;每次按压后必须让胸廓完全回弹,尽量减少中断(<10 秒)……'
|
||||
|
||||
// ⚠ UTS 不提升函数声明(App 端编译报 UTSC error18: 找不到名称),
|
||||
// 被调用的函数一律写在调用点之前
|
||||
function formatTime(sec : number) : string {
|
||||
const m = Math.floor(sec / 60)
|
||||
const s = sec % 60
|
||||
const ss = s < 10 ? '0' + s.toString() : s.toString()
|
||||
return `${m}:${ss}`
|
||||
}
|
||||
|
||||
function stopTimer() : void {
|
||||
if (timer != 0) {
|
||||
clearInterval(timer)
|
||||
timer = 0
|
||||
}
|
||||
}
|
||||
|
||||
const isVideo = computed(() : boolean => {
|
||||
return material.value.kind == 'video'
|
||||
})
|
||||
|
||||
const curTime = computed(() : string => {
|
||||
const sec = Math.floor(totalSeconds * played.value / 100)
|
||||
return formatTime(sec)
|
||||
})
|
||||
|
||||
const totalTime = computed(() : string => {
|
||||
return formatTime(totalSeconds)
|
||||
})
|
||||
|
||||
onLoad((opt) => {
|
||||
const raw = opt['id']
|
||||
if (raw != null) {
|
||||
const id = raw as string
|
||||
for (let i = 0; i < subjectMaterials.length; i++) {
|
||||
if (subjectMaterials[i].id == id) {
|
||||
material.value = subjectMaterials[i]
|
||||
played.value = subjectMaterials[i].progress > 0 ? subjectMaterials[i].progress : 0
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// 视频区保持 16:9:内容宽 = 750rpx - 页面左右各 32rpx
|
||||
videoH.value = Math.round((750 - 64) * 9 / 16)
|
||||
})
|
||||
|
||||
onUnload(() => {
|
||||
stopTimer()
|
||||
})
|
||||
|
||||
function togglePlay() : void {
|
||||
playing.value = !playing.value
|
||||
if (playing.value) {
|
||||
stopTimer()
|
||||
timer = setInterval(() => {
|
||||
if (played.value >= 100) {
|
||||
played.value = 100
|
||||
playing.value = false
|
||||
stopTimer()
|
||||
return
|
||||
}
|
||||
played.value = played.value + 1
|
||||
}, 1000)
|
||||
} else {
|
||||
stopTimer()
|
||||
}
|
||||
}
|
||||
|
||||
function prevPage() : void {
|
||||
if (page.value <= 1) {
|
||||
uni.showToast({ title: '已是第一页', icon: 'none' })
|
||||
return
|
||||
}
|
||||
page.value = page.value - 1
|
||||
}
|
||||
|
||||
function nextPage() : void {
|
||||
if (page.value >= 12) {
|
||||
uni.showToast({ title: '已是最后一页', icon: 'none' })
|
||||
return
|
||||
}
|
||||
page.value = page.value + 1
|
||||
}
|
||||
|
||||
function onStar() : void {
|
||||
starred.value = !starred.value
|
||||
uni.showToast({ title: starred.value ? '已加入收藏' : '已取消收藏', icon: 'none' })
|
||||
}
|
||||
|
||||
function onDownload() : void {
|
||||
if (downloaded.value) {
|
||||
uni.showToast({ title: '已下载到本机', icon: 'none' })
|
||||
return
|
||||
}
|
||||
uni.showLoading({ title: '下载中' })
|
||||
setTimeout(() => {
|
||||
uni.hideLoading()
|
||||
downloaded.value = true
|
||||
uni.showToast({ title: '下载完成 · 可离线查阅', icon: 'success' })
|
||||
}, 900)
|
||||
}
|
||||
|
||||
function onMainAction() : void {
|
||||
if (isVideo.value) {
|
||||
onDownload()
|
||||
return
|
||||
}
|
||||
uni.showToast({ title: '已用系统阅读器打开', icon: 'none' })
|
||||
}
|
||||
|
||||
function onEditNote() : void {
|
||||
uni.showToast({ title: '编辑学习笔记', icon: 'none' })
|
||||
}
|
||||
|
||||
function onFullscreen() : void {
|
||||
uni.showToast({ title: '已进入全屏播放', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* ---------- 视频 ---------- */
|
||||
.vd {
|
||||
width: 100%;
|
||||
background-color: #111827;
|
||||
border-radius: 24rpx;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.vd-play {
|
||||
width: 104rpx;
|
||||
height: 104rpx;
|
||||
border-radius: 52rpx;
|
||||
background-color: rgba(255, 255, 255, 0.92);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.vd-bar {
|
||||
position: absolute;
|
||||
left: 0rpx;
|
||||
right: 0rpx;
|
||||
bottom: 0rpx;
|
||||
padding: 0rpx 24rpx 20rpx 24rpx;
|
||||
}
|
||||
|
||||
.vd-track {
|
||||
height: 6rpx;
|
||||
border-radius: 6rpx;
|
||||
background-color: rgba(255, 255, 255, 0.28);
|
||||
}
|
||||
|
||||
.vd-track-i {
|
||||
height: 6rpx;
|
||||
border-radius: 6rpx;
|
||||
background-color: #2563EB;
|
||||
}
|
||||
|
||||
.vd-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
|
||||
.vd-time {
|
||||
font-size: 24.6rpx;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.vd-acts {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* ---------- 文档预览 ---------- */
|
||||
.dv {
|
||||
background-color: #E5E7EB;
|
||||
border-radius: 24rpx;
|
||||
padding: 24rpx 24rpx 24rpx 24rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.dv-sheet {
|
||||
width: 80%;
|
||||
background-color: #FFFFFF;
|
||||
border-radius: 8rpx;
|
||||
padding: 30rpx 26rpx 32rpx 26rpx;
|
||||
box-shadow: 0 6rpx 24rpx rgba(15, 23, 42, 0.16);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dv-t {
|
||||
height: 18rpx;
|
||||
width: 58%;
|
||||
border-radius: 6rpx;
|
||||
background-color: #CBD5E1;
|
||||
margin-bottom: 22rpx;
|
||||
}
|
||||
|
||||
.dv-l {
|
||||
height: 12rpx;
|
||||
border-radius: 6rpx;
|
||||
background-color: #E5E7EB;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.dv-l-s {
|
||||
width: 88%;
|
||||
}
|
||||
|
||||
.dv-l-m {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
.dv-img {
|
||||
height: 100rpx;
|
||||
border-radius: 12rpx;
|
||||
background-color: #F1F5F9;
|
||||
margin: 6rpx 0rpx 20rpx 0rpx;
|
||||
}
|
||||
|
||||
.dv-pg {
|
||||
font-size: 20.2rpx;
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
.dv-pager {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-top: 16rpx;
|
||||
}
|
||||
|
||||
.dv-pager-b {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
border-radius: 16rpx;
|
||||
background-color: #FFFFFF;
|
||||
border: 2rpx solid #E5E7EB;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.dv-pager-t {
|
||||
font-size: 23.6rpx;
|
||||
color: #9CA3AF;
|
||||
margin-left: 24rpx;
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
|
||||
/* ---------- 详情 ---------- */
|
||||
.md-title {
|
||||
flex: 1;
|
||||
font-size: 33.6rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
margin-right: 18rpx;
|
||||
}
|
||||
|
||||
.md-badge {
|
||||
border-radius: 14rpx;
|
||||
padding: 6rpx 18rpx 6rpx 18rpx;
|
||||
}
|
||||
|
||||
.md-badge-t {
|
||||
font-size: 23.6rpx;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.md-meta {
|
||||
font-size: 25.8rpx;
|
||||
color: #6B7280;
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.md-from {
|
||||
font-size: 24.6rpx;
|
||||
color: #9CA3AF;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.md-seen {
|
||||
font-size: 24.6rpx;
|
||||
font-weight: bold;
|
||||
color: #2563EB;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
.md-desc {
|
||||
font-size: 28rpx;
|
||||
color: #6B7280;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.md-note-time {
|
||||
font-size: 23.6rpx;
|
||||
color: #9CA3AF;
|
||||
margin-top: 18rpx;
|
||||
}
|
||||
|
||||
.md-fav {
|
||||
flex: 0 0 220rpx;
|
||||
margin-right: 18rpx;
|
||||
}
|
||||
|
||||
.md-fav-t {
|
||||
font-size: 31.4rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
.md-main {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.md-main-t {
|
||||
font-size: 32.4rpx;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<hr-page page-bg="#F3F4F6" status-bg="#FFFFFF" nav-title="顺序练习" @right-click="onMore">
|
||||
<template v-slot:right>
|
||||
<x-icon name="more-fill" color="#6B7280" font-size="18"></x-icon>
|
||||
</template>
|
||||
|
||||
<view class="hr-body">
|
||||
|
||||
<!-- ============ hero ============ -->
|
||||
<view class="prac-hero">
|
||||
<view class="prac-c1"></view>
|
||||
<view class="prac-ic">
|
||||
<x-icon name="play-fill" color="#FFFFFF" font-size="27"></x-icon>
|
||||
</view>
|
||||
<text class="prac-t">{{ meta.subject }}</text>
|
||||
<text class="prac-s">顺序练习 · 按章节顺序出题</text>
|
||||
</view>
|
||||
|
||||
<!-- ============ 练习信息 ============ -->
|
||||
<hr-card variant="list" style="margin-top:10px">
|
||||
<hr-lrow icon="▦" theme="pri" title="题目数量" sub="覆盖本课题全部章节">
|
||||
<template v-slot:right>
|
||||
<text class="prac-val">{{ meta.total }} 题</text>
|
||||
</template>
|
||||
</hr-lrow>
|
||||
<hr-lrow icon="◔" theme="amb" title="预计用时" sub="按每题 36 秒估算">
|
||||
<template v-slot:right>
|
||||
<text class="prac-val">约 {{ meta.minutes }} 分钟</text>
|
||||
</template>
|
||||
</hr-lrow>
|
||||
<hr-lrow icon="✓" theme="grn" title="目标正确率" sub="达标后计入课题完成度" :is-last="true">
|
||||
<template v-slot:right>
|
||||
<text class="prac-val prac-val-grn">{{ meta.goal }}</text>
|
||||
</template>
|
||||
</hr-lrow>
|
||||
</hr-card>
|
||||
|
||||
<hr-tip style="margin-top:10px" theme="warn" icon="⚑"
|
||||
:text="'顺序练习不限制次数,答错的题目会自动进入错题本,可随时回来复习。'"></hr-tip>
|
||||
|
||||
<!-- ============ 上次练习 ============ -->
|
||||
<hr-sec title="上次练习" :first="false"></hr-sec>
|
||||
<hr-card>
|
||||
<view class="hr-row-between">
|
||||
<text class="prac-last">{{ meta.lastTime }} · 已练 {{ meta.lastDone }} 题</text>
|
||||
<text class="prac-rate">正确率 {{ meta.lastRate }}%</text>
|
||||
</view>
|
||||
<view style="margin-top:9px">
|
||||
<hr-progress :percent="lastPct"></hr-progress>
|
||||
</view>
|
||||
<text class="prac-note">上次练到第 {{ meta.lastDone }} 题,可继续或重新开始。</text>
|
||||
</hr-card>
|
||||
|
||||
<view style="height:14px"></view>
|
||||
</view>
|
||||
|
||||
<template v-slot:footer>
|
||||
<view class="hr-fixedbar">
|
||||
<view class="hr-btn hr-btn-primary hr-btn-lg" style="flex:1" @click="onStart">
|
||||
<text class="prac-btn-t">开始练习</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</hr-page>
|
||||
</template>
|
||||
|
||||
<script lang="uts" setup>
|
||||
import { computed } from 'vue'
|
||||
import { practiceMeta } from '@/mock/index.uts'
|
||||
import { navTo } from '@/utils/nav.uts'
|
||||
|
||||
/** s36 顺序练习 */
|
||||
const meta = practiceMeta
|
||||
|
||||
const lastPct = computed(() : number => {
|
||||
return Math.round(meta.lastDone * 100 / meta.total)
|
||||
})
|
||||
|
||||
function onStart() : void {
|
||||
navTo('/pages/course/quiz?idx=0')
|
||||
}
|
||||
|
||||
function onMore() : void {
|
||||
uni.showToast({ title: '练习记录 / 重置进度', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.prac-hero {
|
||||
background-image: linear-gradient(to bottom right, #2563EB, #1D4ED8);
|
||||
border-radius: 32rpx;
|
||||
padding: 44rpx 32rpx 44rpx 32rpx;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.prac-c1 {
|
||||
position: absolute;
|
||||
right: -80rpx;
|
||||
bottom: -104rpx;
|
||||
width: 240rpx;
|
||||
height: 240rpx;
|
||||
border-radius: 120rpx;
|
||||
background-color: rgba(255, 255, 255, 0.09);
|
||||
}
|
||||
|
||||
.prac-ic {
|
||||
width: 128rpx;
|
||||
height: 128rpx;
|
||||
border-radius: 40rpx;
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.prac-t {
|
||||
font-size: 35.8rpx;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.prac-s {
|
||||
font-size: 25.8rpx;
|
||||
color: rgba(255, 255, 255, 0.86);
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.prac-val {
|
||||
font-size: 33.6rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
margin-left: 16rpx;
|
||||
}
|
||||
|
||||
.prac-val-grn {
|
||||
color: #059669;
|
||||
}
|
||||
|
||||
.prac-last {
|
||||
font-size: 28rpx;
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
.prac-rate {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #2563EB;
|
||||
}
|
||||
|
||||
.prac-note {
|
||||
font-size: 24.6rpx;
|
||||
color: #9CA3AF;
|
||||
margin-top: 14rpx;
|
||||
}
|
||||
|
||||
.prac-btn-t {
|
||||
font-size: 35.8rpx;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,396 @@
|
||||
<template>
|
||||
<hr-page page-bg="#F3F4F6" status-bg="#FFFFFF" :nav-title="'顺序练习 · 第 ' + (cur + 1) + ' 题'"
|
||||
@right-click="onMarkCurrent">
|
||||
<template v-slot:right>
|
||||
<x-icon :name="isMarked ? 'bookmark-fill' : 'bookmark-line'" :color="isMarked ? '#F59E0B' : '#6B7280'"
|
||||
font-size="19"></x-icon>
|
||||
</template>
|
||||
|
||||
<view class="hr-body">
|
||||
|
||||
<!-- ============ 进度 ============ -->
|
||||
<view class="hr-row">
|
||||
<view style="flex:1">
|
||||
<hr-progress :percent="pct"></hr-progress>
|
||||
</view>
|
||||
<text class="qz-prog">{{ cur + 1 }} / {{ total }}</text>
|
||||
</view>
|
||||
|
||||
<!-- ============ 题卡 ============ -->
|
||||
<hr-card style="margin-top:10px;padding:16px 14px 16px 14px">
|
||||
<text class="qz-stem">{{ q.stem }}</text>
|
||||
|
||||
<view class="qz-opts">
|
||||
<view v-for="(o, i) in q.options" :key="i" :class="optClass(i)" @click="choose(i)">
|
||||
<view :class="optKeyClass(i)">
|
||||
<text :class="optKeyTextClass(i)">{{ o.key }}</text>
|
||||
</view>
|
||||
<text class="qz-opt-t">{{ o.text }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="qz-acts">
|
||||
<view class="hr-btn hr-btn-ghost qz-act" @click="onMarkCurrent">
|
||||
<x-icon :name="isMarked ? 'bookmark-fill' : 'bookmark-line'"
|
||||
:color="isMarked ? '#F59E0B' : '#1F2937'" font-size="16"></x-icon>
|
||||
<text class="qz-act-t">{{ isMarked ? '已标记' : '标记本题' }}</text>
|
||||
</view>
|
||||
<view class="hr-btn hr-btn-ghost qz-act qz-act-last" @click="openCard">
|
||||
<x-icon name="layout-grid-line" color="#1F2937" font-size="16"></x-icon>
|
||||
<text class="qz-act-t">答题卡</text>
|
||||
</view>
|
||||
</view>
|
||||
</hr-card>
|
||||
|
||||
<hr-tip style="margin-top:10px" theme="info" icon="ℹ"
|
||||
text="答错的题目会自动进入错题本,可在课题功能页统一复习。"></hr-tip>
|
||||
|
||||
<!-- 作答反馈 -->
|
||||
<view v-if="showAnswer" class="qz-feedback" :class="isRight ? 'qz-feedback-ok' : 'qz-feedback-err'">
|
||||
<view class="qz-fb-ic" :class="isRight ? 'qz-fb-ic-ok' : 'qz-fb-ic-err'">
|
||||
<text class="qz-fb-ic-t">{{ isRight ? '✓' : '✕' }}</text>
|
||||
</view>
|
||||
<view class="hr-flex1">
|
||||
<text class="qz-fb-b">{{ isRight ? '回答正确' : '回答错误,已加入错题本' }}</text>
|
||||
<text class="qz-fb-s">正确答案:{{ rightAnswer }}</text>
|
||||
<text class="qz-fb-s">{{ q.analysis }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view style="height:14px"></view>
|
||||
</view>
|
||||
|
||||
<template v-slot:footer>
|
||||
<view class="hr-fixedbar">
|
||||
<view class="hr-btn hr-btn-ghost qz-foot-prev" @click="prev">
|
||||
<text class="qz-foot-t">上一题</text>
|
||||
</view>
|
||||
<view class="hr-btn hr-btn-primary" style="flex:1" @click="next">
|
||||
<text class="qz-foot-t2">{{ isLast ? '交卷并查看成绩' : '下一题' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</hr-page>
|
||||
</template>
|
||||
|
||||
<script lang="uts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { quizQuestions } from '@/mock/index.uts'
|
||||
import { quizState, setAnswer, toggleMark, answeredCount } from '@/utils/quiz.uts'
|
||||
import { relaunchTo, navTo } from '@/utils/nav.uts'
|
||||
import { HrQuestion } from '@/mock/types.uts'
|
||||
|
||||
/** s03 答题界面 */
|
||||
const total = quizQuestions.length
|
||||
const cur = ref(0)
|
||||
const refreshKey = ref(0)
|
||||
|
||||
const q = computed(() : HrQuestion => {
|
||||
return quizQuestions[cur.value]
|
||||
})
|
||||
|
||||
const selected = computed(() : number => {
|
||||
const k = refreshKey.value
|
||||
return quizState.answers[cur.value]
|
||||
})
|
||||
|
||||
const isMarked = computed(() : boolean => {
|
||||
const k = refreshKey.value
|
||||
return quizState.marked[cur.value]
|
||||
})
|
||||
|
||||
const isLast = computed(() : boolean => {
|
||||
return cur.value == total - 1
|
||||
})
|
||||
|
||||
const pct = computed(() : number => {
|
||||
return Math.round((cur.value + 1) * 100 / total)
|
||||
})
|
||||
|
||||
const showAnswer = computed(() : boolean => {
|
||||
const k = refreshKey.value
|
||||
return quizState.answers[cur.value] >= 0
|
||||
})
|
||||
|
||||
const isRight = computed(() : boolean => {
|
||||
const k = refreshKey.value
|
||||
return quizState.answers[cur.value] == q.value.answer
|
||||
})
|
||||
|
||||
const rightAnswer = computed(() : string => {
|
||||
const o = q.value.options[q.value.answer]
|
||||
return `${o.key}. ${o.text}`
|
||||
})
|
||||
|
||||
// uni-app x 页面显示生命周期:从答题卡返回时同步当前题号与作答状态
|
||||
onPageShow(() => {
|
||||
cur.value = quizState.current
|
||||
refreshKey.value = refreshKey.value + 1
|
||||
})
|
||||
|
||||
function optClass(i : number) : string {
|
||||
if (selected.value == i) {
|
||||
if (i == q.value.answer) { return 'qz-opt qz-opt-ok' }
|
||||
return 'qz-opt qz-opt-sel'
|
||||
}
|
||||
if (showAnswer.value && i == q.value.answer) { return 'qz-opt qz-opt-ok' }
|
||||
return 'qz-opt'
|
||||
}
|
||||
|
||||
function optKeyClass(i : number) : string {
|
||||
if (selected.value == i) {
|
||||
if (i == q.value.answer) { return 'qz-ok qz-ok-ok' }
|
||||
return 'qz-ok qz-ok-sel'
|
||||
}
|
||||
if (showAnswer.value && i == q.value.answer) { return 'qz-ok qz-ok-ok' }
|
||||
return 'qz-ok'
|
||||
}
|
||||
|
||||
function optKeyTextClass(i : number) : string {
|
||||
if (selected.value == i || (showAnswer.value && i == q.value.answer)) {
|
||||
return 'qz-ok-t qz-ok-t-on'
|
||||
}
|
||||
return 'qz-ok-t'
|
||||
}
|
||||
|
||||
function choose(i : number) : void {
|
||||
if (selected.value >= 0) {
|
||||
uni.showToast({ title: '本题已作答', icon: 'none' })
|
||||
return
|
||||
}
|
||||
setAnswer(cur.value, i)
|
||||
refreshKey.value = refreshKey.value + 1
|
||||
if (i != q.value.answer) {
|
||||
// 答错自动进错题本(mock 阶段仅提示)
|
||||
uni.showToast({ title: '已加入错题本', icon: 'none' })
|
||||
}
|
||||
}
|
||||
|
||||
function onMarkCurrent() : void {
|
||||
toggleMark(cur.value)
|
||||
refreshKey.value = refreshKey.value + 1
|
||||
uni.showToast({ title: isMarked.value ? '已标记本题' : '已取消标记', icon: 'none' })
|
||||
}
|
||||
|
||||
function prev() : void {
|
||||
if (cur.value == 0) {
|
||||
uni.showToast({ title: '已是第一题', icon: 'none' })
|
||||
return
|
||||
}
|
||||
cur.value = cur.value - 1
|
||||
quizState.current = cur.value
|
||||
refreshKey.value = refreshKey.value + 1
|
||||
}
|
||||
|
||||
// ⚠ submit 被 next() 调用,必须先定义(UTS 不提升函数声明)
|
||||
function submit() : void {
|
||||
const done = answeredCount()
|
||||
uni.showModal({
|
||||
title: '交卷确认',
|
||||
content: `已作答 ${done} / ${total} 题${done < total ? ',仍有题目未作答' : ''}。交卷后无法修改。`,
|
||||
cancelText: '继续答题',
|
||||
confirmText: '交卷',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
quizState.submitted = true
|
||||
uni.showToast({ title: '已交卷 · 得分 92', icon: 'success' })
|
||||
setTimeout(() => {
|
||||
relaunchTo('/pages/study/exams')
|
||||
}, 700)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function next() : void {
|
||||
if (isLast.value) {
|
||||
submit()
|
||||
return
|
||||
}
|
||||
cur.value = cur.value + 1
|
||||
quizState.current = cur.value
|
||||
refreshKey.value = refreshKey.value + 1
|
||||
}
|
||||
|
||||
function openCard() : void {
|
||||
quizState.current = cur.value
|
||||
navTo('/pages/course/answer-card')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.qz-prog {
|
||||
font-size: 25.8rpx;
|
||||
font-weight: bold;
|
||||
color: #6B7280;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
.qz-stem {
|
||||
font-size: 33.6rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.qz-opts {
|
||||
flex-direction: column;
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.qz-opt {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
min-height: 112rpx;
|
||||
padding: 20rpx 26rpx 20rpx 26rpx;
|
||||
border: 3rpx solid #E5E7EB;
|
||||
border-radius: 24rpx;
|
||||
background-color: #FFFFFF;
|
||||
margin-bottom: 18rpx;
|
||||
}
|
||||
|
||||
.qz-opt-sel {
|
||||
border: 3rpx solid #2563EB;
|
||||
background-color: #EFF6FF;
|
||||
}
|
||||
|
||||
.qz-opt-ok {
|
||||
border: 3rpx solid #10B981;
|
||||
background-color: #ECFDF5;
|
||||
}
|
||||
|
||||
.qz-ok {
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
border-radius: 26rpx;
|
||||
border: 3rpx solid #E5E7EB;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 22rpx;
|
||||
}
|
||||
|
||||
.qz-ok-sel {
|
||||
background-color: #2563EB;
|
||||
border: 3rpx solid #2563EB;
|
||||
}
|
||||
|
||||
.qz-ok-ok {
|
||||
background-color: #10B981;
|
||||
border: 3rpx solid #10B981;
|
||||
}
|
||||
|
||||
.qz-ok-t {
|
||||
font-size: 26.8rpx;
|
||||
font-weight: bold;
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
.qz-ok-t-on {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.qz-opt-t {
|
||||
flex: 1;
|
||||
font-size: 30.2rpx;
|
||||
color: #1F2937;
|
||||
}
|
||||
|
||||
.qz-acts {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.qz-act {
|
||||
flex: 1;
|
||||
height: 88rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.qz-act-last {
|
||||
margin-right: 0rpx;
|
||||
}
|
||||
|
||||
.qz-act-t {
|
||||
font-size: 30.2rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
|
||||
.qz-feedback {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
margin-top: 20rpx;
|
||||
padding: 22rpx 24rpx 22rpx 24rpx;
|
||||
border-radius: 22rpx;
|
||||
}
|
||||
|
||||
.qz-feedback-ok {
|
||||
background-color: #ECFDF5;
|
||||
border: 2rpx solid #A7F3D0;
|
||||
}
|
||||
|
||||
.qz-feedback-err {
|
||||
background-color: #FEF2F2;
|
||||
border: 2rpx solid #FECACA;
|
||||
}
|
||||
|
||||
.qz-fb-ic {
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
border-radius: 16rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.qz-fb-ic-ok {
|
||||
background-color: #10B981;
|
||||
}
|
||||
|
||||
.qz-fb-ic-err {
|
||||
background-color: #DC2626;
|
||||
}
|
||||
|
||||
.qz-fb-ic-t {
|
||||
font-size: 29.2rpx;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.qz-fb-b {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
}
|
||||
|
||||
.qz-fb-s {
|
||||
font-size: 24.6rpx;
|
||||
color: #6B7280;
|
||||
margin-top: 6rpx;
|
||||
}
|
||||
|
||||
.qz-foot-prev {
|
||||
flex: 0 0 220rpx;
|
||||
margin-right: 18rpx;
|
||||
}
|
||||
|
||||
.qz-foot-t {
|
||||
font-size: 31.4rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
}
|
||||
|
||||
.qz-foot-t2 {
|
||||
font-size: 32.4rpx;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
</style>
|
||||
@@ -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