feat: 会议提交剩余时间+解冻 + 会务/劳务材料批量下载 + 多角色人员/账号模块完善

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
郭庆泰
2026-08-25 06:53:18 +08:00
co-authored by Claude
parent 0c882ae846
commit 591a43fe61
126 changed files with 3789 additions and 1334 deletions
+6 -3
View File
@@ -167,9 +167,12 @@ async function load() {
const type = r.announcementType || '公示'
// 根据 announcementType 选择对应 URL
const urlMap = {
invitation: r.invitationUrl,
support: r.supportLetterUrl,
publish: r.publishUrl
invitation: r.invitationUrl,
support: r.supportLetterUrl,
supportLetter: r.supportLetterUrl,
publish: r.publishUrl,
notice: r.publishUrl,
schedule: r.scheduleUrl
}
return {
annId: r.projectId,
+33 -12
View File
@@ -90,20 +90,28 @@
</main>
</div>
<!-- : 操作按钮 - 悬浮固定到页面最右 -->
<!-- : 操作按钮 - 悬浮固定到页面最右 (按选中 tab 动态显示) -->
<aside class="detail-actions">
<button class="action-btn primary signup-btn" :disabled="signing || signed" @click="onSignup">
<!-- 邀请函: 立即报名 -->
<button v-if="activeTab === 'invitation'" class="action-btn primary signup-btn" :disabled="signing || signed" @click="onSignup">
<svg class="btn-icon" viewBox="0 0 24 24" fill="currentColor" width="14" height="14">
<path d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm-1 7V3.5L18.5 9H13z"/>
</svg>
<span>{{ signed ? '已报名' : (signing ? '报名中…' : '立即报名') }}</span>
</button>
<button v-if="canShowSupportBtn" class="action-btn primary" :disabled="supportSubmitting || supportSubmitted" @click="onSupportIntent">
<span>{{ supportSubmitted ? '已支持' : (supportSubmitting ? '提交中…' : '表达支持意向') }}</span>
<!-- 支持函: 公益支持 (表达支持意向) -->
<button v-if="activeTab === 'supportLetter' && canShowSupportBtn" class="action-btn primary" :disabled="supportSubmitting || supportSubmitted" @click="onSupportIntent">
<span>{{ supportSubmitted ? '已支持' : (supportSubmitting ? '提交中…' : '公益支持') }}</span>
</button>
<button v-if="canShowExecutionBtn" class="action-btn primary" :disabled="executionSubmitting || executionSubmitted" @click="onExecutionIntent">
<span>{{ executionSubmitted ? '已表达意向' : (executionSubmitting ? '提交中…' : '表达执行意向') }}</span>
<!-- 通知: 项目执行申请 (表达执行意向) -->
<button v-if="activeTab === 'notice' && canShowExecutionBtn" class="action-btn primary" :disabled="executionSubmitting || executionSubmitted" @click="onExecutionIntent">
<span>{{ executionSubmitted ? '已申请' : (executionSubmitting ? '提交中…' : '项目执行申请') }}</span>
</button>
<!-- 通知: 查看招标公告 (仅招标项目, 暂跳百度占位) -->
<button v-if="activeTab === 'notice' && isBidProject" class="action-btn primary" @click="onViewBidAnnouncement">
<span>查看招标公告</span>
</button>
<!-- 分享二维码: 所有 tab 均显示 -->
<button class="action-btn primary share-btn" @click="showQr = true">
<svg class="btn-icon" viewBox="0 0 24 24" fill="currentColor" width="14" height="14">
<path d="M3 11h8V3H3v8zm2-6h4v4H5V5zm8-2v8h8V3h-8zm6 6h-4V5h4v4zM3 21h8v-8H3v8zm2-6h4v4H5v-4z"/>
@@ -282,8 +290,10 @@ const activeTab = ref('invitation')
// 按 URL 字段定义固定 tab (key 必须与 biz_project 字段名后缀一致)
const TAB_DEFS = [
{ key: 'invitation', label: '邀请函', urlKey: 'invitationUrl' },
{ key: 'supportLetter', label: '支持函', urlKey: 'supportLetterUrl' }
{ key: 'invitation', label: '专家参与邀请函', urlKey: 'invitationUrl' },
{ key: 'supportLetter', label: '项目公益支持函', urlKey: 'supportLetterUrl' },
{ key: 'notice', label: '项目通知', urlKey: 'publishUrl' },
{ key: 'schedule', label: '日程', urlKey: 'scheduleUrl' }
]
// 只显示项目里"实际有文件 URL"的 tab
@@ -303,6 +313,12 @@ const tabList = computed(() => {
const currentTab = computed(() => tabList.value.find(t => t.key === activeTab.value) || tabList.value[0])
// 是否招标项目 (is_bid_project = 'Y'): 通知 tab 下显示"查看招标公告"按钮
const isBidProject = computed(() => {
const v = ann.value?.isBidProject
return v === 'Y' || v === '1' || v === 1 || v === true
})
// 判断文件类型: 通过 URL 扩展名 (兼容 OSS 签名 URL)
function isPdf(url) {
if (!url) return false
@@ -516,13 +532,13 @@ function onSupportIntent() {
if (supportSubmitting.value || supportSubmitted.value) return
if (loggedIn.value) {
guestDialog.type = 'support'
guestDialog.title = '表达支持意向'
guestDialog.title = '公益支持'
guestDialog.open = true
prefillGuestFormFromUser() // 异步, 不 await; dialog 已先打开, 数据慢慢填进去
} else {
resetGuestForm()
guestDialog.type = 'support'
guestDialog.title = '表达支持意向'
guestDialog.title = '公益支持'
guestDialog.open = true
}
}
@@ -532,13 +548,13 @@ function onExecutionIntent() {
if (executionSubmitting.value || executionSubmitted.value) return
if (loggedIn.value) {
guestDialog.type = 'execution'
guestDialog.title = '表达执行意向'
guestDialog.title = '项目执行申请'
guestDialog.open = true
prefillGuestFormFromUser() // 异步, 不 await
} else {
resetGuestForm()
guestDialog.type = 'execution'
guestDialog.title = '表达执行意向'
guestDialog.title = '项目执行申请'
guestDialog.open = true
}
}
@@ -587,6 +603,11 @@ async function doSubmitIntent(type, fields) {
}
}
// 查看招标公告: 暂跳百度占位 (后续替换为真实招标公告链接)
function onViewBidAnnouncement() {
window.open('https://www.baidu.com', '_blank')
}
function onKeydown(e) { if (e.key === 'Escape') showQr.value = false }
function handleScroll() { isScrolled.value = window.scrollY > 10 }