Compare commits
2
Commits
f8afe9baab
...
44d4920777
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44d4920777 | ||
|
|
1dc200a3cc |
@@ -31,6 +31,10 @@
|
||||
<jwt.version>0.9.1</jwt.version>
|
||||
<jaxb-api.version>2.3.1</jaxb-api.version>
|
||||
<springdoc.version>3.0.3</springdoc.version>
|
||||
<!-- 打包注入的激活 profile: 默认 prod, -Ptest / -Pprod 覆盖 -->
|
||||
<active.profile>prod</active.profile>
|
||||
<!-- jar 名后缀: 默认空 (=ruoyi-admin.jar), -Ptest → -test, -Pprod → -prod -->
|
||||
<jar.suffix></jar.suffix>
|
||||
</properties>
|
||||
|
||||
<!-- 依赖声明 -->
|
||||
@@ -215,6 +219,24 @@
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<!-- 分环境打包: mvn package -Ptest / -Pprod 生成 ruoyi-admin-test.jar / ruoyi-admin-prod.jar (profile 已注入, 免 spring.profiles.active 启动参数) -->
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>test</id>
|
||||
<properties>
|
||||
<active.profile>test</active.profile>
|
||||
<jar.suffix>-test</jar.suffix>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>prod</id>
|
||||
<properties>
|
||||
<active.profile>prod</active.profile>
|
||||
<jar.suffix>-prod</jar.suffix>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>public</id>
|
||||
|
||||
@@ -63,6 +63,23 @@
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<!-- 仅过滤 application*.yml 注入 @active.profile@, 其余资源 (logback/mapper/i18n) 不过滤避免误替换 ${...} -->
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
<includes>
|
||||
<include>application*.yml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>false</filtering>
|
||||
<excludes>
|
||||
<exclude>application*.yml</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@@ -89,7 +106,7 @@
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<finalName>${project.artifactId}${jar.suffix}</finalName>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -6,8 +6,8 @@ spring:
|
||||
# 国际化资源文件路径
|
||||
basename: i18n/messages
|
||||
profiles:
|
||||
# 默认 prod 环境; 本地测试用 --spring.profiles.active=test (group 自动展开为 druid,test)
|
||||
active: prod
|
||||
# 默认 prod; Maven 打包时用 -Ptest/-Pprod 注入 @active.profile@ (见 pom.xml profiles), 免运行时 --spring.profiles.active
|
||||
active: @active.profile@
|
||||
group:
|
||||
test: druid,test
|
||||
prod: druid,prod
|
||||
|
||||
+9
-5
@@ -351,8 +351,8 @@ public class BizMeetingController extends BaseController {
|
||||
/**
|
||||
* 执行人员提交材料 (分轨: 劳务 LABOR / 会务 SERVICE 可多选, 每轨独立提交).
|
||||
* <ul>
|
||||
* <li>校验 1: 当前用户是该会议执行方 (项目级归属, 强校验)</li>
|
||||
* <li>校验 2: 已执行 (is_executed=1) 且未冻结</li>
|
||||
* <li>校验 1: 当前用户是该会议执行方 (项目级归属, 强校验) — 合规员(manager) 自建会议自传自审, 跳过此校验</li>
|
||||
* <li>校验 2: 已执行 (is_executed=1) 且未冻结 — 合规员(manager) 跳过"已执行"与"已冻结"两道时间门槛 (不依赖 scheduler)</li>
|
||||
* <li>校验 3: 所选轨 audit_stage ∈ {NOT_SUBMITTED, REJECTED}</li>
|
||||
* <li>校验 4: 会务轨在 biz_meeting_material 至少 1 条 (M_*); 劳务轨 = 参会人员列表至少 1 人 (非上传文件)</li>
|
||||
* </ul>
|
||||
@@ -366,11 +366,15 @@ public class BizMeetingController extends BaseController {
|
||||
if (m == null) throw new ServiceException("会议不存在");
|
||||
|
||||
Long userId = SecurityUtils.getUserId();
|
||||
if (!bizProjectService.isExecutorOfProject(m.getProjectId(), userId)) {
|
||||
String roleType = SecurityUtils.getLoginUser().getUser().getRoleType();
|
||||
// 合规员(manager) 自建会议可自传自审: 跳过"必须是项目执行方"的强校验
|
||||
if (!"manager".equals(roleType) && !bizProjectService.isExecutorOfProject(m.getProjectId(), userId)) {
|
||||
throw new ServiceException("您不是该项目的执行方, 无法提交材料");
|
||||
}
|
||||
if (!isExecuted(m)) throw new ServiceException("会议尚未执行, 不能提交材料");
|
||||
if (isFrozen(m)) throw new ServiceException("会议已冻结, 不能提交材料");
|
||||
// 合规员(manager) 自建会议自传自审: 不依赖 scheduler 翻 is_executed, 跳过"已执行"时间门槛
|
||||
if (!"manager".equals(roleType) && !isExecuted(m)) throw new ServiceException("会议尚未执行, 不能提交材料");
|
||||
// 合规员(manager) 自建会议自传自审: 同样跳过"已冻结"门槛 (冻结=提交截止已过, 但自审流程不应对合规员本人设卡)
|
||||
if (!"manager".equals(roleType) && isFrozen(m)) throw new ServiceException("会议已冻结, 不能提交材料");
|
||||
|
||||
List<String> types = body == null ? null : body.getTypes();
|
||||
if (types == null || types.isEmpty()) throw new ServiceException("请选择要提交的材料类型");
|
||||
|
||||
@@ -63,8 +63,9 @@
|
||||
<div class="section-title">材料管理</div>
|
||||
<el-tabs v-model="activeTab" class="material-tabs">
|
||||
<el-tab-pane label="劳务材料" name="labor">
|
||||
<!-- 参会人管理 (放在 劳务明细 + 劳务协议 上面, 无表题直接出表) -->
|
||||
<!-- 参会人管理 (放在 劳务明细 + 劳务协议 上面) -->
|
||||
<div class="attendee-section">
|
||||
<div class="attendee-subtitle">劳务明细表</div>
|
||||
<div v-if="!isSponsor && !isReadonly" class="attendee-toolbar">
|
||||
<el-button type="primary" size="small" :loading="attendeeLoading" :disabled="!attendeeEditable" @click="openAttendeeDialog()">+ 新增参会人</el-button>
|
||||
<el-button size="small" :disabled="!attendeeEditable" @click="openAttendeeImport">批量导入</el-button>
|
||||
@@ -195,7 +196,10 @@
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<CameraQrUpload v-if="isCameraSubType(r.subType)" v-model="r.url" :meeting-id="meetingId" :sub-type="r.subType" :label="r.label" :readonly="isSponsor || isReadonly || !laborEditable || laborLocked" class="file-uploader" />
|
||||
<div v-if="isCameraSubType(r.subType)" class="camera-upload-row">
|
||||
<CameraQrUpload v-model="r.url" :meeting-id="meetingId" :sub-type="r.subType" :label="r.label" :readonly="isSponsor || isReadonly || !laborEditable || laborLocked" class="file-uploader" />
|
||||
<OssFileUploader v-model="r.url" v-model:name="r.fileName" :dir="`ry8080/meeting/${meetingId}/labor/`" accept=".png,.jpg,.jpeg,.gif,.webp,.bmp" placeholder="直接上传(本地图片)" :readonly="isSponsor || isReadonly || !laborEditable || laborLocked" class="file-uploader" />
|
||||
</div>
|
||||
<template v-else-if="r.subType === 'L_ESIGN_IN'">
|
||||
<div class="esign-actions">
|
||||
<OssFileUploader v-model="r.url" :dir="`ry8080/meeting/${meetingId}/labor/`" :accept="r.accept" multiple block :max-size="20" placeholder="点击上传多个 Excel (xls/xlsx/csv)" :readonly="isSponsor || isReadonly || !laborEditable || laborLocked" />
|
||||
@@ -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; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user