| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765 |
- <template>
- <div class="app-container">
- <el-form :model="queryParams" ref="queryRef" :inline="true" label-width="68px">
- <el-form-item label="查询方式" prop="queryType">
- <el-select v-model="queryParams.queryType" placeholder="请选择查询方式" clearable style="width: 150px;" @change="handleQuery">
- <el-option label="按年查询" value="year" />
- <el-option label="按月查询" value="month" />
- <el-option label="按时段查询" value="range" />
- </el-select>
- </el-form-item>
- <el-form-item v-if="queryParams.queryType === 'year'" label="年份" prop="year">
- <el-date-picker
- v-model="queryParams.year"
- type="year"
- value-format="YYYY"
- placeholder="请选择年份"
- @change="handleQuery">
- </el-date-picker>
- </el-form-item>
- <el-form-item v-if="queryParams.queryType === 'month'" label="月份" prop="month">
- <el-date-picker
- v-model="queryParams.month"
- type="month"
- value-format="YYYY-MM"
- placeholder="请选择月份"
- @change="handleQuery">
- </el-date-picker>
- </el-form-item>
- <el-form-item v-if="queryParams.queryType === 'range'" label="时段" prop="dateRange">
- <el-date-picker
- v-model="queryParams.dateRange"
- type="daterange"
- value-format="YYYY-MM-DD"
- range-separator="至"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- @change="handleQuery">
- </el-date-picker>
- </el-form-item>
- </el-form>
- <!-- 统计数据卡片 -->
- <el-row :gutter="20" class="mb20">
- <el-col :span="6">
- <el-card class="stat-card total-people">
- <div class="stat-item">
- <div class="stat-number">{{ statistics.totalPeople }}</div>
- <div class="stat-label">夜间出入境总人数</div>
- </div>
- </el-card>
- </el-col>
- <el-col :span="6">
- <el-card class="stat-card total-entries">
- <div class="stat-item">
- <div class="stat-number">{{ statistics.totalEntries }}</div>
- <div class="stat-label">夜间出入境总次数</div>
- </div>
- </el-card>
- </el-col>
- <el-col :span="6">
- <el-card class="stat-card avg-frequency">
- <div class="stat-item">
- <div class="stat-number">{{ statistics.avgFrequency }}</div>
- <div class="stat-label">平均频次</div>
- </div>
- </el-card>
- </el-col>
- <el-col :span="6">
- <el-card class="stat-card max-frequency">
- <div class="stat-item">
- <div class="stat-number">{{ statistics.maxFrequency }}</div>
- <div class="stat-label">最高频次</div>
- </div>
- </el-card>
- </el-col>
- </el-row>
- <!-- 趋势图 -->
- <el-row :gutter="10" style="margin-bottom: 20px;">
- <div style="height: 500px; width: 100%;">
- <div class="table_caption" style="height: 30px; line-height: 30px;">夜间出入境人员数量趋势图</div>
- <div style="height: 470px; width: 100%; border: 1px solid #ededed; background: #fff;" ref="trendChartContainer">
- <div id="trendChart" style="height: 100%; width: 100%;"></div>
- </div>
- </div>
- </el-row>
- <!-- 明细数据表格 -->
- <el-table v-loading="loading" :data="detailsList" style="margin-top: 20px;" @row-click="handleRowClick">
- <el-table-column label="序号" type="index" width="50" align="center" />
- <el-table-column label="姓名" prop="fullName" align="center" 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="createTime" width="150">
- <template #default="scope">
- <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
- </template>
- </el-table-column>
- </el-table>
- <div style="margin-top: 10px;">
- <div v-if="detailsList.length === 0 && !loading" style="margin-top: 10px; color: #f56c6c;">
- <el-icon><Warning /></el-icon> 暂无数据,请检查API返回结果
- </div>
- </div>
- <!-- 出入境记录明细对话框 -->
- <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"
- />
- <div v-if="total === 0 && !loading" style="text-align: center; padding: 20px; color: #909399;">
- 暂无数据
- </div>
- </div>
- </template>
- <script setup name="Night">
- import * as echarts from 'echarts'
- import { getNightInOutStats, getNightInOutDetail } from "@/api/biz/anal";
- import { getCurrentInstance, nextTick, onMounted, onUnmounted, reactive, ref, toRefs, watch } from 'vue';
- import Pagination from "@/components/Pagination/index.vue";
- import { parseTime, resetForm } from "@/utils/ruoyi";
- import { Pointer, Warning } from "@element-plus/icons-vue";
- const { proxy } = getCurrentInstance();
- const detailsList = ref([]);
- const loading = ref(false);
- const total = ref(0);
- const trendChartContainer = ref(null);
- const statistics = ref({
- totalPeople: 0,
- totalEntries: 0,
- avgFrequency: 0,
- maxFrequency: 0
- });
- // 出入境记录明细相关
- const recordDetailOpen = ref(false);
- const recordDetailLoading = ref(false);
- const detailTitle = ref("详细信息");
- const detailForm = ref({});
- const data = reactive({
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- queryType: 'year', // 默认查询类型为年
- year: new Date().getFullYear().toString(), // 默认年份
- month: null, // 初始不设置月份
- dateRange: null // 初始不设置日期范围
- }
- });
- const { queryParams } = toRefs(data);
- // 监听查询方式变化,设置默认值
- watch(() => queryParams.value.queryType, (newVal) => {
- if (newVal === 'month' && (!queryParams.value.month || queryParams.value.month === null)) {
- // 当选择按月查询时,默认选中当月
- const now = new Date();
- queryParams.value.month = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
- // 立即查询
- handleQuery();
- } else if (newVal === 'range' && (!queryParams.value.dateRange || queryParams.value.dateRange.length === 0)) {
- // 当选择按时段查询时,默认最近7天
- const now = new Date();
- const startDate = new Date();
- startDate.setDate(now.getDate() - 6); // 最近7天
-
- const startStr = `${startDate.getFullYear()}-${String(startDate.getMonth() + 1).padStart(2, '0')}-${String(startDate.getDate()).padStart(2, '0')}`;
- const endStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
-
- queryParams.value.dateRange = [startStr, endStr];
- // 立即查询
- handleQuery();
- } else if (newVal === 'year') {
- // 当选择按年查询时,也立即查询
- handleQuery();
- }
- }, { immediate: true });
- /** 查询夜间出入境数据 */
- function getList() {
- loading.value = true;
- // 准备查询参数
- const params = {};
- if (queryParams.value.queryType === 'year') {
- params.year = queryParams.value.year;
- } else if (queryParams.value.queryType === 'month') {
- params.month = queryParams.value.month;
- } else if (queryParams.value.queryType === 'range') {
- if (queryParams.value.dateRange && queryParams.value.dateRange.length === 2) {
- params.startDate = queryParams.value.dateRange[0];
- params.endDate = queryParams.value.dateRange[1];
- }
- }
- // 同时调用统计数据接口和明细数据接口
- Promise.all([
- getNightInOutStats(params),
- getNightInOutDetail({ ...params, pageNum: queryParams.value.pageNum, pageSize: queryParams.value.pageSize })
- ]).then(responses => {
- // 处理统计数据和趋势数据
- const statsResponse = responses[0];
- // 处理明细数据
- const detailResponse = responses[1];
- if (statsResponse.code === 200 && statsResponse.data) {
- const data = statsResponse.data;
- // 处理趋势数据
- const trendData = data.trendData || [];
-
- // 直接使用后端返回的统计数据
- statistics.value = {
- totalPeople: data.totalPeople || 0,
- totalEntries: data.totalCount || 0,
- avgFrequency: Number(data.avgFrequency).toFixed(2) || 0,
- maxFrequency: data.maxFrequency || 0
- };
-
- // 确保在DOM更新后再渲染图表
- nextTick(() => {
- renderTrendChart(trendData, queryParams.value.queryType);
- });
- } else {
- // 如果统计数据API调用失败,初始化空数据
- statistics.value = {
- totalPeople: 0,
- totalEntries: 0,
- avgFrequency: 0,
- maxFrequency: 0
- };
-
- // 即使统计数据失败,也尝试渲染空的图表
- nextTick(() => {
- renderTrendChart([], queryParams.value.queryType);
- });
- }
- if (detailResponse.code === 200) {
- // 处理分页数据 - 使用rows和total字段
- // 根据API响应结构,数据直接在响应对象中,而非data字段下
- detailsList.value = detailResponse.rows || [];
- total.value = detailResponse.total || 0;
-
- } else {
- // 如果明细数据API调用失败,初始化空数据
- detailsList.value = [];
- total.value = 0;
- }
- loading.value = false;
- }).catch(error => {
- console.error('获取夜间出入境数据失败:', error);
- // 初始化空数据
- detailsList.value = [];
- total.value = 0;
- statistics.value = {
- totalPeople: 0,
- totalEntries: 0,
- avgFrequency: 0,
- maxFrequency: 0
- };
-
- // 确保即使出错也渲染空图表
- nextTick(() => {
- renderTrendChart([], queryParams.value.queryType);
- });
-
- loading.value = false;
- });
- }
- /** 处理分页事件 */
- function handlePagination() {
- // 分页只更新表格数据,不重新获取统计和图表数据
- loading.value = true;
- // 准备查询参数(仅用于表格数据)
- const params = {};
- if (queryParams.value.queryType === 'year') {
- params.year = queryParams.value.year;
- } else if (queryParams.value.queryType === 'month') {
- params.month = queryParams.value.month;
- } else if (queryParams.value.queryType === 'range') {
- if (queryParams.value.dateRange && queryParams.value.dateRange.length === 2) {
- params.startDate = queryParams.value.dateRange[0];
- params.endDate = queryParams.value.dateRange[1];
- }
- }
-
- // 添加分页参数
- params.pageNum = queryParams.value.pageNum;
- params.pageSize = queryParams.value.pageSize;
-
- getNightInOutDetail(params).then(response => {
- if (response.code === 200) {
- // 处理分页数据 - 使用rows和total字段
- // 根据API响应结构,数据直接在响应对象中,而非data字段下
- detailsList.value = response.rows || [];
- total.value = response.total || 0;
- } else {
- detailsList.value = [];
- total.value = 0;
- }
-
- loading.value = false;
- }).catch((error) => {
- console.error('分页API调用失败:', error); // 添加错误调试信息
- detailsList.value = [];
- total.value = 0;
- loading.value = false;
- });
- }
- /** 根据趋势数据计算统计数据 */
- function calculateStatisticsFromTrendData(trendData, details) {
- let totalPeople = 0;
- let totalEntries = details.length || 0;
- let maxFreq = 0;
- let avgFrequency = 0;
- // 计算总人数(去重后的证件号码数量)
- const uniquePersons = new Set();
- details.forEach(item => {
- if (item.idNumber) {
- uniquePersons.add(item.idNumber);
- }
- });
- totalPeople = uniquePersons.size;
- // 计算每个证件号码的出入境次数,找出最高频次
- const personCountMap = {};
- details.forEach(item => {
- if (item.idNumber) {
- personCountMap[item.idNumber] = (personCountMap[item.idNumber] || 0) + 1;
- }
- });
- if (Object.keys(personCountMap).length > 0) {
- maxFreq = Math.max(...Object.values(personCountMap));
- avgFrequency = totalEntries / totalPeople;
- }
- // 如果趋势数据包含总数信息,也可以使用
- if (trendData && trendData.length > 0) {
- // 累加趋势数据中的人数
- const trendTotal = trendData.reduce((sum, item) => sum + (item.personCount || item.count || 0), 0);
- // 使用较大的值作为总人数(可能趋势数据和明细数据统计方式不同)
- totalPeople = Math.max(totalPeople, trendTotal);
- }
- return {
- totalPeople: totalPeople,
- totalEntries: totalEntries,
- avgFrequency: Number(avgFrequency).toFixed(2) || 0,
- maxFrequency: maxFreq
- };
- }
- /** 渲染趋势图 */
- function renderTrendChart(trendData, queryType) {
- if (!trendChartContainer.value) return;
- // 如果已有图表实例,先销毁
- if (trendChartContainer.value.__echarts_instance) {
- echarts.getInstanceByDom(trendChartContainer.value)?.dispose();
- }
- const myChart = echarts.init(trendChartContainer.value);
- // 保存图表实例引用
- trendChartContainer.value.__echarts_instance = myChart;
- let xAxisData = [];
- let seriesData = [];
- if (trendData && trendData.length > 0) {
- // 根据查询类型确定X轴标签
- if (queryType === 'year') {
- // 按年查询,显示每月趋势,使用period字段
- xAxisData = trendData.map(item => {
- // period格式可能是 "2023-01" 格式
- if (item.period) {
- // 检查是否包含日期分隔符,提取月份
- if (item.period.includes('-')) {
- const parts = item.period.split('-');
- if (parts.length === 2) {
- return parts[1] + '月'; // 如 "01月"
- }
- }
- return item.period + '月';
- } else {
- return '未知';
- }
- });
- } else if (queryType === 'month') {
- // 按月查询,显示当月每天趋势
- xAxisData = trendData.map(item => {
- if (item.period) {
- // 如果是完整日期格式 "YYYY-MM-DD",取日部分
- if (item.period.includes('-')) {
- const parts = item.period.split('-');
- if (parts.length === 3) {
- return parts[2] + '日'; // 如 "01日"
- }
- }
- return item.period + '日';
- } else {
- return '未知';
- }
- });
- } else {
- // 按时段查询,显示按天趋势
- xAxisData = trendData.map(item => {
- if (item.period) {
- // 如果是完整日期格式 "YYYY-MM-DD",显示 MM-DD
- if (item.period.includes('-')) {
- const parts = item.period.split('-');
- if (parts.length === 3) {
- return parts[1] + '-' + parts[2]; // 如 "05-15"
- }
- }
- return item.period;
- } else {
- return '未知';
- }
- });
- }
- // 获取人数或次数数据 - 使用inOutCount字段
- seriesData = trendData.map(item => {
- // 使用新的字段名inOutCount
- return item.inOutCount !== undefined ? item.inOutCount : 0;
- });
- } else {
- // 如果没有趋势数据,显示提示信息
- xAxisData = ['暂无数据'];
- seriesData = [0];
- }
- const option = {
- title: {
- text: getTrendChartTitle(queryType),
- left: 'center'
- },
- tooltip: {
- trigger: 'axis',
- axisPointer: {
- type: 'shadow'
- },
- formatter: (params) => {
- const param = params[0];
- if (param.name === '暂无数据') {
- return '暂无数据';
- }
- const date = xAxisData[param.dataIndex];
- const value = param.value;
- return `${date}<br/>夜间出入境人数:${value}`;
- }
- },
- xAxis: {
- type: 'category',
- data: xAxisData,
- axisLabel: {
- rotate: 45,
- fontSize: 12
- }
- },
- yAxis: {
- type: 'value',
- name: '人数'
- },
- series: [{
- data: seriesData,
- type: 'line',
- smooth: true,
- itemStyle: {
- color: '#5470c6'
- },
- areaStyle: {
- color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
- { offset: 0, color: 'rgba(84, 112, 198, 0.4)' },
- { offset: 1, color: 'rgba(84, 112, 198, 0.1)' }
- ])
- }
- }]
- };
- myChart.setOption(option);
- }
- /** 获取趋势图标题 */
- function getTrendChartTitle(queryType) {
- if (queryType === 'year') {
- return `年度夜间出入境人员月度趋势图 (年: ${queryParams.value.year})`;
- } else if (queryType === 'month') {
- return `月度夜间出入境人员每日趋势图 (月: ${queryParams.value.month})`;
- } else {
- const start = queryParams.value.dateRange ? queryParams.value.dateRange[0] : '';
- const end = queryParams.value.dateRange ? queryParams.value.dateRange[1] : '';
- return `指定时段夜间出入境人员趋势图 (${start} 至 ${end})`;
- }
- }
- /** 搜索按钮操作 */
- function handleQuery() {
- queryParams.value.pageNum = 1;
- getList();
- }
- /** 重置按钮操作 */
- function resetQuery() {
- proxy.resetForm("queryRef");
- queryParams.value.queryType = 'year';
- queryParams.value.year = new Date().getFullYear().toString();
- queryParams.value.month = null;
- queryParams.value.dateRange = null;
- handleQuery();
- }
- /** 处理表格行点击事件 */
- function handleRowClick(row) {
- // 显示详细信息
- detailForm.value = { ...row };
- detailTitle.value = `${row.fullName || '未知'} 详细信息`;
- recordDetailOpen.value = true;
- }
- // 在组件挂载后,根据默认查询类型执行查询
- onMounted(() => {
- // 确保在DOM更新后再执行查询
- nextTick(() => {
- handleQuery();
- });
- });
- // 在组件卸载时清理图表实例
- onUnmounted(() => {
- if (trendChartContainer.value && trendChartContainer.value.__echarts_instance) {
- echarts.getInstanceByDom(trendChartContainer.value)?.dispose();
- trendChartContainer.value.__echarts_instance = null;
- }
- });
- </script>
- <style lang="scss" scoped>
- .app-container {
- padding: 20px;
- }
- .stat-card {
- height: 80px;
- text-align: center;
- .stat-item {
- .stat-number {
- font-size: 24px;
- font-weight: bold;
- color: #409eff;
- margin-bottom: 5px;
- }
- .stat-label {
- font-size: 14px;
- color: #606266;
- }
- }
- &.total-people { .stat-number { color: #409eff; } }
- &.total-entries { .stat-number { color: #67c21a; } }
- &.avg-frequency { .stat-number { color: #e6a23c; } }
- &.max-frequency { .stat-number { color: #f56c6c; } }
- }
- .mb20 {
- margin-bottom: 20px;
- }
- .table_caption {
- font-weight: bold;
- text-align: left;
- padding-left: 10px;
- background-color: #f5f7fa;
- }
- </style>
|