gaoluyang
2026-06-02 7c2cdcbc7f5585b96fba76a07b0e4417a09c4d7e
src/views/collaborativeApproval/notificationManagement/meetExamine/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,414 @@
<template>
  <div>
    <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 label="审批状态">
          <el-select style="width: 100px" v-model="searchForm.status" placeholder="请选择审批状态" clearable>
            <el-option label="待审批" value="0"/>
            <el-option label="已通过" value="1"/>
            <el-option label="未审批" value="2"/>
            <el-option label="已取消" value="3"/>
          </el-select>
        </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-table v-loading="loading" :data="approvalList" border :height="tableHeight">
        <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 prop="status" label="审批状态" align="center" width="120">
          <template #default="scope">
            <el-tag :type="getStatusType(scope.row.status)">
              {{ getStatusText(scope.row.status) }}
            </el-tag>
          </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
                v-if="scope.row.status == '0'"
                type="primary"
                link
                @click="handleApproval(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="approvalDialogVisible"
    >
      <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="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 v-show="false" class="approval-opinion mt-20">
          <h4>审批意见</h4>
          <el-input
              v-model="approvalOpinion"
              type="textarea"
              placeholder="请输入审批意见"
              :rows="4"
          />
        </div>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="approvalDialogVisible = false">取 æ¶ˆ</el-button>
          <el-button type="danger" @click="submitApproval('2')">不通过</el-button>
          <el-button type="primary" @click="submitApproval('1')">通 è¿‡</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import {ref, reactive, onMounted} from 'vue'
import {ElMessage, ElMessageBox} from 'element-plus'
import Pagination from '@/components/Pagination/index.vue'
import {getRoomEnum, getExamineList,saveMeetingApplication} from '@/api/collaborativeApproval/meeting.js'
import dayjs from "dayjs";
import {staffOnJobListPage} from "@/api/personnelManagement/staffOnJob.js";
// æ•°æ®åˆ—表加载状态
const loading = ref(false)
// æ€»æ¡æ•°
const total = ref(0)
// è¡¨æ ¼é«˜åº¦ï¼ˆæ ¹æ®çª—口高度自适应)
const tableHeight = ref(window.innerHeight - 380)
const roomEnum = ref([])
const staffList = ref([])
// å®¡æ‰¹åˆ—表数据
const approvalList = ref([])
// æŸ¥è¯¢å‚æ•°
const queryParams = reactive({
  current: 1,
  size: 10
})
// æœç´¢è¡¨å•
const searchForm = reactive({
  title: '',
  applicant: '',
  status: ''
})
// æ˜¯å¦æ˜¾ç¤ºå¯¹è¯æ¡†
const detailDialogVisible = ref(false)
const approvalDialogVisible = ref(false)
// å½“前查看的会议
const currentMeeting = ref(null)
// å®¡æ‰¹æ„è§
const approvalOpinion = ref('')
// æŸ¥è¯¢æ•°æ®
const getList = async () => {
  loading.value = true
  let resp = await getExamineList({...searchForm, ...queryParams})
  approvalList.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.postName ? ` (${staff.postName})` : ''}`
      }
    })
    return it
  })
  total.value = resp.data.total
  loading.value = false
}
// æœç´¢æŒ‰é’®æ“ä½œ
const handleSearch = () => {
  queryParams.pageNum = 1
  getList()
}
// é‡ç½®æœç´¢è¡¨å•
const resetSearch = () => {
  Object.assign(searchForm, {
    title: '',
    applicant: '',
    status: ''
  })
  handleSearch()
}
// æŸ¥çœ‹è¯¦æƒ…
const viewDetail = (row) => {
  currentMeeting.value = row
  detailDialogVisible.value = true
}
// å¤„理审批
const handleApproval = (row) => {
  currentMeeting.value = row
  approvalOpinion.value = ''
  approvalDialogVisible.value = true
}
// èŽ·å–çŠ¶æ€ç±»åž‹
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')
}
// æäº¤å®¡æ‰¹
const submitApproval = (status) => {
  // if (status === 'approved' && !approvalOpinion.value.trim()) {
  //   ElMessage.warning('请填写审批意见')
  //   return
  // }
  ElMessageBox.confirm(
      `确认${status === '1' ? '通过' : '不通过'}该会议申请?`,
      '审批确认',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }
  ).then(() => {
    saveMeetingApplication({
      id: currentMeeting.value.id,
      status: status
    }).then(resp=>{
      // æ›´æ–°ä¼šè®®çŠ¶æ€
      currentMeeting.value.status = status
      ElMessage.success('审批提交成功')
      approvalDialogVisible.value = false
      getList()
    })
  }).catch(() => {
  })
}
// é¡µé¢åŠ è½½æ—¶èŽ·å–æ•°æ®
onMounted(async () => {
  const [resp1, resp2]= await Promise.all([getRoomEnum(), staffOnJobListPage({current: -1, size: -1, staffState: 1})])
  roomEnum.value = resp1.data
  staffList.value = resp2.data.records
  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;
}
.approval-opinion h4 {
  margin: 0 0 15px 0;
  color: #303133;
}
.nowrap-label {
  white-space: nowrap !important;
}
.description-content {
  white-space: pre-wrap;
  word-wrap: break-word;
  line-height: 1.6;
  padding: 10px;
  background-color: #f5f7fa;
  border-radius: 4px;
  min-height: 60px;
}
</style>