|
|
@@ -0,0 +1,670 @@
|
|
|
+<template>
|
|
|
+ <div class="app-container">
|
|
|
+ <el-form :model="queryParams" ref="queryRef" :inline="true" label-width="80px">
|
|
|
+ <el-form-item label="年份" prop="year">
|
|
|
+ <div style="display: flex; align-items: center;">
|
|
|
+ <el-button icon="ArrowLeft" @click="changeYear(-1)" style="margin-right: 10px;"></el-button>
|
|
|
+ <el-date-picker
|
|
|
+ v-model="queryParams.year"
|
|
|
+ type="year"
|
|
|
+ value-format="YYYY"
|
|
|
+ placeholder="请选择年份"
|
|
|
+ @change="handleQuery"
|
|
|
+ style="width: 130px">
|
|
|
+ </el-date-picker>
|
|
|
+ <el-button icon="ArrowRight" @click="changeYear(1)" style="margin-left: 10px;"></el-button>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <!-- 图表和统计卡片布局 -->
|
|
|
+ <div class="chart-and-stats-container">
|
|
|
+ <div class="chart-section">
|
|
|
+ <h3 class="section-title">节假日出入境统计</h3>
|
|
|
+ <div ref="chartRef" class="chart-container"></div>
|
|
|
+ </div>
|
|
|
+ <div class="stats-section">
|
|
|
+ <!-- 节假日统计信息列表 -->
|
|
|
+ <el-row :gutter="20" class="mb20">
|
|
|
+ <el-col :span="24">
|
|
|
+ <h3 class="section-title">节假日详情</h3>
|
|
|
+ </el-col>
|
|
|
+ <!-- 使用el-table替代卡片列表,以适应不确定数量的节假日 -->
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-table
|
|
|
+ :data="holidayStats"
|
|
|
+ style="width: 100%"
|
|
|
+ highlight-current-row
|
|
|
+ @row-click="selectHoliday"
|
|
|
+ :row-class-name="tableRowClassName"
|
|
|
+ >
|
|
|
+ <el-table-column prop="holidayName" label="节假日名称" width="150"/>
|
|
|
+ <el-table-column prop="inOutCount" label="出入境次数" width="100"/>
|
|
|
+ <el-table-column prop="startDate" label="开始时间" width="120"/>
|
|
|
+ <el-table-column prop="endDate" label="结束时间" width="120"/>
|
|
|
+ </el-table>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 表格标题显示当前节日 -->
|
|
|
+ <div class="table-header">
|
|
|
+ <h3>
|
|
|
+ 明细数据 -
|
|
|
+ <span class="selected-holiday">{{ selectedHolidayName || '请选择节假日' }}</span>
|
|
|
+ </h3>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-table v-loading="loading" :data="list" style="margin-top: 20px;" @row-click="handleRowClick">
|
|
|
+ <el-table-column label="姓名" align="center" prop="fullName" width="300"/>
|
|
|
+ <el-table-column label="性别" align="center" prop="genderCn"/>
|
|
|
+ <el-table-column label="出生日期" align="center" prop="birthDate" width="100">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ parseTime(scope.row.birthDate, '{y}-{m}-{d}') }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="国家/地区" align="center" prop="countryName"/>
|
|
|
+ <el-table-column label="民族" align="center" prop="ethnicityName"/>
|
|
|
+ <el-table-column label="出入标识" align="center" prop="inOutFlag"/>
|
|
|
+ <el-table-column label="出入时间" align="center" prop="inOutTime" width="180">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ parseTime(scope.row.inOutTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="出入口岸" align="center" prop="portCode">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ scope.row.portCode}}-{{scope.row.portName}}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="前往地/出发地" align="center" prop="destinationName"/>
|
|
|
+ <el-table-column label="节假日" align="center" prop="holidayName"/>
|
|
|
+ <el-table-column label="导入时间" align="center" prop="createTime" width="150">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <!-- 出入境记录明细对话框 -->
|
|
|
+ <el-dialog :title="detailTitle" v-model="recordDetailOpen" width="900px" append-to-body>
|
|
|
+ <el-form :model="detailForm" label-width="120px" disabled>
|
|
|
+ <!-- 个人信息 -->
|
|
|
+ <div style="font-weight: bold; margin: 10px 0 15px 0; border-left: 4px solid #409eff; padding-left: 8px; color: #409eff;">个人信息</div>
|
|
|
+ <el-row>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="人员类别:">
|
|
|
+ <span>{{ detailForm.personnelCategoryName }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="姓名:">
|
|
|
+ <span>{{ detailForm.fullName }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="性别:">
|
|
|
+ <span>{{ detailForm.genderCn }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="出生日期:">
|
|
|
+ <span>{{ parseTime(detailForm.birthDate, '{y}-{m}-{d}') }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="国家/地区:">
|
|
|
+ <span>{{ detailForm.countryCode }}-{{ detailForm.countryName }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="民族:">
|
|
|
+ <span>{{ detailForm.ethnicityName }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <!-- 证件信息 -->
|
|
|
+ <div style="font-weight: bold; margin: 10px 0 15px 0; border-left: 4px solid #409eff; padding-left: 8px; color: #409eff;">证件信息</div>
|
|
|
+ <el-row>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="证件类别:">
|
|
|
+ <span>{{ detailForm.idTypeName }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="证件号码:">
|
|
|
+ <span>{{ detailForm.idNumber }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="签证类型:">
|
|
|
+ <span>{{ detailForm.visaTypeName }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="签证号码:">
|
|
|
+ <span>{{ detailForm.visaNumber }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="停留期:">
|
|
|
+ <span>{{ detailForm.stayDuration }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <!-- 出入境信息 -->
|
|
|
+ <div style="font-weight: bold; margin: 10px 0 15px 0; border-left: 4px solid #409eff; padding-left: 8px; color: #409eff;">出入境信息</div>
|
|
|
+ <el-row>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="出入标识:">
|
|
|
+ <span>{{ detailForm.inOutFlag }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="出入时间:">
|
|
|
+ <span>{{ parseTime(detailForm.inOutTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="出入口岸:">
|
|
|
+ <span>{{ detailForm.portCode }}-{{ detailForm.portName }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="交通方式:">
|
|
|
+ <span>{{ detailForm.transportMode }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="交通工具:">
|
|
|
+ <span>{{ detailForm.transportVehicle }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="前往地/出发地:">
|
|
|
+ <span>{{ detailForm.destinationCode }}-{{ detailForm.destinationName }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="出入境事由:">
|
|
|
+ <span>{{ detailForm.reasonName }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="发证机关:">
|
|
|
+ <span>{{ detailForm.issuingAuthorityCode }}-{{ detailForm.issuingAuthorityName }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <!-- 其他信息 -->
|
|
|
+ <div style="font-weight: bold; margin: 10px 0 15px 0; border-left: 4px solid #409eff; padding-left: 8px; color: #409eff;">其他信息</div>
|
|
|
+ <el-row>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="自助通道标记:">
|
|
|
+ <span>{{ detailForm.selfServiceFlag }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="后台补录标记:">
|
|
|
+ <span>{{ detailForm.backfillFlag }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="创建时间:">
|
|
|
+ <span>{{ parseTime(detailForm.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="疑难字说明:">
|
|
|
+ <span>{{ detailForm.remark }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <div class="dialog-footer">
|
|
|
+ <el-button @click="recordDetailOpen = false">关 闭</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <pagination
|
|
|
+ v-show="total>0"
|
|
|
+ :total="total"
|
|
|
+ v-model:page="queryParams.pageNum"
|
|
|
+ v-model:limit="queryParams.pageSize"
|
|
|
+ @pagination="handlePagination"
|
|
|
+ layout="total, sizes, prev, pager, next, jumper"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup name="Holiday">
|
|
|
+import { getHolidayInOutDetails, getHolidayInOutStats } from "@/api/biz/anal";
|
|
|
+import { ArrowLeft, ArrowRight } from "@element-plus/icons-vue";
|
|
|
+import { ElMessage, ElMessageBox } from 'element-plus';
|
|
|
+import * as echarts from 'echarts';
|
|
|
+
|
|
|
+const { proxy } = getCurrentInstance();
|
|
|
+
|
|
|
+const list = ref([]);
|
|
|
+const loading = ref(false);
|
|
|
+const holidayStats = ref([]);
|
|
|
+
|
|
|
+const total = ref(0);
|
|
|
+
|
|
|
+// 出入境记录明细相关
|
|
|
+const recordDetailOpen = ref(false);
|
|
|
+const detailTitle = ref("详细信息");
|
|
|
+const detailForm = ref({});
|
|
|
+
|
|
|
+// 当前选中的节假日
|
|
|
+const selectedHolidayName = ref("");
|
|
|
+
|
|
|
+// 图表相关
|
|
|
+const chartRef = ref(null);
|
|
|
+let chartInstance = null;
|
|
|
+
|
|
|
+const data = reactive({
|
|
|
+ queryParams: {
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ year: new Date().getFullYear().toString()
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+const { queryParams } = toRefs(data);
|
|
|
+
|
|
|
+/** 初始化图表 */
|
|
|
+function initChart() {
|
|
|
+ if (chartRef.value) {
|
|
|
+ chartInstance = echarts.init(chartRef.value);
|
|
|
+
|
|
|
+ const chartData = holidayStats.value.map(item => ({
|
|
|
+ name: item.holidayName,
|
|
|
+ value: item.inOutCount
|
|
|
+ }));
|
|
|
+
|
|
|
+ const option = {
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'item',
|
|
|
+ formatter: '{a} <br/>{b}: {c} ({d}%)'
|
|
|
+ },
|
|
|
+ legend: {
|
|
|
+ orient: 'horizontal',
|
|
|
+ top: 'bottom'
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '出入境次数',
|
|
|
+ type: 'pie',
|
|
|
+ radius: ['40%', '70%'],
|
|
|
+ avoidLabelOverlap: false,
|
|
|
+ itemStyle: {
|
|
|
+ borderRadius: 10,
|
|
|
+ borderColor: '#fff',
|
|
|
+ borderWidth: 2
|
|
|
+ },
|
|
|
+ label: {
|
|
|
+ show: true,
|
|
|
+ formatter: '{b}: {c}'
|
|
|
+ },
|
|
|
+ emphasis: {
|
|
|
+ label: {
|
|
|
+ show: true,
|
|
|
+ fontSize: '16',
|
|
|
+ fontWeight: 'bold'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ labelLine: {
|
|
|
+ show: true,
|
|
|
+ length: 10,
|
|
|
+ length2: 10
|
|
|
+ },
|
|
|
+ data: chartData
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+
|
|
|
+ chartInstance.setOption(option);
|
|
|
+
|
|
|
+ // 添加点击事件
|
|
|
+ chartInstance.on('click', function(params) {
|
|
|
+ const clickedStat = holidayStats.value.find(item => item.holidayName === params.name);
|
|
|
+ if (clickedStat) {
|
|
|
+ selectHoliday(clickedStat);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/** 更新图表 */
|
|
|
+function updateChart() {
|
|
|
+ if (chartInstance) {
|
|
|
+ const chartData = holidayStats.value.map(item => ({
|
|
|
+ name: item.holidayName,
|
|
|
+ value: item.inOutCount
|
|
|
+ }));
|
|
|
+
|
|
|
+ const option = {
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'item',
|
|
|
+ formatter: '{a} <br/>{b}: {c} ({d}%)'
|
|
|
+ },
|
|
|
+ legend: {
|
|
|
+ orient: 'horizontal',
|
|
|
+ top: 'bottom'
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '出入境次数',
|
|
|
+ type: 'pie',
|
|
|
+ radius: ['40%', '70%'],
|
|
|
+ avoidLabelOverlap: false,
|
|
|
+ itemStyle: {
|
|
|
+ borderRadius: 10,
|
|
|
+ borderColor: '#fff',
|
|
|
+ borderWidth: 2
|
|
|
+ },
|
|
|
+ label: {
|
|
|
+ show: true,
|
|
|
+ formatter: '{b}: {c}'
|
|
|
+ },
|
|
|
+ emphasis: {
|
|
|
+ label: {
|
|
|
+ show: true,
|
|
|
+ fontSize: '16',
|
|
|
+ fontWeight: 'bold'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ labelLine: {
|
|
|
+ show: true,
|
|
|
+ length: 10,
|
|
|
+ length2: 10
|
|
|
+ },
|
|
|
+ data: chartData
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+
|
|
|
+ chartInstance.setOption(option, true);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/** 查询节假日出入境统计数据 */
|
|
|
+function getStats() {
|
|
|
+ const params = {
|
|
|
+ year: queryParams.value.year
|
|
|
+ };
|
|
|
+
|
|
|
+ getHolidayInOutStats(params).then(response => {
|
|
|
+ holidayStats.value = response.data || [];
|
|
|
+
|
|
|
+ // 初始化图表
|
|
|
+ nextTick(() => {
|
|
|
+ initChart();
|
|
|
+ });
|
|
|
+
|
|
|
+ // 如果有节假日数据,找到第一个统计数据不为0的记录
|
|
|
+ if (holidayStats.value.length > 0) {
|
|
|
+ // 找到第一个统计数据不为0的记录
|
|
|
+ const firstNonZeroHoliday = holidayStats.value.find(stat => stat.inOutCount > 0);
|
|
|
+ // 如果没有找到统计数据不为0的记录,则使用第一条记录
|
|
|
+ const selectedHoliday = firstNonZeroHoliday || holidayStats.value[0];
|
|
|
+
|
|
|
+ selectedHolidayName.value = selectedHoliday.holidayName;
|
|
|
+
|
|
|
+ // 更新查询参数
|
|
|
+ queryParams.value.startDate = selectedHoliday.startDate;
|
|
|
+ queryParams.value.endDate = selectedHoliday.endDate;
|
|
|
+
|
|
|
+ // 使用找到的节假日的开始结束时间查询明细数据
|
|
|
+ getList(selectedHoliday.startDate, selectedHoliday.endDate);
|
|
|
+ } else {
|
|
|
+ // 如果没有节假日数据,清空表格并弹出提示
|
|
|
+ list.value = [];
|
|
|
+ total.value = 0;
|
|
|
+
|
|
|
+ // 弹出模态框提示信息,阻止其他操作
|
|
|
+ ElMessageBox.alert(`${queryParams.value.year}年度节假日未配置,请先到参数配置/节假日配置中配置 ${queryParams.value.year} 年度的节假日。`, '提示', {
|
|
|
+ type: 'warning',
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ closeOnClickModal: false, // 点击遮罩层不关闭
|
|
|
+ closeOnPressEscape: false // 按ESC键不关闭
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }).catch(() => {
|
|
|
+ holidayStats.value = [];
|
|
|
+ list.value = [];
|
|
|
+ total.value = 0;
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+/** 查询节假日出入境明细数据 - 只更新表格数据,不重新加载统计信息 */
|
|
|
+function getList(startDate, endDate) {
|
|
|
+ loading.value = true;
|
|
|
+
|
|
|
+ // 准备查询参数
|
|
|
+ const params = {
|
|
|
+ year: queryParams.value.year,
|
|
|
+ startDate: startDate,
|
|
|
+ endDate: endDate
|
|
|
+ };
|
|
|
+
|
|
|
+ // 添加分页参数
|
|
|
+ params.pageNum = queryParams.value.pageNum;
|
|
|
+ params.pageSize = queryParams.value.pageSize;
|
|
|
+
|
|
|
+ // 调用明细数据接口
|
|
|
+ getHolidayInOutDetails(params).then(response => {
|
|
|
+ // 处理明细数据,添加节假日名称
|
|
|
+ const processedList = (response.rows || []).map(row => ({
|
|
|
+ ...row,
|
|
|
+ holidayName: getHolidayNameByDate(startDate, endDate)
|
|
|
+ }));
|
|
|
+
|
|
|
+ list.value = processedList;
|
|
|
+ total.value = response.total || 0;
|
|
|
+
|
|
|
+ loading.value = false;
|
|
|
+ }).catch(() => {
|
|
|
+ list.value = [];
|
|
|
+ total.value = 0;
|
|
|
+ loading.value = false;
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+/** 根据日期获取节假日名称 */
|
|
|
+function getHolidayNameByDate(startDate, endDate) {
|
|
|
+ const holiday = holidayStats.value.find(stat =>
|
|
|
+ stat.startDate === startDate && stat.endDate === endDate
|
|
|
+ );
|
|
|
+ return holiday ? holiday.holidayName : '';
|
|
|
+}
|
|
|
+
|
|
|
+/** 处理分页事件 - 只更新表格数据,不重新加载统计信息 */
|
|
|
+function handlePagination() {
|
|
|
+ // 分页只更新表格数据,不重新获取统计信息
|
|
|
+ loading.value = true;
|
|
|
+
|
|
|
+ // 准备查询参数
|
|
|
+ const params = {
|
|
|
+ year: queryParams.value.year,
|
|
|
+ startDate: queryParams.value.startDate,
|
|
|
+ endDate: queryParams.value.endDate,
|
|
|
+ pageNum: queryParams.value.pageNum,
|
|
|
+ pageSize: queryParams.value.pageSize
|
|
|
+ };
|
|
|
+
|
|
|
+ getHolidayInOutDetails(params).then(response => {
|
|
|
+ // 直接更新list,不进行其他操作
|
|
|
+ list.value = response.rows || [];
|
|
|
+ total.value = response.total || 0;
|
|
|
+
|
|
|
+ loading.value = false;
|
|
|
+ }).catch(() => {
|
|
|
+ list.value = [];
|
|
|
+ total.value = 0;
|
|
|
+ loading.value = false;
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+/** 搜索按钮操作 */
|
|
|
+function handleQuery() {
|
|
|
+ queryParams.value.pageNum = 1;
|
|
|
+ getStats(); // 先获取统计信息
|
|
|
+}
|
|
|
+
|
|
|
+/** 重置按钮操作 */
|
|
|
+function resetQuery() {
|
|
|
+ proxy.resetForm("queryRef");
|
|
|
+ queryParams.value.year = new Date().getFullYear().toString();
|
|
|
+ handleQuery();
|
|
|
+}
|
|
|
+
|
|
|
+/** 处理表格行点击事件 */
|
|
|
+function handleRowClick(row) {
|
|
|
+ detailForm.value = { ...row };
|
|
|
+ detailTitle.value = `详细信息 - ${row.fullName}`;
|
|
|
+ recordDetailOpen.value = true;
|
|
|
+}
|
|
|
+
|
|
|
+/** 改变年份 */
|
|
|
+function changeYear(step) {
|
|
|
+ const currentYear = parseInt(queryParams.value.year);
|
|
|
+ queryParams.value.year = (currentYear + step).toString();
|
|
|
+ handleQuery();
|
|
|
+}
|
|
|
+
|
|
|
+/** 选择节假日 */
|
|
|
+function selectHoliday(row) {
|
|
|
+ selectedHolidayName.value = row.holidayName;
|
|
|
+
|
|
|
+ // 更新查询参数
|
|
|
+ queryParams.value.startDate = row.startDate;
|
|
|
+ queryParams.value.endDate = row.endDate;
|
|
|
+
|
|
|
+ // 查询该节假日的明细数据
|
|
|
+ getList(row.startDate, row.endDate);
|
|
|
+}
|
|
|
+
|
|
|
+/** 表格行样式设置 */
|
|
|
+function tableRowClassName({ row }) {
|
|
|
+ return selectedHolidayName.value === row.holidayName ? 'selected-row' : '';
|
|
|
+}
|
|
|
+
|
|
|
+// 初始化时直接查询,使用reactive中设置的默认值
|
|
|
+onMounted(() => {
|
|
|
+ handleQuery();
|
|
|
+});
|
|
|
+
|
|
|
+onUnmounted(() => {
|
|
|
+ if (chartInstance) {
|
|
|
+ chartInstance.dispose();
|
|
|
+ }
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.app-container {
|
|
|
+ padding: 15px;
|
|
|
+}
|
|
|
+
|
|
|
+.el-row {
|
|
|
+ margin-bottom: 15px;
|
|
|
+}
|
|
|
+
|
|
|
+.el-table {
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
|
+ border-radius: 8px;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.el-card {
|
|
|
+ border-radius: 8px;
|
|
|
+ border: none;
|
|
|
+}
|
|
|
+
|
|
|
+.chart-and-stats-container {
|
|
|
+ display: flex;
|
|
|
+ gap: 20px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.chart-section {
|
|
|
+ flex: 0.7; /* 缩小图表区域,占用70%的宽度 */
|
|
|
+ min-width: 0; /* 允许flex项目收缩到其内容的固有尺寸以下 */
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
+ border-radius: 8px;
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
|
+ padding: 15px;
|
|
|
+ background-color: #fafafa;
|
|
|
+ height: 400px; /* 固定高度 */
|
|
|
+}
|
|
|
+
|
|
|
+.stats-section {
|
|
|
+ flex: 0.3; /* 统计区域占用30%的宽度 */
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
+ border-radius: 8px;
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
|
+ padding: 15px;
|
|
|
+ background-color: #fafafa;
|
|
|
+ height: 400px; /* 设置固定高度 */
|
|
|
+}
|
|
|
+
|
|
|
+.chart-container {
|
|
|
+ width: 100%;
|
|
|
+ height: 400px;
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
+ border-radius: 8px;
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.chart-container {
|
|
|
+ width: 100%;
|
|
|
+ height: 320px; /* 调整为固定高度,留出标题空间 */
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
+ border-radius: 8px;
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
|
+}
|
|
|
+
|
|
|
+.section-title {
|
|
|
+ margin: 0 0 15px 0;
|
|
|
+ color: #303133;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ border-bottom: 2px solid #409eff;
|
|
|
+ padding-bottom: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.table-header {
|
|
|
+ margin-top: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.selected-holiday {
|
|
|
+ color: #409eff;
|
|
|
+ font-weight: bold;
|
|
|
+ font-size: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 高亮选中的表格行 */
|
|
|
+:deep(.selected-row) {
|
|
|
+ background-color: #f5f7fa !important;
|
|
|
+ color: #409eff;
|
|
|
+ font-weight: bold;
|
|
|
+}
|
|
|
+
|
|
|
+/* 为表格添加边框和阴影 */
|
|
|
+:deep(.el-table) {
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
+ border-radius: 8px;
|
|
|
+}
|
|
|
+</style>
|