@@ -898,10 +902,10 @@ const frozen = computed(() => isOne(row.value.isFrozen))
/** 单轨是否处于「可提交/可编辑」态: 执行方仅未提交/被驳回可编辑; 合规(manager)/管理员 永远可编辑 */
const laborEditable = computed(() => isManager.value || isAdmin.value || ['NOT_SUBMITTED', 'REJECTED'].includes(row.value.laborAuditStage))
const serviceEditable = computed(() => isManager.value || isAdmin.value || ['NOT_SUBMITTED', 'REJECTED'].includes(row.value.serviceAuditStage))
-// 提交审核后该轨锁定 (manager/admin 也跟着锁), 让 OssFileUploader 移除按钮消失
+// 提交审核后该轨锁定执行方 (executor), 让 OssFileUploader 移除按钮消失; 合规/管理员 (manager/admin) 任何时候都可编辑保存, 故不锁
// (仅控制 OssFileUploader 的 readonly; 不影响 laborEditable (下载模板/参会人列表的判定))
-const laborLocked = computed(() => ['SUBMITTED', 'APPROVED'].includes(row.value.laborAuditStage))
-const serviceLocked = computed(() => ['SUBMITTED', 'APPROVED'].includes(row.value.serviceAuditStage))
+const laborLocked = computed(() => !isManager.value && !isAdmin.value && ['SUBMITTED', 'APPROVED'].includes(row.value.laborAuditStage))
+const serviceLocked = computed(() => !isManager.value && !isAdmin.value && ['SUBMITTED', 'APPROVED'].includes(row.value.serviceAuditStage))
// 参会人名单是否可改 (新增/导入/编辑/删除): sponsor/只读不可; executor 劳务提交后(SUBMITTED/APPROVED)锁定, 未提交/退回可改; manager/admin 恒可改
const attendeeEditable = computed(() => {
if (isSponsor.value || isReadonly.value) return false
@@ -911,11 +915,17 @@ const attendeeEditable = computed(() => {
/** 单轨状态判定: C0=已提交待合规审 / C1=已提交待支持方审 */
function isC0(stage, compliance) { return stage === 'SUBMITTED' && !isOne(compliance) }
function isC1(stage, compliance) { return stage === 'SUBMITTED' && isOne(compliance) }
-// 材料可提交: 已执行 + 未冻结 + 对应轨可编辑 (三按钮按轨显隐)
-const executorSubmitReady = computed(() => isExecutor.value && executed.value && !frozen.value)
-const canSubmitLabor = computed(() => executorSubmitReady.value && laborEditable.value)
-const canSubmitService = computed(() => executorSubmitReady.value && serviceEditable.value)
-const canSubmitAll = computed(() => executorSubmitReady.value && laborEditable.value && serviceEditable.value)
+// 材料可提交: 执行方需"已执行"+未冻结; 合规员(manager 自建会议自传自审)不受"已执行"与"已冻结"两道时间门槛限制
+const executorSubmitReady = computed(() => {
+ if (isManager.value) return true
+ return isExecutor.value && executed.value && !frozen.value
+})
+// 单轨"可提交"门槛 (区别于 laborEditable 的"可编辑"): 仅未提交/被驳回可提交, 提交后按钮隐藏
+const laborSubmittable = computed(() => ['NOT_SUBMITTED', 'REJECTED'].includes(row.value.laborAuditStage))
+const serviceSubmittable = computed(() => ['NOT_SUBMITTED', 'REJECTED'].includes(row.value.serviceAuditStage))
+const canSubmitLabor = computed(() => executorSubmitReady.value && laborSubmittable.value)
+const canSubmitService = computed(() => executorSubmitReady.value && serviceSubmittable.value)
+const canSubmitAll = computed(() => executorSubmitReady.value && laborSubmittable.value && serviceSubmittable.value)
// 材料可编辑 (保存修改): 任一轨未提交/被驳回 时可保存; 两轨都进入审核后锁定
const materialsEditable = computed(() => laborEditable.value || serviceEditable.value)
// 合规审核 (合规方/manager): 三按钮按轨 C0 显隐
@@ -2590,6 +2600,10 @@ onBeforeUnmount(() => {
.agreement-actions { display: flex; align-items: center; gap: 8px; min-width: 0; }
/* 电子签到表 多文件上传 + zip 按钮 纵向排列 */
.esign-actions { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; min-width: 0; }
+/* 现场照片 (签到表/前全景/后全景): 扫码拍照 + 直接上传 左右并存 */
+.camera-upload-row { display: flex; align-items: flex-start; gap: 8px; min-width: 0; }
+.camera-upload-row :deep(.camera-qr-upload) { width: auto; flex: 0 0 auto; }
+.camera-upload-row :deep(.ht-file-upload) { flex: 1 1 0; min-width: 0; }
.upload-progress { grid-column: 2; display: flex; align-items: center; gap: 8px; max-width: 400px; }
.upload-progress .el-progress { flex: 1; }
.upload-progress-status { font-size: 12px; color: #8c8c8c; white-space: nowrap; }
@@ -2638,6 +2652,7 @@ onBeforeUnmount(() => {
/* 参会人管理 (放在 劳务材料 tab 顶部, 在 劳务明细 + 劳务协议 上面) */
.attendee-section { padding-bottom: 16px; border-bottom: 1px dashed #e8e8e8; }
+.attendee-subtitle { font-size: 14px; font-weight: 600; color: #1a1a1a; margin-bottom: 12px; }
.attendee-toolbar { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; flex-wrap: wrap; }
.form-hint { font-size: 12px; color: #909399; margin-top: -8px; margin-bottom: 8px; line-height: 1.5; grid-column: 1 / -1; }