|
|
@@ -0,0 +1,1352 @@
|
|
|
+<template>
|
|
|
+ <div class="p-2 page-container">
|
|
|
+ <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
|
|
+ <div ref="searchRef" v-show="showSearch" class="mb-[10px]">
|
|
|
+ <el-card shadow="hover">
|
|
|
+ <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="100px">
|
|
|
+ <el-form-item label="报告厅ID" prop="hallId">
|
|
|
+ <el-input v-model="queryParams.hallId" placeholder="请输入报告厅ID" clearable @keyup.enter="handleQuery" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="报告厅名称" prop="hallName">
|
|
|
+ <el-input v-model="queryParams.hallName" placeholder="请输入报告厅名称" clearable @keyup.enter="handleQuery" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="预约开始时间" prop="startTime">
|
|
|
+ <el-date-picker clearable v-model="queryParams.startTime" type="date" placeholder="请选择开始时间" value-format="YYYY-MM-DD" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="预约结束时间" prop="endTime">
|
|
|
+ <el-date-picker clearable v-model="queryParams.endTime" type="date" placeholder="请选择结束时间" value-format="YYYY-MM-DD" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="申请人姓名" prop="applicantName">
|
|
|
+ <el-input v-model="queryParams.applicantName" placeholder="请输入申请人姓名" clearable @keyup.enter="handleQuery" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="预约状态" prop="status">
|
|
|
+ <el-select v-model="queryParams.status" placeholder="请选择预约状态" clearable>
|
|
|
+ <el-option v-for="dict in hall_reserv_status" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
|
|
+ <el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </el-card>
|
|
|
+ </div>
|
|
|
+ </transition>
|
|
|
+
|
|
|
+ <el-card shadow="never" class="button-card table-card">
|
|
|
+ <template #header>
|
|
|
+ <el-row ref="toolbarRef" :gutter="10" class="mb8">
|
|
|
+ <el-col :span="1.5">
|
|
|
+ <el-button type="success" plain icon="Check" :disabled="multiple" @click="handleApprove()" v-hasPermi="['hq:hallReservation:audit']"
|
|
|
+ >批准</el-button
|
|
|
+ >
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="1.5">
|
|
|
+ <el-button type="danger" plain icon="Close" :disabled="multiple" @click="handleReject()" v-hasPermi="['hq:hallReservation:audit']"
|
|
|
+ >拒绝</el-button
|
|
|
+ >
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="1.5">
|
|
|
+ <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['hq:hallReservation:export']">导出</el-button>
|
|
|
+ </el-col>
|
|
|
+ <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
|
|
+ </el-row>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <el-table
|
|
|
+ v-loading="loading"
|
|
|
+ border
|
|
|
+ :data="hallReservationList"
|
|
|
+ @selection-change="handleSelectionChange"
|
|
|
+ :height="tableHeight"
|
|
|
+ style="margin-bottom: 0"
|
|
|
+ >
|
|
|
+ <el-table-column type="selection" width="55" align="center" />
|
|
|
+ <el-table-column label="报告厅ID" align="center" prop="hallId" />
|
|
|
+ <el-table-column label="报告厅名称" align="center" prop="hallName" />
|
|
|
+ <el-table-column label="申请人" align="center" prop="applicantName" />
|
|
|
+ <el-table-column label="申请人电话" align="center" prop="applicantPhone" />
|
|
|
+ <el-table-column label="预约开始时间" align="center" prop="startTime" width="200">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ parseTime(scope.row.startTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="预约结束时间" align="center" prop="endTime" width="200">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ parseTime(scope.row.endTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="预约用途" align="center" prop="reservationPurpose" min-width="120">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-tooltip
|
|
|
+ :content="scope.row.reservationPurpose"
|
|
|
+ placement="top"
|
|
|
+ :disabled="!scope.row.reservationPurpose || scope.row.reservationPurpose.length <= 100"
|
|
|
+ popper-class="purpose-tooltip"
|
|
|
+ :show-after="300"
|
|
|
+ :hide-after="100"
|
|
|
+ effect="dark"
|
|
|
+ >
|
|
|
+ <span class="purpose-text">
|
|
|
+ {{
|
|
|
+ scope.row.reservationPurpose && scope.row.reservationPurpose.length > 100
|
|
|
+ ? scope.row.reservationPurpose.substring(0, 100) + '...'
|
|
|
+ : scope.row.reservationPurpose
|
|
|
+ }}
|
|
|
+ </span>
|
|
|
+ </el-tooltip>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="预约状态" align="center" prop="status">
|
|
|
+ <template #default="scope">
|
|
|
+ <dict-tag :options="hall_reserv_status" :value="scope.row.status" />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="审核人" align="center" prop="auditName" />
|
|
|
+ <el-table-column label="审核时间" align="center" prop="auditTime" width="200">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ parseTime(scope.row.auditTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="审核备注" align="center" prop="auditRemark" min-width="120">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-tooltip
|
|
|
+ :content="scope.row.auditRemark"
|
|
|
+ placement="top"
|
|
|
+ :disabled="!scope.row.auditRemark || scope.row.auditRemark.length <= 100"
|
|
|
+ popper-class="audit-remark-tooltip"
|
|
|
+ :show-after="300"
|
|
|
+ :hide-after="100"
|
|
|
+ effect="dark"
|
|
|
+ >
|
|
|
+ <span class="audit-remark-text">
|
|
|
+ {{
|
|
|
+ scope.row.auditRemark && scope.row.auditRemark.length > 100
|
|
|
+ ? scope.row.auditRemark.substring(0, 100) + '...'
|
|
|
+ : scope.row.auditRemark
|
|
|
+ }}
|
|
|
+ </span>
|
|
|
+ </el-tooltip>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="220">
|
|
|
+ <template #default="scope">
|
|
|
+ <!-- 查看按钮,所有记录都可以查看 -->
|
|
|
+ <el-tooltip content="查看" placement="top">
|
|
|
+ <el-button
|
|
|
+ link
|
|
|
+ type="info"
|
|
|
+ icon="View"
|
|
|
+ size="default"
|
|
|
+ style="font-size: 16px; margin-right: 8px"
|
|
|
+ @click="handleView(scope.row)"
|
|
|
+ ></el-button>
|
|
|
+ </el-tooltip>
|
|
|
+
|
|
|
+ <!-- 只有审核中的记录可以进行审核操作 -->
|
|
|
+ <template v-if="scope.row.status === '0'">
|
|
|
+ <el-tooltip content="批准" placement="top">
|
|
|
+ <el-button
|
|
|
+ link
|
|
|
+ type="success"
|
|
|
+ icon="Check"
|
|
|
+ size="default"
|
|
|
+ style="font-size: 16px; margin-right: 8px"
|
|
|
+ @click="handleApprove(scope.row)"
|
|
|
+ v-hasPermi="['hq:hallReservation:audit']"
|
|
|
+ ></el-button>
|
|
|
+ </el-tooltip>
|
|
|
+ <el-tooltip content="拒绝" placement="top">
|
|
|
+ <el-button
|
|
|
+ link
|
|
|
+ type="danger"
|
|
|
+ icon="Close"
|
|
|
+ size="default"
|
|
|
+ style="font-size: 16px"
|
|
|
+ @click="handleReject(scope.row)"
|
|
|
+ v-hasPermi="['hq:hallReservation:audit']"
|
|
|
+ ></el-button>
|
|
|
+ </el-tooltip>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <pagination
|
|
|
+ v-show="total > 0"
|
|
|
+ :total="total"
|
|
|
+ v-model:page="queryParams.pageNum"
|
|
|
+ v-model:limit="queryParams.pageSize"
|
|
|
+ @pagination="getList"
|
|
|
+ class="pagination-container"
|
|
|
+ />
|
|
|
+ </el-card>
|
|
|
+
|
|
|
+ <!-- 查看报告厅预约详情对话框 -->
|
|
|
+ <el-dialog :title="viewDialog.title" v-model="viewDialog.visible" width="700px" append-to-body>
|
|
|
+ <el-form :model="viewForm" label-width="120px" class="view-form">
|
|
|
+ <el-form-item label="报告厅ID">
|
|
|
+ <span class="form-text">{{ viewForm.hallId }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="报告厅名称">
|
|
|
+ <span class="form-text">{{ viewForm.hallName }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ <!-- 报告厅图片展示区域 -->
|
|
|
+ <el-form-item label="报告厅图片" v-if="viewHallImages.length > 0">
|
|
|
+ <div class="view-hall-images">
|
|
|
+ <div class="image-gallery">
|
|
|
+ <div v-for="(image, index) in viewHallImages" :key="index" class="image-item" @click="previewImage(image, index)">
|
|
|
+ <img :src="image" class="gallery-image" @error="handleImageError" />
|
|
|
+ <div class="image-overlay">
|
|
|
+ <el-icon class="preview-icon"><ZoomIn /></el-icon>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="预约开始时间">
|
|
|
+ <span class="form-text">{{ parseTime(viewForm.startTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="预约结束时间">
|
|
|
+ <span class="form-text">{{ parseTime(viewForm.endTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="预约用途">
|
|
|
+ <div class="purpose-view">
|
|
|
+ {{ viewForm.reservationPurpose }}
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="申请人信息">
|
|
|
+ <div class="applicant-info">
|
|
|
+ <p><strong>姓名:</strong>{{ viewForm.applicantName }}</p>
|
|
|
+ <p><strong>电话:</strong>{{ viewForm.applicantPhone }}</p>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="预约状态">
|
|
|
+ <dict-tag :options="hall_reserv_status" :value="viewForm.status" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="审核人" v-if="viewForm.auditName">
|
|
|
+ <span class="form-text">{{ viewForm.auditName }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="审核时间" v-if="viewForm.auditTime">
|
|
|
+ <span class="form-text">{{ parseTime(viewForm.auditTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="审核备注" v-if="viewForm.auditRemark">
|
|
|
+ <div class="audit-remark">
|
|
|
+ {{ viewForm.auditRemark }}
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <div class="dialog-footer">
|
|
|
+ <el-button @click="closeView">关 闭</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 审核对话框 -->
|
|
|
+ <el-dialog :title="auditDialog.title" v-model="auditDialog.visible" width="800px" append-to-body>
|
|
|
+ <el-form ref="auditFormRef" :model="auditForm" :rules="auditRules" label-width="120px" class="audit-form">
|
|
|
+ <!-- 按报告厅分组显示预约信息 -->
|
|
|
+ <el-form-item label="审核详情">
|
|
|
+ <div class="audit-details">
|
|
|
+ <div v-for="(hallGroup, hallName) in groupedReservations" :key="`hall-group-${hallName}`" class="hall-group">
|
|
|
+ <!-- 报告厅信息 -->
|
|
|
+ <div class="hall-info-section">
|
|
|
+ <div class="hall-header">
|
|
|
+ <div class="hall-name">{{ hallName }}</div>
|
|
|
+ <div class="hall-id">ID: {{ hallGroup.hallId }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="hall-images" v-if="getHallImagesByName(hallName).length > 0">
|
|
|
+ <div class="image-gallery">
|
|
|
+ <div v-for="(image, index) in getHallImagesByName(hallName)" :key="index" class="image-item" @click="previewImage(image, index)">
|
|
|
+ <img :src="image" class="gallery-image" @error="handleImageError" />
|
|
|
+ <div class="image-overlay">
|
|
|
+ <el-icon class="preview-icon"><ZoomIn /></el-icon>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-else class="no-images">暂无图片</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 该报告厅的预约申请列表 -->
|
|
|
+ <div class="reservation-list">
|
|
|
+ <div class="reservation-list-title">预约申请({{ hallGroup.reservations.length }}个)</div>
|
|
|
+ <div v-for="(record, index) in hallGroup.reservations" :key="record.id" class="reservation-item">
|
|
|
+ <div class="reservation-index">申请 {{ index + 1 }}</div>
|
|
|
+ <div class="reservation-details">
|
|
|
+ <div class="detail-row">
|
|
|
+ <span class="detail-label">申请人:</span>
|
|
|
+ <span class="detail-value">{{ record.applicantName }}</span>
|
|
|
+ <span class="detail-phone">({{ record.applicantPhone || '手机号暂无' }})</span>
|
|
|
+ </div>
|
|
|
+ <div class="detail-row">
|
|
|
+ <span class="detail-label">预约时间:</span>
|
|
|
+ <span class="detail-value">
|
|
|
+ {{ parseTime(record.startTime, '{y}-{m}-{d} {h}:{i}') }} - {{ parseTime(record.endTime, '{y}-{m}-{d} {h}:{i}') }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <div class="detail-row">
|
|
|
+ <span class="detail-label">预约用途:</span>
|
|
|
+ <span class="detail-value purpose-content">{{ record.reservationPurpose }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 审核信息 -->
|
|
|
+ <el-form-item label="审核信息">
|
|
|
+ <div class="audit-info">
|
|
|
+ <div class="audit-status">
|
|
|
+ <span class="audit-label">审核状态:</span>
|
|
|
+ <el-tag :type="auditForm.status === '1' ? 'success' : 'danger'" size="large">
|
|
|
+ {{ auditForm.status === '1' ? '批准' : '拒绝' }}
|
|
|
+ </el-tag>
|
|
|
+ </div>
|
|
|
+ <div class="audit-remark-section">
|
|
|
+ <span class="audit-label">审核备注:</span>
|
|
|
+ <el-input
|
|
|
+ v-model="auditForm.auditRemark"
|
|
|
+ type="textarea"
|
|
|
+ :placeholder="auditForm.status === '1' ? '请输入审核备注(选填)' : '请输入拒绝原因'"
|
|
|
+ class="audit-remark-textarea"
|
|
|
+ resize="none"
|
|
|
+ maxlength="500"
|
|
|
+ show-word-limit
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <div class="dialog-footer">
|
|
|
+ <el-button :loading="auditLoading" type="primary" @click="confirmAudit">确 定</el-button>
|
|
|
+ <el-button @click="cancelAudit">取 消</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup name="HallAudit" lang="ts">
|
|
|
+import { listHallReservation, getHallReservation, auditHallReservation, HallReservationAuditForm } from '@/api/hq/hallAudit';
|
|
|
+import { listHallInfo } from '@/api/hq/hallInfo';
|
|
|
+import { HallReservationVO, HallReservationQuery, HallReservationForm } from '@/api/hq/hallReservation/types';
|
|
|
+import { HallInfoVO } from '@/api/hq/hallInfo/types';
|
|
|
+import { useUserStore } from '@/store/modules/user';
|
|
|
+
|
|
|
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
+const { hall_reserv_status } = toRefs<any>(proxy?.useDict('hall_reserv_status'));
|
|
|
+const userStore = useUserStore();
|
|
|
+
|
|
|
+const hallReservationList = ref<HallReservationVO[]>([]);
|
|
|
+const hallList = ref<HallInfoVO[]>([]);
|
|
|
+const viewHallImages = ref<string[]>([]);
|
|
|
+const loading = ref(true);
|
|
|
+const showSearch = ref(true);
|
|
|
+const ids = ref<Array<string | number>>([]);
|
|
|
+const single = ref(true);
|
|
|
+const multiple = ref(true);
|
|
|
+const total = ref(0);
|
|
|
+const windowHeight = ref(window.innerHeight);
|
|
|
+
|
|
|
+const queryFormRef = ref<ElFormInstance>();
|
|
|
+const auditFormRef = ref<ElFormInstance>();
|
|
|
+
|
|
|
+// 审核表单验证规则
|
|
|
+const auditRules = computed(() => ({
|
|
|
+ auditRemark: auditForm.value.status === '2' ? [{ required: true, message: '拒绝原因不能为空', trigger: 'blur' }] : []
|
|
|
+}));
|
|
|
+
|
|
|
+const viewDialog = reactive<DialogOption>({
|
|
|
+ visible: false,
|
|
|
+ title: ''
|
|
|
+});
|
|
|
+
|
|
|
+const auditDialog = reactive<DialogOption>({
|
|
|
+ visible: false,
|
|
|
+ title: ''
|
|
|
+});
|
|
|
+
|
|
|
+const viewForm = ref<HallReservationForm>({
|
|
|
+ id: undefined,
|
|
|
+ hallId: undefined,
|
|
|
+ hallName: undefined,
|
|
|
+ startTime: undefined,
|
|
|
+ endTime: undefined,
|
|
|
+ reservationPurpose: undefined,
|
|
|
+ applicantId: undefined,
|
|
|
+ applicantName: undefined,
|
|
|
+ applicantPhone: undefined,
|
|
|
+ status: undefined,
|
|
|
+ auditBy: undefined,
|
|
|
+ auditName: undefined,
|
|
|
+ auditTime: undefined,
|
|
|
+ auditRemark: undefined
|
|
|
+});
|
|
|
+
|
|
|
+const auditForm = ref({
|
|
|
+ status: '1', // 1-批准, 2-拒绝
|
|
|
+ auditRemark: '',
|
|
|
+ ids: [] as Array<string | number>
|
|
|
+});
|
|
|
+
|
|
|
+const selectedRecords = ref<HallReservationVO[]>([]);
|
|
|
+const auditLoading = ref(false);
|
|
|
+
|
|
|
+const toolbarRef = ref<HTMLElement>();
|
|
|
+const searchRef = ref<HTMLElement>();
|
|
|
+const actualToolbarHeight = ref(70); // 默认工具栏高度
|
|
|
+const actualSearchHeight = ref(160); // 默认搜索栏高度
|
|
|
+
|
|
|
+const queryParams = ref<HallReservationQuery>({
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ hallId: undefined,
|
|
|
+ hallName: undefined,
|
|
|
+ startTime: undefined,
|
|
|
+ endTime: undefined,
|
|
|
+ applicantId: undefined, // 审核界面显示所有用户的预约记录
|
|
|
+ applicantName: undefined, // 申请人姓名搜索条件
|
|
|
+ status: '0', // 默认查询审核中的记录
|
|
|
+ params: {
|
|
|
+ orderByColumn: 'create_time',
|
|
|
+ isAsc: 'desc'
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+/** 计算搜索栏实际高度 */
|
|
|
+const calculateSearchHeight = () => {
|
|
|
+ nextTick(() => {
|
|
|
+ if (searchRef.value && showSearch.value) {
|
|
|
+ // 获取搜索栏元素的完整高度,包括边距和内边距
|
|
|
+ const rect = searchRef.value.getBoundingClientRect();
|
|
|
+ const computedStyle = window.getComputedStyle(searchRef.value);
|
|
|
+ const marginTop = parseFloat(computedStyle.marginTop);
|
|
|
+ const marginBottom = parseFloat(computedStyle.marginBottom);
|
|
|
+ actualSearchHeight.value = rect.height + marginTop + marginBottom;
|
|
|
+ } else {
|
|
|
+ // 如果搜索栏隐藏,高度为0
|
|
|
+ actualSearchHeight.value = 0;
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+/** 计算工具栏实际高度 */
|
|
|
+const calculateToolbarHeight = () => {
|
|
|
+ nextTick(() => {
|
|
|
+ if (toolbarRef.value) {
|
|
|
+ // 获取工具栏元素的完整高度,包括边距和内边距
|
|
|
+ const toolbarElement = toolbarRef.value.closest('.el-card__header');
|
|
|
+ if (toolbarElement) {
|
|
|
+ const rect = toolbarElement.getBoundingClientRect();
|
|
|
+ const computedStyle = window.getComputedStyle(toolbarElement);
|
|
|
+ const marginTop = parseFloat(computedStyle.marginTop);
|
|
|
+ const marginBottom = parseFloat(computedStyle.marginBottom);
|
|
|
+ actualToolbarHeight.value = rect.height + marginTop + marginBottom;
|
|
|
+ } else {
|
|
|
+ // 如果找不到父元素,直接使用工具栏元素高度
|
|
|
+ const rect = toolbarRef.value.getBoundingClientRect();
|
|
|
+ actualToolbarHeight.value = rect.height + 20; // 添加一些边距
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+/** 计算表格高度 */
|
|
|
+const tableHeight = computed(() => {
|
|
|
+ // 精确计算:窗口高度 - 搜索栏高度 - 工具栏高度 - 分页栏高度 - 页面边距 - 分页栏底部边距
|
|
|
+ const searchHeight = actualSearchHeight.value; // 实际搜索栏高度
|
|
|
+ const toolbarHeight = actualToolbarHeight.value; // 实际工具栏高度
|
|
|
+ const pageTopPadding = 8; // 页面顶部边距
|
|
|
+ const pageBottomMargin = 10; // 分页栏距离底部的边距
|
|
|
+ const paginationOwnHeight = 32; // 分页组件自身高度
|
|
|
+ const paginationPadding = 20; // 分页栏上下内边距
|
|
|
+ const cardPadding = 40; // 卡片内边距(上下各20px)
|
|
|
+
|
|
|
+ // 总的固定高度 = 搜索栏 + 工具栏 + 分页栏自身高度 + 分页栏内边距 + 页面边距 + 底部边距 + 卡片边距
|
|
|
+ const fixedHeight = searchHeight + toolbarHeight + paginationOwnHeight + paginationPadding + pageTopPadding + pageBottomMargin + cardPadding;
|
|
|
+
|
|
|
+ const calculatedHeight = windowHeight.value - fixedHeight - 30;
|
|
|
+
|
|
|
+ // 确保至少有300px的表格高度,避免过小
|
|
|
+ return Math.max(calculatedHeight, 300);
|
|
|
+});
|
|
|
+
|
|
|
+/** 获取报告厅列表 */
|
|
|
+const getHallList = async () => {
|
|
|
+ try {
|
|
|
+ const res = await listHallInfo({
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 1000,
|
|
|
+ hallStatus: '1'
|
|
|
+ }); // 获取正常状态的报告厅
|
|
|
+ hallList.value = res.rows || [];
|
|
|
+
|
|
|
+ // 调试信息:检查每个报告厅的图片信息
|
|
|
+ console.log('报告厅列表数据:', hallList.value);
|
|
|
+ hallList.value.forEach((hall, index) => {
|
|
|
+ console.log(`报告厅 ${index + 1} - ${hall.hallName}:`, {
|
|
|
+ id: hall.id,
|
|
|
+ hallImage: hall.hallImage,
|
|
|
+ images: getHallImages(hall.hallImage || '')
|
|
|
+ });
|
|
|
+ });
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取报告厅列表失败:', error);
|
|
|
+ hallList.value = [];
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 处理报告厅图片 - 可能有多张图片,用逗号分隔 */
|
|
|
+const getHallImages = (imageUrl: string): string[] => {
|
|
|
+ if (!imageUrl || imageUrl.trim() === '') return [];
|
|
|
+ // 支持多种分隔符:逗号、分号、空格
|
|
|
+ const separators = /[,;|\s]+/;
|
|
|
+ const images = imageUrl
|
|
|
+ .split(separators)
|
|
|
+ .map((url) => url.trim())
|
|
|
+ .filter((url) => url && url !== 'null' && url !== 'undefined');
|
|
|
+
|
|
|
+ console.log('处理图片URL:', imageUrl, '结果:', images);
|
|
|
+ return images;
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取记录对应的报告厅图片 */
|
|
|
+const getRecordHallImages = (record: HallReservationVO): string[] => {
|
|
|
+ const selectedHall = hallList.value.find((hall) => hall.hallName === record.hallName);
|
|
|
+ if (selectedHall && selectedHall.hallImage) {
|
|
|
+ return getHallImages(selectedHall.hallImage);
|
|
|
+ }
|
|
|
+ return [];
|
|
|
+};
|
|
|
+
|
|
|
+/** 根据报告厅名称获取图片 */
|
|
|
+const getHallImagesByName = (hallName: string): string[] => {
|
|
|
+ const selectedHall = hallList.value.find((hall) => hall.hallName === hallName);
|
|
|
+ if (selectedHall && selectedHall.hallImage) {
|
|
|
+ return getHallImages(selectedHall.hallImage);
|
|
|
+ }
|
|
|
+ return [];
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取选中记录中的唯一报告厅名称 */
|
|
|
+const uniqueHallNames = computed(() => {
|
|
|
+ return [...new Set(selectedRecords.value.map((record) => record.hallName))];
|
|
|
+});
|
|
|
+
|
|
|
+/** 按报告厅分组的预约记录 */
|
|
|
+const groupedReservations = computed(() => {
|
|
|
+ const groups: Record<string, { hallId: string; reservations: HallReservationVO[] }> = {};
|
|
|
+
|
|
|
+ selectedRecords.value.forEach((record) => {
|
|
|
+ const hallName = record.hallName;
|
|
|
+ if (!groups[hallName]) {
|
|
|
+ groups[hallName] = {
|
|
|
+ hallId: String(record.hallId || ''),
|
|
|
+ reservations: []
|
|
|
+ };
|
|
|
+ }
|
|
|
+ groups[hallName].reservations.push(record);
|
|
|
+ });
|
|
|
+
|
|
|
+ return groups;
|
|
|
+});
|
|
|
+
|
|
|
+/** 处理图片加载成功 */
|
|
|
+const handleImageLoad = (event: Event) => {
|
|
|
+ const img = event.target as HTMLImageElement;
|
|
|
+ console.log('图片加载成功:', img.src);
|
|
|
+};
|
|
|
+
|
|
|
+/** 处理图片加载错误 */
|
|
|
+const handleImageError = (event: Event) => {
|
|
|
+ const img = event.target as HTMLImageElement;
|
|
|
+ console.log('图片加载失败:', img.src);
|
|
|
+ img.style.display = 'none';
|
|
|
+};
|
|
|
+
|
|
|
+/** 预览图片 */
|
|
|
+const previewImage = (imageUrl: string, index: number) => {
|
|
|
+ // 创建一个临时的图片预览对话框
|
|
|
+ const imageViewer = document.createElement('div');
|
|
|
+ imageViewer.style.cssText = `
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ background: rgba(0, 0, 0, 0.8);
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ z-index: 9999;
|
|
|
+ cursor: pointer;
|
|
|
+ `;
|
|
|
+
|
|
|
+ const img = document.createElement('img');
|
|
|
+ img.src = imageUrl;
|
|
|
+ img.style.cssText = `
|
|
|
+ max-width: 90%;
|
|
|
+ max-height: 90%;
|
|
|
+ object-fit: contain;
|
|
|
+ `;
|
|
|
+
|
|
|
+ imageViewer.appendChild(img);
|
|
|
+ document.body.appendChild(imageViewer);
|
|
|
+
|
|
|
+ // 点击关闭预览
|
|
|
+ imageViewer.addEventListener('click', () => {
|
|
|
+ document.body.removeChild(imageViewer);
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+/** 查询报告厅预约列表 */
|
|
|
+const getList = async () => {
|
|
|
+ loading.value = true;
|
|
|
+ try {
|
|
|
+ // 构建查询参数,处理时间格式
|
|
|
+ const params = { ...queryParams.value };
|
|
|
+
|
|
|
+ // 审核界面显示所有用户的预约记录,不限制申请人
|
|
|
+ // 注释掉原来的用户限制逻辑
|
|
|
+ // params.applicantId = userStore.userId;
|
|
|
+
|
|
|
+ console.log('查询参数:', params);
|
|
|
+
|
|
|
+ // 将时间参数转换为字符串格式的参数
|
|
|
+ if (params.startTime) {
|
|
|
+ params.startTimeStr = params.startTime + ' 00:00:00';
|
|
|
+ params.startTime = undefined; // 清除原始的Date参数
|
|
|
+ }
|
|
|
+
|
|
|
+ if (params.endTime) {
|
|
|
+ params.endTimeStr = params.endTime + ' 23:59:59';
|
|
|
+ params.endTime = undefined; // 清除原始的Date参数
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('最终查询参数:', params);
|
|
|
+
|
|
|
+ const res = await listHallReservation(params);
|
|
|
+ console.log('查询结果:', res);
|
|
|
+
|
|
|
+ hallReservationList.value = res.rows;
|
|
|
+ total.value = res.total;
|
|
|
+ } catch (error) {
|
|
|
+ console.error('查询报告厅预约列表失败:', error);
|
|
|
+ hallReservationList.value = [];
|
|
|
+ total.value = 0;
|
|
|
+ } finally {
|
|
|
+ loading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 搜索按钮操作 */
|
|
|
+const handleQuery = () => {
|
|
|
+ queryParams.value.pageNum = 1;
|
|
|
+ getList();
|
|
|
+};
|
|
|
+
|
|
|
+/** 监听搜索栏显示状态变化 */
|
|
|
+watch(showSearch, () => {
|
|
|
+ // 搜索栏显示状态变化时重新计算高度
|
|
|
+ calculateSearchHeight();
|
|
|
+});
|
|
|
+
|
|
|
+/** 重置按钮操作 */
|
|
|
+const resetQuery = () => {
|
|
|
+ queryFormRef.value?.resetFields();
|
|
|
+ // 审核界面重置后不限制申请人
|
|
|
+ queryParams.value.applicantId = undefined;
|
|
|
+ handleQuery();
|
|
|
+};
|
|
|
+
|
|
|
+/** 多选框选中数据 */
|
|
|
+const handleSelectionChange = (selection: HallReservationVO[]) => {
|
|
|
+ ids.value = selection.map((item) => item.id);
|
|
|
+
|
|
|
+ // 只有审核中的记录可以进行编辑和删除操作
|
|
|
+ const editableSelection = selection.filter((item) => item.status === '0');
|
|
|
+
|
|
|
+ single.value = editableSelection.length != 1;
|
|
|
+ multiple.value = !editableSelection.length;
|
|
|
+};
|
|
|
+
|
|
|
+/** 查看按钮操作 */
|
|
|
+const handleView = async (row: HallReservationVO) => {
|
|
|
+ const res = await getHallReservation(row.id);
|
|
|
+ Object.assign(viewForm.value, res.data);
|
|
|
+
|
|
|
+ // 查找对应的报告厅并显示图片
|
|
|
+ if (viewForm.value.hallName) {
|
|
|
+ const selectedHall = hallList.value.find((hall) => hall.hallName === viewForm.value.hallName);
|
|
|
+ if (selectedHall && selectedHall.hallImage) {
|
|
|
+ viewHallImages.value = getHallImages(selectedHall.hallImage);
|
|
|
+ } else {
|
|
|
+ viewHallImages.value = [];
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ viewHallImages.value = [];
|
|
|
+ }
|
|
|
+
|
|
|
+ viewDialog.visible = true;
|
|
|
+ viewDialog.title = '查看报告厅预约详情';
|
|
|
+};
|
|
|
+
|
|
|
+/** 关闭查看对话框 */
|
|
|
+const closeView = () => {
|
|
|
+ viewDialog.visible = false;
|
|
|
+ viewHallImages.value = [];
|
|
|
+};
|
|
|
+
|
|
|
+/** 批准按钮操作 */
|
|
|
+const handleApprove = async (row?: HallReservationVO) => {
|
|
|
+ let _ids;
|
|
|
+ let records: HallReservationVO[] = [];
|
|
|
+
|
|
|
+ if (row) {
|
|
|
+ // 单个批准时检查状态
|
|
|
+ if (row.status !== '0') {
|
|
|
+ proxy?.$modal.msgWarning('该记录已审核,不能重复操作');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ _ids = [row.id];
|
|
|
+ records = [row];
|
|
|
+ } else {
|
|
|
+ // 批量批准时过滤出可操作的记录
|
|
|
+ const auditableRecords = hallReservationList.value.filter((item) => ids.value.includes(item.id) && item.status === '0');
|
|
|
+
|
|
|
+ if (auditableRecords.length === 0) {
|
|
|
+ proxy?.$modal.msgWarning('所选记录已审核,不能重复操作');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ _ids = auditableRecords.map((item) => item.id);
|
|
|
+ records = auditableRecords;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 显示审核对话框
|
|
|
+ openAuditDialog('1', _ids, records, '批准预约申请');
|
|
|
+};
|
|
|
+
|
|
|
+/** 拒绝按钮操作 */
|
|
|
+const handleReject = async (row?: HallReservationVO) => {
|
|
|
+ let _ids;
|
|
|
+ let records: HallReservationVO[] = [];
|
|
|
+
|
|
|
+ if (row) {
|
|
|
+ // 单个拒绝时检查状态
|
|
|
+ if (row.status !== '0') {
|
|
|
+ proxy?.$modal.msgWarning('该记录已审核,不能重复操作');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ _ids = [row.id];
|
|
|
+ records = [row];
|
|
|
+ } else {
|
|
|
+ // 批量拒绝时过滤出可操作的记录
|
|
|
+ const auditableRecords = hallReservationList.value.filter((item) => ids.value.includes(item.id) && item.status === '0');
|
|
|
+
|
|
|
+ if (auditableRecords.length === 0) {
|
|
|
+ proxy?.$modal.msgWarning('所选记录已审核,不能重复操作');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ _ids = auditableRecords.map((item) => item.id);
|
|
|
+ records = auditableRecords;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 显示审核对话框
|
|
|
+ openAuditDialog('2', _ids, records, '拒绝预约申请');
|
|
|
+};
|
|
|
+
|
|
|
+/** 打开审核对话框 */
|
|
|
+const openAuditDialog = (status: string, ids: Array<string | number>, records: HallReservationVO[], title: string) => {
|
|
|
+ auditForm.value.status = status;
|
|
|
+ auditForm.value.auditRemark = '';
|
|
|
+ auditForm.value.ids = ids;
|
|
|
+ selectedRecords.value = records;
|
|
|
+ auditDialog.title = title;
|
|
|
+ auditDialog.visible = true;
|
|
|
+};
|
|
|
+
|
|
|
+/** 确认审核操作 */
|
|
|
+const confirmAudit = async () => {
|
|
|
+ auditFormRef.value?.validate(async (valid: boolean) => {
|
|
|
+ if (valid) {
|
|
|
+ auditLoading.value = true;
|
|
|
+ try {
|
|
|
+ // 构建审核数据
|
|
|
+ const auditData: HallReservationAuditForm = {
|
|
|
+ ids: auditForm.value.ids,
|
|
|
+ status: auditForm.value.status,
|
|
|
+ auditRemark: auditForm.value.auditRemark || ''
|
|
|
+ };
|
|
|
+
|
|
|
+ console.log('提交审核数据:', auditData);
|
|
|
+
|
|
|
+ // 调用审核接口
|
|
|
+ await auditHallReservation(auditData);
|
|
|
+
|
|
|
+ const actionText = auditForm.value.status === '1' ? '批准' : '拒绝';
|
|
|
+ proxy?.$modal.msgSuccess(`${actionText}成功`);
|
|
|
+
|
|
|
+ // 关闭对话框并刷新列表
|
|
|
+ auditDialog.visible = false;
|
|
|
+ await getList();
|
|
|
+
|
|
|
+ // 清空选中状态
|
|
|
+ ids.value = [];
|
|
|
+ selectedRecords.value = [];
|
|
|
+ } catch (error) {
|
|
|
+ console.error('审核失败:', error);
|
|
|
+ const actionText = auditForm.value.status === '1' ? '批准' : '拒绝';
|
|
|
+ proxy?.$modal.msgError(`${actionText}失败,请稍后重试`);
|
|
|
+ } finally {
|
|
|
+ auditLoading.value = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+/** 取消审核操作 */
|
|
|
+const cancelAudit = () => {
|
|
|
+ // 重置表单数据
|
|
|
+ auditForm.value.auditRemark = '';
|
|
|
+ auditForm.value.ids = [];
|
|
|
+ selectedRecords.value = [];
|
|
|
+
|
|
|
+ // 清除表单验证状态
|
|
|
+ auditFormRef.value?.resetFields();
|
|
|
+
|
|
|
+ // 关闭对话框
|
|
|
+ auditDialog.visible = false;
|
|
|
+};
|
|
|
+
|
|
|
+/** 导出按钮操作 */
|
|
|
+const handleExport = () => {
|
|
|
+ proxy?.download(
|
|
|
+ 'hq/hallReservation/export',
|
|
|
+ {
|
|
|
+ ...queryParams.value
|
|
|
+ },
|
|
|
+ `hallReservation_${new Date().getTime()}.xlsx`
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+/** 窗口大小变化监听 */
|
|
|
+const handleResize = () => {
|
|
|
+ windowHeight.value = window.innerHeight;
|
|
|
+ // 窗口大小变化时重新计算搜索栏和工具栏高度
|
|
|
+ calculateSearchHeight();
|
|
|
+ calculateToolbarHeight();
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(async () => {
|
|
|
+ // 审核界面不需要限制用户信息
|
|
|
+
|
|
|
+ getList();
|
|
|
+ getHallList(); // 获取报告厅列表
|
|
|
+ // 初始计算搜索栏和工具栏高度
|
|
|
+ calculateSearchHeight();
|
|
|
+ calculateToolbarHeight();
|
|
|
+ // 监听窗口大小变化
|
|
|
+ window.addEventListener('resize', handleResize);
|
|
|
+});
|
|
|
+
|
|
|
+onUnmounted(() => {
|
|
|
+ // 移除监听器
|
|
|
+ window.removeEventListener('resize', handleResize);
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+/* 页面容器样式 */
|
|
|
+.page-container {
|
|
|
+ height: calc(100vh - 85px);
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ overflow: hidden;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 8px 8px 0 8px !important; /* 顶部和左右边距,底部无边距 */
|
|
|
+}
|
|
|
+
|
|
|
+/* 隐藏滚动条但保持滚动功能 */
|
|
|
+.page-container::-webkit-scrollbar {
|
|
|
+ display: none;
|
|
|
+}
|
|
|
+
|
|
|
+.page-container {
|
|
|
+ -ms-overflow-style: none; /* IE and Edge */
|
|
|
+ scrollbar-width: none; /* Firefox */
|
|
|
+}
|
|
|
+
|
|
|
+/* 表格卡片布局 */
|
|
|
+.table-card {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ overflow: hidden;
|
|
|
+ min-height: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.table-card :deep(.el-card__body) {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ overflow: hidden;
|
|
|
+ padding: 0px 20px 0 20px !important;
|
|
|
+ min-height: 0;
|
|
|
+ margin-bottom: 0 !important;
|
|
|
+}
|
|
|
+
|
|
|
+/* 表格主体 */
|
|
|
+.table-main {
|
|
|
+ flex: 1;
|
|
|
+ overflow: auto;
|
|
|
+}
|
|
|
+
|
|
|
+/* 分页容器固定在底部 */
|
|
|
+.pagination-container {
|
|
|
+ flex-shrink: 0;
|
|
|
+ padding-top: 10px 0 0 0 !important;
|
|
|
+ margin: 0 !important;
|
|
|
+ /* padding-bottom: 10px !important; 距离底部10px */
|
|
|
+ /* margin: 0 !important; */
|
|
|
+ /* margin-bottom: 10px !important; 确保距离视窗底部10px */
|
|
|
+}
|
|
|
+
|
|
|
+/* 移除按钮栏底部边框 */
|
|
|
+.button-card :deep(.el-card__header) {
|
|
|
+ border-bottom: none !important;
|
|
|
+}
|
|
|
+
|
|
|
+.hall-option {
|
|
|
+ padding: 8px 0;
|
|
|
+ line-height: 1.4;
|
|
|
+}
|
|
|
+
|
|
|
+.hall-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.hall-name {
|
|
|
+ font-weight: 600;
|
|
|
+ color: #303133;
|
|
|
+ margin-right: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.hall-id {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #909399;
|
|
|
+}
|
|
|
+
|
|
|
+.hall-description {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #606266;
|
|
|
+ margin-bottom: 4px;
|
|
|
+ line-height: 1.3;
|
|
|
+ max-height: 36px;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ display: -webkit-box;
|
|
|
+ -webkit-line-clamp: 2;
|
|
|
+ -webkit-box-orient: vertical;
|
|
|
+}
|
|
|
+
|
|
|
+.hall-images {
|
|
|
+ display: flex;
|
|
|
+ gap: 4px;
|
|
|
+ flex-wrap: wrap;
|
|
|
+}
|
|
|
+
|
|
|
+.hall-image {
|
|
|
+ width: 40px;
|
|
|
+ height: 30px;
|
|
|
+ object-fit: cover;
|
|
|
+ border-radius: 4px;
|
|
|
+ border: 1px solid #dcdfe6;
|
|
|
+}
|
|
|
+
|
|
|
+.no-image-text {
|
|
|
+ font-size: 11px;
|
|
|
+ color: #c0c4cc;
|
|
|
+ font-style: italic;
|
|
|
+}
|
|
|
+
|
|
|
+/* 预约用途固定宽高 */
|
|
|
+.purpose-textarea :deep(.el-textarea__inner) {
|
|
|
+ width: 100%;
|
|
|
+ max-width: 450px;
|
|
|
+ height: 120px;
|
|
|
+ resize: none;
|
|
|
+ min-height: 120px;
|
|
|
+ max-height: 120px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 表格中预约用途文本样式 */
|
|
|
+.purpose-text {
|
|
|
+ display: inline-block;
|
|
|
+ max-width: 100%;
|
|
|
+ word-break: break-all;
|
|
|
+ word-wrap: break-word;
|
|
|
+ line-height: 1.4;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+/* 表格中审核备注文本样式 */
|
|
|
+.audit-remark-text {
|
|
|
+ display: inline-block;
|
|
|
+ max-width: 100%;
|
|
|
+ word-break: break-all;
|
|
|
+ word-wrap: break-word;
|
|
|
+ line-height: 1.4;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+/* 查看详情表单样式 */
|
|
|
+.view-form .form-text {
|
|
|
+ color: #303133;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 1.6;
|
|
|
+}
|
|
|
+
|
|
|
+.purpose-view {
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
+ border-radius: 4px;
|
|
|
+ padding: 12px;
|
|
|
+ width: 450px;
|
|
|
+ height: 120px;
|
|
|
+ line-height: 1.6;
|
|
|
+ color: #303133;
|
|
|
+ white-space: pre-wrap;
|
|
|
+ word-break: break-word;
|
|
|
+ overflow-y: auto;
|
|
|
+}
|
|
|
+
|
|
|
+.applicant-info p {
|
|
|
+ margin: 0 0 8px 0;
|
|
|
+ color: #303133;
|
|
|
+ line-height: 1.6;
|
|
|
+}
|
|
|
+
|
|
|
+.applicant-info p:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.audit-remark {
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
+ border-radius: 4px;
|
|
|
+ padding: 12px;
|
|
|
+ width: 450px;
|
|
|
+ height: 80px;
|
|
|
+ line-height: 1.6;
|
|
|
+ color: #303133;
|
|
|
+ white-space: pre-wrap;
|
|
|
+ word-break: break-word;
|
|
|
+ overflow-y: auto;
|
|
|
+}
|
|
|
+
|
|
|
+.view-hall-images {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+/* 选中报告厅的图片展示区域 */
|
|
|
+.selected-hall-images {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.image-gallery {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.image-item {
|
|
|
+ position: relative;
|
|
|
+ width: 120px;
|
|
|
+ height: 90px;
|
|
|
+ border-radius: 8px;
|
|
|
+ overflow: hidden;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: transform 0.2s ease;
|
|
|
+ border: 2px solid #e4e7ed;
|
|
|
+}
|
|
|
+
|
|
|
+.image-item:hover {
|
|
|
+ transform: scale(1.05);
|
|
|
+ border-color: #409eff;
|
|
|
+}
|
|
|
+
|
|
|
+.gallery-image {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ object-fit: cover;
|
|
|
+ display: block;
|
|
|
+}
|
|
|
+
|
|
|
+.image-overlay {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ background: rgba(0, 0, 0, 0.5);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ opacity: 0;
|
|
|
+ transition: opacity 0.2s ease;
|
|
|
+}
|
|
|
+
|
|
|
+.image-item:hover .image-overlay {
|
|
|
+ opacity: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.preview-icon {
|
|
|
+ color: white;
|
|
|
+ font-size: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 审核对话框样式 */
|
|
|
+.audit-form .form-text {
|
|
|
+ color: #303133;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 1.6;
|
|
|
+}
|
|
|
+
|
|
|
+/* 审核详情分组样式 */
|
|
|
+.audit-details {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.hall-group {
|
|
|
+ border-radius: 12px;
|
|
|
+ padding: 20px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ border: 2px solid #e9ecef;
|
|
|
+ background: #fafbfc;
|
|
|
+}
|
|
|
+
|
|
|
+.hall-group:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* 报告厅信息区域 */
|
|
|
+.hall-info-section {
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 16px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
+}
|
|
|
+
|
|
|
+.hall-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.hall-name {
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #1e40af;
|
|
|
+ margin-right: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.hall-id {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #909399;
|
|
|
+ background: #f0f2f5;
|
|
|
+ padding: 4px 8px;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.hall-images {
|
|
|
+ margin-top: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.no-images {
|
|
|
+ color: #9ca3af;
|
|
|
+ font-style: italic;
|
|
|
+ text-align: center;
|
|
|
+ padding: 16px;
|
|
|
+ background: #f9fafb;
|
|
|
+ border-radius: 6px;
|
|
|
+ border: 2px dashed #d1d5db;
|
|
|
+ margin-top: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 预约申请列表 */
|
|
|
+.reservation-list {
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
+}
|
|
|
+
|
|
|
+.reservation-list-title {
|
|
|
+ background: #f5f7fa;
|
|
|
+ padding: 12px 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #606266;
|
|
|
+ border-bottom: 1px solid #e4e7ed;
|
|
|
+ border-radius: 8px 8px 0 0;
|
|
|
+}
|
|
|
+
|
|
|
+.reservation-item {
|
|
|
+ padding: 16px;
|
|
|
+ border-bottom: 1px solid #f0f2f5;
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+
|
|
|
+.reservation-item:last-child {
|
|
|
+ border-bottom: none;
|
|
|
+ border-radius: 0 0 8px 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.reservation-index {
|
|
|
+ position: absolute;
|
|
|
+ top: 12px;
|
|
|
+ right: 16px;
|
|
|
+ background: #1e40af;
|
|
|
+ color: white;
|
|
|
+ padding: 4px 8px;
|
|
|
+ border-radius: 12px;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+.reservation-details {
|
|
|
+ line-height: 1.8;
|
|
|
+ padding-right: 80px; /* 为右上角标签留出空间 */
|
|
|
+}
|
|
|
+
|
|
|
+.detail-row {
|
|
|
+ display: flex;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ align-items: flex-start;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-row:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-label {
|
|
|
+ font-weight: 600;
|
|
|
+ color: #606266;
|
|
|
+ min-width: 80px;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-value {
|
|
|
+ color: #303133;
|
|
|
+ flex: 1;
|
|
|
+ word-break: break-word;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-phone {
|
|
|
+ color: #909399;
|
|
|
+ margin-left: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.purpose-content {
|
|
|
+ line-height: 1.6;
|
|
|
+ max-height: 60px;
|
|
|
+ overflow-y: auto;
|
|
|
+ padding: 4px 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* 审核信息样式 */
|
|
|
+.audit-info {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.audit-status {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.audit-label {
|
|
|
+ font-weight: 600;
|
|
|
+ color: #606266;
|
|
|
+ margin-right: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.audit-remark-section {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+
|
|
|
+.audit-remark-section .audit-label {
|
|
|
+ margin-bottom: 8px;
|
|
|
+ margin-right: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.audit-remark-textarea :deep(.el-textarea__inner) {
|
|
|
+ width: 100%;
|
|
|
+ height: 120px !important;
|
|
|
+ min-height: 120px !important;
|
|
|
+ max-height: 120px !important;
|
|
|
+ line-height: 1.6;
|
|
|
+ font-size: 14px;
|
|
|
+ resize: none !important;
|
|
|
+}
|
|
|
+</style>
|
|
|
+
|
|
|
+<style>
|
|
|
+/* 全局样式,用于美化下拉框 */
|
|
|
+.hall-select-dropdown .el-select-dropdown__item.hall-option-item {
|
|
|
+ height: auto !important;
|
|
|
+ padding: 12px 20px !important;
|
|
|
+ line-height: normal !important;
|
|
|
+}
|
|
|
+
|
|
|
+.hall-select-dropdown .el-select-dropdown__item.hall-option-item:hover {
|
|
|
+ background-color: #f5f7fa;
|
|
|
+}
|
|
|
+
|
|
|
+.hall-select-dropdown .el-select-dropdown__item.hall-option-item.selected {
|
|
|
+ background-color: #ecf5ff;
|
|
|
+}
|
|
|
+
|
|
|
+.hall-select-dropdown {
|
|
|
+ max-height: 400px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 预约用途tooltip美化 */
|
|
|
+.purpose-tooltip {
|
|
|
+ max-width: 400px !important;
|
|
|
+ width: auto !important;
|
|
|
+}
|
|
|
+
|
|
|
+.purpose-tooltip .el-tooltip__content {
|
|
|
+ max-width: 400px !important;
|
|
|
+ white-space: pre-wrap !important;
|
|
|
+ word-break: break-word !important;
|
|
|
+ line-height: 1.6 !important;
|
|
|
+ padding: 12px 16px !important;
|
|
|
+ font-size: 14px !important;
|
|
|
+ border-radius: 8px !important;
|
|
|
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
|
|
|
+}
|
|
|
+
|
|
|
+/* 审核备注tooltip美化 */
|
|
|
+.audit-remark-tooltip {
|
|
|
+ max-width: 400px !important;
|
|
|
+ width: auto !important;
|
|
|
+}
|
|
|
+
|
|
|
+.audit-remark-tooltip .el-tooltip__content {
|
|
|
+ max-width: 400px !important;
|
|
|
+ white-space: pre-wrap !important;
|
|
|
+ word-break: break-word !important;
|
|
|
+ line-height: 1.6 !important;
|
|
|
+ padding: 12px 16px !important;
|
|
|
+ font-size: 14px !important;
|
|
|
+ border-radius: 8px !important;
|
|
|
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
|
|
|
+}
|
|
|
+</style>
|