feat: 会议阶段劳务/会务前缀投影 + 结算前未保存拦截
- 阶段投影: 待审核/审核通过/待整改/待结算 按劳务/会务前缀区分 (前后端镜像) - 劳务材料提交门槛改为参会人员列表≥1人 (非上传文件) - sponsor/manager 操作列「审核」「结算」提为直链 - 会议结算时间轴节点: 待结算态显示「补充凭证并结算」 - 结算前检测未保存改动, 弹「保存并结算」拦截 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+14
-6
@@ -285,7 +285,7 @@ public class BizMeetingController extends BaseController {
|
||||
* <li>校验 1: 当前用户是该会议执行方 (项目级归属, 强校验)</li>
|
||||
* <li>校验 2: 已执行 (is_executed=1) 且未冻结</li>
|
||||
* <li>校验 3: 所选轨 audit_stage ∈ {NOT_SUBMITTED, REJECTED}</li>
|
||||
* <li>校验 4: 所选轨在 biz_meeting_material 各至少 1 条 (劳务 L_* / 会务 M_*)</li>
|
||||
* <li>校验 4: 会务轨在 biz_meeting_material 至少 1 条 (M_*); 劳务轨 = 参会人员列表至少 1 人 (非上传文件)</li>
|
||||
* </ul>
|
||||
* body: { "types": ["LABOR","SERVICE"] }
|
||||
* 通过后该轨 → SUBMITTED (compliance_approved=0), 每轨记一条 audit_log.
|
||||
@@ -310,8 +310,9 @@ public class BizMeetingController extends BaseController {
|
||||
}
|
||||
|
||||
List<BizMeetingMaterial> mats = bizMeetingMaterialService.selectByMeetingId(meetingId);
|
||||
boolean hasLabor = mats.stream().anyMatch(x -> x.getSubType() != null && x.getSubType().startsWith("L_"));
|
||||
boolean hasService = mats.stream().anyMatch(x -> x.getSubType() != null && x.getSubType().startsWith("M_"));
|
||||
// 劳务材料 = 参会人员列表 (不是上传的文件), 提交门槛 = 至少 1 名参会人
|
||||
boolean hasLabor = !attendeeService.selectByMeetingId(meetingId).isEmpty();
|
||||
|
||||
for (String type : types) {
|
||||
String label = "LABOR".equals(type) ? "劳务材料" : "会务材料";
|
||||
@@ -319,8 +320,11 @@ public class BizMeetingController extends BaseController {
|
||||
if (!"NOT_SUBMITTED".equals(stage) && !"REJECTED".equals(stage)) {
|
||||
throw new ServiceException(label + "当前阶段 (" + stage + ") 不允许提交");
|
||||
}
|
||||
boolean has = "LABOR".equals(type) ? hasLabor : hasService;
|
||||
if (!has) throw new ServiceException(label + "至少上传一条");
|
||||
if ("LABOR".equals(type)) {
|
||||
if (!hasLabor) throw new ServiceException("请先添加参会人员 (劳务材料)");
|
||||
} else if (!hasService) {
|
||||
throw new ServiceException("会务材料至少上传一条");
|
||||
}
|
||||
}
|
||||
|
||||
for (String type : types) {
|
||||
@@ -685,8 +689,12 @@ public class BizMeetingController extends BaseController {
|
||||
log.setAuditResult(result);
|
||||
log.setOpinion(opinion);
|
||||
log.setMaterialType(materialType);
|
||||
log.setCreateTime(new Date());
|
||||
log.setAuditTime(new Date());
|
||||
Date now = new Date();
|
||||
log.setCreateTime(now);
|
||||
log.setAuditTime(now);
|
||||
// 本次动作所在轨「最近时间」记为 now, 供 deriveDisplay 按最近时间合并两轨 (4 列阶段快照)
|
||||
if ("LABOR".equals(materialType)) m.setLaborAuditTime(now);
|
||||
else if ("SERVICE".equals(materialType)) m.setServiceAuditTime(now);
|
||||
log.setExecutorStage(stageDeriver.deriveDisplay("executor", m));
|
||||
log.setSponsorStage(stageDeriver.deriveDisplay("sponsor", m));
|
||||
log.setManagerStage(stageDeriver.deriveDisplay("manager", m));
|
||||
|
||||
@@ -99,6 +99,12 @@ public class BizMeeting extends BaseEntity {
|
||||
/** 材料最近一次审核动作时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date materialAuditTime;
|
||||
/** 劳务材料最后一次动作时间 (派生字段, 标量子查询 max(audit_time) where material_type='LABOR', 不落库) */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date laborAuditTime;
|
||||
/** 会务材料最后一次动作时间 (派生字段, 标量子查询 max(audit_time) where material_type='SERVICE', 不落库) */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date serviceAuditTime;
|
||||
/** 劳务材料合规是否已通过 0否1是 (区分 SUBMITTED 内合规审/支持方审) */
|
||||
private Integer laborComplianceApproved;
|
||||
/** 会务材料合规是否已通过 0否1是 (区分 SUBMITTED 内合规审/支持方审) */
|
||||
@@ -219,6 +225,10 @@ public class BizMeeting extends BaseEntity {
|
||||
public void setFreezeTime(Date freezeTime) { this.freezeTime = freezeTime; }
|
||||
public Date getMaterialAuditTime() { return materialAuditTime; }
|
||||
public void setMaterialAuditTime(Date materialAuditTime) { this.materialAuditTime = materialAuditTime; }
|
||||
public Date getLaborAuditTime() { return laborAuditTime; }
|
||||
public void setLaborAuditTime(Date laborAuditTime) { this.laborAuditTime = laborAuditTime; }
|
||||
public Date getServiceAuditTime() { return serviceAuditTime; }
|
||||
public void setServiceAuditTime(Date serviceAuditTime) { this.serviceAuditTime = serviceAuditTime; }
|
||||
public Integer getLaborComplianceApproved() { return laborComplianceApproved; }
|
||||
public void setLaborComplianceApproved(Integer laborComplianceApproved) { this.laborComplianceApproved = laborComplianceApproved; }
|
||||
public Integer getServiceComplianceApproved() { return serviceComplianceApproved; }
|
||||
|
||||
@@ -88,8 +88,42 @@ public class StageDeriver
|
||||
if (t(m.getIsFinished())) return "已完结";
|
||||
if (t(m.getIsSettled())) return "已结算";
|
||||
|
||||
int chosen = chooseState(role, laborState(m), serviceState(m));
|
||||
return render(role, chosen, executionPhase(m));
|
||||
int phase = executionPhase(m);
|
||||
int labor = laborState(m);
|
||||
int service = serviceState(m);
|
||||
|
||||
// 中性角色 (admin/doctor/expert): 维持原逻辑 (最小进度 + 单轨措辞), 不加前缀
|
||||
if (!"executor".equals(role) && !"sponsor".equals(role) && !"manager".equals(role))
|
||||
{
|
||||
return render(role, Math.min(labor, service), phase);
|
||||
}
|
||||
|
||||
// 三流程角色: 两轨合并 + 劳务/会务前缀
|
||||
String laborLabel = render(role, labor, phase);
|
||||
String serviceLabel = render(role, service, phase);
|
||||
if (laborLabel.equals(serviceLabel)) return laborLabel;
|
||||
|
||||
// 待办态最高优先: manager=C0(2), sponsor=C1(3), executor=R(0)
|
||||
int urgent = "manager".equals(role) ? 2 : "sponsor".equals(role) ? 3 : 0;
|
||||
String track;
|
||||
String label;
|
||||
if (labor == urgent) { track = "labor"; label = laborLabel; }
|
||||
else if (service == urgent) { track = "service"; label = serviceLabel; }
|
||||
else
|
||||
{
|
||||
Date lt = m.getLaborAuditTime();
|
||||
Date st = m.getServiceAuditTime();
|
||||
boolean laborNewer = lt != null && (st == null || !lt.before(st));
|
||||
if (laborNewer) { track = "labor"; label = laborLabel; }
|
||||
else { track = "service"; label = serviceLabel; }
|
||||
}
|
||||
|
||||
// 仅 待审核/审核通过/待整改/待结算 四类加前缀
|
||||
if ("待审核".equals(label) || "审核通过".equals(label) || "待整改".equals(label) || "待结算".equals(label))
|
||||
{
|
||||
return ("labor".equals(track) ? "劳务" : "会务") + label;
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
/** 按角色优先级选代表轨 (两轨中优先级更高的那轨). */
|
||||
@@ -139,7 +173,7 @@ public class StageDeriver
|
||||
switch (s)
|
||||
{
|
||||
case 0: // R 退回
|
||||
return "executor".equals(role) ? "已退回" : "待整改";
|
||||
return "待整改";
|
||||
case 1: // N 未提交 (时间驱动三态: 未执行 → 执行中 → 已执行, 所有角色统一)
|
||||
if (phase == 0) return "未执行";
|
||||
if (phase == 1) return "执行中";
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
<result property="isFrozen" column="is_frozen" />
|
||||
<result property="freezeTime" column="freeze_time" />
|
||||
<result property="materialAuditTime" column="material_audit_time" />
|
||||
<result property="laborAuditTime" column="labor_audit_time" />
|
||||
<result property="serviceAuditTime" column="service_audit_time" />
|
||||
<result property="laborComplianceApproved" column="labor_compliance_approved" />
|
||||
<result property="serviceComplianceApproved" column="service_compliance_approved" />
|
||||
<result property="submitDeadline" column="submit_deadline" />
|
||||
@@ -59,6 +61,8 @@
|
||||
<select id="selectByPrimaryKey" resultMap="BizMeetingResult" parameterType="Long">
|
||||
select
|
||||
(select o.org_name from biz_project p join biz_org o on o.org_id = p.sponsor_org_id where p.project_id = biz_meeting.project_id limit 1) as org_name,
|
||||
(select max(a2.audit_time) from biz_meeting_audit_log a2 where a2.meeting_id = biz_meeting.meeting_id and a2.material_type = 'LABOR' and a2.is_deleted = 0) as labor_audit_time,
|
||||
(select max(a2.audit_time) from biz_meeting_audit_log a2 where a2.meeting_id = biz_meeting.meeting_id and a2.material_type = 'SERVICE' and a2.is_deleted = 0) as service_audit_time,
|
||||
<include refid="selectFields"/>
|
||||
from biz_meeting
|
||||
where meeting_id = #{meetingId} and is_deleted = 0
|
||||
@@ -71,6 +75,8 @@
|
||||
(select o.org_name from biz_project p join biz_org o on o.org_id = p.sponsor_org_id where p.project_id = biz_meeting.project_id limit 1) as org_name,
|
||||
(select p.invitation_url from biz_project p where p.project_id = biz_meeting.project_id limit 1) as project_invitation_url,
|
||||
<if test="params.assignedExecutorUserId != null">(select coalesce(sum(a.sessions), 0) from biz_project_assign a where a.project_id = biz_meeting.project_id and a.is_deleted = 0 and a.execution_unit_id = (select org_id from biz_org where user_id = #{params.assignedExecutorUserId} and org_type = 'executor')) as assigned_sessions,</if>
|
||||
(select max(a2.audit_time) from biz_meeting_audit_log a2 where a2.meeting_id = biz_meeting.meeting_id and a2.material_type = 'LABOR' and a2.is_deleted = 0) as labor_audit_time,
|
||||
(select max(a2.audit_time) from biz_meeting_audit_log a2 where a2.meeting_id = biz_meeting.meeting_id and a2.material_type = 'SERVICE' and a2.is_deleted = 0) as service_audit_time,
|
||||
<include refid="selectFields"/>
|
||||
from biz_meeting
|
||||
<where>
|
||||
|
||||
@@ -79,7 +79,7 @@ function chooseState(role, labor, service) {
|
||||
function render(role, s, phase) {
|
||||
switch (s) {
|
||||
case 0: // R 退回
|
||||
return role === 'executor' ? '已退回' : '待整改'
|
||||
return '待整改'
|
||||
case 1: // N 未提交 (时间驱动三态: 未执行 → 执行中 → 已执行, 所有角色统一)
|
||||
if (phase === 0) return '未执行'
|
||||
if (phase === 1) return '执行中'
|
||||
@@ -119,8 +119,40 @@ export function deriveStage(role, row) {
|
||||
if (isTrue(row.isFrozen)) return '冻结中'
|
||||
if (isTrue(row.isFinished)) return '已完结'
|
||||
if (isTrue(row.isSettled)) return '已结算'
|
||||
const chosen = chooseState(role, laborState(row), serviceState(row))
|
||||
return render(role, chosen, executionPhase(row))
|
||||
const phase = executionPhase(row)
|
||||
const ls = laborState(row)
|
||||
const ss = serviceState(row)
|
||||
// admin/doctor 等中性角色: 维持原逻辑 (最小进度 + 单轨措辞), 不加前缀
|
||||
if (role !== 'executor' && role !== 'sponsor' && role !== 'manager') {
|
||||
return render(role, Math.min(ls, ss), phase)
|
||||
}
|
||||
// 三流程角色: 两轨合并 + 劳务/会务前缀
|
||||
const ll = render(role, ls, phase)
|
||||
const sl = render(role, ss, phase)
|
||||
if (ll === sl) return ll
|
||||
// 待办态最高优先: manager=C0(2), sponsor=C1(3), executor=R(0)
|
||||
const urgent = role === 'manager' ? 2 : role === 'sponsor' ? 3 : 0
|
||||
let track, label
|
||||
if (ls === urgent) { track = 'labor'; label = ll }
|
||||
else if (ss === urgent) { track = 'service'; label = sl }
|
||||
else {
|
||||
const lt = ts(row.laborAuditTime)
|
||||
const st = ts(row.serviceAuditTime)
|
||||
if (lt >= st) { track = 'labor'; label = ll }
|
||||
else { track = 'service'; label = sl }
|
||||
}
|
||||
// 仅 待审核/审核通过/待整改/待结算 四类加前缀
|
||||
if (label === '待审核' || label === '审核通过' || label === '待整改' || label === '待结算') {
|
||||
return (track === 'labor' ? '劳务' : '会务') + label
|
||||
}
|
||||
return label
|
||||
}
|
||||
|
||||
/** 时间戳解析 (null/非法 → -1, 保证 null 时间在最近时间比较里输给任何真实时间). */
|
||||
function ts(v) {
|
||||
if (v == null) return -1
|
||||
const t = new Date(v).getTime()
|
||||
return Number.isNaN(t) ? -1 : t
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -134,14 +166,13 @@ export function stageLabel(role, row) {
|
||||
* 展示阶段名 → 颜色映射 (class + el-tag type), 与 render() 措辞一一对应.
|
||||
* 颜色跟随「各角色看到的展示阶段」而非物理阶段, 避免文案与颜色错位
|
||||
* (如 sponsor 看「待审核」却因物理阶段 RECTIFYING 显示红色).
|
||||
* 规则: 待整改/已退回=红, 未执行=灰, 执行中/已执行/已执行未传材料=蓝, 待审核=橙, 通过/待结算/完结=绿.
|
||||
* 规则: 待整改=红, 未执行=灰, 执行中/已执行/已执行未传材料=蓝, 待审核=橙, 通过/待结算/完结=绿.
|
||||
*/
|
||||
const STAGE_STYLE = {
|
||||
'冻结中': { cls: 'frozen', tag: 'info' },
|
||||
'已完结': { cls: 'done', tag: 'success' },
|
||||
'已结算': { cls: 'done', tag: 'success' },
|
||||
'待整改': { cls: 'waiting', tag: 'danger' },
|
||||
'已退回': { cls: 'waiting', tag: 'danger' },
|
||||
'未执行': { cls: 'pending', tag: 'info' },
|
||||
'执行中': { cls: 'running', tag: 'primary' },
|
||||
'已执行': { cls: 'running', tag: 'primary' },
|
||||
@@ -149,6 +180,14 @@ const STAGE_STYLE = {
|
||||
'待审核': { cls: 'reviewing', tag: 'warning' },
|
||||
'审核通过': { cls: 'done', tag: 'success' },
|
||||
'待结算': { cls: 'done', tag: 'success' },
|
||||
'劳务待审核': { cls: 'reviewing', tag: 'warning' },
|
||||
'会务待审核': { cls: 'reviewing', tag: 'warning' },
|
||||
'劳务审核通过': { cls: 'done', tag: 'success' },
|
||||
'会务审核通过': { cls: 'done', tag: 'success' },
|
||||
'劳务待整改': { cls: 'waiting', tag: 'danger' },
|
||||
'会务待整改': { cls: 'waiting', tag: 'danger' },
|
||||
'劳务待结算': { cls: 'done', tag: 'success' },
|
||||
'会务待结算': { cls: 'done', tag: 'success' },
|
||||
}
|
||||
|
||||
function stageStyle(role, row) {
|
||||
@@ -174,7 +213,7 @@ export const STAGE_OPTIONS = [
|
||||
{ label: '执行中', value: 'IN_PROGRESS' },
|
||||
{ label: '已执行', value: 'RUNNING' },
|
||||
{ label: '待合规审核', value: 'AWAITING_COMPLIANCE' },
|
||||
{ label: '待支持方审核', value: 'AWAITING_SUPERVISION' },
|
||||
{ label: '待支持审核', value: 'AWAITING_SUPERVISION' },
|
||||
{ label: '待整改', value: 'RECTIFYING' },
|
||||
{ label: '待结算', value: 'AWAITING_SETTLEMENT' },
|
||||
{ label: '已完结', value: 'FINISHED' },
|
||||
|
||||
@@ -813,7 +813,11 @@ function fixedNodeStatus(slot) {
|
||||
function nodeDesc(slot) {
|
||||
const s = derivePhysicalStage(row.value)
|
||||
if (slot === 'PRE') return s !== 'NOT_STARTED' && s !== 'FROZEN' ? '已执行' : '待执行'
|
||||
if (slot === 'POST') return s === 'AWAITING_SETTLEMENT' || s === 'SETTLED' || s === 'FINISHED' ? '已结算' : '未结算'
|
||||
if (slot === 'POST') {
|
||||
if (s === 'SETTLED' || s === 'FINISHED') return '已结算'
|
||||
if (s === 'AWAITING_SETTLEMENT') return '补充凭证并结算'
|
||||
return '未结算'
|
||||
}
|
||||
if (slot === 'DONE') return isOne(row.value.isFinished) ? '已完结' : '未完结'
|
||||
return '-'
|
||||
}
|
||||
@@ -877,9 +881,35 @@ async function loadMaterials() {
|
||||
target.fileName = item.fileName || ''
|
||||
}
|
||||
})
|
||||
captureSnapshot()
|
||||
} catch (e) { console.error('[meeting-detail] loadMaterials failed', e) }
|
||||
}
|
||||
|
||||
// ===================== 未保存改动检测 (结算前拦截用) =====================
|
||||
/** 已落库快照 (load 后 + 保存后各刷新一次): 4 组上传行 url + 海报/邀请函 */
|
||||
const savedSnapshot = ref(null)
|
||||
function captureSnapshot() {
|
||||
const urls = new Map()
|
||||
;[...serviceMaterialRows.value, ...laborMaterialRows.value,
|
||||
...laborVoucherRows.value, ...serviceVoucherRows.value]
|
||||
.forEach(r => urls.set(r.subType, (r.url || '').trim()))
|
||||
savedSnapshot.value = {
|
||||
urls,
|
||||
scheduleUrl: scheduleUrl.value || '',
|
||||
invitationUrl: invitationUrl.value || '',
|
||||
}
|
||||
}
|
||||
/** 是否有「已上传但未落库」的改动 (材料/凭证/海报/邀请函) */
|
||||
const hasUnsavedChanges = computed(() => {
|
||||
const s = savedSnapshot.value
|
||||
if (!s) return false
|
||||
if ((scheduleUrl.value || '') !== s.scheduleUrl) return true
|
||||
if ((invitationUrl.value || '') !== s.invitationUrl) return true
|
||||
return [...serviceMaterialRows.value, ...laborMaterialRows.value,
|
||||
...laborVoucherRows.value, ...serviceVoucherRows.value]
|
||||
.some(r => (r.url || '').trim() !== (s.urls.get(r.subType) || ''))
|
||||
})
|
||||
|
||||
// ===================== 参会人 CRUD =====================
|
||||
/** 会议下的参会人列表 (放在 劳务材料 tab 表格) */
|
||||
const attendeeRows = ref([])
|
||||
@@ -1714,6 +1744,7 @@ async function doSave() {
|
||||
if (canUploadVoucher.value) await saveVouchers()
|
||||
// 材料落库 → 会议费用待重算, 刷新状态并轮询到汇总完成
|
||||
refreshFee()
|
||||
captureSnapshot()
|
||||
return ocrCount
|
||||
}
|
||||
|
||||
@@ -1888,6 +1919,27 @@ async function confirmAudit() {
|
||||
|
||||
// ===================== 结算 / 完结 (合规/管理员 手动点击) =====================
|
||||
async function onSettle() {
|
||||
// ① 有「已上传未保存」的改动 → 先保存再结算
|
||||
if (hasUnsavedChanges.value) {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
'检测到尚未保存的上传内容(材料/付款凭证等),是否先保存再结算?',
|
||||
'未保存的改动',
|
||||
{ type: 'warning', confirmButtonText: '保存并结算', cancelButtonText: '取消' }
|
||||
)
|
||||
} catch { return }
|
||||
busy.value.settle = true
|
||||
try {
|
||||
await doSave()
|
||||
} catch (e) {
|
||||
ElMessage.error('保存失败,已取消结算:' + (e?.msg || e?.message || ''))
|
||||
return
|
||||
} finally {
|
||||
busy.value.settle = false
|
||||
}
|
||||
ElMessage.success('已保存')
|
||||
}
|
||||
// ② 结算确认
|
||||
try {
|
||||
await ElMessageBox.confirm('确认结算? 结算前请确保已上传劳务/会务付款凭证。', '结算确认', { type: 'warning' })
|
||||
} catch { return }
|
||||
|
||||
@@ -81,6 +81,8 @@
|
||||
<el-link :underline="false" type="primary" @click="viewOnly(row)">查看</el-link>
|
||||
<el-link :underline="false" v-if="isRole('manager') && isCompliancePending(row)" type="warning" @click="onAudit(row)">审核</el-link>
|
||||
<el-link :underline="false" v-if="isRole('admin', 'manager')" type="primary" @click="viewDetail(row)">编辑材料</el-link>
|
||||
<!-- 结算: 直链 (两轨均审核通过才出现; 与「审核」互斥, 不增加宽度) -->
|
||||
<el-link :underline="false" v-if="isRole('admin', 'manager') && canSettleRow(row)" type="warning" @click="onSettle(row)">结算</el-link>
|
||||
<!-- 更多: admin/manager 视角 ≥7 个次操作折叠 -->
|
||||
<el-dropdown v-if="isRole('admin', 'manager')" trigger="hover" @command="(cmd) => onMoreAction(cmd, row)">
|
||||
<el-link :underline="false" type="primary" class="op-dropdown">
|
||||
@@ -90,7 +92,6 @@
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="edit">修改</el-dropdown-item>
|
||||
<el-dropdown-item command="copy">复制</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canSettleRow(row)" command="settle">结算</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canFinishRow(row)" command="finish">完结</el-dropdown-item>
|
||||
<el-dropdown-item v-if="isOneVal(row.isFrozen)" command="unfreeze">解冻</el-dropdown-item>
|
||||
<el-dropdown-item command="downloadService">会务下载</el-dropdown-item>
|
||||
@@ -101,17 +102,8 @@
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<!-- sponsor 视角: 仅"审核"折叠到下拉 (sponsor 不参与其他次操作) -->
|
||||
<el-dropdown v-if="isRole('sponsor') && isSponsorPending(row)" trigger="hover" @command="(cmd) => onMoreAction(cmd, row)">
|
||||
<el-link :underline="false" type="primary" class="op-dropdown">
|
||||
更多<el-icon class="op-caret"><ArrowDown /></el-icon>
|
||||
</el-link>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="audit">审核</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<!-- sponsor 视角: 审核直链 (支持方审核, 不折叠到更多) -->
|
||||
<el-link :underline="false" v-if="isRole('sponsor') && isSponsorPending(row)" type="warning" @click="onAudit(row)">审核</el-link>
|
||||
</div></template>
|
||||
</el-table-column>
|
||||
</GrTable>
|
||||
@@ -367,8 +359,8 @@ function canSettleRow(row) {
|
||||
return row.laborAuditStage === 'APPROVED' && row.serviceAuditStage === 'APPROVED' && !isOneVal(row.isSettled)
|
||||
}
|
||||
function onSettle(row) {
|
||||
// 结算需要上传付款凭证 (详情页结算 dialog 二合一), 跳详情并自动打开结算 dialog
|
||||
router.push({ path: `${detailBase.value}/detail/${row.meetingId}`, query: { settle: '1' } })
|
||||
// 结算: 跳详情页即可, 不自动弹结算 dialog
|
||||
router.push(`${detailBase.value}/detail/${row.meetingId}`)
|
||||
}
|
||||
// 列表完结按钮显隐: 已结算 且 未完结
|
||||
function canFinishRow(row) {
|
||||
|
||||
Reference in New Issue
Block a user