327 lines
7.5 KiB
Vue
327 lines
7.5 KiB
Vue
<template>
|
||
<view class="status-bar"></view>
|
||
|
||
<view class="wyxd-container page-container">
|
||
<!-- ===== 顶部导航栏 ===== -->
|
||
<view class="wyxd-header">
|
||
<view class="custom-navbar">
|
||
<view class="navbar-left" @click="goBack">
|
||
<view class="iconfont icon-fanhui custom-navbar-icon"></view>
|
||
<view class="navbar-before-title workspace-text">返回</view>
|
||
</view>
|
||
<view class="navbar-title workspace-text">{{ displayName }}</view>
|
||
<view class="navbar-right"></view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- ===== 主舞台 ===== -->
|
||
<view class="wyxd-content">
|
||
<!-- 加载中 / 错误状态 -->
|
||
<view v-if="loading || errorMsg" class="wyxd-state">
|
||
<view class="iconfont wyxd-state-icon"
|
||
:class="errorMsg ? 'icon-quxiao' : 'icon-sousuo'"></view>
|
||
<view class="wyxd-state-title">{{ errorMsg || statusText }}</view>
|
||
<view v-if="errorMsg" class="wyxd-state-desc">请返回重试</view>
|
||
</view>
|
||
|
||
<!-- 无内容 -->
|
||
<view v-else-if="!slides.length" class="wyxd-state">
|
||
<view class="iconfont icon-wenjianjia wyxd-state-icon"></view>
|
||
<view class="wyxd-state-title">暂无内容</view>
|
||
</view>
|
||
|
||
<!-- 幻灯片 -->
|
||
<view v-else class="wyxd-slide-area">
|
||
<scroll-view class="wyxd-slide-scroll" scroll-y :show-scrollbar="false">
|
||
<view class="wyxd-slide-card" v-html="currentSlide.html"></view>
|
||
</scroll-view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- ===== 底部翻页 ===== -->
|
||
<view class="wyxd-pager" v-if="slides.length > 1">
|
||
<view class="wyxd-pager-inner">
|
||
<view class="wyxd-nav-btn" :class="{ disabled: currentIndex <= 0 }" @click="prevSlide">
|
||
<view class="iconfont icon-fanhui" style="font-size:24rpx;"></view>
|
||
</view>
|
||
<view class="wyxd-page-indicator">
|
||
<text class="wyxd-current">{{ pad(currentIndex + 1) }}</text>
|
||
<text class="wyxd-divider">/</text>
|
||
<text class="wyxd-total">{{ pad(slides.length) }}</text>
|
||
</view>
|
||
<view class="wyxd-nav-btn" :class="{ disabled: currentIndex >= slides.length - 1 }" @click="nextSlide">
|
||
<view class="iconfont icon-fanhui" style="transform:rotate(180deg);font-size:24rpx;"></view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed } from 'vue'
|
||
import { onLoad } from '@dcloudio/uni-app'
|
||
import {
|
||
isWyxdCached, getCachedWyxd, setCachedWyxd,
|
||
downloadWyxdAsZip, extractWyxd, parseSlides
|
||
} from '@/utils/wyxd-parser.js'
|
||
|
||
const workspaceId = ref('')
|
||
const filePath = ref('')
|
||
const fileName = ref('')
|
||
const userToken = ref('')
|
||
|
||
const slides = ref([])
|
||
const currentIndex = ref(0)
|
||
|
||
const status = ref('')
|
||
const loading = ref(false)
|
||
const errorMsg = ref('')
|
||
|
||
const statusText = computed(() => {
|
||
const map = {
|
||
downloading: '下载中...',
|
||
extracting: '解压中...',
|
||
parsing: '解析中...',
|
||
error: '加载失败'
|
||
}
|
||
return map[status.value] || '处理中...'
|
||
})
|
||
|
||
const displayName = computed(() => fileName.value || '未命名文档')
|
||
|
||
const currentSlide = computed(() => slides.value[currentIndex.value] || { html: '' })
|
||
|
||
const pad = (n) => String(n).padStart(2, '0')
|
||
|
||
const goBack = () => {
|
||
uni.navigateBack()
|
||
}
|
||
|
||
const prevSlide = () => {
|
||
if (currentIndex.value > 0) currentIndex.value--
|
||
}
|
||
|
||
const nextSlide = () => {
|
||
if (currentIndex.value < slides.value.length - 1) currentIndex.value++
|
||
}
|
||
|
||
const loadFromCache = () => {
|
||
const cached = getCachedWyxd(workspaceId.value, filePath.value)
|
||
if (!cached || !cached.slides || cached.slides.length === 0) {
|
||
startDownload()
|
||
return
|
||
}
|
||
slides.value = cached.slides
|
||
currentIndex.value = 0
|
||
loading.value = false
|
||
errorMsg.value = ''
|
||
status.value = ''
|
||
}
|
||
|
||
const startDownload = async () => {
|
||
if (!userToken.value || !workspaceId.value || !filePath.value) {
|
||
errorMsg.value = '缺少必要参数'
|
||
status.value = 'error'
|
||
return
|
||
}
|
||
try {
|
||
loading.value = true
|
||
errorMsg.value = ''
|
||
slides.value = []
|
||
currentIndex.value = 0
|
||
|
||
status.value = 'downloading'
|
||
console.log("userToken.value",userToken.value);
|
||
console.log("workspaceId.value",workspaceId.value);
|
||
console.log("filePath.value",filePath.value);
|
||
const tempPath = await downloadWyxdAsZip(
|
||
userToken.value, workspaceId.value, filePath.value
|
||
)
|
||
console.log("获取到的下载地址:",tempPath);
|
||
|
||
status.value = 'extracting'
|
||
const extracted = await extractWyxd(tempPath)
|
||
console.log("extracted",extracted);
|
||
|
||
status.value = 'parsing'
|
||
const slideList = parseSlides(extracted.html, extracted.header, extracted.images)
|
||
|
||
if (!slideList || slideList.length === 0) {
|
||
throw new Error('无法解析文档内容')
|
||
}
|
||
|
||
slides.value = slideList
|
||
currentIndex.value = 0
|
||
loading.value = false
|
||
status.value = ''
|
||
|
||
setCachedWyxd(workspaceId.value, filePath.value, {
|
||
fileName: fileName.value,
|
||
slides: slideList
|
||
})
|
||
} catch (err) {
|
||
loading.value = false
|
||
status.value = 'error'
|
||
const msg = typeof err === 'string' ? err : (err.message || '下载失败')
|
||
errorMsg.value = msg
|
||
console.error('[WYXD] download error:', err)
|
||
}
|
||
}
|
||
|
||
onLoad((options) => {
|
||
workspaceId.value = options.workspaceId || ''
|
||
filePath.value = options?.filePath ? decodeURIComponent(options.filePath) : ''
|
||
fileName.value = options?.fileName ? decodeURIComponent(options.fileName) : '未命名文档'
|
||
userToken.value = options?.userToken ?? uni.getStorageSync('user_token') ?? ''
|
||
console.log('页面接收options原始参数:', options)
|
||
console.log('最终赋值变量:', {
|
||
workspaceId: workspaceId.value,
|
||
filePath: filePath.value,
|
||
fileName: fileName.value,
|
||
userToken: userToken.value
|
||
})
|
||
|
||
if (isWyxdCached(workspaceId.value, filePath.value)) {
|
||
loadFromCache()
|
||
} else {
|
||
startDownload()
|
||
}
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
@import url("@/pages/WorkSpace/WorkSpace.css");
|
||
|
||
.wyxd-container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
background: #f5f5f5;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.wyxd-header {
|
||
flex-shrink: 0;
|
||
background: #fff;
|
||
}
|
||
|
||
.wyxd-content {
|
||
flex: 1;
|
||
min-height: 0;
|
||
overflow: hidden;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* ===== 状态占位 ===== */
|
||
.wyxd-state {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 40rpx;
|
||
}
|
||
|
||
.wyxd-state-icon {
|
||
font-size: 80rpx;
|
||
color: #ccc;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.wyxd-state-title {
|
||
font-size: 28rpx;
|
||
font-weight: 600;
|
||
color: #666;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.wyxd-state-desc {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
|
||
/* ===== 幻灯片区域 ===== */
|
||
.wyxd-slide-area {
|
||
flex: 1;
|
||
min-height: 0;
|
||
/* padding: 20rpx; */
|
||
}
|
||
|
||
.wyxd-slide-scroll {
|
||
height: 100%;
|
||
background: #fff;
|
||
border-radius: 12rpx;
|
||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
||
}
|
||
|
||
/* .wyxd-slide-card {
|
||
padding: 32rpx;
|
||
min-height: 100%;
|
||
box-sizing: border-box;
|
||
} */
|
||
.wyxd-slide-card {
|
||
min-height: 100%;
|
||
box-sizing: border-box;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
flex-direction: column; /* 子元素垂直排列 */
|
||
}
|
||
|
||
/* ===== 底部翻页 ===== */
|
||
.wyxd-pager {
|
||
flex-shrink: 0;
|
||
background: #fff;
|
||
border-top: 1rpx solid #eee;
|
||
padding: 16rpx 0;
|
||
padding-bottom: calc(16rpx + env(safe-area-inset-bottom));
|
||
}
|
||
|
||
.wyxd-pager-inner {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.wyxd-nav-btn {
|
||
width: 64rpx;
|
||
height: 64rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 32rpx;
|
||
background: #f5f5f5;
|
||
margin: 0 32rpx;
|
||
}
|
||
|
||
.wyxd-nav-btn:active {
|
||
background: #e0e0e0;
|
||
}
|
||
|
||
.wyxd-nav-btn.disabled {
|
||
opacity: 0.3;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.wyxd-page-indicator {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.wyxd-current {
|
||
color: #3b82f6;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.wyxd-divider {
|
||
margin: 0 8rpx;
|
||
color: #ccc;
|
||
}
|
||
|
||
.wyxd-total {
|
||
color: #999;
|
||
}
|
||
</style>
|