1
This commit is contained in:
@@ -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>
|
||||
Reference in New Issue
Block a user