<template>
|
<div class="app-container">
|
<!-- 页面标题 -->
|
<div class="page-header">
|
<h2>会议纪要</h2>
|
</div>
|
|
<!-- 搜索区域 -->
|
<el-card class="search-card">
|
<el-form :model="searchForm" inline>
|
<el-form-item label="会议主题">
|
<el-input v-model="searchForm.title" placeholder="请输入会议主题" clearable />
|
</el-form-item>
|
<el-form-item label="申请人">
|
<el-input v-model="searchForm.applicant" placeholder="请输入申请人" clearable />
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary" @click="handleSearch">搜索</el-button>
|
<el-button @click="resetSearch">重置</el-button>
|
</el-form-item>
|
</el-form>
|
</el-card>
|
|
<!-- 会议列表 -->
|
<el-card>
|
<el-table v-loading="loading" :data="meetingList" border>
|
<el-table-column prop="title" label="会议主题" align="center" min-width="200" show-overflow-tooltip />
|
<el-table-column prop="applicant" label="申请人" align="center" width="120" />
|
<el-table-column prop="host" label="主持人" align="center" width="120" />
|
<el-table-column prop="meetingTime" label="会议时间" align="center" width="180">
|
<template #default="scope">
|
{{ formatDateTime(scope.row.meetingTime) }}
|
</template>
|
</el-table-column>
|
<el-table-column prop="location" label="会议地点" align="center" width="150" />
|
<el-table-column prop="participants" label="参会人数" align="center" width="100">
|
<template #default="scope">
|
{{ scope.row.participants.length }}人
|
</template>
|
</el-table-column>
|
<el-table-column label="操作" align="center" width="200" fixed="right">
|
<template #default="scope">
|
<el-button type="primary" link @click="viewDetail(scope.row)">查看</el-button>
|
<el-button
|
type="primary"
|
link
|
@click="addMinutes(scope.row)"
|
>
|
添加纪要
|
</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
|
<!-- 分页 -->
|
<pagination
|
v-show="total > 0"
|
:total="total"
|
v-model:page="queryParams.current"
|
v-model:limit="queryParams.size"
|
@pagination="getList"
|
/>
|
</el-card>
|
|
<!-- 会议详情对话框 -->
|
<el-dialog
|
title="会议详情"
|
v-model="detailDialogVisible"
|
width="800px"
|
>
|
<div v-if="currentMeeting">
|
<el-descriptions label-width="100px" class="meeting-desc" :column="2" border>
|
<el-descriptions-item label="会议主题" label-class-name="nowrap-label">{{
|
currentMeeting.title
|
}}</el-descriptions-item>
|
<el-descriptions-item label="申请人" label-class-name="nowrap-label">{{
|
currentMeeting.applicant
|
}}</el-descriptions-item>
|
<el-descriptions-item label="主持人" label-class-name="nowrap-label">{{
|
currentMeeting.host
|
}}</el-descriptions-item>
|
<el-descriptions-item label="会议时间" :span="2" label-class-name="nowrap-label">
|
{{ formatDateTime(currentMeeting.meetingTime) }}
|
</el-descriptions-item>
|
<el-descriptions-item label="会议地点" label-class-name="nowrap-label">{{
|
currentMeeting.location
|
}}</el-descriptions-item>
|
<el-descriptions-item label="参会人数" label-class-name="nowrap-label">{{
|
currentMeeting.participants.length
|
}}人</el-descriptions-item>
|
<el-descriptions-item label="审批状态" label-class-name="nowrap-label">
|
<el-tag :type="getStatusType(currentMeeting.status)">
|
{{ getStatusText(currentMeeting.status) }}
|
</el-tag>
|
</el-descriptions-item>
|
<el-descriptions-item label="申请时间" label-class-name="nowrap-label">{{
|
currentMeeting.createTime
|
}}</el-descriptions-item>
|
<el-descriptions-item style="max-height: 400px" label="会议说明" :span="2"
|
label-class-name="nowrap-label">{{ currentMeeting.description }}</el-descriptions-item>
|
</el-descriptions>
|
|
<div class="content-section mt-20">
|
<h4>参会人员</h4>
|
<div class="participants-list">
|
<el-tag
|
v-for="participant in currentMeeting.participants"
|
:key="participant.id"
|
style="margin-right: 10px; margin-bottom: 10px;"
|
>
|
{{ participant.name }}
|
</el-tag>
|
</div>
|
</div>
|
</div>
|
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button @click="detailDialogVisible = false">关 闭</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
|
<!-- 添加会议纪要对话框 -->
|
<el-dialog
|
title="添加会议纪要"
|
v-model="minutesDialogVisible"
|
width="80%"
|
@close="handleCloseMinutesDialog"
|
>
|
<div v-if="currentMeeting">
|
<el-descriptions :column="2" border>
|
<el-descriptions-item label="会议主题">{{ currentMeeting.title }}</el-descriptions-item>
|
<el-descriptions-item label="申请人">{{ currentMeeting.applicant }}</el-descriptions-item>
|
<el-descriptions-item label="主持人">{{ currentMeeting.host }}</el-descriptions-item>
|
<el-descriptions-item label="会议时间" :span="2">
|
{{ formatDateTime(currentMeeting.meetingTime) }}
|
</el-descriptions-item>
|
<el-descriptions-item label="会议地点">{{ currentMeeting.location }}</el-descriptions-item>
|
<el-descriptions-item label="参会人数">{{ currentMeeting.participants.length }}人</el-descriptions-item>
|
</el-descriptions>
|
|
<div class="content-section mt-20">
|
<h4>会议纪要内容</h4>
|
<div class="editor-container">
|
<Editor
|
v-model="minutesContent"
|
:min-height="400"
|
/>
|
</div>
|
</div>
|
</div>
|
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button @click="minutesDialogVisible = false">取 消</el-button>
|
<el-button type="primary" @click="submitMinutes">保 存</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, reactive, onMounted } from 'vue'
|
import { ElMessage } from 'element-plus'
|
import Pagination from '@/components/Pagination/index.vue'
|
import Editor from '@/components/Editor/index.vue'
|
import { getRoomEnum, getMeetingPublish ,getMeetingMinutesByMeetingId,saveMeetingMinutes} from '@/api/collaborativeApproval/meeting.js'
|
import { getStaffOnJob } from "@/api/personnelManagement/onboarding.js"
|
import dayjs from "dayjs"
|
|
// 数据列表加载状态
|
const loading = ref(false)
|
|
// 总条数
|
const total = ref(0)
|
const roomEnum = ref([])
|
const staffList = ref([])
|
|
// 会议列表数据
|
const meetingList = ref([])
|
|
// 查询参数
|
const queryParams = reactive({
|
current: 1,
|
size: 10
|
})
|
|
// 搜索表单
|
const searchForm = reactive({
|
title: '',
|
applicant: '',
|
// status: '1' // 默认只显示已通过审批的会议
|
})
|
|
// 是否显示对话框
|
const detailDialogVisible = ref(false)
|
const minutesDialogVisible = ref(false)
|
|
// 当前查看的会议
|
const currentMeeting = ref(null)
|
|
// 会议纪要内容
|
const minutesContent = ref('')
|
const minutesContentId = ref('')
|
|
// 查询数据
|
const getList = async () => {
|
loading.value = true
|
let resp = await getMeetingPublish({ ...searchForm, ...queryParams })
|
meetingList.value = resp.data.records.map(it => {
|
let room = roomEnum.value.find(room => it.roomId === room.id)
|
it.location = `${room.name}(${room.location})`
|
let staffs = JSON.parse(it.participants)
|
it.staffCount = staffs.size
|
it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format('HH:mm:ss')} ~ ${dayjs(it.endTime).format('HH:mm:ss')}`
|
it.participants = staffList.value.filter(staff => staffs.some(id => id === staff.id)).map(staff => {
|
return {
|
id: staff.id,
|
name: `${staff.staffName}(${staff.postJob})`
|
}
|
})
|
|
return it
|
})
|
total.value = resp.data.total
|
loading.value = false
|
}
|
|
// 搜索按钮操作
|
const handleSearch = () => {
|
queryParams.current = 1
|
getList()
|
}
|
|
// 重置搜索表单
|
const resetSearch = () => {
|
Object.assign(searchForm, {
|
title: '',
|
applicant: '',
|
// status: '1'
|
})
|
handleSearch()
|
}
|
|
// 查看详情
|
const viewDetail = (row) => {
|
currentMeeting.value = row
|
detailDialogVisible.value = true
|
}
|
|
// 添加会议纪要
|
const addMinutes = async (row) => {
|
let resp = await getMeetingMinutesByMeetingId(row.id)
|
currentMeeting.value = row
|
if (resp.data){
|
minutesContent.value = resp.data.content
|
minutesContentId.value = resp.data.id
|
}else {
|
minutesContent.value = `<h2>${row.title}会议纪要</h2>
|
<p><strong>会议时间:</strong>${row.meetingTime}</p>
|
<p><strong>会议地点:</strong>${row.location}</p>
|
<p><strong>主持人:</strong>${row.host}</p>
|
<p><strong>参会人员:</strong></p>
|
<ol>
|
${row.participants.map(p => `<li>${p.name}</li>`).join('')}
|
</ol>
|
<p><strong>会议内容:</strong></p>
|
<ol>
|
<li>议题一:
|
<ul>
|
<li>讨论内容:</li>
|
<li>决议事项:</li>
|
</ul>
|
</li>
|
<li>议题二:
|
<ul>
|
<li>讨论内容:</li>
|
<li>决议事项:</li>
|
</ul>
|
</li>
|
</ol>
|
<p><strong>备注:</strong></p>`
|
}
|
|
minutesDialogVisible.value = true
|
}
|
|
// 提交会议纪要
|
const submitMinutes = () => {
|
if (!minutesContent.value) {
|
ElMessage.warning('请输入会议纪要内容')
|
return
|
}
|
saveMeetingMinutes({
|
id: minutesContentId.value,
|
content: minutesContent.value,
|
meetingId: currentMeeting.value.id,
|
title: currentMeeting.value.title
|
}).then(resp=>{
|
console.log('会议纪要内容:', minutesContent.value)
|
ElMessage.success('会议纪要保存成功')
|
minutesDialogVisible.value = false
|
})
|
|
}
|
|
// 关闭会议纪要对话框
|
const handleCloseMinutesDialog = () => {
|
minutesContent.value = ''
|
}
|
|
// 获取状态类型
|
const getStatusType = (status) => {
|
const statusMap = {
|
'0': 'info', // 待审批
|
'1': 'success', // 已通过
|
'2': 'warning', // 未通过
|
'3': 'danger' // 取消
|
}
|
return statusMap[status] || 'info'
|
}
|
|
// 获取状态文本
|
const getStatusText = (status) => {
|
const statusMap = {
|
'0': '待审批',
|
'1': '已通过',
|
'2': '未通过',
|
'3': '已取消'
|
}
|
return statusMap[status] || '未知'
|
}
|
|
// 格式化日期时间
|
const formatDateTime = (dateTime) => {
|
if (!dateTime) return ''
|
return dateTime.replace(' ', '\n')
|
}
|
|
// 页面加载时获取数据
|
onMounted(async () => {
|
const [resp1, resp2] = await Promise.all([getRoomEnum(), getStaffOnJob()])
|
roomEnum.value = resp1.data
|
staffList.value = resp2.data
|
|
await getList()
|
})
|
</script>
|
|
<style scoped>
|
.app-container {
|
padding: 20px;
|
}
|
|
.page-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 20px;
|
}
|
|
.page-header h2 {
|
margin: 0;
|
color: #303133;
|
}
|
|
.search-card {
|
margin-bottom: 20px;
|
}
|
|
.dialog-footer {
|
display: flex;
|
justify-content: flex-end;
|
gap: 10px;
|
}
|
|
.content-section h4 {
|
margin: 0 0 15px 0;
|
color: #303133;
|
}
|
|
.mt-20 {
|
margin-top: 20px;
|
}
|
|
.participants-list {
|
min-height: 40px;
|
padding: 15px;
|
border-radius: 4px;
|
line-height: 1.6;
|
}
|
|
.nowrap-label {
|
white-space: nowrap !important;
|
}
|
|
.editor-container {
|
border: 1px solid #dcdfe6;
|
border-radius: 4px;
|
}
|
</style>
|