<template>
|
<view class="page">
|
<view class="nav-shell">
|
<view class="safe-space" :style="'height:' + navTop + 'px'"></view>
|
<view class="nav-row" :style="'height:' + navHeight + 'px;padding-right:' + navRight + 'px'">
|
<view class="back" @tap="goBack"><image src="/static/news-assets/arrow-left.svg" mode="aspectFit"></image></view>
|
<text class="nav-title">资讯详情</text>
|
<view class="capsule-reserve" :style="'width:' + navWidth + 'px'"></view>
|
</view>
|
<view class="nav-bottom-space"></view>
|
</view>
|
|
<scroll-view class="article-scroll" scroll-y>
|
<view v-if="isLoading" class="state-panel">
|
<view class="loading-spinner"></view>
|
<text class="state-title">正在加载资讯</text>
|
<text class="state-desc">请稍候</text>
|
</view>
|
<view v-else-if="loadFailed" class="state-panel">
|
<view class="state-symbol"><text>!</text></view>
|
<text class="state-title">资讯内容加载失败</text>
|
<text class="state-desc">{{loadErrorMessage == '' ? '请检查网络后重新加载' : loadErrorMessage}}</text>
|
<view class="retry-button" @tap="retryLoad"><text>重新加载</text></view>
|
</view>
|
<view v-else-if="contentHtml.trim() == ''" class="state-panel">
|
<view class="state-symbol is-empty"><text>—</text></view>
|
<text class="state-title">暂无资讯内容</text>
|
<text class="state-desc">该资讯可能已下架或正文暂未发布</text>
|
</view>
|
<view v-else>
|
<view class="article-head">
|
<text class="article-title">{{articleTitle}}</text>
|
<view class="article-meta"><view class="meta-left"><text class="publisher">{{publisher}}</text><text class="publish-time">{{publishTime}}</text></view><view class="views"><image src="/static/news-assets/eye.svg" mode="aspectFit"></image><text>{{viewCount}}</text></view></view>
|
</view>
|
<view class="article-body">
|
<rich-text class="rich-content" :nodes="contentHtml"></rich-text>
|
<view class="bottom-space"></view>
|
</view>
|
</view>
|
</scroll-view>
|
</view>
|
</template>
|
|
<script setup lang="uts">
|
import { isApiConfigured } from '../../config/api.uts'
|
import { safeBack } from '../../utils/navigation.uts'
|
import { sanitizeRichText } from '../../services/business.uts'
|
import { getNewsDetail } from '../../services/portal.uts'
|
|
const navTop = ref(28)
|
const navHeight = ref(32)
|
const navWidth = ref(88)
|
const navRight = ref(10)
|
const articleTitle = ref('')
|
const publisher = ref('')
|
const publishTime = ref('')
|
const viewCount = ref('')
|
const contentHtml = ref('')
|
const isLoading = ref(true)
|
const loadFailed = ref(false)
|
const loadErrorMessage = ref('')
|
const previewState = ref('success')
|
const newsId = ref('')
|
const demoContentHtml = '<div style="color:#747F8F;font-size:16px;line-height:1.9;word-break:break-all;">'
|
+ '<p style="margin:0 0 14px;">根据《关于攀枝花市事业单位2026年上半年公开考试招聘工作人员的公告》规定,现将本次东区岗位考生加分情况、笔试总成绩及岗位排名、面试资格复审相关事宜公告如下。</p>'
|
+ '<p style="margin:18px 0 6px;color:#687585;font-weight:600;">一、加分情况</p>'
|
+ '<p style="margin:0 0 14px;">此次事业单位公开考试招聘东区岗位政策性加分情况见附件1。</p>'
|
+ '<p style="margin:18px 0 6px;color:#687585;font-weight:600;">二、笔试总成绩和岗位排名</p>'
|
+ '<p style="margin:0 0 14px;">一般事业单位岗位笔试总成绩按以下原则计算:</p>'
|
+ '<p style="margin:0 0 14px;">笔试总成绩=《公共基础知识》×50%+《综合能力测试》×50%+政策性加分</p>'
|
+ '<p style="margin:0 0 14px;">请考生自行查询本人成绩及排名(具体见附件2),应聘人员笔试总成绩(含政策性加分)低于合格分数线的不能进入下一环节。</p>'
|
+ '<p style="margin:0 0 14px;">笔试考试中任一科目存在缺考、零分或违纪的考生,不进行笔试排名。</p>'
|
+ '<p style="margin:18px 0 6px;color:#687585;font-weight:600;">三、笔试成绩平均分及合格分数线</p>'
|
+ '<p style="margin:0 0 14px;">笔试成绩合格分数线为此次参加我市事业单位公招考试相同科目所有参考人员有效笔试成绩的平均分×90%。</p>'
|
+ '<p style="margin:0 0 14px;">笔试科目《公共基础知识》和《综合能力测试》笔试成绩平均分为54.43分,笔试成绩合格分数线为48.99分。</p>'
|
+ '<p style="margin:18px 0 6px;color:#687585;font-weight:600;">四、资格复审</p>'
|
+ '<p style="margin:0;">资格复审时间、地点及相关材料要求以公告附件及后续通知为准,请考生保持通讯畅通。</p>'
|
+ '</div>'
|
const seniorTalentContentHtml = '<div style="color:#747F8F;font-size:16px;line-height:1.9;word-break:break-all;">'
|
+ '<p style="margin:0 0 14px;">根据事业单位公开招聘有关规定,攀枝花市东区面向社会直接考核招聘副高职称及以上人才,现将有关事项公告如下。</p>'
|
+ '<p style="margin:18px 0 6px;color:#687585;font-weight:600;">一、招聘对象</p>'
|
+ '<p style="margin:0 0 14px;">符合岗位条件、具有副高级及以上专业技术职称的专业人才。</p>'
|
+ '<p style="margin:18px 0 6px;color:#687585;font-weight:600;">二、报名与考核</p>'
|
+ '<p style="margin:0;">报名时间、岗位条件、资格审查及考核安排以正式公告附件为准,请报名人员保持联系方式畅通。</p>'
|
+ '</div>'
|
const teacherReviewContentHtml = '<div style="color:#747F8F;font-size:16px;line-height:1.9;word-break:break-all;">'
|
+ '<p style="margin:0 0 14px;">根据攀枝花市2026年上半年公开考试招聘中小学教师工作安排,现公布东区岗位面试资格复审及面试通知书领取事项。</p>'
|
+ '<p style="margin:18px 0 6px;color:#687585;font-weight:600;">一、资格复审</p>'
|
+ '<p style="margin:0 0 14px;">进入资格复审人员须按规定携带身份证、学历学位证书、教师资格证及岗位要求的其他材料。</p>'
|
+ '<p style="margin:18px 0 6px;color:#687585;font-weight:600;">二、面试通知书</p>'
|
+ '<p style="margin:0;">资格复审合格人员按现场通知领取面试通知书,并按规定时间和地点参加面试。</p>'
|
+ '</div>'
|
const talentNoticeContentHtml = '<div style="color:#747F8F;font-size:16px;line-height:1.9;word-break:break-all;">'
|
+ '<p style="margin:0 0 14px;">为做好2026年春季综合类、教育系统事业单位引才工作,现将资格确认、材料提交及后续安排公告如下。</p>'
|
+ '<p style="margin:18px 0 6px;color:#687585;font-weight:600;">有关安排</p>'
|
+ '<p style="margin:0;">请进入后续环节的人员按通知要求准备材料,并持续关注东区人才工作相关公告。</p>'
|
+ '</div>'
|
const medicalCheckContentHtml = '<div style="color:#747F8F;font-size:16px;line-height:1.9;word-break:break-all;">'
|
+ '<p style="margin:0 0 14px;">根据2026年春季综合类、教育系统事业单位引才工作安排,现将体检人员、时间及注意事项公告如下。</p>'
|
+ '<p style="margin:18px 0 6px;color:#687585;font-weight:600;">体检要求</p>'
|
+ '<p style="margin:0 0 14px;">参加体检人员须携带本人有效身份证件,按通知时间到指定地点集合。</p>'
|
+ '<p style="margin:18px 0 6px;color:#687585;font-weight:600;">注意事项</p>'
|
+ '<p style="margin:0;">体检前请注意休息并保持空腹,未按规定参加体检的,按相关招聘规定处理。</p>'
|
+ '</div>'
|
|
onLoad((options: any) => {
|
// #ifdef MP-WEIXIN
|
const capsule = uni.getMenuButtonBoundingClientRect()
|
const systemInfo = uni.getSystemInfoSync()
|
navTop.value = capsule.top
|
navHeight.value = capsule.height
|
navWidth.value = capsule.width
|
navRight.value = systemInfo.windowWidth - capsule.right
|
// #endif
|
if (options != null && options['previewState'] != null) previewState.value = options['previewState'] as string
|
if (options != null && options['newsId'] != null) newsId.value = decodeURIComponent(options['newsId'] as string)
|
loadArticle()
|
})
|
|
const applyArticle = (id: string) : boolean => {
|
publisher.value = '东区发布'
|
if (id == 'news-20260603-senior-talent') {
|
articleTitle.value = '攀枝花市东区事业单位2026年直接考核招聘副高职称及以上人才公告'
|
publishTime.value = '2026-06-03 09:19'
|
viewCount.value = '1268'
|
contentHtml.value = seniorTalentContentHtml
|
return true
|
}
|
if (id == 'news-20260601-score-review') {
|
articleTitle.value = '关于攀枝花市东区事业单位2026年上半年公开考试招聘工作人员东区岗位加分情况、笔试总成绩及岗位排名、面试资格复审有关事宜的公告'
|
publishTime.value = '2026-06-01 16:36'
|
viewCount.value = '888'
|
contentHtml.value = demoContentHtml
|
return true
|
}
|
if (id == 'news-20260529-teacher-review') {
|
articleTitle.value = '攀枝花市2026年上半年公开考试招聘中小学教师东区岗位面试资格复审及领取面试通知书公告'
|
publishTime.value = '2026-05-29 10:42'
|
viewCount.value = '736'
|
contentHtml.value = teacherReviewContentHtml
|
return true
|
}
|
if (id == 'news-20260522-talent-notice') {
|
articleTitle.value = '关于攀枝花市东区2026年春季综合类、教育系统事业单位引才有关事宜的公告'
|
publishTime.value = '2026-05-22 11:01'
|
viewCount.value = '654'
|
contentHtml.value = talentNoticeContentHtml
|
return true
|
}
|
if (id == 'news-20260522-medical-check') {
|
articleTitle.value = '关于攀枝花市东区2026年春季综合类、教育系统事业单位引才体检有关事宜的公告'
|
publishTime.value = '2026-05-22 11:01'
|
viewCount.value = '592'
|
contentHtml.value = medicalCheckContentHtml
|
return true
|
}
|
if (id == 'news-20260518-service') {
|
articleTitle.value = '东区人才综合服务窗口办事指南'
|
publishTime.value = '2026-05-18 09:30'
|
viewCount.value = '486'
|
contentHtml.value = demoContentHtml
|
return true
|
}
|
if (id == 'news-20260512-policy') {
|
articleTitle.value = '2026年度东区人才政策申报工作提示'
|
publishTime.value = '2026-05-12 14:20'
|
viewCount.value = '421'
|
contentHtml.value = demoContentHtml
|
return true
|
}
|
if (id == 'news-20260508-training') {
|
articleTitle.value = '东区青年人才能力提升培训报名通知'
|
publishTime.value = '2026-05-08 10:05'
|
viewCount.value = '368'
|
contentHtml.value = demoContentHtml
|
return true
|
}
|
if (id == 'news-20260428-event') {
|
articleTitle.value = '东区人才交流活动安排公告'
|
publishTime.value = '2026-04-28 16:10'
|
viewCount.value = '315'
|
contentHtml.value = demoContentHtml
|
return true
|
}
|
return false
|
}
|
|
const loadArticle = () => {
|
isLoading.value = true
|
loadFailed.value = false
|
loadErrorMessage.value = ''
|
articleTitle.value = ''
|
publisher.value = ''
|
publishTime.value = ''
|
viewCount.value = ''
|
contentHtml.value = ''
|
const isRemoteNewsId = /^\d+$/.test(newsId.value)
|
if (isApiConfigured() && isRemoteNewsId) {
|
getNewsDetail(newsId.value, (data: any) => {
|
articleTitle.value = data != null && data.title != null ? data.title as string : ''
|
publisher.value = data != null && data.source != null ? data.source as string : '东区发布'
|
if (data != null && data.author != null && (data.author as string).length > 0) publisher.value = data.author as string
|
const publishValue = data != null && data.publishTime != null ? '' + data.publishTime : ''
|
publishTime.value = publishValue.length >= 16 ? publishValue.substring(0, 16).replace('T', ' ') : publishValue.replace('T', ' ')
|
viewCount.value = data != null && data.viewCount != null ? '' + data.viewCount : '0'
|
contentHtml.value = sanitizeRichText(data != null && data.content != null ? data.content as string : '')
|
isLoading.value = false
|
}, (error) => {
|
isLoading.value = false
|
loadFailed.value = true
|
loadErrorMessage.value = error.message
|
console.error('资讯详情请求失败', error)
|
})
|
return
|
}
|
if (apiEnvironment != 'development') {
|
isLoading.value = false
|
loadFailed.value = true
|
loadErrorMessage.value = '资讯内容加载失败'
|
return
|
}
|
setTimeout(() => {
|
if (previewState.value == 'error') {
|
isLoading.value = false
|
loadFailed.value = true
|
return
|
}
|
if (previewState.value != 'empty') {
|
applyArticle(newsId.value)
|
contentHtml.value = sanitizeRichText(contentHtml.value)
|
}
|
isLoading.value = false
|
}, 350)
|
}
|
const retryLoad = () => {
|
previewState.value = 'success'
|
loadArticle()
|
}
|
const goBack = () => safeBack('/pages/news/news')
|
</script>
|
|
<style>
|
.page { display: flex; flex-direction: column; width: 100%; height: 100vh; background-color: #FFFFFF; }
|
.nav-shell { flex-shrink: 0; background-image: linear-gradient(180deg, #FFF0B8 0%, #FFF8E4 58%, #FFFFFF 100%); }
|
.safe-space { height: 28px; }
|
.nav-row { display: flex; position: relative; height: 32px; align-items: center; justify-content: flex-end; box-sizing: border-box; }
|
.back { display: flex; position: absolute; z-index: 2; left: 24rpx; top: 0; width: 72rpx; height: 100%; justify-content: center; align-items: center; }
|
.back image { width: 38rpx; height: 38rpx; }
|
.nav-title { position: absolute; left: 190rpx; right: 190rpx; color: #171717; font-size: 35rpx; font-weight: 700; text-align: center; white-space: nowrap; }
|
.capsule-reserve { width: 88px; height: 100%; flex-shrink: 0; }
|
.nav-bottom-space { height: 34rpx; }
|
.article-scroll { flex: 1; height: 0; background-color: #FFFFFF; }
|
.article-head { padding: 0 34rpx 25rpx; border-bottom-width: 1rpx; border-bottom-color: #F0F0F0; }
|
.article-title { display: block; color: #272727; font-size: 32rpx; font-weight: 700; line-height: 47rpx; }
|
.article-meta { display: flex; height: 48rpx; margin-top: 22rpx; flex-direction: row; align-items: center; justify-content: space-between; }
|
.meta-left { display: flex; flex-direction: row; align-items: center; } .publisher { padding: 5rpx 9rpx; border-radius: 5rpx; background-color: #FFF8E9; color: #F2A22C; font-size: 19rpx; } .publish-time { margin-left: 12rpx; color: #A5A8AE; font-size: 22rpx; }
|
.views { display: flex; flex-direction: row; align-items: center; color: #A5A8AE; font-size: 20rpx; } .views image { width: 28rpx; height: 28rpx; margin-right: 8rpx; }
|
.article-body { padding: 23rpx 35rpx 0; }
|
.rich-content { display: block; width: 100%; color: #747F8F; font-size: 27rpx; line-height: 51rpx; overflow: hidden; }
|
.state-panel { display: flex; min-height: 640rpx; box-sizing: border-box; padding: 120rpx 48rpx 80rpx; flex-direction: column; align-items: center; }
|
.loading-spinner { width: 48rpx; height: 48rpx; box-sizing: border-box; border-width: 5rpx; border-style: solid; border-color: #FFE0C3; border-top-color: #F28B2F; border-radius: 50%; animation: article-loading 760ms linear infinite; }
|
.state-symbol { display: flex; width: 78rpx; height: 78rpx; border-radius: 50%; background-color: #FFF2E8; justify-content: center; align-items: center; }
|
.state-symbol text { color: #EF7C31; font-size: 40rpx; font-weight: 600; }
|
.state-symbol.is-empty { background-color: #F2F4F7; }
|
.state-symbol.is-empty text { color: #A6ADB7; }
|
.state-title { margin-top: 28rpx; color: #424A55; font-size: 29rpx; font-weight: 600; }
|
.state-desc { margin-top: 13rpx; color: #9AA1AA; font-size: 23rpx; text-align: center; line-height: 34rpx; }
|
.retry-button { display: flex; width: 190rpx; height: 68rpx; margin-top: 34rpx; border-radius: 35rpx; background-image: linear-gradient(90deg, #FF9A32 0%, #FF6D21 100%); justify-content: center; align-items: center; }
|
.retry-button text { color: #FFFFFF; font-size: 25rpx; }
|
@keyframes article-loading { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
|
.bottom-space { height: calc(40rpx + env(safe-area-inset-bottom)); }
|
</style>
|