From 41c9d91da0c73303ea6f8eae03f030ce28b6cd1d Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期五, 16 一月 2026 16:08:02 +0800
Subject: [PATCH] 会议列表时间段修改
---
src/pages/managementMeetings/meetingList/index.vue | 537 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 537 insertions(+), 0 deletions(-)
diff --git a/src/pages/managementMeetings/meetingList/index.vue b/src/pages/managementMeetings/meetingList/index.vue
new file mode 100644
index 0000000..ad8a0de
--- /dev/null
+++ b/src/pages/managementMeetings/meetingList/index.vue
@@ -0,0 +1,537 @@
+<template>
+ <view class="meeting-list">
+ <PageHeader title="浼氳鍒楄〃"
+ @back="goBack" />
+ <!-- 鏌ヨ琛ㄥ崟 -->
+ <view class="search-section">
+ <view class="search-bar">
+ <view class="search-input">
+ <up-input class="search-text"
+ placeholder="鏌ヨ鏃ユ湡"
+ @click.stop="showDatePicker"
+ v-model="queryForm.meetingDate"
+ clearable />
+ </view>
+ <view class="filter-button"
+ @click="clearDate">
+ <u-icon name="close-circle-fill"
+ size="24"
+ color="#999"></u-icon>
+ </view>
+ </view>
+ </view>
+ <!-- 鏃ユ湡閫夋嫨鍣� -->
+ <up-datetime-picker v-model="datePickerValue"
+ mode="date"
+ :show="showDatePickerDialog"
+ @confirm="handleDateConfirm"
+ @cancel="showDatePickerDialog = false"
+ format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD" />
+ <!-- 浼氳瀹や娇鐢ㄦ儏鍐� -->
+ <view class="table-container">
+ <scroll-view scroll-x="true"
+ style="width: 100%;">
+ <view class="time-table">
+ <!-- 琛ㄥご -->
+ <view class="table-header">
+ <view class="header-cell room-header">浼氳瀹�</view>
+ <view v-for="timeSlot in timeSlots"
+ :key="timeSlot.value"
+ class="header-cell time-header">
+ {{ timeSlot.label }}
+ </view>
+ </view>
+ <!-- 琛ㄦ牸鍐呭 -->
+ <view class="table-body">
+ <view v-for="room in roomUsage"
+ :key="room.id"
+ class="table-row">
+ <view class="cell room-cell">{{ room.name }}</view>
+ <view class="cells-container">
+ <template v-for="(cell, index) in generateMeetingCells(room)"
+ :key="index">
+ <view class="cell content-cell"
+ :class="[cell.type, `status-${cell.meeting?.status || '0'}`]"
+ :style="{ width: `${cell.span * 120}rpx` }"
+ @click="viewMeetingDetails(cell)">
+ <view v-if="cell.type === 'meeting'"
+ class="meeting-content">
+ <view class="meeting-title">{{ cell.meeting.title }}</view>
+ <view class="meeting-time">{{ cell.startTime }}-{{ cell.endTime }}</view>
+ </view>
+ <view v-else
+ class="free-content">
+ 绌洪棽
+ </view>
+ </view>
+ </template>
+ </view>
+ </view>
+ </view>
+ </view>
+ </scroll-view>
+ </view>
+ <!-- 浼氳璇︽儏瀵硅瘽妗� -->
+ <u-popup :show="detailDialogVisible"
+ mode="center"
+ customStyle="width: 80%;"
+ :round="10">
+ <view class="dialog-content">
+ <view class="dialog-header">
+ <text class="dialog-title">浼氳璇︽儏</text>
+ <up-icon name="close"
+ @click="detailDialogVisible = false"
+ class="close-icon"></up-icon>
+ </view>
+ <view v-if="currentMeeting"
+ class="dialog-body">
+ <view class="detail-item">
+ <text class="detail-label">浼氳涓婚</text>
+ <text class="detail-value">{{ currentMeeting.title }}</text>
+ </view>
+ <view class="detail-item">
+ <text class="detail-label">浼氳瀹�</text>
+ <text class="detail-value">{{ currentMeeting.room }}</text>
+ </view>
+ <view class="detail-item">
+ <text class="detail-label">浼氳鏃堕棿</text>
+ <text class="detail-value">{{ currentMeeting.time }}</text>
+ </view>
+ <view class="detail-item">
+ <text class="detail-label">涓绘寔浜�</text>
+ <text class="detail-value">{{ currentMeeting.host }}</text>
+ </view>
+ <view class="detail-item">
+ <text class="detail-label">鍙備細浜烘暟</text>
+ <text class="detail-value">{{ currentMeeting.participants }}浜�</text>
+ </view>
+ <view class="detail-item">
+ <text class="detail-label">浼氳璇存槑</text>
+ <text class="detail-value">{{ currentMeeting.description }}</text>
+ </view>
+ </view>
+ <view class="dialog-footer">
+ <u-button @click="detailDialogVisible = false">鍏抽棴</u-button>
+ </view>
+ </view>
+ </u-popup>
+ </view>
+</template>
+
+<script setup>
+ import { ref, reactive, onMounted } from "vue";
+ import PageHeader from "@/components/PageHeader.vue";
+ import { getMeetingUseList } from "@/api/managementMeetings/meeting.js";
+ import dayjs from "dayjs";
+
+ // 鏌ヨ琛ㄥ崟
+ const queryForm = reactive({
+ meetingDate: dayjs().format("YYYY-MM-DD"),
+ });
+
+ const loading = ref(false);
+ const timeSlots = ref([]);
+ const roomUsage = ref([]);
+ const currentMeeting = ref(null);
+ const detailDialogVisible = ref(false);
+ const showDatePickerDialog = ref(false);
+ const datePickerValue = ref(Date.now());
+
+ // 杩斿洖涓婁竴椤�
+ const goBack = () => {
+ uni.navigateBack();
+ };
+
+ // 娓呯┖鏃ユ湡
+ const clearDate = () => {
+ datePickerValue.value = Date.now();
+ queryForm.meetingDate = dayjs().format("YYYY-MM-DD");
+ getList();
+ };
+
+ // 鏄剧ず鏃ユ湡閫夋嫨鍣�
+ const showDatePicker = () => {
+ if (queryForm.meetingDate) {
+ datePickerValue.value = new Date(queryForm.meetingDate).getTime();
+ } else {
+ datePickerValue.value = Date.now();
+ }
+ console.log(datePickerValue.value, "datePickerValue.value");
+ showDatePickerDialog.value = true;
+ };
+
+ // 澶勭悊鏃ユ湡閫夋嫨纭
+ const handleDateConfirm = value => {
+ // dayjs().format("YYYY-MM-DD")
+ console.log(value, "value");
+
+ queryForm.meetingDate = dayjs(value.value).format("YYYY-MM-DD");
+ showDatePickerDialog.value = false;
+ getList();
+ };
+
+ // 鑾峰彇鍒楄〃鏁版嵁
+ const getList = () => {
+ handleSearch();
+ };
+
+ // 鍒濆鍖栨椂闂存Ы锛堜互鍗婂皬鏃朵负闂撮殧锛屼粠8:00鍒�17:30锛�
+ const initTimeSlots = () => {
+ const slots = [];
+ // 鐢熸垚8:00鍒�17:00鐨勬椂闂存
+ for (let hour = 8; hour <= 17; hour++) {
+ // 娣诲姞鏁寸偣
+ slots.push({
+ label: `${hour.toString().padStart(2, "0")}:00`,
+ value: `${hour.toString().padStart(2, "0")}:00`,
+ });
+
+ // 娣诲姞鍗婄偣锛岀洿鍒�17:30
+ if (hour <= 17) {
+ slots.push({
+ label: `${hour.toString().padStart(2, "0")}:30`,
+ value: `${hour.toString().padStart(2, "0")}:30`,
+ });
+ }
+ }
+ // 绉婚櫎鏈�鍚庝竴涓�18:00鐨勬椂闂存
+ if (slots.length > 0 && slots[slots.length - 1].value === "18:00") {
+ slots.pop();
+ }
+ timeSlots.value = slots;
+ console.log(timeSlots.value, "timeSlots.value");
+ };
+
+ // 鐢熸垚浼氳瀹ょ殑鏃堕棿鍗曞厓鏍�
+ const generateMeetingCells = room => {
+ const cells = [];
+ const meetings = room.meetings || [];
+ const occupiedSlots = new Set();
+
+ // 澶勭悊姣忎釜浼氳
+ for (const meeting of meetings) {
+ 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;
+ }
+
+ if (startIdx !== -1) {
+ // 鏍囪琚崰鐢ㄧ殑鏃堕棿娈�
+ for (let i = startIdx; i < endIdx; i++) {
+ if (timeSlots.value[i]) {
+ occupiedSlots.add(timeSlots.value[i].value);
+ }
+ }
+
+ // 鍒涘缓浼氳鍗曞厓鏍�
+ cells.push({
+ type: "meeting",
+ meeting: meeting,
+ span: endIdx - startIdx,
+ startTime: meeting.startTime,
+ endTime: meeting.endTime,
+ });
+ }
+ }
+
+ // 澶勭悊绌洪棽鏃堕棿娈�
+ 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)
+ ) {
+ occupiedSlots.add(timeSlots.value[i + span].value);
+ span++;
+ }
+
+ cells.push({
+ type: "free",
+ span: span,
+ time: slot.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)
+ );
+ });
+ console.log(cells, "cells");
+ return cells;
+ };
+
+ // 鏌ョ湅浼氳璇︽儏
+ const viewMeetingDetails = cell => {
+ console.log(cell, "cell");
+
+ if (cell && cell.type === "meeting") {
+ currentMeeting.value = cell.meeting;
+ detailDialogVisible.value = true;
+ } else {
+ uni.showToast({
+ title: "璇ユ椂闂存浼氳瀹ょ┖闂�",
+ icon: "info",
+ });
+ }
+ };
+
+ // 鏌ヨ鎸夐挳鎿嶄綔
+ const handleSearch = async () => {
+ loading.value = true;
+ try {
+ const resp = await getMeetingUseList({ ...queryForm });
+ roomUsage.value = resp.data;
+ } catch (error) {
+ uni.showToast({
+ title: "鑾峰彇鏁版嵁澶辫触",
+ icon: "error",
+ });
+ } finally {
+ loading.value = false;
+ }
+ };
+
+ // 閲嶇疆鎼滅储琛ㄥ崟
+ const resetSearch = () => {
+ queryForm.meetingDate = dayjs().format("YYYY-MM-DD");
+ };
+
+ // 椤甸潰鍔犺浇鏃惰幏鍙栨暟鎹�
+ onMounted(() => {
+ // 鍒濆鍖栨椂闂存Ы
+ initTimeSlots();
+
+ // 榛樿鏌ヨ浠婂ぉ鐨勬暟鎹�
+ handleSearch();
+ });
+</script>
+
+<style scoped lang="scss">
+ @import "../../../styles/sales-common.scss";
+ .meeting-list {
+ min-height: 100vh;
+ background: #f8f9fa;
+ padding: 16rpx;
+ }
+
+ .search-section {
+ background: #fff;
+ padding: 16rpx;
+ border-radius: 8rpx;
+ margin-bottom: 16rpx;
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
+ }
+
+ .search-bar {
+ display: flex;
+ align-items: center;
+ gap: 12rpx;
+ }
+
+ .search-input {
+ flex: 1;
+ }
+
+ .filter-button {
+ padding: 12rpx 16rpx;
+ background: #f5f7fa;
+ border-radius: 4rpx;
+ }
+
+ .form-buttons {
+ display: flex;
+ gap: 12rpx;
+ margin-top: 16rpx;
+ justify-content: center;
+ }
+
+ .table-container {
+ margin-top: 16rpx;
+ overflow-x: auto;
+ }
+
+ .time-table {
+ width: 100%;
+ }
+
+ .table-header {
+ display: flex;
+ border: 1rpx solid #e4e7ed;
+ background: #f5f7fa;
+ }
+
+ .header-cell {
+ padding: 12rpx 8rpx;
+ text-align: center;
+ font-weight: bold;
+ border-right: 1rpx solid #e4e7ed;
+ }
+
+ .room-header {
+ width: 120rpx;
+ flex-shrink: 0;
+ }
+
+ .time-header {
+ width: 120rpx;
+ flex-shrink: 0;
+ }
+
+ .table-body {
+ border: 1rpx solid #e4e7ed;
+ border-top: none;
+ }
+
+ .table-row {
+ display: flex;
+ border-top: 1rpx solid #e4e7ed;
+ }
+
+ .table-row:first-child {
+ border-top: none;
+ }
+
+ .cell {
+ padding: 16rpx 8rpx;
+ text-align: center;
+ border-right: 1rpx solid #e4e7ed;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ word-break: break-word;
+ line-height: 1.2;
+ }
+
+ .room-cell {
+ width: 120rpx;
+ font-weight: bold;
+ flex-shrink: 0;
+ background: #f9fafc;
+ }
+
+ .cells-container {
+ display: flex;
+ }
+
+ .content-cell {
+ min-height: 120rpx;
+ cursor: pointer;
+ transition: all 0.3s;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ padding: 16rpx;
+ box-sizing: border-box;
+ }
+
+ .content-cell:active {
+ opacity: 0.8;
+ }
+
+ .free {
+ color: #f56c6c;
+ }
+
+ .meeting {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ }
+
+ .status-1 {
+ background-color: #fef0f0;
+ color: #d14646;
+ }
+
+ .status-0 {
+ background-color: #ecf5ff;
+ color: #409eff;
+ }
+
+ .meeting-content {
+ width: 100%;
+ }
+
+ .meeting-title {
+ font-weight: bold;
+ margin-bottom: 8rpx;
+ font-size: 24rpx;
+ }
+
+ .meeting-time {
+ font-size: 20rpx;
+ opacity: 0.8;
+ }
+
+ .free-content {
+ color: #909399;
+ }
+
+ /* 瀵硅瘽妗嗘牱寮� */
+ .dialog-content {
+ padding: 24rpx;
+ }
+
+ .dialog-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 24rpx;
+ padding-bottom: 16rpx;
+ border-bottom: 1rpx solid #e4e7ed;
+ }
+
+ .dialog-title {
+ font-size: 32rpx;
+ font-weight: bold;
+ color: #303133;
+ }
+
+ .close-icon {
+ font-size: 32rpx;
+ color: #909399;
+ }
+
+ .dialog-body {
+ margin-bottom: 24rpx;
+ }
+
+ .detail-item {
+ display: flex;
+ margin-bottom: 16rpx;
+ padding: 8rpx 0;
+ border-bottom: 1rpx solid #f0f0f0;
+ }
+
+ .detail-label {
+ width: 140rpx;
+ font-weight: bold;
+ color: #606266;
+ }
+
+ .detail-value {
+ flex: 1;
+ color: #303133;
+ }
+
+ .dialog-footer {
+ display: flex;
+ justify-content: center;
+ margin-top: 16rpx;
+ }
+</style>
\ No newline at end of file
--
Gitblit v1.9.3