feat: OA(ecology)项目拉取 + 会议邀请函PDF/微信分享 + 参会人/执行意向增强

OA ecology:
- BizEcologyController + EcologyProjectService: 项目编号搜索/详情回填, 负责人静默建档
- ComplianceLoginService: 合规/负责人登录校验 + 视图 role 匹配
- application-prod/test.yml: ecology 只读库数据源

会议邀请函/分享:
- InvitationPdfService + WxShareService: 邀请函 PDF 生成 + 微信分享
- PdfViewer.vue (pdfjs-dist) + MeetingInvitation.vue: PDF 预览 + 邀请函页

参会人/执行意向:
- BizMeetingAttendee*: 参会人模块增强
- BizExecutionIntent*: 执行意向增强

签到/劳务/导入:
- BizSignServiceImpl + SignFill.vue: 签到劳务
- FieldMismatch/ImportMismatch: 导入校验 VO

公示/会议详情:
- PublicityDetail.vue / MeetingDetail.vue 等前端增强

配置:
- test 短信 mock + 供应商/招标接口切生产域名
This commit is contained in:
郭庆泰
2026-09-03 20:12:15 +08:00
parent beb9799a06
commit 56615f9806
55 changed files with 3296 additions and 516 deletions
+7 -20
View File
@@ -5,13 +5,13 @@
<el-button type="primary" @click="goBack">返回</el-button>
</div>
<div v-else v-loading="loading">
<!-- 已签署: 再次打开签署链接, 直接展示劳务协议 PDF (复用 publicity OSS 代理预览) -->
<!-- 已签署: 再次打开签署链接, 本页内嵌 PDF.js 渲染 (微信/移动端无 Chrome 内置 PDF viewer) -->
<div v-if="signed" class="signed-pdf">
<div class="sign-header">
<div class="sign-header-title">{{ meetingName || '劳务协议' }}</div>
<div v-if="periodDisplay" class="sign-header-period">期数{{ periodDisplay }}</div>
</div>
<iframe v-if="laborPdfUrl" :src="proxyUrl(laborPdfUrl)" class="signed-pdf-frame"></iframe>
<PdfViewer v-if="laborPdfUrl" :url="laborPdfUrl" class="signed-pdf-viewer" />
<div v-else class="signed-pdf-empty">协议已签署暂无可展示的 PDF</div>
<div class="signed-pdf-actions">
<el-button v-if="laborPdfUrl" type="primary" @click="downloadPdf">下载劳务协议</el-button>
@@ -108,6 +108,7 @@ import { getInfo } from '@/api/auth'
import { useUserStore } from '@/store/user'
import IdCardUploader from '@/components/IdCardUploader.vue'
import AreaCascader from '@/components/AreaCascader.vue'
import PdfViewer from '@/components/PdfViewer.vue'
const route = useRoute()
const router = useRouter()
@@ -247,16 +248,10 @@ async function load() {
loading.value = true
try {
const { data } = await getSignInfo(attendeeId.value)
// 已签署: 再次打开签署链接 → 整页跳转到 OSS proxy 的 PDF 地址 (全屏显示, 不用 iframe 内嵌)
// 已签署: 再次打开签署链接 → 本页内嵌 PDF.js 渲染 (微信/移动端无 Chrome 内置 PDF viewer)
if (data.signed || (data.laborProtocol && data.laborProtocol.trim())) {
const url = data.laborProtocol
if (url) {
window.location.href = proxyUrl(url)
return
}
// 无 PDF URL 兜底: 仍留在本页显示"已签署但无可展示 PDF"
signed.value = true
laborPdfUrl.value = ''
laborPdfUrl.value = data.laborProtocol || ''
meetingName.value = data.meetingName || ''
periodNo.value = data.periodNo ?? null
totalPeriods.value = data.totalPeriods ?? null
@@ -357,14 +352,6 @@ async function onSubmit() {
}
}
// OSS 代理预览 (同 publicity / doctor/Meetings.vue): 重写 Content-Disposition 为 inline, 隐藏工具栏撑满宽度
function proxyUrl(url) {
if (!url) return url
if (url.includes('hwtossbamlorgcn.oss-cn-beijing.aliyuncs.com')) {
return import.meta.env.VITE_APP_BASE_API + '/common/oss/proxy?url=' + encodeURIComponent(url) + '#toolbar=0&zoom=page-width'
}
return url
}
function downloadPdf() {
if (!laborPdfUrl.value) return
const a = document.createElement('a')
@@ -391,9 +378,9 @@ onMounted(init)
.sign-header-title { font-size: 20px; font-weight: 600; color: #1a1a1a; line-height: 1.4; }
.sign-header-period { margin-top: 6px; font-size: 14px; color: #595959; }
/* 已签署: 直接展示 PDF (宽度 100%, 高度不限制) */
/* 已签署: 直接展示 PDF (PdfViewer 内部自适应宽度/高度 + 滚动) */
.signed-pdf { display: flex; flex-direction: column; }
.signed-pdf-frame { width: 100%; height: 424vw; border: 0; }
.signed-pdf-viewer { width: 100%; }
.signed-pdf-empty { padding: 48px 16px; text-align: center; color: #909399; }
.signed-pdf-actions { margin-top: 16px; display: flex; gap: 12px; }