|
|
|
|
|
<template>
|
|
|
|
|
|
<div class="travel-meeting-container">
|
|
|
|
|
|
<!-- 差旅费预算明细表 -->
|
|
|
|
|
|
<el-card class="mb-6">
|
|
|
|
|
|
<div class="flex items-center justify-between mb-4">
|
|
|
|
|
|
<h3 class="text-lg font-medium">差旅费预算明细表</h3>
|
|
|
|
|
|
<div class="flex gap-2 items-center">
|
|
|
|
|
|
<span class="mr-2">行数:</span>
|
|
|
|
|
|
<el-input-number
|
|
|
|
|
|
v-model="travelAddRowCount"
|
|
|
|
|
|
:min="1"
|
|
|
|
|
|
:max="10"
|
|
|
|
|
|
:step="1"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
style="width: 100px"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<el-button type="primary" @click="confirmTravelAdd" size="small">
|
|
|
|
|
|
<el-icon><Plus /></el-icon>
|
|
|
|
|
|
添加
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
<el-button @click="deleteSelectedTravel" size="small" :disabled="selectedTravelRows.length === 0">
|
|
|
|
|
|
<el-icon><Delete /></el-icon>
|
|
|
|
|
|
删除
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<el-table
|
|
|
|
|
|
v-loading="loading"
|
|
|
|
|
|
:data="travelList"
|
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
|
border
|
|
|
|
|
|
@selection-change="handleTravelSelectionChange"
|
|
|
|
|
|
show-summary
|
|
|
|
|
|
:summary-method="() => {
|
|
|
|
|
|
return [
|
|
|
|
|
|
'合计', '', '', '', '', '', '', '',
|
|
|
|
|
|
travelTransportTotal.toString(),
|
|
|
|
|
|
travelAccommodationTotal.toString(),
|
|
|
|
|
|
travelSubsidyTotal.toString(),
|
|
|
|
|
|
travelSubtotalTotal.toFixed(2), ''
|
|
|
|
|
|
]
|
|
|
|
|
|
}"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-table-column type="selection" width="55" />
|
|
|
|
|
|
<el-table-column prop="id" label="序号" type="index" width="80" />
|
|
|
|
|
|
<el-table-column prop="location" label="出差地点" width="150">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="scope.row.location"
|
|
|
|
|
|
placeholder="请输入出差地点"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="reason" label="事由" width="200">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="scope.row.reason"
|
|
|
|
|
|
type="textarea"
|
|
|
|
|
|
placeholder="请输入事由"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
:rows="2"
|
|
|
|
|
|
resize="vertical"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="times" label="次数" width="100">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input-number
|
|
|
|
|
|
v-model="scope.row.times"
|
|
|
|
|
|
:min="1"
|
|
|
|
|
|
:step="1"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@change="calculateTravelSubtotal"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="personCount" label="人数" width="100">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input-number
|
|
|
|
|
|
v-model="scope.row.personCount"
|
|
|
|
|
|
:min="1"
|
|
|
|
|
|
:step="1"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@change="calculateTravelSubtotal"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="days" label="天数" width="100">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input-number
|
|
|
|
|
|
v-model="scope.row.days"
|
|
|
|
|
|
:min="1"
|
|
|
|
|
|
:step="1"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@change="calculateTravelSubtotal"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="accommodationStandard" label="住宿标准(元)" width="150">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input-number
|
|
|
|
|
|
v-model="scope.row.accommodationStandard"
|
|
|
|
|
|
:min="0"
|
|
|
|
|
|
:step="50"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@change="calculateTravelSubtotal"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="transportFee" label="往返路费(元)" width="150">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input-number
|
|
|
|
|
|
v-model="scope.row.transportFee"
|
|
|
|
|
|
:min="0"
|
|
|
|
|
|
:step="100"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@change="calculateTravelSubtotal"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="accommodationFee" label="住宿费(元)" width="120">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model.number="scope.row.accommodationFee"
|
|
|
|
|
|
disabled
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="subsidy" label="补贴(元)" width="100">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model.number="scope.row.subsidy"
|
|
|
|
|
|
disabled
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="subtotal" label="小计(万元)" width="120">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model.number="scope.row.subtotal"
|
|
|
|
|
|
disabled
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
:precision="2"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column label="操作" width="120" fixed="right">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
type="danger"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@click="deleteTravelRow(scope.row)"
|
|
|
|
|
|
icon="Delete"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 会议费预算明细表 -->
|
|
|
|
|
|
<el-card class="mb-6">
|
|
|
|
|
|
<div class="flex items-center justify-between mb-4">
|
|
|
|
|
|
<h3 class="text-lg font-medium">会议费预算明细表</h3>
|
|
|
|
|
|
<div class="flex gap-2 items-center">
|
|
|
|
|
|
<span class="mr-2">行数:</span>
|
|
|
|
|
|
<el-input-number
|
|
|
|
|
|
v-model="meetingAddRowCount"
|
|
|
|
|
|
:min="1"
|
|
|
|
|
|
:max="10"
|
|
|
|
|
|
:step="1"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
style="width: 100px"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<el-button type="primary" @click="confirmMeetingAdd" size="small">
|
|
|
|
|
|
<el-icon><Plus /></el-icon>
|
|
|
|
|
|
添加
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
<el-button @click="deleteSelectedMeeting" size="small" :disabled="selectedMeetingRows.length === 0">
|
|
|
|
|
|
<el-icon><Delete /></el-icon>
|
|
|
|
|
|
删除
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<el-table
|
|
|
|
|
|
v-loading="loading"
|
|
|
|
|
|
:data="meetingList"
|
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
|
border
|
|
|
|
|
|
@selection-change="handleMeetingSelectionChange"
|
|
|
|
|
|
show-summary
|
|
|
|
|
|
:summary-method="() => {
|
|
|
|
|
|
const cols = ['合计', '', '', '', '', '', '', '', '', '', '', '']
|
|
|
|
|
|
cols[cols.length - 2] = meetingFeeTotal.toFixed(2)
|
|
|
|
|
|
return cols
|
|
|
|
|
|
}"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-table-column type="selection" width="55" />
|
|
|
|
|
|
<el-table-column prop="id" label="序号" type="index" width="80" />
|
|
|
|
|
|
<el-table-column label="会议类型" width="150">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-select
|
|
|
|
|
|
v-model="scope.row.meetingType"
|
|
|
|
|
|
placeholder="请选择会议类型"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@change="calculateMeetingFee"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-option label="公司组织会议" value="company" />
|
|
|
|
|
|
<el-option label="外出参加会议" value="external" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 组合列:公司组织会议 -->
|
|
|
|
|
|
<el-table-column prop="content" label="会议内容" width="200">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="scope.row.content"
|
|
|
|
|
|
placeholder="请输入会议内容"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="venueDailyRent" label="场地日租金(元)" width="150" v-if="showCompanyMeetingColumns">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input-number
|
|
|
|
|
|
v-model="scope.row.venueDailyRent"
|
|
|
|
|
|
:min="0"
|
|
|
|
|
|
:step="100"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@change="calculateMeetingFee"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="dailyMiscFee" label="日均杂费(元)" width="150" v-if="showCompanyMeetingColumns">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input-number
|
|
|
|
|
|
v-model="scope.row.dailyMiscFee"
|
|
|
|
|
|
:min="0"
|
|
|
|
|
|
:step="50"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@change="calculateMeetingFee"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="meetingDays" label="天数" width="100">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input-number
|
|
|
|
|
|
v-model="scope.row.meetingDays"
|
|
|
|
|
|
:min="1"
|
|
|
|
|
|
:step="1"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@change="calculateMeetingFee"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="expertTransportAccommodation" label="专家交通住宿费" width="180" v-if="showCompanyMeetingColumns">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input-number
|
|
|
|
|
|
v-model="scope.row.expertTransportAccommodation"
|
|
|
|
|
|
:min="0"
|
|
|
|
|
|
:step="100"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@change="calculateMeetingFee"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 组合列:外出参加会议 -->
|
|
|
|
|
|
<el-table-column prop="participantCount" label="人数" width="100" v-if="showExternalMeetingColumns">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input-number
|
|
|
|
|
|
v-model="scope.row.participantCount"
|
|
|
|
|
|
:min="1"
|
|
|
|
|
|
:step="1"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@change="calculateMeetingFee"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="feePerPerson" label="人均交费" width="120" v-if="showExternalMeetingColumns">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input-number
|
|
|
|
|
|
v-model="scope.row.feePerPerson"
|
|
|
|
|
|
:min="0"
|
|
|
|
|
|
:step="100"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@change="calculateMeetingFee"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
|
|
|
|
<el-table-column prop="meetingFee" label="会议费(万元)" width="120">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model.number="scope.row.meetingFee"
|
|
|
|
|
|
disabled
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
:precision="2"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column label="操作" width="120" fixed="right">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
type="danger"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@click="deleteMeetingRow(scope.row)"
|
|
|
|
|
|
icon="Delete"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 国际交流费预算明细表 -->
|
|
|
|
|
|
<el-card>
|
|
|
|
|
|
<div class="flex items-center justify-between mb-4">
|
|
|
|
|
|
<h3 class="text-lg font-medium">国际交流费预算明细表</h3>
|
|
|
|
|
|
<div class="flex gap-2 items-center">
|
|
|
|
|
|
<span class="mr-2">行数:</span>
|
|
|
|
|
|
<el-input-number
|
|
|
|
|
|
v-model="internationalAddRowCount"
|
|
|
|
|
|
:min="1"
|
|
|
|
|
|
:max="10"
|
|
|
|
|
|
:step="1"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
style="width: 100px"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<el-button type="primary" @click="confirmInternationalAdd" size="small">
|
|
|
|
|
|
<el-icon><Plus /></el-icon>
|
|
|
|
|
|
添加
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
<el-button @click="deleteSelectedInternational" size="small" :disabled="selectedInternationalRows.length === 0">
|
|
|
|
|
|
<el-icon><Delete /></el-icon>
|
|
|
|
|
|
删除
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<el-table
|
|
|
|
|
|
v-loading="loading"
|
|
|
|
|
|
:data="internationalList"
|
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
|
border
|
|
|
|
|
|
@selection-change="handleInternationalSelectionChange"
|
|
|
|
|
|
show-summary
|
|
|
|
|
|
:summary-method="() => {
|
|
|
|
|
|
const cols = ['合计', '', '', '', '', '', '', '', '', '']
|
|
|
|
|
|
cols[cols.length - 2] = internationalSubtotalTotal.toFixed(2)
|
|
|
|
|
|
return cols
|
|
|
|
|
|
}"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-table-column type="selection" width="55" />
|
|
|
|
|
|
<el-table-column prop="id" label="序号" type="index" width="80" />
|
|
|
|
|
|
<el-table-column prop="exchangeType" label="合作交流类型" width="180">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-select
|
|
|
|
|
|
v-model="scope.row.exchangeType"
|
|
|
|
|
|
placeholder="请选择交流类型"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
filterable
|
|
|
|
|
|
allow-create
|
|
|
|
|
|
default-first-option
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-option label="学术访问" value="学术访问" />
|
|
|
|
|
|
<el-option label="技术培训" value="技术培训" />
|
|
|
|
|
|
<el-option label="国际会议" value="国际会议" />
|
|
|
|
|
|
<el-option label="合作研发" value="合作研发" />
|
|
|
|
|
|
<el-option label="出国考察" value="出国考察" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="country" label="国家和地区" width="120">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="scope.row.country"
|
|
|
|
|
|
placeholder="请输入国家和地区"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="institution" label="机构" width="150">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="scope.row.institution"
|
|
|
|
|
|
placeholder="请输入机构"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="personCount" label="人数(人)" width="120">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input-number
|
|
|
|
|
|
v-model="scope.row.personCount"
|
|
|
|
|
|
:min="1"
|
|
|
|
|
|
:step="1"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@change="calculateInternationalSubtotal"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="days" label="时间(天)" width="120">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input-number
|
|
|
|
|
|
v-model="scope.row.days"
|
|
|
|
|
|
:min="1"
|
|
|
|
|
|
:step="1"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@change="calculateInternationalSubtotal"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="transportAccommodationFee" label="往返路费及住宿费" width="180">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input-number
|
|
|
|
|
|
v-model="scope.row.transportAccommodationFee"
|
|
|
|
|
|
:min="0"
|
|
|
|
|
|
:step="100"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@change="calculateInternationalSubtotal"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="subsidy" label="补贴(元)" width="120">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model.number="scope.row.subsidy"
|
|
|
|
|
|
disabled
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="subtotal" label="小计(万元)" width="120">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model.number="scope.row.subtotal"
|
|
|
|
|
|
disabled
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
:precision="2"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column label="操作" width="120" fixed="right">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
type="danger"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@click="deleteInternationalRow(scope.row)"
|
|
|
|
|
|
icon="Delete"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
|
import { ref, computed, watch } from 'vue'
|
|
|
|
|
|
import { ElMessage } from 'element-plus'
|
|
|
|
|
|
|
|
|
|
|
|
// 定义差旅费数据类型
|
|
|
|
|
|
interface TravelItem {
|
|
|
|
|
|
id?: string
|
|
|
|
|
|
location: string
|
|
|
|
|
|
reason: string
|
|
|
|
|
|
times: number
|
|
|
|
|
|
personCount: number
|
|
|
|
|
|
days: number
|
|
|
|
|
|
accommodationStandard: number
|
|
|
|
|
|
transportFee: number
|
|
|
|
|
|
accommodationFee: number
|
|
|
|
|
|
subsidy: number
|
|
|
|
|
|
subtotal: number
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 定义会议费数据类型
|
|
|
|
|
|
interface MeetingItem {
|
|
|
|
|
|
id?: string
|
|
|
|
|
|
meetingType: string
|
|
|
|
|
|
content: string
|
|
|
|
|
|
venueDailyRent: number
|
|
|
|
|
|
dailyMiscFee: number
|
|
|
|
|
|
meetingDays: number
|
|
|
|
|
|
expertTransportAccommodation: number
|
|
|
|
|
|
participantCount: number
|
|
|
|
|
|
feePerPerson: number
|
|
|
|
|
|
meetingFee: number
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 定义国际交流费数据类型
|
|
|
|
|
|
interface InternationalItem {
|
|
|
|
|
|
id?: string
|
|
|
|
|
|
exchangeType: string
|
|
|
|
|
|
country: string
|
|
|
|
|
|
institution: string
|
|
|
|
|
|
personCount: number
|
|
|
|
|
|
days: number
|
|
|
|
|
|
transportAccommodationFee: number
|
|
|
|
|
|
subsidy: number
|
|
|
|
|
|
subtotal: number
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Props
|
|
|
|
|
|
const props = defineProps<{
|
|
|
|
|
|
projectId?: string
|
|
|
|
|
|
}>()
|
|
|
|
|
|
|
|
|
|
|
|
// Emits
|
|
|
|
|
|
const emit = defineEmits<{
|
|
|
|
|
|
update: [data: {
|
|
|
|
|
|
travelTotal: number,
|
|
|
|
|
|
meetingTotal: number,
|
|
|
|
|
|
internationalTotal: number
|
|
|
|
|
|
}]
|
|
|
|
|
|
}>()
|
|
|
|
|
|
|
|
|
|
|
|
// 响应式数据
|
|
|
|
|
|
const loading = ref(false)
|
|
|
|
|
|
|
|
|
|
|
|
// 差旅费相关
|
|
|
|
|
|
const travelList = ref<TravelItem[]>([])
|
|
|
|
|
|
const selectedTravelRows = ref<TravelItem[]>([])
|
|
|
|
|
|
const travelAddRowCount = ref(1)
|
|
|
|
|
|
|
|
|
|
|
|
// 会议费相关
|
|
|
|
|
|
const meetingList = ref<MeetingItem[]>([])
|
|
|
|
|
|
const selectedMeetingRows = ref<MeetingItem[]>([])
|
|
|
|
|
|
const meetingAddRowCount = ref(1)
|
|
|
|
|
|
const showCompanyMeetingColumns = ref(true)
|
|
|
|
|
|
const showExternalMeetingColumns = ref(true)
|
|
|
|
|
|
|
|
|
|
|
|
// 国际交流费相关
|
|
|
|
|
|
const internationalList = ref<InternationalItem[]>([])
|
|
|
|
|
|
const selectedInternationalRows = ref<InternationalItem[]>([])
|
|
|
|
|
|
const internationalAddRowCount = ref(1)
|
|
|
|
|
|
|
|
|
|
|
|
// 计算差旅费合计
|
|
|
|
|
|
const travelTransportTotal = computed(() => {
|
|
|
|
|
|
return travelList.value.reduce((sum, item) => sum + (item.transportFee || 0), 0)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const travelAccommodationTotal = computed(() => {
|
|
|
|
|
|
return travelList.value.reduce((sum, item) => sum + (item.accommodationFee || 0), 0)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const travelSubsidyTotal = computed(() => {
|
|
|
|
|
|
return travelList.value.reduce((sum, item) => sum + (item.subsidy || 0), 0)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const travelSubtotalTotal = computed(() => {
|
|
|
|
|
|
return travelList.value.reduce((sum, item) => sum + (item.subtotal || 0), 0)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 计算会议费合计
|
|
|
|
|
|
const meetingFeeTotal = computed(() => {
|
|
|
|
|
|
return meetingList.value.reduce((sum, item) => sum + (item.meetingFee || 0), 0)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 计算国际交流费合计
|
|
|
|
|
|
const internationalSubtotalTotal = computed(() => {
|
|
|
|
|
|
return internationalList.value.reduce((sum, item) => sum + (item.subtotal || 0), 0)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 计算差旅费小计
|
|
|
|
|
|
const calculateTravelSubtotal = () => {
|
|
|
|
|
|
travelList.value.forEach(item => {
|
|
|
|
|
|
// 住宿费 = 人数 * 天数 * 住宿标准
|
|
|
|
|
|
item.accommodationFee = (item.personCount || 0) * (item.days || 0) * (item.accommodationStandard || 0)
|
|
|
|
|
|
// 补贴 = 50 * 人数 * 天数
|
|
|
|
|
|
item.subsidy = 50 * (item.personCount || 0) * (item.days || 0)
|
|
|
|
|
|
// 小计 = (往返路费 + 住宿费 + 补贴) / 10000
|
|
|
|
|
|
item.subtotal = ((item.transportFee || 0) + item.accommodationFee + item.subsidy) / 10000
|
|
|
|
|
|
item.subtotal = Math.round(item.subtotal * 100) / 100 // 保留两位小数
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
emitUpdate()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算会议费
|
|
|
|
|
|
const calculateMeetingFee = () => {
|
|
|
|
|
|
meetingList.value.forEach(item => {
|
|
|
|
|
|
if (item.meetingType === 'company') {
|
|
|
|
|
|
// 公司组织会议:((场地日租金 + 日均杂费) * 天数 + 专家交通住宿费) / 10000
|
|
|
|
|
|
item.meetingFee = (((item.venueDailyRent || 0) + (item.dailyMiscFee || 0)) * (item.meetingDays || 0) +
|
|
|
|
|
|
(item.expertTransportAccommodation || 0)) / 10000
|
|
|
|
|
|
} else if (item.meetingType === 'external') {
|
|
|
|
|
|
// 外出参加会议:(人数 * 人均交费) / 10000
|
|
|
|
|
|
item.meetingFee = ((item.participantCount || 0) * (item.feePerPerson || 0)) / 10000
|
|
|
|
|
|
}
|
|
|
|
|
|
item.meetingFee = Math.round(item.meetingFee * 100) / 100 // 保留两位小数
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
emitUpdate()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算国际交流费小计
|
|
|
|
|
|
const calculateInternationalSubtotal = () => {
|
|
|
|
|
|
internationalList.value.forEach(item => {
|
|
|
|
|
|
// 如果合作交流类型是出国考察,则补贴=40*人数*时间
|
|
|
|
|
|
if (item.exchangeType === '出国考察') {
|
|
|
|
|
|
item.subsidy = 40 * (item.personCount || 0) * (item.days || 0)
|
|
|
|
|
|
} else if (!item.subsidy) {
|
|
|
|
|
|
// 其他类型如果没有设置补贴,默认设为0
|
|
|
|
|
|
item.subsidy = 0
|
|
|
|
|
|
}
|
|
|
|
|
|
// 小计 = (往返路费及住宿费 + 补贴) / 10000
|
|
|
|
|
|
item.subtotal = ((item.transportAccommodationFee || 0) + (item.subsidy || 0)) / 10000
|
|
|
|
|
|
item.subtotal = Math.round(item.subtotal * 100) / 100 // 保留两位小数
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
emitUpdate()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 发出更新事件
|
|
|
|
|
|
const emitUpdate = () => {
|
|
|
|
|
|
emit('update', {
|
|
|
|
|
|
travelCost: travelSubtotalTotal.value,
|
|
|
|
|
|
meetingCost: meetingFeeTotal.value,
|
|
|
|
|
|
internationalExchangeCost: internationalSubtotalTotal.value
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 差旅费相关方法
|
|
|
|
|
|
const confirmTravelAdd = () => {
|
|
|
|
|
|
for (let i = 0; i < travelAddRowCount.value; i++) {
|
|
|
|
|
|
const newItem: TravelItem = {
|
|
|
|
|
|
location: '',
|
|
|
|
|
|
reason: '',
|
|
|
|
|
|
times: 1,
|
|
|
|
|
|
personCount: 1,
|
|
|
|
|
|
days: 1,
|
|
|
|
|
|
accommodationStandard: 0,
|
|
|
|
|
|
transportFee: 0,
|
|
|
|
|
|
accommodationFee: 0,
|
|
|
|
|
|
subsidy: 0,
|
|
|
|
|
|
subtotal: 0
|
|
|
|
|
|
}
|
|
|
|
|
|
travelList.value.push(newItem)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 滚动到最下方并聚焦到新添加的行
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
const table = document.querySelector('.el-table__body-wrapper')
|
|
|
|
|
|
if (table) {
|
|
|
|
|
|
table.scrollTop = table.scrollHeight
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 尝试聚焦到新添加的第一行的第一个输入框
|
|
|
|
|
|
const rows = document.querySelectorAll('.el-table__body tr')
|
|
|
|
|
|
const newRow = rows[rows.length - travelAddRowCount.value]
|
|
|
|
|
|
if (newRow) {
|
|
|
|
|
|
const firstInput = newRow.querySelector('input')
|
|
|
|
|
|
if (firstInput) {
|
|
|
|
|
|
firstInput.focus()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 0)
|
|
|
|
|
|
|
|
|
|
|
|
ElMessage.success(`成功添加 ${travelAddRowCount.value} 行`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const deleteTravelRow = (row: TravelItem) => {
|
|
|
|
|
|
const index = travelList.value.findIndex(item => item === row)
|
|
|
|
|
|
if (index !== -1) {
|
|
|
|
|
|
travelList.value.splice(index, 1)
|
|
|
|
|
|
calculateTravelSubtotal()
|
|
|
|
|
|
ElMessage.success('删除成功')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const deleteSelectedTravel = () => {
|
|
|
|
|
|
if (selectedTravelRows.value.length === 0) {
|
|
|
|
|
|
ElMessage.warning('请先选择要删除的行')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
selectedTravelRows.value.forEach(row => {
|
|
|
|
|
|
const index = travelList.value.findIndex(item => item === row)
|
|
|
|
|
|
if (index !== -1) {
|
|
|
|
|
|
travelList.value.splice(index, 1)
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
selectedTravelRows.value = []
|
|
|
|
|
|
calculateTravelSubtotal()
|
|
|
|
|
|
ElMessage.success('删除成功')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const handleTravelSelectionChange = (selection: TravelItem[]) => {
|
|
|
|
|
|
selectedTravelRows.value = selection
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 会议费相关方法
|
|
|
|
|
|
const confirmMeetingAdd = () => {
|
|
|
|
|
|
for (let i = 0; i < meetingAddRowCount.value; i++) {
|
|
|
|
|
|
const newItem: MeetingItem = {
|
|
|
|
|
|
meetingType: 'company',
|
|
|
|
|
|
content: '',
|
|
|
|
|
|
venueDailyRent: 0,
|
|
|
|
|
|
dailyMiscFee: 0,
|
|
|
|
|
|
meetingDays: 1,
|
|
|
|
|
|
expertTransportAccommodation: 0,
|
|
|
|
|
|
participantCount: 1,
|
|
|
|
|
|
feePerPerson: 0,
|
|
|
|
|
|
meetingFee: 0
|
|
|
|
|
|
}
|
|
|
|
|
|
meetingList.value.push(newItem)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 滚动到最下方并聚焦到新添加的行
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
const table = document.querySelector('.el-table__body-wrapper')
|
|
|
|
|
|
if (table) {
|
|
|
|
|
|
table.scrollTop = table.scrollHeight
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 尝试聚焦到新添加的第一行的第一个输入框
|
|
|
|
|
|
const rows = document.querySelectorAll('.el-table__body tr')
|
|
|
|
|
|
const newRow = rows[rows.length - meetingAddRowCount.value]
|
|
|
|
|
|
if (newRow) {
|
|
|
|
|
|
const firstInput = newRow.querySelector('input, select')
|
|
|
|
|
|
if (firstInput) {
|
|
|
|
|
|
firstInput.focus()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 0)
|
|
|
|
|
|
|
|
|
|
|
|
ElMessage.success(`成功添加 ${meetingAddRowCount.value} 行`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const deleteMeetingRow = (row: MeetingItem) => {
|
|
|
|
|
|
const index = meetingList.value.findIndex(item => item === row)
|
|
|
|
|
|
if (index !== -1) {
|
|
|
|
|
|
meetingList.value.splice(index, 1)
|
|
|
|
|
|
calculateMeetingFee()
|
|
|
|
|
|
ElMessage.success('删除成功')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const deleteSelectedMeeting = () => {
|
|
|
|
|
|
if (selectedMeetingRows.value.length === 0) {
|
|
|
|
|
|
ElMessage.warning('请先选择要删除的行')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
selectedMeetingRows.value.forEach(row => {
|
|
|
|
|
|
const index = meetingList.value.findIndex(item => item === row)
|
|
|
|
|
|
if (index !== -1) {
|
|
|
|
|
|
meetingList.value.splice(index, 1)
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
selectedMeetingRows.value = []
|
|
|
|
|
|
calculateMeetingFee()
|
|
|
|
|
|
ElMessage.success('删除成功')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const handleMeetingSelectionChange = (selection: MeetingItem[]) => {
|
|
|
|
|
|
selectedMeetingRows.value = selection
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 国际交流费相关方法
|
|
|
|
|
|
const confirmInternationalAdd = () => {
|
|
|
|
|
|
for (let i = 0; i < internationalAddRowCount.value; i++) {
|
|
|
|
|
|
const newItem: InternationalItem = {
|
|
|
|
|
|
exchangeType: '',
|
|
|
|
|
|
country: '',
|
|
|
|
|
|
institution: '',
|
|
|
|
|
|
personCount: 1,
|
|
|
|
|
|
days: 1,
|
|
|
|
|
|
transportAccommodationFee: 0,
|
|
|
|
|
|
subsidy: 0,
|
|
|
|
|
|
subtotal: 0
|
|
|
|
|
|
}
|
|
|
|
|
|
internationalList.value.push(newItem)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 滚动到最下方并聚焦到新添加的行
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
const table = document.querySelector('.el-table__body-wrapper')
|
|
|
|
|
|
if (table) {
|
|
|
|
|
|
table.scrollTop = table.scrollHeight
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 尝试聚焦到新添加的第一行的第一个输入框
|
|
|
|
|
|
const rows = document.querySelectorAll('.el-table__body tr')
|
|
|
|
|
|
const newRow = rows[rows.length - internationalAddRowCount.value]
|
|
|
|
|
|
if (newRow) {
|
|
|
|
|
|
const firstInput = newRow.querySelector('input, select')
|
|
|
|
|
|
if (firstInput) {
|
|
|
|
|
|
firstInput.focus()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 0)
|
|
|
|
|
|
|
|
|
|
|
|
// 新增行后立即计算一次,确保补贴正确
|
|
|
|
|
|
calculateInternationalSubtotal()
|
|
|
|
|
|
|
|
|
|
|
|
ElMessage.success(`成功添加 ${internationalAddRowCount.value} 行`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const deleteInternationalRow = (row: InternationalItem) => {
|
|
|
|
|
|
const index = internationalList.value.findIndex(item => item === row)
|
|
|
|
|
|
if (index !== -1) {
|
|
|
|
|
|
internationalList.value.splice(index, 1)
|
|
|
|
|
|
calculateInternationalSubtotal()
|
|
|
|
|
|
ElMessage.success('删除成功')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const deleteSelectedInternational = () => {
|
|
|
|
|
|
if (selectedInternationalRows.value.length === 0) {
|
|
|
|
|
|
ElMessage.warning('请先选择要删除的行')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
selectedInternationalRows.value.forEach(row => {
|
|
|
|
|
|
const index = internationalList.value.findIndex(item => item === row)
|
|
|
|
|
|
if (index !== -1) {
|
|
|
|
|
|
internationalList.value.splice(index, 1)
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
selectedInternationalRows.value = []
|
|
|
|
|
|
calculateInternationalSubtotal()
|
|
|
|
|
|
ElMessage.success('删除成功')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const handleInternationalSelectionChange = (selection: InternationalItem[]) => {
|
|
|
|
|
|
selectedInternationalRows.value = selection
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 监听projectId变化,重新加载数据
|
|
|
|
|
|
watch(() => props.projectId, (newProjectId) => {
|
|
|
|
|
|
if (newProjectId) {
|
|
|
|
|
|
loadAllData(newProjectId)
|
|
|
|
|
|
}
|
|
|
|
|
|
}, { immediate: true })
|
|
|
|
|
|
|
|
|
|
|
|
// 加载所有数据
|
|
|
|
|
|
const loadAllData = async (projectId: string) => {
|
|
|
|
|
|
loading.value = true
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 模拟API请求延迟
|
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 500))
|
|
|
|
|
|
|
|
|
|
|
|
// 模拟差旅费数据
|
|
|
|
|
|
travelList.value = [
|
|
|
|
|
|
{
|
|
|
|
|
|
id: '1',
|
|
|
|
|
|
location: '北京',
|
|
|
|
|
|
reason: '项目启动会议',
|
|
|
|
|
|
times: 1,
|
|
|
|
|
|
personCount: 3,
|
|
|
|
|
|
days: 2,
|
|
|
|
|
|
accommodationStandard: 400,
|
|
|
|
|
|
transportFee: 1200,
|
|
|
|
|
|
accommodationFee: 2400,
|
|
|
|
|
|
subsidy: 300,
|
|
|
|
|
|
subtotal: 0.39
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
// 模拟会议费数据
|
|
|
|
|
|
meetingList.value = [
|
|
|
|
|
|
{
|
|
|
|
|
|
id: '1',
|
|
|
|
|
|
meetingType: 'company',
|
|
|
|
|
|
content: '技术研讨会',
|
|
|
|
|
|
venueDailyRent: 5000,
|
|
|
|
|
|
dailyMiscFee: 1000,
|
|
|
|
|
|
meetingDays: 2,
|
|
|
|
|
|
expertTransportAccommodation: 10000,
|
|
|
|
|
|
participantCount: 0,
|
|
|
|
|
|
feePerPerson: 0,
|
|
|
|
|
|
meetingFee: 2.2
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
// 模拟国际交流费数据
|
|
|
|
|
|
internationalList.value = [
|
|
|
|
|
|
{
|
|
|
|
|
|
id: '1',
|
|
|
|
|
|
exchangeType: 'conference',
|
|
|
|
|
|
country: '美国',
|
|
|
|
|
|
institution: 'IEEE',
|
|
|
|
|
|
personCount: 2,
|
|
|
|
|
|
days: 7,
|
|
|
|
|
|
transportAccommodationFee: 50000,
|
|
|
|
|
|
subsidy: 5000,
|
|
|
|
|
|
subtotal: 5.5
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
// 计算各项费用
|
|
|
|
|
|
calculateTravelSubtotal()
|
|
|
|
|
|
calculateMeetingFee()
|
|
|
|
|
|
calculateInternationalSubtotal()
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
ElMessage.error('加载数据失败')
|
|
|
|
|
|
console.error('加载数据失败:', error)
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
loading.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 暴露方法供父组件调用
|
|
|
|
|
|
defineExpose({
|
|
|
|
|
|
travelList,
|
|
|
|
|
|
meetingList,
|
|
|
|
|
|
internationalList,
|
|
|
|
|
|
travelSubtotalTotal,
|
|
|
|
|
|
meetingFeeTotal,
|
|
|
|
|
|
internationalSubtotalTotal,
|
|
|
|
|
|
calculateTravelSubtotal,
|
|
|
|
|
|
calculateMeetingFee,
|
|
|
|
|
|
calculateInternationalSubtotal,
|
|
|
|
|
|
loadAllData
|
|
|
|
|
|
})
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.travel-meeting-container {
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.el-table) {
|
|
|
|
|
|
margin-bottom: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.el-table__footer-wrapper) {
|
|
|
|
|
|
background-color: #f5f7fa;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.el-table__footer-wrapper .el-table__footer) {
|
|
|
|
|
|
padding: 12px 0;
|
|
|
|
|
|
border-top: 1px solid #ebeef5;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.el-table__footer-wrapper td) {
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.el-input__wrapper) {
|
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.el-input-number) {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.dialog-footer {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.bg-gray-50 {
|
|
|
|
|
|
background-color: #f5f7fa;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.p-3 {
|
|
|
|
|
|
padding: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.rounded {
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|