|
|
|
|
@ -19,10 +19,12 @@
|
|
|
|
|
<!-- 关联流程组件 -->
|
|
|
|
|
<RelatedFlows
|
|
|
|
|
v-model="form.related_flow_ids"
|
|
|
|
|
:meeting-minute-value.sync="form.related_meeting_minute_ids"
|
|
|
|
|
:readonly="/\/detail/.test($route.path) || (!!$route.query.flow_id && !isFirstNode)"
|
|
|
|
|
:flow-id="$route.query.flow_id"
|
|
|
|
|
:collapsible="(!/\/detail/.test($route.path)) && (!$route.query.flow_id || isFirstNode)"
|
|
|
|
|
style="margin-bottom: 20px;"
|
|
|
|
|
@open-meeting-minute="openMeetingMinutesDrawer"
|
|
|
|
|
></RelatedFlows>
|
|
|
|
|
|
|
|
|
|
<!-- 关联的支付信息(查看/办理:只要有 flow_id 就展示,没数据时展示空态) -->
|
|
|
|
|
@ -136,16 +138,20 @@
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 会议纪要:点击抽屉查看 -->
|
|
|
|
|
<!-- 会议纪要:点击抽屉查看(一对多,多条链接) -->
|
|
|
|
|
<div v-else-if="el.type === 'meeting_minutes'">
|
|
|
|
|
<el-link
|
|
|
|
|
v-if="extractMeetingMinuteId(getPaymentTemplateElementValue(el, payment))"
|
|
|
|
|
type="primary"
|
|
|
|
|
:underline="false"
|
|
|
|
|
@click="openMeetingMinutesDrawer(extractMeetingMinuteId(getPaymentTemplateElementValue(el, payment)))"
|
|
|
|
|
>
|
|
|
|
|
{{ (getPaymentTemplateElementValue(el, payment) && getPaymentTemplateElementValue(el, payment).title) ? getPaymentTemplateElementValue(el, payment).title : '查看会议纪要' }}
|
|
|
|
|
</el-link>
|
|
|
|
|
<template v-if="getPaymentMeetingMinutesList(el, payment).length">
|
|
|
|
|
<span v-for="(item, idx) in getPaymentMeetingMinutesList(el, payment)" :key="item.id">
|
|
|
|
|
<el-link
|
|
|
|
|
type="primary"
|
|
|
|
|
:underline="false"
|
|
|
|
|
@click="openMeetingMinutesDrawer(item.id)"
|
|
|
|
|
>
|
|
|
|
|
{{ item.title || '查看会议纪要' }}
|
|
|
|
|
</el-link>
|
|
|
|
|
<span v-if="idx < getPaymentMeetingMinutesList(el, payment).length - 1">、</span>
|
|
|
|
|
</span>
|
|
|
|
|
</template>
|
|
|
|
|
<span v-else>-</span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
@ -305,16 +311,20 @@
|
|
|
|
|
<span v-if="getPlannedFileItems(expId, f).length === 0">-</span>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- meeting_minutes:点击抽屉查看 -->
|
|
|
|
|
<!-- meeting_minutes:点击抽屉查看(一对多,多条链接) -->
|
|
|
|
|
<template v-else-if="f.element_type === 'meeting_minutes'">
|
|
|
|
|
<el-link
|
|
|
|
|
v-if="extractMeetingMinuteId(getIndirectFieldValue(expId, getTplFieldKey(f)))"
|
|
|
|
|
type="primary"
|
|
|
|
|
:underline="false"
|
|
|
|
|
@click="openMeetingMinutesDrawer(extractMeetingMinuteId(getIndirectFieldValue(expId, getTplFieldKey(f))))"
|
|
|
|
|
>
|
|
|
|
|
查看会议纪要
|
|
|
|
|
</el-link>
|
|
|
|
|
<template v-if="getIndirectMeetingMinutesList(expId, getTplFieldKey(f)).length">
|
|
|
|
|
<span v-for="(item, idx) in getIndirectMeetingMinutesList(expId, getTplFieldKey(f))" :key="item.id">
|
|
|
|
|
<el-link
|
|
|
|
|
type="primary"
|
|
|
|
|
:underline="false"
|
|
|
|
|
@click="openMeetingMinutesDrawer(item.id)"
|
|
|
|
|
>
|
|
|
|
|
{{ item.title || '查看会议纪要' }}
|
|
|
|
|
</el-link>
|
|
|
|
|
<span v-if="idx < getIndirectMeetingMinutesList(expId, getTplFieldKey(f)).length - 1">、</span>
|
|
|
|
|
</span>
|
|
|
|
|
</template>
|
|
|
|
|
<span v-else>-</span>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
@ -392,7 +402,24 @@
|
|
|
|
|
<!-- 合同基本信息 -->
|
|
|
|
|
<el-descriptions v-if="contractDetail" :column="2" border size="small" style="margin-bottom: 12px;">
|
|
|
|
|
<el-descriptions-item label="合同编号">
|
|
|
|
|
{{ contractDetail.contract_no || '-' }}
|
|
|
|
|
<template v-if="contractDetail.id">
|
|
|
|
|
<el-link
|
|
|
|
|
type="primary"
|
|
|
|
|
:underline="false"
|
|
|
|
|
@click="openContractDrawer(contractDetail.id, contractDetail.title || contractDetail.contract_no)"
|
|
|
|
|
>
|
|
|
|
|
{{ contractDetail.contract_no || '-' }}
|
|
|
|
|
</el-link>
|
|
|
|
|
<el-link
|
|
|
|
|
type="primary"
|
|
|
|
|
:underline="false"
|
|
|
|
|
style="margin-left: 8px;"
|
|
|
|
|
@click="openContractDrawer(contractDetail.id, contractDetail.title || contractDetail.contract_no)"
|
|
|
|
|
>
|
|
|
|
|
查看详情
|
|
|
|
|
</el-link>
|
|
|
|
|
</template>
|
|
|
|
|
<span v-else>{{ contractDetail.contract_no || '-' }}</span>
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="合同名称">
|
|
|
|
|
{{ contractDetail.title || '-' }}
|
|
|
|
|
@ -770,8 +797,9 @@
|
|
|
|
|
:visible.sync="rightDrawerVisible"
|
|
|
|
|
:title="rightDrawerTitle"
|
|
|
|
|
direction="rtl"
|
|
|
|
|
size="60%"
|
|
|
|
|
:size="$store.getters.device === 'mobile' ? '100%' : (rightDrawerType === 'contract' ? '78%' : '60%')"
|
|
|
|
|
:with-header="true"
|
|
|
|
|
custom-class="flow-detail-drawer"
|
|
|
|
|
>
|
|
|
|
|
<!-- 流程详情:iframe -->
|
|
|
|
|
<div v-if="rightDrawerType === 'flow'" style="width: 100%; height: 100%;">
|
|
|
|
|
@ -782,33 +810,196 @@
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 会议纪要:请求数据展示 -->
|
|
|
|
|
<!-- 会议纪要:请求数据展示(与会议纪要管理查看模式字段、顺序一致) -->
|
|
|
|
|
<div v-else-if="rightDrawerType === 'meetingMinutes'" v-loading="loadingMeetingMinutes">
|
|
|
|
|
<div v-if="meetingMinutesDetail">
|
|
|
|
|
<el-descriptions :column="1" border>
|
|
|
|
|
<el-descriptions-item label="标题">
|
|
|
|
|
{{ meetingMinutesDetail.title || '-' }}
|
|
|
|
|
<el-descriptions-item label="会议纪要标题">
|
|
|
|
|
<span style="font-weight: 500;">{{ meetingMinutesDetail.title || '-' }}</span>
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="内容清单">
|
|
|
|
|
<div v-if="meetingMinutesDetail.items && meetingMinutesDetail.items.length">
|
|
|
|
|
<div v-for="(it, idx) in meetingMinutesDetail.items" :key="idx" style="margin-bottom: 8px;">
|
|
|
|
|
<span style="color:#409EFF;">{{ it.type || '类型' }}:</span>
|
|
|
|
|
<span>{{ it.content || '-' }}</span>
|
|
|
|
|
<el-descriptions-item label="关联上会审议流程">
|
|
|
|
|
<div v-if="meetingMinutesDetail.flows && meetingMinutesDetail.flows.length">
|
|
|
|
|
<el-tag
|
|
|
|
|
v-for="flow in meetingMinutesDetail.flows"
|
|
|
|
|
:key="flow.id"
|
|
|
|
|
type="info"
|
|
|
|
|
style="margin-right: 8px; margin-bottom: 4px;"
|
|
|
|
|
>
|
|
|
|
|
{{ flow.title || flow.no || ('流程' + flow.id) }}
|
|
|
|
|
<span v-if="flow.no" style="color: #909399; margin-left: 4px;">({{ flow.no }})</span>
|
|
|
|
|
</el-tag>
|
|
|
|
|
</div>
|
|
|
|
|
<span v-else style="color: #909399;">未关联</span>
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="附件">
|
|
|
|
|
<div v-if="meetingMinutesDetail.files_details && meetingMinutesDetail.files_details.length">
|
|
|
|
|
<div v-for="(f, idx) in meetingMinutesDetail.files_details" :key="idx" style="margin-bottom: 8px;">
|
|
|
|
|
<el-link type="primary" :underline="false" :href="f.url" target="_blank" style="margin-right: 10px;">
|
|
|
|
|
<i class="el-icon-view"></i> {{ f.original_name || f.name || '附件' }}
|
|
|
|
|
</el-link>
|
|
|
|
|
<el-link type="primary" :underline="false" :href="f.url" target="_blank" download>
|
|
|
|
|
<i class="el-icon-download"></i> 下载
|
|
|
|
|
</el-link>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<span v-else>无</span>
|
|
|
|
|
<span v-else style="color: #909399;">无附件</span>
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="附件" v-if="meetingMinutesDetail.files_details && meetingMinutesDetail.files_details.length">
|
|
|
|
|
<div v-for="(f, idx) in meetingMinutesDetail.files_details" :key="idx" style="margin-bottom: 6px;">
|
|
|
|
|
<el-link type="primary" :underline="false" :href="f.url" target="_blank">
|
|
|
|
|
{{ f.original_name || f.name || '附件' }}
|
|
|
|
|
</el-link>
|
|
|
|
|
<el-descriptions-item label="内容清单">
|
|
|
|
|
<div v-if="meetingMinutesDetail.items && meetingMinutesDetail.items.length">
|
|
|
|
|
<div
|
|
|
|
|
v-for="(it, idx) in meetingMinutesDetail.items"
|
|
|
|
|
:key="idx"
|
|
|
|
|
style="margin-bottom: 12px; padding: 12px; background-color: #f5f7fa; border-radius: 4px;"
|
|
|
|
|
>
|
|
|
|
|
<div style="margin-bottom: 4px;">
|
|
|
|
|
<el-tag size="small" type="primary">{{ it.type || '未分类' }}</el-tag>
|
|
|
|
|
</div>
|
|
|
|
|
<div style="color: #606266; line-height: 1.6;">{{ it.content || '-' }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<span v-else style="color: #909399;">无内容清单</span>
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
</el-descriptions>
|
|
|
|
|
</div>
|
|
|
|
|
<div v-else style="color:#909399;">未获取到会议纪要数据</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 合同详情:请求数据展示 -->
|
|
|
|
|
<div v-else-if="rightDrawerType === 'contract'" v-loading="loadingContractDrawer">
|
|
|
|
|
<div v-if="contractDrawerDetail">
|
|
|
|
|
<div class="contract-drawer">
|
|
|
|
|
<el-descriptions :column="2" border class="contract-drawer-descriptions">
|
|
|
|
|
<el-descriptions-item label="合同编号">
|
|
|
|
|
{{ contractDrawerDetail.contract_no || '-' }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="合同名称">
|
|
|
|
|
{{ contractDrawerDetail.title || '-' }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="合同主要内容" :span="2">
|
|
|
|
|
{{ contractDrawerDetail.main_content || '-' }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="甲方">
|
|
|
|
|
{{ contractDrawerDetail.party_a || '-' }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="乙方">
|
|
|
|
|
{{ contractDrawerDetail.party_b || '-' }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="合同金额(元)">
|
|
|
|
|
{{ formatAmount(contractDrawerDetail.amount_total) }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="项目预算金额(元)">
|
|
|
|
|
{{ formatAmount(contractDrawerDetail.budget_amount) }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="金额类型">
|
|
|
|
|
<el-tag v-if="contractDrawerDetail.amount_type === 'fixed'" type="success" size="small">闭口合同</el-tag>
|
|
|
|
|
<el-tag v-else-if="contractDrawerDetail.amount_type === 'open'" type="warning" size="small">开口合同</el-tag>
|
|
|
|
|
<span v-else>-</span>
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="金额说明" v-if="contractDrawerDetail.amount_type === 'open'">
|
|
|
|
|
{{ contractDrawerDetail.amount_description || '-' }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="签订日期">
|
|
|
|
|
{{ formatDate(contractDrawerDetail.sign_date) || '-' }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="申请日期">
|
|
|
|
|
{{ formatDate(contractDrawerDetail.apply_date) || '-' }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="合同履行期">
|
|
|
|
|
{{ contractDrawerDetail.perform_period || '-' }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="付款方式">
|
|
|
|
|
{{ contractDrawerDetail.pay_method || '-' }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="预算年度">
|
|
|
|
|
{{ getContractBudgetYear(contractDrawerDetail) }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="计划资金来源" :span="2">
|
|
|
|
|
{{ getContractPlanFundSource(contractDrawerDetail) }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="实际资金来源" :span="2">
|
|
|
|
|
{{ formatArrayText(contractDrawerDetail.actual_fund_sources) }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="合同类型">
|
|
|
|
|
{{ (contractDrawerDetail.contractType && contractDrawerDetail.contractType.name) || '-' }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="采购类别">
|
|
|
|
|
{{ (contractDrawerDetail.purchaseCategory && contractDrawerDetail.purchaseCategory.name) || '-' }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="采购方式">
|
|
|
|
|
{{ getContractPurchaseMethod(contractDrawerDetail) }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="是否政府采购">
|
|
|
|
|
<el-tag v-if="contractDrawerDetail.is_government_purchase" type="success" size="small">是</el-tag>
|
|
|
|
|
<el-tag v-else type="info" size="small">否</el-tag>
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="招标代理">
|
|
|
|
|
{{ contractDrawerDetail.tender_agent || '-' }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="合同履行情况">
|
|
|
|
|
{{ contractDrawerDetail.perform_status || '-' }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="是否验收">
|
|
|
|
|
<el-tag v-if="contractDrawerDetail.is_accepted" type="success" size="small">是</el-tag>
|
|
|
|
|
<el-tag v-else type="info" size="small">否</el-tag>
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="科室">
|
|
|
|
|
{{ formatDepartmentNames(contractDrawerDetail.owner_department_ids || contractDrawerDetail.owner_department_id) }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="合同签订/变更经办人">
|
|
|
|
|
{{ formatUserNames(contractDrawerDetail.handler_admin_ids) }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="申请科室经办人">
|
|
|
|
|
{{ formatUserNames(contractDrawerDetail.apply_handler_id) }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="采购科室经办人">
|
|
|
|
|
{{ formatUserNames(contractDrawerDetail.purchase_handler_id) }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="已发起付款">
|
|
|
|
|
<span style="font-weight: 600;">
|
|
|
|
|
<span style="color: #409eff;">{{ (contractDrawerDetail.payment_stats && contractDrawerDetail.payment_stats.payment_count) || 0 }} 次</span>
|
|
|
|
|
<span style="color: #67c23a; margin-left: 8px;">{{ formatAmount((contractDrawerDetail.payment_stats && contractDrawerDetail.payment_stats.paid_amount) || 0) }}</span>
|
|
|
|
|
</span>
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="备注" :span="2">
|
|
|
|
|
{{ contractDrawerDetail.remark || '-' }}
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="附件" :span="2">
|
|
|
|
|
<template v-if="getContractAttachmentUrl(contractDrawerDetail)">
|
|
|
|
|
<el-link
|
|
|
|
|
type="primary"
|
|
|
|
|
:underline="false"
|
|
|
|
|
:href="getContractAttachmentUrl(contractDrawerDetail)"
|
|
|
|
|
target="_blank"
|
|
|
|
|
>
|
|
|
|
|
{{ (contractDrawerDetail.attachment && contractDrawerDetail.attachment.original_name) || (contractDrawerDetail.attachment && contractDrawerDetail.attachment.name) || '查看附件' }}
|
|
|
|
|
</el-link>
|
|
|
|
|
</template>
|
|
|
|
|
<span v-else>-</span>
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
</el-descriptions>
|
|
|
|
|
|
|
|
|
|
<el-divider content-position="left">付款计划</el-divider>
|
|
|
|
|
<el-table :data="contractDrawerDetail.pay_plans || []" border size="small" style="width: 100%;">
|
|
|
|
|
<el-table-column prop="phase_no" label="期次" width="100" />
|
|
|
|
|
<el-table-column label="计划付款日" width="150">
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
{{ formatDate(scope.row.due_date) || '-' }}
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="计划金额" min-width="160" align="right">
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
<span style="color: #F56C6C; font-weight: bold;">¥{{ formatAmount(scope.row.amount_plan) }}</span>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
</el-table>
|
|
|
|
|
|
|
|
|
|
<div v-if="!(contractDrawerDetail.pay_plans && contractDrawerDetail.pay_plans.length)" class="contract-empty-tip">
|
|
|
|
|
暂无付款计划
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div v-else style="color:#909399;">未获取到合同详情</div>
|
|
|
|
|
</div>
|
|
|
|
|
</el-drawer>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
@ -928,6 +1119,8 @@ export default {
|
|
|
|
|
rightDrawerUrl: '',
|
|
|
|
|
meetingMinutesDetail: null,
|
|
|
|
|
loadingMeetingMinutes: false,
|
|
|
|
|
contractDrawerDetail: null,
|
|
|
|
|
loadingContractDrawer: false,
|
|
|
|
|
// fill_flow_title 自动填充:专用 watcher(避免 deep watcher oldVal/newVal 引用问题)
|
|
|
|
|
_unwatchFillFlowTitle: null,
|
|
|
|
|
};
|
|
|
|
|
@ -962,12 +1155,9 @@ export default {
|
|
|
|
|
return this.getOaCustomModelBindings(expenditureId, field).length > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// meeting_minutes 类型:仅当有会议纪要ID时才显示
|
|
|
|
|
// meeting_minutes 类型:有至少一条会议纪要时显示(一对多)
|
|
|
|
|
if (field.element_type === 'meeting_minutes') {
|
|
|
|
|
const meetingMinuteId = this.extractMeetingMinuteId(
|
|
|
|
|
this.getIndirectFieldValue(expenditureId, this.getTplFieldKey(field))
|
|
|
|
|
);
|
|
|
|
|
return meetingMinuteId !== null && meetingMinuteId !== undefined;
|
|
|
|
|
return this.getIndirectMeetingMinutesList(expenditureId, this.getTplFieldKey(field)).length > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// attachment/file 类型:仅当有文件项时才显示
|
|
|
|
|
@ -1049,6 +1239,9 @@ export default {
|
|
|
|
|
if (el.type === 'form_element' && el.field_type === 'attachment') {
|
|
|
|
|
return Array.isArray(val) && val.length > 0;
|
|
|
|
|
}
|
|
|
|
|
if (el.type === 'meeting_minutes') {
|
|
|
|
|
return this.normalizeMeetingMinutesValue(val).length > 0;
|
|
|
|
|
}
|
|
|
|
|
return !this.isEmptyValue(val);
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
@ -1434,6 +1627,9 @@ export default {
|
|
|
|
|
if (!object.hasOwnProperty('related_flow_ids')) {
|
|
|
|
|
object['related_flow_ids'] = '';
|
|
|
|
|
}
|
|
|
|
|
if (!object.hasOwnProperty('related_meeting_minute_ids')) {
|
|
|
|
|
object['related_meeting_minute_ids'] = '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 查找 fill_flow_title=1 的字段
|
|
|
|
|
const fillFlowTitleField = (fields || []).find(f =>
|
|
|
|
|
@ -1487,6 +1683,80 @@ export default {
|
|
|
|
|
if (!date) return '';
|
|
|
|
|
return this.$moment(date).format('YYYY-MM-DD');
|
|
|
|
|
},
|
|
|
|
|
formatArrayText(val) {
|
|
|
|
|
if (!val) return '-';
|
|
|
|
|
if (Array.isArray(val)) {
|
|
|
|
|
const arr = val.map(item => (item === null || item === undefined ? '' : String(item).trim())).filter(Boolean);
|
|
|
|
|
return arr.length ? arr.join(' | ') : '-';
|
|
|
|
|
}
|
|
|
|
|
if (typeof val === 'string') {
|
|
|
|
|
const s = val.trim();
|
|
|
|
|
return s || '-';
|
|
|
|
|
}
|
|
|
|
|
return String(val);
|
|
|
|
|
},
|
|
|
|
|
parseIdList(val) {
|
|
|
|
|
if (val === null || val === undefined || val === '') return [];
|
|
|
|
|
if (Array.isArray(val)) {
|
|
|
|
|
return val
|
|
|
|
|
.map(item => {
|
|
|
|
|
if (item && typeof item === 'object') return item.id || item.value || item.user_id || item.department_id || null;
|
|
|
|
|
return item;
|
|
|
|
|
})
|
|
|
|
|
.filter(item => item !== null && item !== undefined && item !== '');
|
|
|
|
|
}
|
|
|
|
|
if (typeof val === 'number') return [val];
|
|
|
|
|
if (typeof val === 'string') {
|
|
|
|
|
return val
|
|
|
|
|
.split(',')
|
|
|
|
|
.map(item => item.trim())
|
|
|
|
|
.filter(Boolean);
|
|
|
|
|
}
|
|
|
|
|
if (typeof val === 'object') {
|
|
|
|
|
const id = val.id || val.value || val.user_id || val.department_id;
|
|
|
|
|
return id ? [id] : [];
|
|
|
|
|
}
|
|
|
|
|
return [];
|
|
|
|
|
},
|
|
|
|
|
formatDepartmentNames(val) {
|
|
|
|
|
const ids = this.parseIdList(val);
|
|
|
|
|
if (!ids.length) return '-';
|
|
|
|
|
return ids
|
|
|
|
|
.map(id => this.simpleDepartmentMap?.[id] || this.simpleDepartmentMap?.[Number(id)] || `部门ID: ${id}`)
|
|
|
|
|
.join('、');
|
|
|
|
|
},
|
|
|
|
|
formatUserNames(val) {
|
|
|
|
|
const ids = this.parseIdList(val);
|
|
|
|
|
if (!ids.length) return '-';
|
|
|
|
|
return ids
|
|
|
|
|
.map(id => this.simpleUserMap?.[id] || this.simpleUserMap?.[Number(id)] || `用户ID: ${id}`)
|
|
|
|
|
.join('、');
|
|
|
|
|
},
|
|
|
|
|
getContractBudgetYear(detail) {
|
|
|
|
|
const year = detail?.fund_source_year?.year || detail?.fundSourceYear?.year || detail?.fund_source_budget_data?.budget_year?.year || detail?.fundSourceBudgetData?.budget_year?.year;
|
|
|
|
|
return year ? `${year}年` : '-';
|
|
|
|
|
},
|
|
|
|
|
getContractPlanFundSource(detail) {
|
|
|
|
|
return detail?.fund_source_budget_data?.name || detail?.fundSourceBudgetData?.name || detail?.fund_source || '-';
|
|
|
|
|
},
|
|
|
|
|
getContractPurchaseMethod(detail) {
|
|
|
|
|
const relationValue = detail && detail.purchaseMethod;
|
|
|
|
|
if (relationValue && typeof relationValue === 'object') {
|
|
|
|
|
return relationValue.name || relationValue.label || relationValue.title || '-';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const rawValue = detail && detail.purchase_method;
|
|
|
|
|
if (!rawValue) return '-';
|
|
|
|
|
if (typeof rawValue === 'string') return rawValue;
|
|
|
|
|
if (typeof rawValue === 'object') {
|
|
|
|
|
return rawValue.name || rawValue.label || rawValue.title || rawValue.text || '-';
|
|
|
|
|
}
|
|
|
|
|
return String(rawValue);
|
|
|
|
|
},
|
|
|
|
|
getContractAttachmentUrl(detail) {
|
|
|
|
|
const att = detail?.attachment;
|
|
|
|
|
return att?.url || att?.path || att?.file_url || att?.download_url || att?.preview_url || '';
|
|
|
|
|
},
|
|
|
|
|
// 格式化日期时间
|
|
|
|
|
formatDateTime(dateTime) {
|
|
|
|
|
if (!dateTime) return '';
|
|
|
|
|
@ -1894,6 +2164,33 @@ export default {
|
|
|
|
|
return null;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/** 将会议纪要值归一化为 [{ id, title }, ...],兼容单条与多条 */
|
|
|
|
|
normalizeMeetingMinutesValue(val) {
|
|
|
|
|
if (val === null || val === undefined) return [];
|
|
|
|
|
if (Array.isArray(val)) {
|
|
|
|
|
return val
|
|
|
|
|
.map((item) => {
|
|
|
|
|
const id = this.extractMeetingMinuteId(item);
|
|
|
|
|
if (!id) return null;
|
|
|
|
|
const title = (item && typeof item === 'object' && item.title) ? item.title : '';
|
|
|
|
|
return { id, title };
|
|
|
|
|
})
|
|
|
|
|
.filter(Boolean);
|
|
|
|
|
}
|
|
|
|
|
const id = this.extractMeetingMinuteId(val);
|
|
|
|
|
if (!id) return [];
|
|
|
|
|
const title = (val && typeof val === 'object' && val.title) ? val.title : '';
|
|
|
|
|
return [{ id, title }];
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getPaymentMeetingMinutesList(el, payment) {
|
|
|
|
|
return this.normalizeMeetingMinutesValue(this.getPaymentTemplateElementValue(el, payment));
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getIndirectMeetingMinutesList(expenditureId, fieldKey) {
|
|
|
|
|
return this.normalizeMeetingMinutesValue(this.getIndirectFieldValue(expenditureId, fieldKey));
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
async openFlowDrawer({ flowId, customModelId, title }) {
|
|
|
|
|
const fid = Number(flowId);
|
|
|
|
|
if (!fid || Number.isNaN(fid)) return;
|
|
|
|
|
@ -1930,11 +2227,12 @@ export default {
|
|
|
|
|
this.rightDrawerTitle = '查看会议纪要';
|
|
|
|
|
this.rightDrawerUrl = '';
|
|
|
|
|
this.meetingMinutesDetail = null;
|
|
|
|
|
this.contractDrawerDetail = null;
|
|
|
|
|
this.rightDrawerVisible = true;
|
|
|
|
|
this.loadingMeetingMinutes = true;
|
|
|
|
|
try {
|
|
|
|
|
// meetingMinutesShow 成功时返回 res.data
|
|
|
|
|
const detail = await meetingMinutesShow({ id: meetingMinuteId });
|
|
|
|
|
const detail = await meetingMinutesShow({ id: meetingMinuteId, show_relation: ['flows', 'items'] });
|
|
|
|
|
this.meetingMinutesDetail = detail || null;
|
|
|
|
|
this.rightDrawerTitle = detail?.title || '查看会议纪要';
|
|
|
|
|
} catch (e) {
|
|
|
|
|
@ -1945,6 +2243,33 @@ export default {
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
async openContractDrawer(contractId, title = '') {
|
|
|
|
|
const cid = Number(contractId);
|
|
|
|
|
if (!cid || Number.isNaN(cid)) return;
|
|
|
|
|
|
|
|
|
|
this.rightDrawerType = 'contract';
|
|
|
|
|
this.rightDrawerTitle = title || '查看合同详情';
|
|
|
|
|
this.rightDrawerUrl = '';
|
|
|
|
|
this.meetingMinutesDetail = null;
|
|
|
|
|
this.contractDrawerDetail = null;
|
|
|
|
|
this.rightDrawerVisible = true;
|
|
|
|
|
this.loadingContractDrawer = true;
|
|
|
|
|
try {
|
|
|
|
|
const [detail] = await Promise.all([
|
|
|
|
|
getBudgetContractDetail(cid),
|
|
|
|
|
this.loadSimpleDepartmentMap(),
|
|
|
|
|
this.loadSimpleUserMap(),
|
|
|
|
|
]);
|
|
|
|
|
this.contractDrawerDetail = detail || null;
|
|
|
|
|
this.rightDrawerTitle = detail?.title || detail?.contract_no || title || '查看合同详情';
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error('加载合同详情失败:', e);
|
|
|
|
|
this.contractDrawerDetail = null;
|
|
|
|
|
} finally {
|
|
|
|
|
this.loadingContractDrawer = false;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 通用只读展示
|
|
|
|
|
formatReadonlyValue(val) {
|
|
|
|
|
if (val === undefined || val === null || val === '') return '-';
|
|
|
|
|
@ -1956,25 +2281,30 @@ export default {
|
|
|
|
|
// 加载关联的支付信息
|
|
|
|
|
async loadRelatedPayments() {
|
|
|
|
|
if (!this.$route.query.flow_id) {
|
|
|
|
|
return;
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.loadingPayments = true;
|
|
|
|
|
try {
|
|
|
|
|
// request.js 成功时会直接返回 res.data(也就是 payment 对象或 null)
|
|
|
|
|
const payment = await getPaymentsByFlowId(this.$route.query.flow_id, { all: true });
|
|
|
|
|
// 接口约定:要么无数据(null),要么唯一的一条记录
|
|
|
|
|
if (payment) {
|
|
|
|
|
// request.js 成功时会直接返回 res.data;兼容旧接口单对象和新接口数组。
|
|
|
|
|
const result = await getPaymentsByFlowId(this.$route.query.flow_id, { all: true })
|
|
|
|
|
const payments = Array.isArray(result) ? result : (result ? [result] : [])
|
|
|
|
|
if (payments.length > 0) {
|
|
|
|
|
// 兼容 breadcrumb 为字符串或数组
|
|
|
|
|
if (payment.payment_type_info && payment.payment_type_info.breadcrumb) {
|
|
|
|
|
const bc = payment.payment_type_info.breadcrumb;
|
|
|
|
|
payments.forEach((payment) => {
|
|
|
|
|
if (!payment.payment_type_info || !payment.payment_type_info.breadcrumb) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
const bc = payment.payment_type_info.breadcrumb
|
|
|
|
|
if (Array.isArray(bc)) {
|
|
|
|
|
payment.payment_type_info.breadcrumb = bc;
|
|
|
|
|
payment.payment_type_info.breadcrumb = bc
|
|
|
|
|
} else if (typeof bc === 'string') {
|
|
|
|
|
payment.payment_type_info.breadcrumb = bc.split(/\s*>\s*|\s*\/\s*/).filter(Boolean);
|
|
|
|
|
payment.payment_type_info.breadcrumb = bc.split(/\s*>\s*|\s*\/\s*/).filter(Boolean)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
this.relatedPayments = [payment];
|
|
|
|
|
})
|
|
|
|
|
this.relatedPayments = payments
|
|
|
|
|
|
|
|
|
|
const payment = payments[0]
|
|
|
|
|
|
|
|
|
|
// 支付模板元素(用于展示 fields)
|
|
|
|
|
await this.loadPaymentTemplateElements(payment);
|
|
|
|
|
@ -2124,6 +2454,10 @@ export default {
|
|
|
|
|
const relatedIds = res.flow.related_flows.map(f => f.id).join(',');
|
|
|
|
|
this.form.related_flow_ids = relatedIds;
|
|
|
|
|
}
|
|
|
|
|
if (res?.flow?.related_meeting_minutes && res.flow.related_meeting_minutes.length > 0) {
|
|
|
|
|
const relatedMeetingMinuteIds = res.flow.related_meeting_minutes.map(item => item.id).join(',');
|
|
|
|
|
this.form.related_meeting_minute_ids = relatedMeetingMinuteIds;
|
|
|
|
|
}
|
|
|
|
|
// form赋值
|
|
|
|
|
const { data } = res?.flow;
|
|
|
|
|
for (let key in data) {
|
|
|
|
|
@ -2246,6 +2580,10 @@ export default {
|
|
|
|
|
const relatedIds = res.flow.related_flows.map(f => f.id).join(',');
|
|
|
|
|
this.form.related_flow_ids = relatedIds;
|
|
|
|
|
}
|
|
|
|
|
if (res?.flow?.related_meeting_minutes && res.flow.related_meeting_minutes.length > 0) {
|
|
|
|
|
const relatedMeetingMinuteIds = res.flow.related_meeting_minutes.map(item => item.id).join(',');
|
|
|
|
|
this.form.related_meeting_minute_ids = relatedMeetingMinuteIds;
|
|
|
|
|
}
|
|
|
|
|
this.handleDefaultJSON();
|
|
|
|
|
const { data } = res?.flow;
|
|
|
|
|
for (let key in data) {
|
|
|
|
|
@ -2353,7 +2691,7 @@ export default {
|
|
|
|
|
let myField = this.fields.find(i => i.name === key)
|
|
|
|
|
|
|
|
|
|
// 保留关联流程ID字段,即使它不在writeableFields中
|
|
|
|
|
if (key === 'related_flow_ids') {
|
|
|
|
|
if (key === 'related_flow_ids' || key === 'related_meeting_minute_ids') {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -2382,8 +2720,10 @@ export default {
|
|
|
|
|
// 确保 related_flow_ids 被包含在提交数据中
|
|
|
|
|
// 无论是否有值,都要传递这个字段,以便后端能正确处理
|
|
|
|
|
copyForm.related_flow_ids = this.form.related_flow_ids || ''
|
|
|
|
|
copyForm.related_meeting_minute_ids = this.form.related_meeting_minute_ids || ''
|
|
|
|
|
console.log("copyForm",copyForm,this.$refs["desktopForm"].form)
|
|
|
|
|
console.log("related_flow_ids:", copyForm.related_flow_ids, "form.related_flow_ids:", this.form.related_flow_ids)
|
|
|
|
|
console.log("related_meeting_minute_ids:", copyForm.related_meeting_minute_ids, "form.related_meeting_minute_ids:", this.form.related_meeting_minute_ids)
|
|
|
|
|
// return
|
|
|
|
|
if (this.$route.query.flow_id) {
|
|
|
|
|
copyForm.id = this.$route.query.flow_id;
|
|
|
|
|
@ -2750,6 +3090,38 @@ export default {
|
|
|
|
|
word-break: break-word;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.contract-drawer {
|
|
|
|
|
padding: 20px 24px 28px;
|
|
|
|
|
}
|
|
|
|
|
.contract-drawer-descriptions {
|
|
|
|
|
::v-deep .el-descriptions__table {
|
|
|
|
|
width: 100%;
|
|
|
|
|
table-layout: fixed;
|
|
|
|
|
}
|
|
|
|
|
::v-deep .el-descriptions-item__label {
|
|
|
|
|
width: 160px;
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
}
|
|
|
|
|
::v-deep .el-descriptions-item__content {
|
|
|
|
|
word-break: break-word;
|
|
|
|
|
line-height: 1.7;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.contract-empty-tip {
|
|
|
|
|
padding: 18px 4px 8px;
|
|
|
|
|
color: #909399;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
::v-deep .flow-detail-drawer > .el-drawer__header {
|
|
|
|
|
margin-bottom: 0;
|
|
|
|
|
padding: 20px 24px 16px;
|
|
|
|
|
border-bottom: 1px solid #ebeef5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
::v-deep .flow-detail-drawer > .el-drawer__body {
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
<style lang="scss">
|
|
|
|
|
.log-table-scroll {
|
|
|
|
|
|