Merge remote-tracking branch 'origin/dev_新疆_大罗素马铃薯new' into dev_新疆_大罗素马铃薯new
| | |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="开始时间" prop="startTime"> |
| | | <el-select |
| | | <el-time-picker |
| | | v-model="meetingForm.startTime" |
| | | placeholder="请选择开始时间" |
| | | value-format="HH:mm" |
| | | format="HH:mm" |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="time in startTimeOptions" |
| | | :key="time.value" |
| | | :label="time.label" |
| | | :value="time.value" |
| | | /> |
| | | </el-select> |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="结束时间" prop="endTime"> |
| | | <el-select |
| | | <el-time-picker |
| | | v-model="meetingForm.endTime" |
| | | placeholder="请选择结束时间" |
| | | value-format="HH:mm" |
| | | format="HH:mm" |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="time in endTimeOptions" |
| | | :key="time.value" |
| | | :label="time.label" |
| | | :value="time.value" |
| | | /> |
| | | </el-select> |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {ref, reactive, onMounted, computed, watch} from 'vue' |
| | | import {ref, reactive, onActivated} from 'vue' |
| | | import {ElMessage} from 'element-plus' |
| | | import {Plus, Document, Promotion, Bell} from '@element-plus/icons-vue' |
| | | import {Document, Promotion, Bell} from '@element-plus/icons-vue' |
| | | import {getRoomEnum, saveMeetingApplication} from '@/api/collaborativeApproval/meeting.js' |
| | | import {userListNoPageByTenantId} from "@/api/system/user.js"; |
| | | |
| | |
| | | // 员工列表 |
| | | const employees = ref([]) |
| | | |
| | | // 时间选项(以半小时为间隔) |
| | | const timeOptions = ref([]) |
| | | |
| | | 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 validateStartTime = (_rule, value, callback) => { |
| | | if (!value) { |
| | | callback() |
| | | return |
| | | } |
| | | |
| | | if (isToday(meetingForm.meetingDate)) { |
| | | const now = new Date() |
| | | const currentMinutes = now.getHours() * 60 + now.getMinutes() |
| | | if (getTimeInMinutes(value) > currentMinutes) { |
| | | callback(new Error('当天开始时间不能晚于当前时间')) |
| | | return |
| | | } |
| | | } |
| | | |
| | | callback() |
| | | } |
| | | |
| | | const validateEndTime = (_rule, value, callback) => { |
| | | if (!value || !meetingForm.startTime) { |
| | | callback() |
| | | return |
| | | } |
| | | |
| | | if (getTimeInMinutes(value) <= getTimeInMinutes(meetingForm.startTime)) { |
| | | callback(new Error('结束时间必须大于开始时间')) |
| | | return |
| | | } |
| | | |
| | | 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'}], |
| | | startTime: [ |
| | | {required: true, message: '请选择开始时间', trigger: 'change'}, |
| | | {validator: validateStartTime, trigger: 'change'} |
| | | ], |
| | | endTime: [ |
| | | {required: true, message: '请选择结束时间', trigger: 'change'}, |
| | | {validator: validateEndTime, trigger: 'change'} |
| | | ], |
| | | startTime: [{required: true, message: '请选择开始时间', trigger: 'change'}], |
| | | endTime: [{required: true, message: '请选择结束时间', trigger: 'change'}], |
| | | participants: [{required: true, message: '请选择参会人员', trigger: 'change'}] |
| | | } |
| | | |
| | | const startTimeOptions = computed(() => { |
| | | if (!isToday(meetingForm.meetingDate)) { |
| | | return timeOptions.value |
| | | } |
| | | 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 |
| | | } |
| | | 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() |
| | | // meetingDate 是 "yyyy-MM-dd" |
| | | const meetingDate = new Date(meetingForm.meetingDate) |
| | | |
| | | const isSameDay = |
| | | now.getFullYear() === meetingDate.getFullYear() && |
| | | now.getMonth() === meetingDate.getMonth() && |
| | | now.getDate() === meetingDate.getDate() |
| | | |
| | | console.log('是否同一天:', isSameDay) |
| | | for (let hour = 8; hour <= 18; hour++) { |
| | | // 开始时间必须晚于当前时间 |
| | | if (hour < currentHour && isSameDay) { |
| | | continue |
| | | } |
| | | if (hour === currentHour && currentMinute > 30 && isSameDay) { |
| | | continue |
| | | } |
| | | // 每个小时添加两个选项:整点和半点 |
| | | options.push({ |
| | | value: `${hour.toString().padStart(2, '0')}:00`, |
| | | label: `${hour.toString().padStart(2, '0')}:00` |
| | | }) |
| | | |
| | | if (hour < 18) { // 18:00之后没有半点选项 |
| | | options.push({ |
| | | value: `${hour.toString().padStart(2, '0')}:30`, |
| | | label: `${hour.toString().padStart(2, '0')}:30` |
| | | }) |
| | | } |
| | | } |
| | | timeOptions.value = options |
| | | } |
| | | |
| | | 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.startTime) { |
| | | meetingFormRef.value?.validateField('startTime') |
| | | } |
| | | if (meetingForm.endTime) { |
| | | meetingFormRef.value?.validateField('endTime') |
| | | } |
| | | initTimeOptions() |
| | | }) |
| | | |
| | | watch(() => meetingForm.startTime, () => { |
| | | if (meetingForm.endTime && getTimeInMinutes(meetingForm.endTime) <= getTimeInMinutes(meetingForm.startTime)) { |
| | | meetingForm.endTime = '' |
| | | } |
| | | if (meetingForm.endTime) { |
| | | meetingFormRef.value?.validateField('endTime') |
| | | } |
| | | |
| | | }) |
| | | |
| | | // 禁用日期(禁用今天之前的日期) |
| | | const disabledDate = (time) => { |
| | |
| | | |
| | | // 模拟提交操作 |
| | | ElMessage.success(`${getCurrentTypeName()}提交成功`) |
| | | |
| | | // 根据不同类型执行不同操作 |
| | | switch (currentType.value) { |
| | | case 'approval': |
| | | ElMessage.info('会议已提交审批流程') |
| | | break |
| | | case 'department': |
| | | ElMessage.info('部门级会议申请已提交') |
| | | break |
| | | case 'notification': |
| | | ElMessage.info('会议通知已发布') |
| | | break |
| | | } |
| | | resetForm() |
| | | }) |
| | | |
| | |
| | | } |
| | | |
| | | // 页面加载时初始化 |
| | | onMounted(() => { |
| | | initTimeOptions() |
| | | onActivated(() => { |
| | | getRoomEnum().then(res => { |
| | | meetingRooms.value = res.data |
| | | }) |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {ref, reactive, onMounted} from 'vue' |
| | | import {ref, reactive, onMounted, onActivated} 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) |
| | |
| | | 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.staffCount = staffs.length |
| | | 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 => { |
| | | it.participants = staffList.value.filter(staff => staffs.some(id => id == staff.userId)).map(staff => { |
| | | return { |
| | | id: staff.id, |
| | | name: `${staff.staffName}${staff.postName ? ` (${staff.postName})` : ''}` |
| | | id: staff.userId, |
| | | name: `${staff.nickName || staff.userName}${staff.dept?.deptName ? ` (${staff.dept.deptName})` : ''}` |
| | | } |
| | | }) |
| | | |
| | |
| | | |
| | | // 页面加载时获取数据 |
| | | onMounted(async () => { |
| | | const [resp1, resp2]= await Promise.all([getRoomEnum(), staffOnJobListPage({current: -1, size: -1, staffState: 1})]) |
| | | const [resp1, resp2]= await Promise.all([getRoomEnum(), userListNoPageByTenantId()]) |
| | | roomEnum.value = resp1.data |
| | | staffList.value = resp2.data.records |
| | | staffList.value = resp2.data || [] |
| | | }) |
| | | |
| | | await getList() |
| | | onActivated(() => { |
| | | getList() |
| | | }) |
| | | </script> |
| | | |
| | |
| | | <div |
| | | class="cell content-cell" |
| | | :class="[cell.type, `status-${cell.meeting?.status || '0'}`]" |
| | | :style="{ flex: cell.span-0.2 }" |
| | | :style="{ flex: cell.span }" |
| | | @click="viewMeetingDetails(cell)" |
| | | > |
| | | <div v-if="cell.type === 'meeting'" class="meeting-content"> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {ref, reactive, onMounted} from 'vue' |
| | | import {ref, reactive, onMounted, onActivated} from 'vue' |
| | | import {ElMessage} from 'element-plus' |
| | | import {getMeetingUseList} from "@/api/collaborativeApproval/meeting.js" |
| | | import dayjs from "dayjs"; |
| | |
| | | // 是否显示详情对话框 |
| | | const detailDialogVisible = ref(false) |
| | | |
| | | // 初始化时间槽(以半小时为间隔,从8:00到18:00) |
| | | // 初始化时间槽(以半小时为间隔,从8:00到19:00) |
| | | const initTimeSlots = () => { |
| | | const slots = [] |
| | | for (let hour = 8; hour < 18; hour++) { |
| | | for (let hour = 8; hour < 19; hour++) { |
| | | // 每个小时添加两个时间段:整点和半点 |
| | | slots.push({ |
| | | label: `${hour.toString().padStart(2, '0')}:00`, |
| | | value: `${hour.toString().padStart(2, '0')}:00` |
| | | }) |
| | | |
| | | if (hour < 18) { // 到17:30为止 |
| | | if (hour < 19) { // 到18:30为止 |
| | | slots.push({ |
| | | label: `${hour.toString().padStart(2, '0')}:30`, |
| | | value: `${hour.toString().padStart(2, '0')}:30` |
| | |
| | | timeSlots.value = slots |
| | | } |
| | | |
| | | const toMinutes = (time) => { |
| | | if (!time) return 0 |
| | | const [h, m] = time.split(':').map(Number) |
| | | return h * 60 + m |
| | | } |
| | | |
| | | // 生成会议室的时间单元格 |
| | | const generateMeetingCells = (room) => { |
| | | const cells = [] |
| | | const meetings = room.meetings || [] |
| | | const occupiedSlots = new Set() |
| | | |
| | | // 处理每个会议 |
| | | for (const meeting of meetings) { |
| | | const startMin = toMinutes(meeting.startTime) |
| | | const endMin = toMinutes(meeting.endTime) |
| | | |
| | | const startIdx = timeSlots.value.findIndex(slot => slot.value === meeting.startTime) |
| | | let endIdx = timeSlots.value.findIndex(slot => slot.value === meeting.endTime) |
| | | if (endIdx === -1) { |
| | | endIdx = timeSlots.value.length |
| | | } |
| | | console.log('endIdx111', endIdx) |
| | | if (startIdx !== -1 && endIdx !== -1) { |
| | | // 标记被占用的时间段 |
| | | // 找到第一个时间 > startMin 的槽位,再往前退一格 |
| | | let startIdx = timeSlots.value.findIndex(slot => toMinutes(slot.value) > startMin) |
| | | if (startIdx === -1) startIdx = timeSlots.value.length |
| | | startIdx = Math.max(0, startIdx - 1) |
| | | |
| | | // 找到第一个时间 >= endMin 的槽位,没找到则延伸到末尾 |
| | | let endIdx = timeSlots.value.findIndex(slot => toMinutes(slot.value) >= endMin) |
| | | if (endIdx === -1) endIdx = timeSlots.value.length |
| | | |
| | | if (startIdx < endIdx) { |
| | | for (let i = startIdx; i < endIdx; i++) { |
| | | occupiedSlots.add(timeSlots.value[i].value) |
| | | } |
| | | |
| | | // 创建会议单元格 |
| | | cells.push({ |
| | | type: 'meeting', |
| | | meeting: meeting, |
| | |
| | | } |
| | | } |
| | | |
| | | // 处理空闲时间段 |
| | | for (let i = 0; i < timeSlots.value.length; i++) { |
| | | const slot = timeSlots.value[i] |
| | | if (!occupiedSlots.has(slot.value)) { |
| | | // 查找连续的空闲时间段 |
| | | let span = 1 |
| | | while (i + span < timeSlots.value.length && |
| | | !occupiedSlots.has(timeSlots.value[i + span].value)) { |
| | |
| | | } |
| | | } |
| | | |
| | | // 按时间排序 |
| | | cells.sort((a, b) => { |
| | | const timeA = a.startTime || a.time |
| | | const timeB = b.startTime || b.time |
| | | return timeSlots.value.findIndex(s => s.value === timeA) - |
| | | timeSlots.value.findIndex(s => s.value === timeB) |
| | | return toMinutes(timeA) - toMinutes(timeB) |
| | | }) |
| | | console.log('cells', cells) |
| | | return cells |
| | | } |
| | | |
| | |
| | | |
| | | // 页面加载时获取数据 |
| | | onMounted(() => { |
| | | // 初始化时间槽 |
| | | initTimeSlots() |
| | | }) |
| | | |
| | | // 默认查询今天的数据 |
| | | const today = new Date() |
| | | queryForm.date = today.toISOString().split('T')[0] |
| | | onActivated(() => { |
| | | handleSearch() |
| | | }) |
| | | </script> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {ref, reactive, onMounted} from 'vue' |
| | | import {ref, reactive, onMounted, onActivated} 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) |
| | |
| | | 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.staffCount = staffs.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 = staffList.value.filter(staff => staffs.some(id=>id === staff.id)).map(staff => { |
| | | it.participants = staffList.value.filter(staff => staffs.some(id => id == staff.userId)).map(staff => { |
| | | return { |
| | | id: staff.id, |
| | | name: `${staff.staffName}${staff.postName ? ` (${staff.postName})` : ''}` |
| | | id: staff.userId, |
| | | name: `${staff.nickName || staff.userName}${staff.dept?.deptName ? ` (${staff.dept.deptName})` : ''}` |
| | | } |
| | | }) |
| | | |
| | |
| | | |
| | | // 页面加载时获取数据 |
| | | onMounted(async () => { |
| | | const [resp1, resp2]= await Promise.all([getRoomEnum(), staffOnJobListPage({current: -1, size: -1, staffState: 1})]) |
| | | const [resp1, resp2]= await Promise.all([getRoomEnum(), userListNoPageByTenantId()]) |
| | | roomEnum.value = resp1.data |
| | | staffList.value = resp2.data.records |
| | | staffList.value = resp2.data || [] |
| | | }) |
| | | |
| | | await getList() |
| | | onActivated(() => { |
| | | getList() |
| | | }) |
| | | </script> |
| | | |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted, getCurrentInstance } from 'vue' |
| | | import { ref, reactive, onActivated, getCurrentInstance } from 'vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { Plus } from '@element-plus/icons-vue' |
| | | import Pagination from '@/components/Pagination/index.vue' |
| | |
| | | proxy.download('/meeting/export', { ...searchForm }, '会议室设置.xlsx') |
| | | } |
| | | |
| | | // 页面加载时获取数据 |
| | | onMounted(() => { |
| | | onActivated(() => { |
| | | getList() |
| | | }) |
| | | </script> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from 'vue' |
| | | import { ref, reactive, onMounted, onActivated } 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 {userListNoPageByTenantId} from "@/api/system/user.js"; |
| | | |
| | | // 数据列表加载状态 |
| | | const loading = ref(false) |
| | |
| | | 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.staffCount = staffs.length |
| | | 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 => { |
| | | it.participants = staffList.value.filter(staff => staffs.some(id => id == staff.userId)).map(staff => { |
| | | return { |
| | | id: staff.id, |
| | | name: `${staff.staffName}${staff.postName ? ` (${staff.postName})` : ''}` |
| | | id: staff.userId, |
| | | name: `${staff.nickName || staff.userName}${staff.dept?.deptName ? ` (${staff.dept.deptName})` : ''}` |
| | | } |
| | | }) |
| | | |
| | |
| | | |
| | | // 页面加载时获取数据 |
| | | onMounted(async () => { |
| | | const [resp1, resp2] = await Promise.all([getRoomEnum(), staffOnJobListPage({current: -1, size: -1, staffState: 1})]) |
| | | const [resp1, resp2] = await Promise.all([getRoomEnum(), userListNoPageByTenantId()]) |
| | | roomEnum.value = resp1.data |
| | | staffList.value = resp2.data.records |
| | | staffList.value = resp2.data || [] |
| | | }) |
| | | |
| | | await getList() |
| | | onActivated(() => { |
| | | getList() |
| | | }) |
| | | </script> |
| | | |