wukai 4 месяцев назад
Родитель
Сommit
a105bb20fd

+ 9 - 0
src/api/biz/anal.js

@@ -71,3 +71,12 @@ export function getNightInOutDetail(params) {
         params: params
     })
 }
+
+// 查询短期往返明细数据
+export function getRapid(params) {
+    return request({
+        url: '/biz/anal/rapid',
+        method: 'get',
+        params: params
+    })
+}

+ 280 - 0
src/components/RecordListDetailDialog.vue

@@ -0,0 +1,280 @@
+<template>
+  <!-- 出入境记录列表对话框 -->
+  <el-dialog :title="recordListTitle" v-model="recordListOpen" width="1200px" append-to-body>
+    <el-table :data="recordList" v-loading="recordListLoading" @row-click="handleRecordRowClick">
+      <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="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>
+  </el-dialog>
+</template>
+
+<script setup>
+import {ref, watch} from 'vue';
+import {getRecords} from "@/api/biz/anal";
+import {parseTime} from "@/utils/ruoyi";
+
+// 定义组件属性
+const props = defineProps({
+  visible: {
+    type: Boolean,
+    default: false
+  },
+  personInfo: {
+    type: Object,
+    default: () => ({})
+  },
+  dateRange: {
+    type: Array,
+    default: () => []
+  }
+});
+
+// 定义事件
+const emit = defineEmits(['update:visible', 'close']);
+
+// 响应式数据
+const recordListOpen = ref(false);
+const recordListLoading = ref(false);
+const recordListTitle = ref("出入境记录列表");
+const recordList = ref([]);
+
+const recordDetailOpen = ref(false);
+const detailTitle = ref("详细信息");
+const detailForm = ref({});
+
+// 监听 visible 属性变化
+watch(() => props.visible, (newVal) => {
+  recordListOpen.value = newVal;
+  if (newVal && props.personInfo) {
+    loadRecordList();
+  }
+});
+
+// 监听对话框关闭
+watch(() => recordListOpen.value, (newVal) => {
+  if (!newVal) {
+    emit('update:visible', false);
+    emit('close');
+  }
+});
+
+// 加载记录列表
+function loadRecordList() {
+  if (!props.personInfo || !props.personInfo.idNumber) {
+    console.error('缺少人员信息');
+    return;
+  }
+
+  recordListLoading.value = true;
+
+  // 准备查询参数
+  const params = {};
+  if (props.dateRange && props.dateRange.length === 2) {
+    params.startDate = props.dateRange[0];
+    params.endDate = props.dateRange[1];
+  }
+
+  // 添加证件号码参数
+  params.idNumber = props.personInfo.idNumber;
+
+  getRecords(params).then(response => {
+    const records = response.rows || response.data || [];
+    recordList.value = records;
+    recordListTitle.value = `${props.personInfo.fullName}的出入境记录列表 (${records.length}条记录)`;
+  }).catch(error => {
+    console.error('获取出入境记录失败:', error);
+    recordList.value = [];
+    recordListTitle.value = `${props.personInfo.fullName}的出入境记录列表 (0条记录)`;
+  }).finally(() => {
+    recordListLoading.value = false;
+  });
+}
+
+// 处理记录列表行点击事件
+function handleRecordRowClick(recordRow) {
+  detailForm.value = {...recordRow};
+  detailTitle.value = `详细信息 - ${recordRow.fullName}`;
+  recordDetailOpen.value = true;
+}
+</script>

+ 32 - 209
src/views/biz/anal/high.vue

@@ -99,182 +99,14 @@
       <el-table-column label="出入境次数" prop="count" align="center" />
     </el-table>
 
-    <!-- 出入境记录列表对话框 -->
-    <el-dialog :title="recordListTitle" v-model="recordListOpen" width="1200px" append-to-body>
-      <el-table :data="recordList" v-loading="recordListLoading" @row-click="handleRecordRowClick">
-        <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="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>
-
-    <!-- 出入境记录明细对话框 -->
-    <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>
+    <!-- 使用公共组件 -->
+    <RecordListDetailDialog 
+      :visible="recordListOpen" 
+      :person-info="selectedPersonInfo" 
+      :date-range="getDateRangeForQuery()"
+      @update:visible="recordListOpen = $event"
+      @close="recordListOpen = false"
+    />
 
     <pagination
       v-show="total>0"
@@ -289,6 +121,7 @@
 <script setup name="High">
 import * as echarts from 'echarts'
 import { listHighFrequencyInOut, getInOutStats, getRecords } from "@/api/biz/anal";
+import RecordListDetailDialog from '@/components/RecordListDetailDialog.vue';
 
 const { proxy } = getCurrentInstance();
 
@@ -319,6 +152,7 @@ const recordListOpen = ref(false);
 const recordListLoading = ref(false);
 const recordListTitle = ref("出入境记录列表");
 const recordList = ref([]);
+const selectedPersonInfo = ref({});
 
 const data = reactive({
   queryParams: {
@@ -994,45 +828,34 @@ function resetQuery() {
 
 /** 处理表格行点击事件 */
 function handleRowClick(row) {
-  // 根据证件号码查询出入境记录列表
-  recordListLoading.value = true;
+  // 设置选中人员信息
+  selectedPersonInfo.value = { ...row };
+  // 打开记录列表对话框
   recordListOpen.value = true;
-  
-  // 准备查询参数,使用当前页面的日期范围参数
-  const params = {};
+}
+
+/** 获取用于查询的日期范围 */
+function getDateRangeForQuery() {
   if (queryParams.value.queryType === 'year') {
-    params.year = queryParams.value.year;
+    // 按年查询,返回该年的开始和结束日期
+    const year = queryParams.value.year;
+    return [`${year}-01-01`, `${year}-12-31`];
   } 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];
-    }
+    // 按月查询,返回该月的开始和结束日期
+    const month = queryParams.value.month;
+    const date = new Date(`${month}-01`);
+    const lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
+    return [`${month}-01`, `${month}-${String(lastDay).padStart(2, '0')}`];
+  } else if (queryParams.value.queryType === 'range' && 
+             queryParams.value.dateRange && 
+             queryParams.value.dateRange.length === 2) {
+    // 按时段查询,直接返回选择的日期范围
+    return queryParams.value.dateRange;
   }
-  
-  // 添加证件号码参数
-  params.idNumber = row.idNumber;
-  
-  getRecords(params).then(response => {
-    const records = response.rows || response.data || [];
-    recordList.value = records;
-    recordListTitle.value = `${row.fullName}的出入境记录列表 (${records.length}条记录)`;
-  }).catch(error => {
-    console.error('获取出入境记录失败:', error);
-    recordList.value = [];
-    recordListTitle.value = `${row.fullName}的出入境记录列表 (0条记录)`;
-  }).finally(() => {
-    recordListLoading.value = false;
-  });
+  return [];
 }
 
-/** 处理记录列表行点击事件 */
-function handleRecordRowClick(recordRow) {
-  detailForm.value = { ...recordRow };
-  detailTitle.value = `详细信息 - ${recordRow.fullName}`;
-  recordDetailOpen.value = true;
-}
+
 
 // 页面加载时获取数据
 onMounted(() => {

+ 250 - 0
src/views/biz/anal/rapid.vue

@@ -0,0 +1,250 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" label-width="150px">
+      <el-form-item 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-form-item>
+      <el-form-item label="往返次数大于等于" prop="times">
+        <el-input-number v-model="queryParams.times" :min="2" :step="1" placeholder="" @change="handleQuery" />
+      </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-table v-loading="loading" :data="detailsList" style="margin-top: 20px;" @row-click="handleRowClick">
+      <el-table-column label="序号" type="index" align="center" />
+      <el-table-column label="证件号码" prop="idNumber" align="center" />
+      <el-table-column label="姓名" prop="fullName" align="center" />
+      <el-table-column label="出境次数" align="center" prop="outTimes" />
+      <el-table-column label="入境次数" align="center" prop="inTimes" />
+      <el-table-column label="往返次数" align="center" prop="times" />
+    </el-table>
+
+    <!-- 使用公共组件 -->
+    <RecordListDetailDialog
+      :visible="recordListOpen"
+      :person-info="selectedPersonInfo"
+      :date-range="queryParams.dateRange"
+      @update:visible="recordListOpen = $event"
+      @close="recordListOpen = false"
+    />
+  </div>
+</template>
+
+<script setup name="Rapid">
+import { getRapid } from "@/api/biz/anal";
+import { getCurrentInstance, onMounted, reactive, ref, toRefs } from 'vue';
+import { parseTime, resetForm } from "@/utils/ruoyi";
+import { Pointer } from "@element-plus/icons-vue";
+import RecordListDetailDialog from '@/components/RecordListDetailDialog.vue';
+
+const { proxy } = getCurrentInstance();
+
+const detailsList = ref([]);
+const loading = ref(false);
+
+const statistics = ref({
+  totalPeople: 0,
+  totalEntries: 0,
+  avgFrequency: 0,
+  maxFrequency: 0
+});
+
+// 记录列表对话框相关
+const recordListOpen = ref(false);
+const selectedPersonInfo = ref({});
+
+const data = reactive({
+  queryParams: {
+    dateRange: [],  // 默认为空,后续会设置为最近7天
+    times: 3        // 默认次数为3
+  }
+});
+
+const { queryParams } = toRefs(data);
+
+// 初始化日期范围为最近7天
+onMounted(() => {
+  // 计算最近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();
+});
+
+/** 查询短期往返数据 */
+function getList() {
+  loading.value = true;
+
+  // 准备查询参数
+  const params = {};
+  if (queryParams.value.dateRange && queryParams.value.dateRange.length === 2) {
+    params.startDate = queryParams.value.dateRange[0];
+    params.endDate = queryParams.value.dateRange[1];
+  }
+  params.minTimes = queryParams.value.times;  // 添加次数参数,后端参数名为minTimes
+
+  // 调用后端接口获取数据
+  getRapid(params).then(response => {
+    if (response.code === 200) {
+      // 处理返回的完整列表数据
+      // 后端返回的是直接的列表数据,不是包装在rows中的
+      detailsList.value = response.data || [];
+
+      // 从前端计算统计数据
+      calculateStatisticsFromDetails(detailsList.value);
+    } else {
+      // 如果API调用失败,初始化空数据
+      detailsList.value = [];
+      statistics.value = {
+        totalPeople: 0,
+        totalEntries: 0,
+        avgFrequency: 0,
+        maxFrequency: 0
+      };
+      console.error('API返回错误:', response.msg);
+    }
+
+    loading.value = false;
+  }).catch(error => {
+    console.error('获取短期往返数据失败:', error);
+    // 初始化空数据
+    detailsList.value = [];
+    statistics.value = {
+      totalPeople: 0,
+      totalEntries: 0,
+      avgFrequency: 0,
+      maxFrequency: 0
+    };
+
+    loading.value = false;
+  });
+}
+
+/** 从前端数据计算统计数据 */
+function calculateStatisticsFromDetails(details) {
+  let totalPeople = details.length || 0;
+  let totalOutTimes = 0;
+  let totalInTimes = 0;
+  let totalTimes = 0;
+
+  // 计算总出境次数、入境次数和往返次数
+  details.forEach(item => {
+    totalOutTimes += item.outTimes || 0;
+    totalInTimes += item.inTimes || 0;
+    totalTimes += item.times || 0;
+  });
+
+  // 更新统计数据
+  statistics.value = {
+    totalPeople: totalPeople,
+    totalEntries: totalOutTimes,
+    avgFrequency: totalInTimes,
+    maxFrequency: totalTimes
+  };
+}
+
+/** 搜索按钮操作 */
+function handleQuery() {
+  getList();
+}
+
+/** 处理表格行点击事件 */
+function handleRowClick(row) {
+  // 设置选中人员信息
+  selectedPersonInfo.value = { ...row };
+  // 打开记录列表对话框
+  recordListOpen.value = true;
+}
+</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>

+ 133 - 98
src/views/biz/other/index.vue

@@ -1,91 +1,71 @@
 <template>
   <div class="app-container">
     <div class="form-wrapper">
+      <h2 style="text-align: center; margin-bottom: 30px; color: #303133;">其他参数配置</h2>
+      
       <el-form ref="otherRef" :model="form" :rules="rules" label-width="120px" class="config-form">
-        <el-form-item label="夜间时段配置" prop="cfg1">
-          <div style="display: flex; align-items: center;">
-            <el-input-number
-              v-model="startHour"
-              :min="18"
-              :max="24"
-              :step="1"
-              placeholder="开始时"
-              style="width: 100px; margin-right: 10px;"
-            />
-            <span style="margin: 0 10px;">-</span>
-            <el-input-number
-              v-model="endHour"
-              :min="1"
-              :max="8"
-              :step="1"
-              placeholder="结束时"
-              style="width: 100px;"
-            />
+        <!-- 夜间时段配置区域 -->
+        <el-card class="config-section" shadow="never">
+          <template #header>
+            <span class="section-title">夜间时段配置</span>
+          </template>
+          <el-form-item label="夜间时段" prop="cfg1">
+            <div style="display: flex; align-items: center;">
+              <el-input-number
+                v-model="startHour"
+                :min="18"
+                :max="24"
+                :step="1"
+                placeholder="开始时"
+                style="width: 100px; margin-right: 10px;"
+              />
+              <span style="margin: 0 10px;">-</span>
+              <el-input-number
+                v-model="endHour"
+                :min="1"
+                :max="8"
+                :step="1"
+                placeholder="结束时"
+                style="width: 100px;"
+              />
+            </div>
+            <div style="margin-top: 5px; color: #909399; font-size: 12px;">最终格式: {{ formatTimeDisplay }}</div>
+          </el-form-item>
+        </el-card>
+        
+        <!-- 短期定义配置区域 -->
+        <el-card class="config-section" shadow="never">
+          <template #header>
+            <span class="section-title">短期定义配置</span>
+          </template>
+          <div style="display: flex; gap: 20px;">
+            <el-form-item label="短期定义天数" prop="cfg2Days" style="flex: 1;">
+              <el-input-number v-model.number="cfg2Days" :min="0" :step="1" placeholder="请输入短期定义天数" />
+            </el-form-item>
+            <el-form-item label="往返次数" prop="cfg2Times" style="flex: 1;">
+              <el-input-number v-model.number="cfg2Times" :min="0" :step="1" placeholder="请输入往返次数" />
+            </el-form-item>
           </div>
-          <div style="margin-top: 5px; color: #909399; font-size: 12px;">最终格式: {{ formatTimeDisplay }}</div>
-        </el-form-item>
-        <el-form-item label="短期定义天数" prop="cfg2">
-          <el-input-number v-model.number="form.cfg2" :min="0" :step="1" placeholder="请输入短期定义天数" />
-        </el-form-item>
-        <el-form-item label="境外滞留天数" prop="cfg3">
-          <el-input-number v-model.number="form.cfg3" :min="0" :step="1" placeholder="请输入境外滞留天数" />
-        </el-form-item>
-        <!--
-        <el-form-item label="配置4" prop="cfg4">
-          <el-input v-model="form.cfg4" placeholder="请输入配置4" />
-        </el-form-item>
-        <el-form-item label="配置5" prop="cfg5">
-          <el-input v-model="form.cfg5" placeholder="请输入配置5" />
-        </el-form-item>
-        <el-form-item label="配置6" prop="cfg6">
-          <el-input v-model="form.cfg6" placeholder="请输入配置6" />
-        </el-form-item>
-        <el-form-item label="配置7" prop="cfg7">
-          <el-input v-model="form.cfg7" placeholder="请输入配置7" />
-        </el-form-item>
-        <el-form-item label="配置8" prop="cfg8">
-          <el-input v-model="form.cfg8" placeholder="请输入配置8" />
-        </el-form-item>
-        <el-form-item label="配置9" prop="cfg9">
-          <el-input v-model="form.cfg9" placeholder="请输入配置9" />
-        </el-form-item>
-        <el-form-item label="配置10" prop="cfg10">
-          <el-input v-model="form.cfg10" placeholder="请输入配置10" />
-        </el-form-item>
-        <el-form-item label="配置11" prop="cfg11">
-          <el-input v-model="form.cfg11" placeholder="请输入配置11" />
-        </el-form-item>
-        <el-form-item label="配置12" prop="cfg12">
-          <el-input v-model="form.cfg12" placeholder="请输入配置12" />
-        </el-form-item>
-        <el-form-item label="配置13" prop="cfg13">
-          <el-input v-model="form.cfg13" placeholder="请输入配置13" />
-        </el-form-item>
-        <el-form-item label="配置14" prop="cfg14">
-          <el-input v-model="form.cfg14" placeholder="请输入配置14" />
-        </el-form-item>
-        <el-form-item label="配置15" prop="cfg15">
-          <el-input v-model="form.cfg15" placeholder="请输入配置15" />
-        </el-form-item>
-        <el-form-item label="配置16" prop="cfg16">
-          <el-input v-model="form.cfg16" placeholder="请输入配置16" />
-        </el-form-item>
-        <el-form-item label="配置17" prop="cfg17">
-          <el-input v-model="form.cfg17" placeholder="请输入配置17" />
-        </el-form-item>
-        <el-form-item label="配置18" prop="cfg18">
-          <el-input v-model="form.cfg18" placeholder="请输入配置18" />
-        </el-form-item>
-        <el-form-item label="配置19" prop="cfg19">
-          <el-input v-model="form.cfg19" placeholder="请输入配置19" />
-        </el-form-item>
-        <el-form-item label="配置20" prop="cfg20">
-          <el-input v-model="form.cfg20" placeholder="请输入配置20" />
-        </el-form-item>
-        -->
-        <el-form-item style="text-align: center; margin-top: 20px;">
-          <el-button type="primary" @click="submitForm" style="width: 120px;">确 定</el-button>
-        </el-form-item>
+          <el-input v-model="form.cfg2" type="hidden" />
+        </el-card>
+        
+        <!-- 境外滞留配置区域 -->
+        <el-card class="config-section" shadow="never">
+          <template #header>
+            <span class="section-title">境外滞留配置</span>
+          </template>
+          <el-form-item label="境外滞留天数" prop="cfg3">
+            <el-input-number v-model.number="form.cfg3" :min="0" :step="1" placeholder="请输入境外滞留天数" />
+          </el-form-item>
+        </el-card>
+        
+        <!-- 操作按钮区域 -->
+        <el-card class="config-section" shadow="never">
+          <div style="text-align: center; margin-top: 20px;">
+            <el-button type="primary" @click="submitForm" style="width: 120px; margin-right: 20px;">确 定</el-button>
+            <el-button @click="handleReset" style="width: 120px;">重 置</el-button>
+          </div>
+        </el-card>
       </el-form>
     </div>
   </div>
@@ -103,6 +83,10 @@ const title = ref("修改其他参数配置");
 const startHour = ref(22);
 const endHour = ref(4);
 
+// 短期定义天数和往返次数
+const cfg2Days = ref(0);
+const cfg2Times = ref(0);
+
 // 计算时间显示格式
 const formatTimeDisplay = computed(() => {
   const start = String(startHour.value).padStart(2, '0');
@@ -133,7 +117,8 @@ const data = reactive({
     cfg1: [
       { validator: validateNightTime, trigger: 'blur' }
     ],
-    // 取消cfg2和cfg3的验证
+    // 取消验证规则
+  
   }
 });
 
@@ -156,6 +141,18 @@ onMounted(() => {
       startHour.value = 22;
       endHour.value = 4;
     }
+    
+    // 解析cfg2中的天数-次数格式
+    if (form.value.cfg2 && form.value.cfg2.includes('-')) {
+      const [days, times] = form.value.cfg2.split('-');
+      cfg2Days.value = parseInt(days) || 0;
+      cfg2Times.value = parseInt(times) || 0;
+    } else {
+      // 如果cfg2不是天数-次数格式,则保持默认值
+      cfg2Days.value = 0;
+      cfg2Times.value = 0;
+    }
+    
     loading.value = false;
   });
 });
@@ -177,6 +174,17 @@ function handleReset() {
       startHour.value = 22;
       endHour.value = 4;
     }
+
+    // 解析cfg2中的天数-次数格式
+    if (form.value.cfg2 && form.value.cfg2.includes('-')) {
+      const [days, times] = form.value.cfg2.split('-');
+      cfg2Days.value = parseInt(days) || 0;
+      cfg2Times.value = parseInt(times) || 0;
+    } else {
+      // 如果cfg2不是天数-次数格式,则保持默认值
+      cfg2Days.value = 0;
+      cfg2Times.value = 0;
+    }
   });
 }
 
@@ -187,25 +195,24 @@ function submitForm() {
   const end = String(endHour.value).padStart(2, '0');
   form.value.cfg1 = `${start}:00-${end}:00`;
 
-  proxy.$refs["otherRef"].validate(valid => {
-    if (valid) {
-      if (form.value.cfgId != null) {
-        updateOther(form.value).then(response => {
-          proxy.$modal.msgSuccess("修改成功");
-        });
-      } else {
-        addOther(form.value).then(response => {
-          proxy.$modal.msgSuccess("新增成功");
-        });
-      }
-    }
-  });
+  // 将短期定义天数和往返次数合并成'天数-次数'格式存储到cfg2
+  form.value.cfg2 = `${cfg2Days.value}-${cfg2Times.value}`;
+
+  if (form.value.cfgId != null) {
+    updateOther(form.value).then(response => {
+      proxy.$modal.msgSuccess("修改成功");
+    });
+  } else {
+    addOther(form.value).then(response => {
+      proxy.$modal.msgSuccess("新增成功");
+    });
+  }
 }
 </script>
 
 <style scoped>
 .form-wrapper {
-  max-width: 600px;
+  max-width: 1000px;
   margin: 0 auto;
   padding: 20px;
   background: #fff;
@@ -216,4 +223,32 @@ function submitForm() {
 .config-form {
   padding: 20px;
 }
+
+.config-section {
+  margin-bottom: 20px;
+  border: 1px solid #e4e7ed;
+  border-radius: 8px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+}
+
+.config-section :deep(.el-card__header) {
+  background-color: #f5f7fa;
+  border-bottom: 1px solid #e4e7ed;
+  padding: 12px 20px;
+}
+
+.section-title {
+  font-size: 16px;
+  font-weight: 600;
+  color: #303133;
+}
+
+.config-section :deep(.el-card__body) {
+  padding: 20px;
+}
+
+/* 为短期定义配置区域的输入框设置最小宽度 */
+.config-section :deep(.el-form-item) {
+  margin-bottom: 22px;
+}
 </style>