221 lines
4.7 KiB
Vue
221 lines
4.7 KiB
Vue
<template>
|
||
<view class="content">
|
||
<view class="page-header">
|
||
<text class="header-back" @tap="goBack">‹</text>
|
||
<text class="header-title">活动规则</text>
|
||
</view>
|
||
<view class="preview-wrap">
|
||
<view class="loading-box" v-if="loading">
|
||
<u-loading mode="circle" size="40"></u-loading>
|
||
<text class="loading-text">内容加载中...</text>
|
||
</view>
|
||
<scroll-view class="doc-scroll" scroll-y v-if="!loading && !error">
|
||
<rich-text class="doc-content" :nodes="htmlContent"></rich-text>
|
||
<view style="height:30rpx;"></view>
|
||
</scroll-view>
|
||
<view class="error-box" v-if="error">
|
||
<text class="error-text">{{ error }}</text>
|
||
<button class="preview-btn" @tap="loadDoc">重新加载</button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
data() {
|
||
return {
|
||
docUrl: 'https://goldnar.hntgov.net/img/gift_rules.docx',
|
||
loading: false,
|
||
error: '',
|
||
htmlContent: ''
|
||
}
|
||
},
|
||
onReady() {
|
||
this.loadDoc()
|
||
},
|
||
methods: {
|
||
goBack() {
|
||
uni.navigateBack()
|
||
},
|
||
loadDoc() {
|
||
this.loading = true
|
||
this.error = ''
|
||
this.htmlContent = ''
|
||
this.ensureMammoth().then(() => {
|
||
return this.fetchDocx(this.docUrl)
|
||
}).then(arrayBuffer => {
|
||
return window.mammoth.convertToHtml({
|
||
arrayBuffer
|
||
})
|
||
}).then(result => {
|
||
this.htmlContent = result.value || ''
|
||
this.loading = false
|
||
}).catch(err => {
|
||
console.error('加载文档失败', err)
|
||
this.loading = false
|
||
this.error = '文档加载失败,请重试'
|
||
})
|
||
},
|
||
ensureMammoth() {
|
||
if (window.mammoth) return Promise.resolve()
|
||
return new Promise((resolve, reject) => {
|
||
const urls = [
|
||
'/static/mammoth.browser.min.js',
|
||
'https://unpkg.com/mammoth@1.6.0/mammoth.browser.min.js'
|
||
]
|
||
let i = 0
|
||
const loadNext = () => {
|
||
if (i >= urls.length) {
|
||
reject(new Error('解析组件加载失败'))
|
||
return
|
||
}
|
||
const s = document.createElement('script')
|
||
s.src = urls[i++]
|
||
s.onload = () => window.mammoth ? resolve() : loadNext()
|
||
s.onerror = loadNext
|
||
document.head.appendChild(s)
|
||
}
|
||
loadNext()
|
||
})
|
||
},
|
||
fetchDocx(url) {
|
||
return new Promise((resolve, reject) => {
|
||
if (typeof fetch !== 'undefined') {
|
||
fetch(url).then(res => {
|
||
if (!res.ok) throw new Error('HTTP ' + res.status)
|
||
return res.arrayBuffer()
|
||
}).then(resolve).catch(() => this.downloadDocx(url).then(resolve).catch(reject))
|
||
return
|
||
}
|
||
this.downloadDocx(url).then(resolve).catch(reject)
|
||
})
|
||
},
|
||
downloadDocx(url) {
|
||
return new Promise((resolve, reject) => {
|
||
uni.downloadFile({
|
||
url: url,
|
||
success: (res) => {
|
||
if (res.statusCode !== 200) {
|
||
reject(new Error('下载失败'))
|
||
return
|
||
}
|
||
uni.getFileSystemManager().readFile({
|
||
filePath: res.tempFilePath,
|
||
success: (r) => resolve(r.data),
|
||
fail: () => {
|
||
if (res.tempFilePath && typeof fetch !== 'undefined') {
|
||
fetch(res.tempFilePath).then(r => r.arrayBuffer())
|
||
.then(resolve).catch(reject)
|
||
} else {
|
||
reject(new Error('读取文件失败'))
|
||
}
|
||
}
|
||
})
|
||
},
|
||
fail: reject
|
||
})
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
page {
|
||
background-color: #F8F8F8;
|
||
}
|
||
|
||
.content {
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100vh;
|
||
height: 100dvh;
|
||
}
|
||
|
||
.page-header {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 20rpx 30rpx;
|
||
background: linear-gradient(135deg, #FD5401, #FF7A3D);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.header-back {
|
||
font-size: 48rpx;
|
||
color: #fff;
|
||
line-height: 1;
|
||
margin-right: 16rpx;
|
||
padding: 0 10rpx;
|
||
}
|
||
|
||
.header-title {
|
||
font-size: 30rpx;
|
||
font-weight: 600;
|
||
color: #fff;
|
||
flex: 1;
|
||
overflow: hidden;
|
||
white-space: nowrap;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.preview-wrap {
|
||
flex: 1;
|
||
background: #fff;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.loading-box {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 100%;
|
||
}
|
||
|
||
.loading-text {
|
||
font-size: 26rpx;
|
||
color: #999;
|
||
margin-top: 20rpx;
|
||
}
|
||
|
||
.error-box {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 100%;
|
||
}
|
||
|
||
.error-text {
|
||
font-size: 26rpx;
|
||
color: #999;
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
.preview-btn {
|
||
width: 300rpx;
|
||
height: 76rpx;
|
||
line-height: 76rpx;
|
||
background: linear-gradient(135deg, #FD5401, #FF7A3D);
|
||
color: #fff;
|
||
font-size: 28rpx;
|
||
font-weight: 600;
|
||
border: none;
|
||
border-radius: 38rpx;
|
||
}
|
||
|
||
.doc-scroll {
|
||
height: 100%;
|
||
padding: 20rpx 30rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.doc-content {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
line-height: 1.8;
|
||
}
|
||
</style>
|