zhangwencui
2026-06-04 fbba46986e98abe68cd2460d1ed2e296cc4ad269
会议的参会人员改为用户管理的数据选择及其他页面的回显
已修改4个文件
1646 ■■■■■ 文件已修改
src/views/collaborativeApproval/notificationManagement/meetApplication/index.vue 470 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/notificationManagement/meetExamine/index.vue 408 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/notificationManagement/meetPublish/index.vue 394 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/notificationManagement/summary/index.vue 374 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/notificationManagement/meetApplication/index.vue
@@ -1,18 +1,17 @@
<template>
  <div>
    <!-- 申请类型选择 -->
    <el-card class="type-card">
      <div class="type-selector">
        <div
            v-for="type in applicationTypes"
        <div v-for="type in applicationTypes"
            :key="type.value"
            class="type-item"
            :class="{ active: currentType === type.value }"
            @click="changeType(type.value)"
        >
             @click="changeType(type.value)">
          <div class="type-icon">
            <el-icon :size="24"><component :is="type.icon"/></el-icon>
            <el-icon :size="24">
              <component :is="type.icon" />
            </el-icon>
          </div>
          <div class="type-info">
            <div class="type-name">{{ type.name }}</div>
@@ -21,408 +20,429 @@
        </div>
      </div>
    </el-card>
    <!-- 会议申请表单 -->
    <el-card>
      <div class="form-header">
        <h3>{{ getCurrentTypeName() }}申请</h3>
      </div>
      <el-form
          ref="meetingFormRef"
      <el-form ref="meetingFormRef"
          :model="meetingForm"
          :rules="rules"
          label-width="100px"
      >
               label-width="100px">
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="会议主题" prop="title">
              <el-input v-model="meetingForm.title" placeholder="请输入会议主题"/>
            <el-form-item label="会议主题"
                          prop="title">
              <el-input v-model="meetingForm.title"
                        placeholder="请输入会议主题" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="会议室" prop="roomId">
              <el-select v-model="meetingForm.roomId" placeholder="请选择会议室" style="width: 100%">
                <el-option
                    v-for="room in meetingRooms"
            <el-form-item label="会议室"
                          prop="roomId">
              <el-select v-model="meetingForm.roomId"
                         placeholder="请选择会议室"
                         style="width: 100%">
                <el-option v-for="room in meetingRooms"
                    :key="room.id"
                    :label="`${room.name} (${room.location})`"
                    :value="room.id"
                />
                           :value="room.id" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="主持人" prop="host">
              <el-input v-model="meetingForm.host" placeholder="请输入主持人姓名"/>
            <el-form-item label="主持人"
                          prop="host">
              <el-input v-model="meetingForm.host"
                        placeholder="请输入主持人姓名" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="会议日期" prop="meetingDate">
              <el-date-picker
                  v-model="meetingForm.meetingDate"
            <el-form-item label="会议日期"
                          prop="meetingDate">
              <el-date-picker v-model="meetingForm.meetingDate"
                  type="date"
                  placeholder="请选择会议日期"
                  value-format="YYYY-MM-DD"
                  format="YYYY-MM-DD"
                  :disabled-date="disabledDate"
                  style="width: 100%"
              />
                              style="width: 100%" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <!-- 空列,保持布局 -->
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="开始时间" prop="startTime">
              <el-select
                  v-model="meetingForm.startTime"
            <el-form-item label="开始时间"
                          prop="startTime">
              <el-select v-model="meetingForm.startTime"
                  placeholder="请选择开始时间"
                  style="width: 100%"
              >
                <el-option
                    v-for="time in startTimeOptions"
                         style="width: 100%">
                <el-option v-for="time in startTimeOptions"
                    :key="time.value"
                    :label="time.label"
                    :value="time.value"
                />
                           :value="time.value" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="结束时间" prop="endTime">
              <el-select
                  v-model="meetingForm.endTime"
            <el-form-item label="结束时间"
                          prop="endTime">
              <el-select v-model="meetingForm.endTime"
                  placeholder="请选择结束时间"
                  style="width: 100%"
              >
                <el-option
                    v-for="time in endTimeOptions"
                         style="width: 100%">
                <el-option v-for="time in endTimeOptions"
                    :key="time.value"
                    :label="time.label"
                    :value="time.value"
                />
                           :value="time.value" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-form-item label="参会人员" prop="participants">
          <el-select
              v-model="meetingForm.participants"
        <el-form-item label="参会人员"
                      prop="participants">
          <el-select v-model="meetingForm.participants"
              multiple
              filterable
              placeholder="请选择参会人员"
              style="width: 100%"
          >
            <el-option
                v-for="person in employees"
                :key="person.id"
                :label="`${person.staffName}${person.postName ? ` (${person.postName})` : ''}`"
                :value="person.id"
            />
                     style="width: 100%">
            <el-option v-for="user in users"
                       :key="user.userId"
                       :label="user.deptNames ? `${user.nickName} (${user.deptNames})` : user.nickName"
                       :value="user.userId" />
          </el-select>
        </el-form-item>
        <el-form-item label="会议说明" prop="description">
          <el-input
              v-model="meetingForm.description"
        <el-form-item label="会议说明"
                      prop="description">
          <el-input v-model="meetingForm.description"
              type="textarea"
              :rows="4"
              placeholder="请输入会议说明"
          />
                    placeholder="请输入会议说明" />
        </el-form-item>
      </el-form>
      <div class="form-footer">
        <el-button @click="resetForm">重置</el-button>
        <el-button type="primary" @click="submitForm">提交</el-button>
        <el-button type="primary"
                   @click="submitForm">提交</el-button>
      </div>
    </el-card>
  </div>
</template>
<script setup>
import {ref, reactive, onMounted, computed, watch} from 'vue'
import {ElMessage} from 'element-plus'
import {Plus, Document, Promotion, Bell} from '@element-plus/icons-vue'
import {getRoomEnum, saveMeetingApplication} from '@/api/collaborativeApproval/meeting.js'
import {staffOnJobListPage} from "@/api/personnelManagement/staffOnJob.js";
  import { ref, reactive, onMounted, computed, watch } from "vue";
  import { ElMessage } from "element-plus";
  import { Plus, Document, Promotion, Bell } from "@element-plus/icons-vue";
  import {
    getRoomEnum,
    saveMeetingApplication,
  } from "@/api/collaborativeApproval/meeting.js";
  import { userListNoPageByTenantId } from "@/api/system/user.js";
// 当前申请类型
const currentType = ref('department') // approval: 审批流程, department: 部门级, notification: 通知发布
  const currentType = ref("department"); // approval: 审批流程, department: 部门级, notification: 通知发布
// 申请类型选项
const applicationTypes = ref([
  {
    value: 'approval',
    name: '审批流程会议',
    desc: '需要经过多级审批的会议申请',
    icon: Document
      value: "approval",
      name: "审批流程会议",
      desc: "需要经过多级审批的会议申请",
      icon: Document,
  },
  {
    value: 'department',
    name: '部门级会议',
    desc: '部门内部会议申请流程',
    icon: Promotion
      value: "department",
      name: "部门级会议",
      desc: "部门内部会议申请流程",
      icon: Promotion,
  },
  {
    value: 'notification',
    name: '会议通知',
    desc: '无需审批直接发布的会议通知',
    icon: Bell
  }
])
      value: "notification",
      name: "会议通知",
      desc: "无需审批直接发布的会议通知",
      icon: Bell,
    },
  ]);
// 表单数据
const meetingForm = reactive({
  title: '',
  type: '',
  roomId: '',
  host: '',
  meetingDate: '',
  startTime: '',
  endTime: '',
    title: "",
    type: "",
    roomId: "",
    host: "",
    meetingDate: "",
    startTime: "",
    endTime: "",
  participants: [],
  description: ''
})
    description: "",
  });
// 表单引用
const meetingFormRef = ref(null)
  const meetingFormRef = ref(null);
// 会议室列表
const meetingRooms = ref([])
  const meetingRooms = ref([]);
// 员工列表
const employees = ref([])
  // 用户列表(系统管理-用户管理)
  const users = ref([]);
// 时间选项(以半小时为间隔)
const timeOptions = ref([])
  const timeOptions = ref([]);
const getTimeInMinutes = (time) => {
  if (!time) return -1
  const [hour, minute] = time.split(':').map(Number)
  return hour * 60 + minute
}
  const getTimeInMinutes = time => {
    if (!time) return -1;
    const [hour, minute] = time.split(":").map(Number);
    return hour * 60 + minute;
  };
const isToday = (dateText) => {
  if (!dateText) return false
  const [year, month, day] = dateText.split('-').map(Number)
  const now = new Date()
  return year === now.getFullYear() && month === now.getMonth() + 1 && day === now.getDate()
}
  const isToday = dateText => {
    if (!dateText) return false;
    const [year, month, day] = dateText.split("-").map(Number);
    const now = new Date();
    return (
      year === now.getFullYear() &&
      month === now.getMonth() + 1 &&
      day === now.getDate()
    );
  };
const validateStartTime = (_rule, value, callback) => {
  if (!value) {
    callback()
    return
      callback();
      return;
  }
  if (isToday(meetingForm.meetingDate)) {
    const now = new Date()
    const currentMinutes = now.getHours() * 60 + now.getMinutes()
      const now = new Date();
      const currentMinutes = now.getHours() * 60 + now.getMinutes();
    if (getTimeInMinutes(value) > currentMinutes) {
      callback(new Error('当天开始时间不能晚于当前时间'))
      return
        callback(new Error("当天开始时间不能晚于当前时间"));
        return;
    }
  }
  callback()
}
    callback();
  };
const validateEndTime = (_rule, value, callback) => {
  if (!value || !meetingForm.startTime) {
    callback()
    return
      callback();
      return;
  }
  if (getTimeInMinutes(value) <= getTimeInMinutes(meetingForm.startTime)) {
    callback(new Error('结束时间必须大于开始时间'))
    return
      callback(new Error("结束时间必须大于开始时间"));
      return;
  }
  callback()
}
    callback();
  };
// 表单校验规则
const rules = {
  title: [{required: true, message: '请输入会议主题', trigger: 'blur'}],
  roomId: [{required: true, message: '请选择会议室', trigger: 'change'}],
  host: [{required: true, message: '请输入主持人', trigger: 'blur'}],
  meetingDate: [{required: true, message: '请选择会议日期', trigger: 'change'}],
    title: [{ required: true, message: "请输入会议主题", trigger: "blur" }],
    roomId: [{ required: true, message: "请选择会议室", trigger: "change" }],
    host: [{ required: true, message: "请输入主持人", trigger: "blur" }],
    meetingDate: [
      { required: true, message: "请选择会议日期", trigger: "change" },
    ],
  startTime: [
    {required: true, message: '请选择开始时间', trigger: 'change'},
    {validator: validateStartTime, trigger: 'change'}
      { required: true, message: "请选择开始时间", trigger: "change" },
      { validator: validateStartTime, trigger: "change" },
  ],
  endTime: [
    {required: true, message: '请选择结束时间', trigger: 'change'},
    {validator: validateEndTime, trigger: 'change'}
      { required: true, message: "请选择结束时间", trigger: "change" },
      { validator: validateEndTime, trigger: "change" },
  ],
  participants: [{required: true, message: '请选择参会人员', trigger: 'change'}]
}
    participants: [
      { required: true, message: "请选择参会人员", trigger: "change" },
    ],
  };
const startTimeOptions = computed(() => {
  if (!isToday(meetingForm.meetingDate)) {
    return timeOptions.value
      return timeOptions.value;
  }
  const now = new Date()
  const currentMinutes = now.getHours() * 60 + now.getMinutes()
  return timeOptions.value.filter(item => getTimeInMinutes(item.value) <= currentMinutes)
})
    const now = new Date();
    const currentMinutes = now.getHours() * 60 + now.getMinutes();
    return timeOptions.value.filter(
      item => getTimeInMinutes(item.value) <= currentMinutes
    );
  });
const endTimeOptions = computed(() => {
  if (!meetingForm.startTime) {
    return timeOptions.value
      return timeOptions.value;
  }
  const startMinutes = getTimeInMinutes(meetingForm.startTime)
  return timeOptions.value.filter(item => getTimeInMinutes(item.value) > startMinutes)
})
    const startMinutes = getTimeInMinutes(meetingForm.startTime);
    return timeOptions.value.filter(
      item => getTimeInMinutes(item.value) > startMinutes
    );
  });
// 初始化时间选项
const initTimeOptions = () => {
  const options = []
  const now = new Date()
  const currentHour = now.getHours()
  const currentMinute = now.getMinutes()
    const options = [];
    const now = new Date();
    const currentHour = now.getHours();
    const currentMinute = now.getMinutes();
  // meetingDate 是 "yyyy-MM-dd"
  const meetingDate = new Date(meetingForm.meetingDate)
    const meetingDate = new Date(meetingForm.meetingDate);
  const isSameDay =
    now.getFullYear() === meetingDate.getFullYear() &&
    now.getMonth() === meetingDate.getMonth() &&
    now.getDate() === meetingDate.getDate()
      now.getDate() === meetingDate.getDate();
  console.log('是否同一天:', isSameDay)
    console.log("是否同一天:", isSameDay);
  for (let hour = 8; hour <= 18; hour++) {
    // 开始时间必须晚于当前时间
    if (hour < currentHour && isSameDay) {
      continue
        continue;
    }
    if (hour === currentHour && currentMinute > 30 && isSameDay) {
      continue
        continue;
    }
    // 每个小时添加两个选项:整点和半点
    options.push({
      value: `${hour.toString().padStart(2, '0')}:00`,
      label: `${hour.toString().padStart(2, '0')}:00`
    })
        value: `${hour.toString().padStart(2, "0")}:00`,
        label: `${hour.toString().padStart(2, "0")}:00`,
      });
    if (hour < 18) { // 18:00之后没有半点选项
      if (hour < 18) {
        // 18:00之后没有半点选项
      options.push({
        value: `${hour.toString().padStart(2, '0')}:30`,
        label: `${hour.toString().padStart(2, '0')}:30`
      })
          value: `${hour.toString().padStart(2, "0")}:30`,
          label: `${hour.toString().padStart(2, "0")}:30`,
        });
    }
  }
  timeOptions.value = options
}
    timeOptions.value = options;
  };
watch(() => meetingForm.meetingDate, () => {
  if (meetingForm.startTime && !startTimeOptions.value.some(item => item.value === meetingForm.startTime)) {
    meetingForm.startTime = ''
  watch(
    () => meetingForm.meetingDate,
    () => {
      if (
        meetingForm.startTime &&
        !startTimeOptions.value.some(item => item.value === meetingForm.startTime)
      ) {
        meetingForm.startTime = "";
  }
  if (meetingForm.endTime && !endTimeOptions.value.some(item => item.value === meetingForm.endTime)) {
    meetingForm.endTime = ''
      if (
        meetingForm.endTime &&
        !endTimeOptions.value.some(item => item.value === meetingForm.endTime)
      ) {
        meetingForm.endTime = "";
  }
  if (meetingForm.startTime) {
    meetingFormRef.value?.validateField('startTime')
        meetingFormRef.value?.validateField("startTime");
  }
  if (meetingForm.endTime) {
    meetingFormRef.value?.validateField('endTime')
        meetingFormRef.value?.validateField("endTime");
  }
  initTimeOptions()
})
      initTimeOptions();
    }
  );
watch(() => meetingForm.startTime, () => {
  if (meetingForm.endTime && getTimeInMinutes(meetingForm.endTime) <= getTimeInMinutes(meetingForm.startTime)) {
    meetingForm.endTime = ''
  watch(
    () => meetingForm.startTime,
    () => {
      if (
        meetingForm.endTime &&
        getTimeInMinutes(meetingForm.endTime) <=
          getTimeInMinutes(meetingForm.startTime)
      ) {
        meetingForm.endTime = "";
  }
  if (meetingForm.endTime) {
    meetingFormRef.value?.validateField('endTime')
        meetingFormRef.value?.validateField("endTime");
  }
})
    }
  );
// 禁用日期(禁用今天之前的日期)
const disabledDate = (time) => {
  const disabledDate = time => {
  // 禁用今天之前的日期
  return time.getTime() < Date.now() - 86400000
}
    return time.getTime() < Date.now() - 86400000;
  };
// 切换申请类型
const changeType = (type) => {
  currentType.value = type
}
  const changeType = type => {
    currentType.value = type;
  };
// 获取当前类型名称
const getCurrentTypeName = () => {
  const type = applicationTypes.value.find(t => t.value === currentType.value)
  return type ? type.name : ''
}
    const type = applicationTypes.value.find(t => t.value === currentType.value);
    return type ? type.name : "";
  };
// 重置表单
const resetForm = () => {
  meetingFormRef.value?.resetFields()
}
    meetingFormRef.value?.resetFields();
  };
// 提交表单
const submitForm = () => {
  meetingFormRef.value?.validate((valid) => {
    meetingFormRef.value?.validate(valid => {
    if (valid) {
      let formData = {...meetingForm}
      formData.applicationType = currentType.value
      formData.startTime = `${meetingForm.meetingDate} ${meetingForm.startTime}:00`
      formData.endTime = `${meetingForm.meetingDate} ${meetingForm.endTime}:00`
      formData.participants = JSON.stringify(formData.participants)
      console.log(formData)
        let formData = { ...meetingForm };
        formData.applicationType = currentType.value;
        formData.startTime = `${meetingForm.meetingDate} ${meetingForm.startTime}:00`;
        formData.endTime = `${meetingForm.meetingDate} ${meetingForm.endTime}:00`;
        formData.participants = JSON.stringify(formData.participants);
        console.log(formData);
      saveMeetingApplication(formData).then(() => {
        // 模拟提交操作
        ElMessage.success(`${getCurrentTypeName()}提交成功`)
          ElMessage.success(`${getCurrentTypeName()}提交成功`);
        // 根据不同类型执行不同操作
        switch (currentType.value) {
          case 'approval':
            ElMessage.info('会议已提交审批流程')
            break
          case 'department':
            ElMessage.info('部门级会议申请已提交')
            break
          case 'notification':
            ElMessage.info('会议通知已发布')
            break
            case "approval":
              ElMessage.info("会议已提交审批流程");
              break;
            case "department":
              ElMessage.info("部门级会议申请已提交");
              break;
            case "notification":
              ElMessage.info("会议通知已发布");
              break;
        }
        resetForm()
      })
          resetForm();
        });
    }
  })
}
    });
  };
// 页面加载时初始化
onMounted(() => {
  initTimeOptions()
    initTimeOptions();
  getRoomEnum().then(res => {
    meetingRooms.value = res.data
  })
  staffOnJobListPage({
    current: -1,
    size: -1,
    staffState: 1
  }).then(res => {
    employees.value = res.data.records.sort((a, b) => (a.postName || '').localeCompare(b.postName || ''))
  })
})
      meetingRooms.value = res.data;
    });
    userListNoPageByTenantId().then(res => {
      const list = Array.isArray(res?.data) ? res.data : [];
      users.value = list
        .map(item => ({
          userId: item?.userId,
          nickName:
            item?.nickName || item?.userName || String(item?.userId ?? ""),
          deptNames: item?.deptNames || "",
        }))
        .filter(
          item =>
            item.userId !== null && item.userId !== undefined && item.nickName
        )
        .sort((a, b) => String(a.nickName).localeCompare(String(b.nickName)));
    });
  });
</script>
<style scoped>
src/views/collaborativeApproval/notificationManagement/meetExamine/index.vue
@@ -1,182 +1,219 @@
<template>
  <div>
    <el-form :model="searchForm" inline>
    <el-form :model="searchForm"
             inline>
        <el-form-item label="会议主题">
          <el-input v-model="searchForm.title" placeholder="请输入会议主题" clearable/>
        <el-input v-model="searchForm.title"
                  placeholder="请输入会议主题"
                  clearable />
        </el-form-item>
        <el-form-item label="申请人">
          <el-input v-model="searchForm.applicant" placeholder="请输入申请人" clearable/>
        <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 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 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">
      <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">
        <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">
        <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">
        <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'"
            <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)"
            >
                       @click="handleApproval(scope.row)">
              审批
            </el-button>
          </template>
        </el-table-column>
      </el-table>
      <!-- 分页 -->
      <pagination
          v-show="total > 0"
      <pagination v-show="total > 0"
          :total="total"
          v-model:page="queryParams.current"
          v-model:limit="queryParams.size"
          @pagination="getList"
      />
                  @pagination="getList" />
    </el-card>
    <!-- 会议详情对话框 -->
    <el-dialog
        title="会议详情"
    <el-dialog title="会议详情"
        v-model="detailDialogVisible"
        width="800px"
    >
               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">{{
        <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">{{
          <el-descriptions-item label="申请人"
                                label-class-name="nowrap-label">{{
              currentMeeting.applicant
            }}</el-descriptions-item>
          <el-descriptions-item label="主理人" label-class-name="nowrap-label">{{
          <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">
          <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">{{
          <el-descriptions-item label="会议地点"
                                label-class-name="nowrap-label">{{
              currentMeeting.location
            }}</el-descriptions-item>
          <el-descriptions-item label="参会人数" label-class-name="nowrap-label">{{
          <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-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">{{
          <el-descriptions-item label="申请时间"
                                label-class-name="nowrap-label">{{
              currentMeeting.createTime
            }}</el-descriptions-item>
          <el-descriptions-item style="max-height: 400px" label="会议说明" :span="2"
          <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"
            <el-tag v-for="participant in currentMeeting.participants"
                :key="participant.id"
                style="margin-right: 10px; margin-bottom: 10px;"
            >
                    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"
    >
    <el-dialog title="会议审批"
               v-model="approvalDialogVisible">
      <div v-if="currentMeeting">
        <el-descriptions :column="2" border>
        <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">
          <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"
            <el-tag v-for="participant in currentMeeting.participants"
                :key="participant.id"
                style="margin-right: 10px; margin-bottom: 10px;"
            >
                    style="margin-right: 10px; margin-bottom: 10px;">
              {{ participant.name }}
            </el-tag>
          </div>
        </div>
        <div v-show="false" class="approval-opinion mt-20">
        <div v-show="false"
             class="approval-opinion mt-20">
          <h4>审批意见</h4>
          <el-input
              v-model="approvalOpinion"
          <el-input v-model="approvalOpinion"
              type="textarea"
              placeholder="请输入审批意见"
              :rows="4"
          />
                    :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>
          <el-button type="danger"
                     @click="submitApproval('2')">不通过</el-button>
          <el-button type="primary"
                     @click="submitApproval('1')">通 过</el-button>
        </div>
      </template>
    </el-dialog>
@@ -184,170 +221,199 @@
</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 { 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";
  import { userListNoPageByTenantId } from "@/api/system/user.js";
// 数据列表加载状态
const loading = ref(false)
  const loading = ref(false);
// 总条数
const total = ref(0)
  const total = ref(0);
// 表格高度(根据窗口高度自适应)
const tableHeight = ref(window.innerHeight - 380)
const roomEnum = ref([])
const staffList = ref([])
  const tableHeight = ref(window.innerHeight - 380);
  const roomEnum = ref([]);
  const userList = ref([]);
// 审批列表数据
const approvalList = ref([])
  const approvalList = ref([]);
// 查询参数
const queryParams = reactive({
  current: 1,
  size: 10
})
    size: 10,
  });
// 搜索表单
const searchForm = reactive({
  title: '',
  applicant: '',
  status: ''
})
    title: "",
    applicant: "",
    status: "",
  });
// 是否显示对话框
const detailDialogVisible = ref(false)
const approvalDialogVisible = ref(false)
  const detailDialogVisible = ref(false);
  const approvalDialogVisible = ref(false);
// 当前查看的会议
const currentMeeting = ref(null)
  const currentMeeting = ref(null);
// 审批意见
const approvalOpinion = ref('')
  const approvalOpinion = ref("");
// 查询数据
const getList = async () => {
  loading.value = true
  let resp = await getExamineList({...searchForm, ...queryParams})
    loading.value = true;
    let resp = await getExamineList({ ...searchForm, ...queryParams });
    const userMap = new Map(userList.value.map(u => [String(u.userId), u]));
  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 => {
      let room = roomEnum.value.find(room => it.roomId === room.id);
      it.location = `${room.name}(${room.location})`;
      let participantIds = [];
      try {
        participantIds = Array.isArray(it.participants)
          ? it.participants
          : JSON.parse(it.participants);
      } catch (_e) {
        participantIds = [];
      }
      if (!Array.isArray(participantIds)) participantIds = [];
      it.staffCount = participantIds.length;
      it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format(
        "HH:mm:ss"
      )} ~ ${dayjs(it.endTime).format("HH:mm:ss")}`;
      it.participants = participantIds.map(id => {
        const user = userMap.get(String(id));
        const nickName = user?.nickName || user?.userName || String(id ?? "");
        const deptNames = user?.deptNames || "";
      return {
        id: staff.id,
        name:  `${staff.staffName}${staff.postName ? ` (${staff.postName})` : ''}`
      }
    })
          id,
          name: deptNames ? `${nickName} (${deptNames})` : nickName,
        };
      });
    return it
  })
  total.value = resp.data.total
  loading.value = false
}
      return it;
    });
    total.value = resp.data.total;
    loading.value = false;
  };
// 搜索按钮操作
const handleSearch = () => {
  queryParams.pageNum = 1
  getList()
}
    queryParams.pageNum = 1;
    getList();
  };
// 重置搜索表单
const resetSearch = () => {
  Object.assign(searchForm, {
    title: '',
    applicant: '',
    status: ''
  })
  handleSearch()
}
      title: "",
      applicant: "",
      status: "",
    });
    handleSearch();
  };
// 查看详情
const viewDetail = (row) => {
  currentMeeting.value = row
  detailDialogVisible.value = true
}
  const viewDetail = row => {
    currentMeeting.value = row;
    detailDialogVisible.value = true;
  };
// 处理审批
const handleApproval = (row) => {
  currentMeeting.value = row
  approvalOpinion.value = ''
  approvalDialogVisible.value = true
}
  const handleApproval = row => {
    currentMeeting.value = row;
    approvalOpinion.value = "";
    approvalDialogVisible.value = true;
  };
// 获取状态类型
const getStatusType = (status) => {
  const getStatusType = status => {
  const statusMap = {
    '0': 'info',     // 待审批
    '1': 'success',  // 已通过
    '2': 'warning',  // 未通过
    '3': 'danger'   // 取消
  }
  return statusMap[status] || 'info'
}
      0: "info", // 待审批
      1: "success", // 已通过
      2: "warning", // 未通过
      3: "danger", // 取消
    };
    return statusMap[status] || "info";
  };
// 获取状态文本
const getStatusText = (status) => {
  const getStatusText = status => {
  const statusMap = {
    '0': '待审批',
    '1': '已通过',
    '2': '未通过',
    '3': '已取消'
  }
  return statusMap[status] || '未知'
}
      0: "待审批",
      1: "已通过",
      2: "未通过",
      3: "已取消",
    };
    return statusMap[status] || "未知";
  };
// 格式化日期时间
const formatDateTime = (dateTime) => {
  if (!dateTime) return ''
  return dateTime.replace(' ', '\n')
}
  const formatDateTime = dateTime => {
    if (!dateTime) return "";
    return dateTime.replace(" ", "\n");
  };
// 提交审批
const submitApproval = (status) => {
  const submitApproval = status => {
  // if (status === 'approved' && !approvalOpinion.value.trim()) {
  //   ElMessage.warning('请填写审批意见')
  //   return
  // }
  ElMessageBox.confirm(
      `确认${status === '1' ? '通过' : '不通过'}该会议申请?`,
      '审批确认',
      `确认${status === "1" ? "通过" : "不通过"}该会议申请?`,
      "审批确认",
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }
  ).then(() => {
    )
      .then(() => {
    saveMeetingApplication({
      id: currentMeeting.value.id,
      status: status
          status: status,
    }).then(resp=>{
      // 更新会议状态
      currentMeeting.value.status = status
          currentMeeting.value.status = status;
      ElMessage.success('审批提交成功')
      approvalDialogVisible.value = false
      getList()
          ElMessage.success("审批提交成功");
          approvalDialogVisible.value = false;
          getList();
        });
    })
  }).catch(() => {
  })
}
      .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
    const [resp1, resp2] = await Promise.all([
      getRoomEnum(),
      userListNoPageByTenantId(),
    ]);
    roomEnum.value = resp1.data;
    const list = Array.isArray(resp2?.data) ? resp2.data : [];
    userList.value = list
      .map(item => ({
        userId: item?.userId,
        nickName: item?.nickName,
        userName: item?.userName,
        deptNames:
          item?.deptNames || (item?.dept?.deptName ? item.dept.deptName : ""),
      }))
      .filter(item => item.userId !== null && item.userId !== undefined);
  await getList()
})
    await getList();
  });
</script>
<style scoped>
src/views/collaborativeApproval/notificationManagement/meetPublish/index.vue
@@ -1,180 +1,213 @@
<template>
  <div>
    <el-form :model="searchForm" inline>
    <el-form :model="searchForm"
             inline>
        <el-form-item label="会议主题">
          <el-input v-model="searchForm.title" placeholder="请输入会议主题" clearable/>
        <el-input v-model="searchForm.title"
                  placeholder="请输入会议主题"
                  clearable />
        </el-form-item>
        <el-form-item label="申请人">
          <el-input v-model="searchForm.applicant" placeholder="请输入申请人" clearable/>
        <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-select style="width: 100px"
                   v-model="searchForm.status"
                   placeholder="请选择发布状态"
                   clearable>
          <el-option label="待发布"
                     value="0" />
          <el-option label="已发布"
                     value="1" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleSearch">搜索</el-button>
        <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">
      <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">
        <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">
        <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">
        <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'"
            <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)"
            >
                       @click="handleApproval(scope.row)">
              发布
            </el-button>
          </template>
        </el-table-column>
      </el-table>
      <!-- 分页 -->
      <pagination
          v-show="total > 0"
      <pagination v-show="total > 0"
          :total="total"
          v-model:page="queryParams.current"
          v-model:limit="queryParams.size"
          @pagination="getList"
      />
                  @pagination="getList" />
    </el-card>
    <!-- 会议详情对话框 -->
    <el-dialog
        title="会议详情"
    <el-dialog title="会议详情"
        v-model="detailDialogVisible"
        width="800px"
    >
               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">{{
        <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">{{
          <el-descriptions-item label="申请人"
                                label-class-name="nowrap-label">{{
              currentMeeting.applicant
            }}</el-descriptions-item>
          <el-descriptions-item label="主理人" label-class-name="nowrap-label">{{
          <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">
          <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">{{
          <el-descriptions-item label="会议地点"
                                label-class-name="nowrap-label">{{
              currentMeeting.location
            }}</el-descriptions-item>
          <el-descriptions-item label="参会人数" label-class-name="nowrap-label">{{
          <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-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">{{
          <el-descriptions-item label="申请时间"
                                label-class-name="nowrap-label">{{
              currentMeeting.createTime
            }}</el-descriptions-item>
          <el-descriptions-item style="max-height: 400px" label="会议说明" :span="2"
          <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"
            <el-tag v-for="participant in currentMeeting.participants"
                :key="participant.id"
                style="margin-right: 10px; margin-bottom: 10px;"
            >
                    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"
    >
    <el-dialog title="会议发布"
               v-model="approvalDialogVisible">
      <div v-if="currentMeeting">
        <el-descriptions :column="2" border>
        <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">
          <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"
            <el-tag v-for="participant in currentMeeting.participants"
                :key="participant.id"
                style="margin-right: 10px; margin-bottom: 10px;"
            >
                    style="margin-right: 10px; margin-bottom: 10px;">
              {{ participant.name }}
            </el-tag>
          </div>
        </div>
        <div class="approval-opinion mt-20">
          <h4>发布意见</h4>
          <el-input
              v-model="publishComment"
          <el-input v-model="publishComment"
              type="textarea"
              placeholder="请输入发布意见"
              :rows="4"
          />
                    :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>
          <el-button type="primary"
                     @click="submitApproval('1')">发 布</el-button>
        </div>
      </template>
    </el-dialog>
@@ -182,170 +215,199 @@
</template>
<script setup>
import {ref, reactive, onMounted} from 'vue'
import {ElMessage, ElMessageBox} from 'element-plus'
import Pagination from '@/components/Pagination/index.vue'
import {getRoomEnum, getMeetingPublish,saveMeetingApplication} from '@/api/collaborativeApproval/meeting.js'
  import { ref, reactive, onMounted } from "vue";
  import { ElMessage, ElMessageBox } from "element-plus";
  import Pagination from "@/components/Pagination/index.vue";
  import {
    getRoomEnum,
    getMeetingPublish,
    saveMeetingApplication,
  } from "@/api/collaborativeApproval/meeting.js";
import dayjs from "dayjs";
import {staffOnJobListPage} from "@/api/personnelManagement/staffOnJob.js";
  import { userListNoPageByTenantId } from "@/api/system/user.js";
// 数据列表加载状态
const loading = ref(false)
  const loading = ref(false);
// 总条数
const total = ref(0)
  const total = ref(0);
// 表格高度(根据窗口高度自适应)
const tableHeight = ref(window.innerHeight - 380)
const roomEnum = ref([])
const staffList = ref([])
  const tableHeight = ref(window.innerHeight - 380);
  const roomEnum = ref([]);
  const userList = ref([]);
// 发布列表数据
const approvalList = ref([])
  const approvalList = ref([]);
// 查询参数
const queryParams = reactive({
  current: 1,
  size: 10
})
    size: 10,
  });
// 搜索表单
const searchForm = reactive({
  title: '',
  applicant: '',
  status: ''
})
    title: "",
    applicant: "",
    status: "",
  });
// 是否显示对话框
const detailDialogVisible = ref(false)
const approvalDialogVisible = ref(false)
  const detailDialogVisible = ref(false);
  const approvalDialogVisible = ref(false);
// 当前查看的会议
const currentMeeting = ref(null)
  const currentMeeting = ref(null);
// 发布意见
const publishComment = ref('')
  const publishComment = ref("");
// 查询数据
const getList = async () => {
  loading.value = true
  let resp = await getMeetingPublish({...searchForm, ...queryParams})
    loading.value = true;
    let resp = await getMeetingPublish({ ...searchForm, ...queryParams });
    const userMap = new Map(userList.value.map(u => [String(u.userId), u]));
  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.status = it.publishStatus
    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 => {
      let room = roomEnum.value.find(room => it.roomId === room.id);
      it.location = `${room.name}(${room.location})`;
      let participantIds = [];
      try {
        participantIds = Array.isArray(it.participants)
          ? it.participants
          : JSON.parse(it.participants);
      } catch (_e) {
        participantIds = [];
      }
      if (!Array.isArray(participantIds)) participantIds = [];
      it.staffCount = participantIds.length;
      it.status = it.publishStatus;
      it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format(
        "HH:mm:ss"
      )} ~ ${dayjs(it.endTime).format("HH:mm:ss")}`;
      it.participants = participantIds.map(id => {
        const user = userMap.get(String(id));
        const nickName = user?.nickName || user?.userName || String(id ?? "");
        const deptNames = user?.deptNames || "";
      return {
        id: staff.id,
        name: `${staff.staffName}${staff.postName ? ` (${staff.postName})` : ''}`
      }
    })
          id,
          name: deptNames ? `${nickName} (${deptNames})` : nickName,
        };
      });
    return it
  })
  total.value = resp.data.total
  loading.value = false
}
      return it;
    });
    total.value = resp.data.total;
    loading.value = false;
  };
// 搜索按钮操作
const handleSearch = () => {
  queryParams.pageNum = 1
  getList()
}
    queryParams.pageNum = 1;
    getList();
  };
// 重置搜索表单
const resetSearch = () => {
  Object.assign(searchForm, {
    title: '',
    applicant: '',
    status: ''
  })
  handleSearch()
}
      title: "",
      applicant: "",
      status: "",
    });
    handleSearch();
  };
// 查看详情
const viewDetail = (row) => {
  currentMeeting.value = row
  detailDialogVisible.value = true
}
  const viewDetail = row => {
    currentMeeting.value = row;
    detailDialogVisible.value = true;
  };
// 处理发布
const handleApproval = (row) => {
  currentMeeting.value = row
  publishComment.value = ''
  approvalDialogVisible.value = true
}
  const handleApproval = row => {
    currentMeeting.value = row;
    publishComment.value = "";
    approvalDialogVisible.value = true;
  };
// 获取状态类型
const getStatusType = (status) => {
  const getStatusType = status => {
  const statusMap = {
    '0': 'info',     // 待发布
    '1': 'success',  // 已通过
    '2': 'danger',  // 未通过
  }
  return statusMap[status] || 'info'
}
      0: "info", // 待发布
      1: "success", // 已通过
      2: "danger", // 未通过
    };
    return statusMap[status] || "info";
  };
// 获取状态文本
const getStatusText = (status) => {
  const getStatusText = status => {
  const statusMap = {
    '0': '待发布',
    '1': '已发布',
    '2': '已取消',
  }
  return statusMap[status] || '未知'
}
      0: "待发布",
      1: "已发布",
      2: "已取消",
    };
    return statusMap[status] || "未知";
  };
// 格式化日期时间
const formatDateTime = (dateTime) => {
  if (!dateTime) return ''
  return dateTime.replace(' ', '\n')
}
  const formatDateTime = dateTime => {
    if (!dateTime) return "";
    return dateTime.replace(" ", "\n");
  };
// 提交发布
const submitApproval = (status) => {
  const submitApproval = status => {
  // if (status === 'approved' && !publishComment.value.trim()) {
  //   ElMessage.warning('请填写发布意见')
  //   return
  // }
  ElMessageBox.confirm(
      `确认${status === '1' ? '发布' : '取消'}该会议?`,
      '发布确认',
      `确认${status === "1" ? "发布" : "取消"}该会议?`,
      "发布确认",
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }
  ).then(() => {
    )
      .then(() => {
    saveMeetingApplication({
      id: currentMeeting.value.id,
      publishStatus: status,
      publishComment: publishComment.value
          publishComment: publishComment.value,
    }).then(resp=>{
      // 更新会议状态
      currentMeeting.value.status = status
          currentMeeting.value.status = status;
      ElMessage.success('发布提交成功')
      approvalDialogVisible.value = false
      getList()
          ElMessage.success("发布提交成功");
          approvalDialogVisible.value = false;
          getList();
        });
    })
  }).catch(() => {
  })
}
      .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
    const [resp1, resp2] = await Promise.all([
      getRoomEnum(),
      userListNoPageByTenantId(),
    ]);
    roomEnum.value = resp1.data;
    const list = Array.isArray(resp2?.data) ? resp2.data : [];
    userList.value = list
      .map(item => ({
        userId: item?.userId,
        nickName: item?.nickName,
        userName: item?.userName,
        deptNames:
          item?.deptNames || (item?.dept?.deptName ? item.dept.deptName : ""),
      }))
      .filter(item => item.userId !== null && item.userId !== undefined);
  await getList()
})
    await getList();
  });
</script>
<style scoped>
src/views/collaborativeApproval/notificationManagement/summary/index.vue
@@ -1,153 +1,182 @@
<template>
  <div>
    <el-form :model="searchForm" inline>
    <el-form :model="searchForm"
             inline>
        <el-form-item label="会议主题">
          <el-input v-model="searchForm.title" placeholder="请输入会议主题" clearable />
        <el-input v-model="searchForm.title"
                  placeholder="请输入会议主题"
                  clearable />
        </el-form-item>
        <el-form-item label="申请人">
          <el-input v-model="searchForm.applicant" placeholder="请输入申请人" clearable />
        <el-input v-model="searchForm.applicant"
                  placeholder="请输入申请人"
                  clearable />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleSearch">搜索</el-button>
        <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="meetingList" 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">
      <el-table v-loading="loading"
                :data="meetingList"
                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">
        <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">
        <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"
            <el-button type="primary"
              link
              @click="addMinutes(scope.row)"
            >
                       @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"
      <pagination v-show="total > 0"
        :total="total"
        v-model:page="queryParams.current"
        v-model:limit="queryParams.size"
        @pagination="getList"
      />
                  @pagination="getList" />
    </el-card>
    <!-- 会议详情对话框 -->
    <el-dialog
      title="会议详情"
    <el-dialog title="会议详情"
      v-model="detailDialogVisible"
      width="800px"
    >
               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">{{
        <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">{{
          <el-descriptions-item label="申请人"
                                label-class-name="nowrap-label">{{
            currentMeeting.applicant
          }}</el-descriptions-item>
          <el-descriptions-item label="主持人" label-class-name="nowrap-label">{{
          <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">
          <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">{{
          <el-descriptions-item label="会议地点"
                                label-class-name="nowrap-label">{{
            currentMeeting.location
          }}</el-descriptions-item>
          <el-descriptions-item label="参会人数" label-class-name="nowrap-label">{{
          <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-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">{{
          <el-descriptions-item label="申请时间"
                                label-class-name="nowrap-label">{{
            currentMeeting.createTime
          }}</el-descriptions-item>
          <el-descriptions-item style="max-height: 400px" label="会议说明" :span="2"
          <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"
            <el-tag v-for="participant in currentMeeting.participants"
              :key="participant.id"
              style="margin-right: 10px; margin-bottom: 10px;"
            >
                    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="添加会议纪要"
    <el-dialog title="添加会议纪要"
      v-model="minutesDialogVisible"
      width="80%"
      @close="handleCloseMinutesDialog"
    >
               @close="handleCloseMinutesDialog">
      <div v-if="currentMeeting">
        <el-descriptions :column="2" border>
        <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">
          <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"
            />
            <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>
          <el-button type="primary"
                     @click="submitMinutes">保 存</el-button>
        </div>
      </template>
    </el-dialog>
@@ -155,104 +184,126 @@
</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 dayjs from "dayjs"
import {staffOnJobListPage} from "@/api/personnelManagement/staffOnJob.js";
  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 dayjs from "dayjs";
  import { userListNoPageByTenantId } from "@/api/system/user.js";
// 数据列表加载状态
const loading = ref(false)
  const loading = ref(false);
// 总条数
const total = ref(0)
  const total = ref(0);
// 表格高度(根据窗口高度自适应)
const tableHeight = ref(window.innerHeight - 380)
const roomEnum = ref([])
const staffList = ref([])
  const tableHeight = ref(window.innerHeight - 380);
  const roomEnum = ref([]);
  const userList = ref([]);
// 会议列表数据
const meetingList = ref([])
  const meetingList = ref([]);
// 查询参数
const queryParams = reactive({
  current: 1,
  size: 10
})
    size: 10,
  });
// 搜索表单
const searchForm = reactive({
  title: '',
  applicant: '',
    title: "",
    applicant: "",
  // status: '1' // 默认只显示已通过审批的会议
})
  });
// 是否显示对话框
const detailDialogVisible = ref(false)
const minutesDialogVisible = ref(false)
  const detailDialogVisible = ref(false);
  const minutesDialogVisible = ref(false);
// 当前查看的会议
const currentMeeting = ref(null)
  const currentMeeting = ref(null);
// 会议纪要内容
const minutesContent = ref('')
const minutesContentId = ref('')
  const minutesContent = ref("");
  const minutesContentId = ref("");
  const parseParticipants = raw => {
    if (!raw) return [];
    if (Array.isArray(raw)) return raw;
    try {
      const parsed = JSON.parse(raw);
      return Array.isArray(parsed) ? parsed : [];
    } catch (_e) {
      return [];
    }
  };
// 查询数据
const getList = async () => {
  loading.value = true
  let resp = await getMeetingPublish({ ...searchForm, ...queryParams })
    loading.value = true;
    let resp = await getMeetingPublish({ ...searchForm, ...queryParams });
    const userMap = new Map(userList.value.map(u => [String(u.userId), u]));
  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 => {
      let room = roomEnum.value.find(room => it.roomId === room.id);
      it.location = `${room.name}(${room.location})`;
      const participantIds = parseParticipants(it.participants);
      it.staffCount = participantIds.length;
      it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format(
        "HH:mm:ss"
      )} ~ ${dayjs(it.endTime).format("HH:mm:ss")}`;
      it.participants = participantIds.map(id => {
        const user = userMap.get(String(id));
        const nickName = user?.nickName || user?.userName || String(id ?? "");
        const deptNames = user?.deptNames || "";
      return {
        id: staff.id,
        name:  `${staff.staffName}${staff.postName ? ` (${staff.postName})` : ''}`
      }
    })
          id,
          name: deptNames ? `${nickName} (${deptNames})` : nickName,
        };
      });
    return it
  })
  total.value = resp.data.total
  loading.value = false
}
      return it;
    });
    total.value = resp.data.total;
    loading.value = false;
  };
// 搜索按钮操作
const handleSearch = () => {
  queryParams.current = 1
  getList()
}
    queryParams.current = 1;
    getList();
  };
// 重置搜索表单
const resetSearch = () => {
  Object.assign(searchForm, {
    title: '',
    applicant: '',
      title: "",
      applicant: "",
    // status: '1'
  })
  handleSearch()
}
    });
    handleSearch();
  };
// 查看详情
const viewDetail = (row) => {
  currentMeeting.value = row
  detailDialogVisible.value = true
}
  const viewDetail = row => {
    currentMeeting.value = row;
    detailDialogVisible.value = true;
  };
// 添加会议纪要
const addMinutes = async (row) => {
  let resp = await getMeetingMinutesByMeetingId(row.id)
  currentMeeting.value = row
  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
      minutesContent.value = resp.data.content;
      minutesContentId.value = resp.data.id;
  }else {
    minutesContent.value = `<h2>${row.title}会议纪要</h2>
<p><strong>会议时间:</strong>${row.meetingTime}</p>
@@ -260,7 +311,7 @@
<p><strong>主持人:</strong>${row.host}</p>
<p><strong>参会人员:</strong></p>
<ol>
  ${row.participants.map(p => `<li>${p.name}</li>`).join('')}
    ${row.participants.map(p => `<li>${p.name}</li>`).join("")}
</ol>
<p><strong>会议内容:</strong></p>
<ol>
@@ -277,72 +328,83 @@
    </ul>
  </li>
</ol>
<p><strong>备注:</strong></p>`
  <p><strong>备注:</strong></p>`;
  }
  minutesDialogVisible.value = true
}
    minutesDialogVisible.value = true;
  };
// 提交会议纪要
const submitMinutes = () => {
  if (!minutesContent.value) {
    ElMessage.warning('请输入会议纪要内容')
    return
      ElMessage.warning("请输入会议纪要内容");
      return;
  }
  saveMeetingMinutes({
    id: minutesContentId.value,
    content: minutesContent.value,
    meetingId: currentMeeting.value.id,
    title: currentMeeting.value.title
      title: currentMeeting.value.title,
  }).then(resp=>{
    console.log('会议纪要内容:', minutesContent.value)
    ElMessage.success('会议纪要保存成功')
    minutesDialogVisible.value = false
  })
}
      console.log("会议纪要内容:", minutesContent.value);
      ElMessage.success("会议纪要保存成功");
      minutesDialogVisible.value = false;
    });
  };
// 关闭会议纪要对话框
const handleCloseMinutesDialog = () => {
  minutesContent.value = ''
}
    minutesContent.value = "";
  };
// 获取状态类型
const getStatusType = (status) => {
  const getStatusType = status => {
  const statusMap = {
    '0': 'info',     // 待审批
    '1': 'success',  // 已通过
    '2': 'warning',  // 未通过
    '3': 'danger'   // 取消
  }
  return statusMap[status] || 'info'
}
      0: "info", // 待审批
      1: "success", // 已通过
      2: "warning", // 未通过
      3: "danger", // 取消
    };
    return statusMap[status] || "info";
  };
// 获取状态文本
const getStatusText = (status) => {
  const getStatusText = status => {
  const statusMap = {
    '0': '待审批',
    '1': '已通过',
    '2': '未通过',
    '3': '已取消'
  }
  return statusMap[status] || '未知'
}
      0: "待审批",
      1: "已通过",
      2: "未通过",
      3: "已取消",
    };
    return statusMap[status] || "未知";
  };
// 格式化日期时间
const formatDateTime = (dateTime) => {
  if (!dateTime) return ''
  return dateTime.replace(' ', '\n')
}
  const formatDateTime = dateTime => {
    if (!dateTime) return "";
    return dateTime.replace(" ", "\n");
  };
// 页面加载时获取数据
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
    const [resp1, resp2] = await Promise.all([
      getRoomEnum(),
      userListNoPageByTenantId(),
    ]);
    roomEnum.value = resp1.data;
    const list = Array.isArray(resp2?.data) ? resp2.data : [];
    userList.value = list
      .map(item => ({
        userId: item?.userId,
        nickName: item?.nickName,
        userName: item?.userName,
        deptNames:
          item?.deptNames || (item?.dept?.deptName ? item.dept.deptName : ""),
      }))
      .filter(item => item.userId !== null && item.userId !== undefined);
  await getList()
})
    await getList();
  });
</script>
<style scoped>