|
|
@@ -0,0 +1,363 @@
|
|
|
+<template>
|
|
|
+ <!-- 自定义左侧抽屉-->
|
|
|
+ <div class="custom-drawer" :class="{ 'custom-drawer-open': visible }">
|
|
|
+ <!-- 抽屉头部:标题 + 关闭按钮 -->
|
|
|
+ <div class="custom-drawer-header">
|
|
|
+ <span class="custom-drawer-title">老空区永久密闭管理</span>
|
|
|
+ <div @click="handleClose" class="close-btn"> X </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 抽屉内容区 -->
|
|
|
+ <div class="custom-drawer-body" v-if="visible">
|
|
|
+ <div class="drawer-content">
|
|
|
+ <!-- 搜索区域 -->
|
|
|
+ <!-- <div class="search-section">
|
|
|
+ <MineCascader
|
|
|
+ v-model:value="selectedMineId"
|
|
|
+ placeholder="请选择煤矿"
|
|
|
+ style="width: 60%; margin-right: 8px"
|
|
|
+ :syncToStore="false"
|
|
|
+ :initFromStore="false"
|
|
|
+ :showSearch="true"
|
|
|
+ :allowClear="true"
|
|
|
+ @change="handleMineChange"
|
|
|
+ />
|
|
|
+ <a-button type="primary" @click="handleGoafSearch" style="margin-right: 8px">
|
|
|
+ 搜索
|
|
|
+ </a-button>
|
|
|
+ <a-button @click="handleRefresh">
|
|
|
+ 刷新
|
|
|
+ </a-button>
|
|
|
+ </div> -->
|
|
|
+ <div class="search-section">
|
|
|
+ <a-input v-model:value="searchValue" placeholder="密闭位置" style="width: 60%; margin-right: 8px" />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 传感器数据表格 -->
|
|
|
+ <div class="table-section">
|
|
|
+ <a-table
|
|
|
+ :columns="columns"
|
|
|
+ :data-source="filteredDataWithStatus"
|
|
|
+ :pagination="pagination"
|
|
|
+ :row-key="(record) => record.id"
|
|
|
+ @change="handleTableChange"
|
|
|
+ :scroll="{ y: 'calc(100vh - 320px)' }"
|
|
|
+ size="middle"
|
|
|
+ >
|
|
|
+ <!-- 操作列自定义渲染 -->
|
|
|
+ <template #operation="{ record }">
|
|
|
+ <a-space>
|
|
|
+ <a-button v-if="!record.isPlaced" size="small" @click="handleDeploy(record)"> 布点 </a-button>
|
|
|
+ <a-button v-else size="small" danger @click="handleRemove(record)"> 移除 </a-button>
|
|
|
+ </a-space>
|
|
|
+ </template>
|
|
|
+ </a-table>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts" setup>
|
|
|
+ import { ref, computed, onMounted, watch } from 'vue';
|
|
|
+ import { message } from 'ant-design-vue';
|
|
|
+ import { bindPosition, removePosition, getMarkerStatusList, renderGoafMarkers } from '../app';
|
|
|
+ import { getGoafList } from '../cad.api';
|
|
|
+
|
|
|
+ interface Props {
|
|
|
+ visible: boolean;
|
|
|
+ mineCode: string;
|
|
|
+ }
|
|
|
+ const props = defineProps<Props>();
|
|
|
+ const emit = defineEmits<{
|
|
|
+ (e: 'update:visible', value: boolean): void;
|
|
|
+ }>();
|
|
|
+
|
|
|
+ // 响应式数据
|
|
|
+ const searchValue = ref('');
|
|
|
+ const pagination = ref({
|
|
|
+ current: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ total: 0, // 初始化为0,由接口数据决定
|
|
|
+ });
|
|
|
+ const selectedMineId = ref('');
|
|
|
+ // 新增:存储接口返回的密闭数据
|
|
|
+ const goafList = ref<any[]>([]);
|
|
|
+
|
|
|
+ // 表格列配置 - 修复字段拼写错误(devicePos → devicePos)
|
|
|
+ const columns = [
|
|
|
+ {
|
|
|
+ title: '操作',
|
|
|
+ key: 'operation',
|
|
|
+ slots: { customRender: 'operation' },
|
|
|
+ width: 80,
|
|
|
+ fixed: 'left',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '密闭位置',
|
|
|
+ dataIndex: 'devicePos', // 修正拼写错误
|
|
|
+ key: 'devicePos',
|
|
|
+ ellipsis: true,
|
|
|
+ tooltip: true,
|
|
|
+ },
|
|
|
+ ];
|
|
|
+
|
|
|
+ // 表格数据过滤逻辑 - 核心修改:基于接口坐标判断isPlaced
|
|
|
+ const filteredDataWithStatus = computed(() => {
|
|
|
+ // 从接口返回的goafList过滤
|
|
|
+ let filteredData = goafList.value.filter((item) => {
|
|
|
+ // 密闭位置搜索匹配(兼容空值)
|
|
|
+ const isSearchMatch = searchValue.value ? (item.devicePos || '').includes(searchValue.value) : true;
|
|
|
+ return isSearchMatch;
|
|
|
+ });
|
|
|
+
|
|
|
+ // 关联标记状态 + 核心:优先判断接口返回的坐标
|
|
|
+ const placedMarkers = getMarkerStatusList() || [];
|
|
|
+ const dataWithStatus = filteredData.map((item) => {
|
|
|
+ // 判断接口坐标是否有效(非null/""且为数字)
|
|
|
+ const hasValidX = item.xcoordinate && !isNaN(Number(item.xcoordinate));
|
|
|
+ const hasValidY = item.ycoordinate && !isNaN(Number(item.ycoordinate));
|
|
|
+ // 兜底:本地标记是否存在(防止接口未同步的临时状态)
|
|
|
+ const matchedMarker = placedMarkers.find((marker) => marker.data?.id === item.id);
|
|
|
+
|
|
|
+ return {
|
|
|
+ ...item,
|
|
|
+ // 优先用接口坐标判断,无接口坐标时用本地标记
|
|
|
+ isPlaced: hasValidX && hasValidY,
|
|
|
+ sensorId: matchedMarker?.sensorId || item.id,
|
|
|
+ };
|
|
|
+ });
|
|
|
+
|
|
|
+ // 分页逻辑
|
|
|
+ const start = (pagination.value.current - 1) * pagination.value.pageSize;
|
|
|
+ const end = start + pagination.value.pageSize;
|
|
|
+ pagination.value.total = filteredData.length;
|
|
|
+ return dataWithStatus.slice(start, end);
|
|
|
+ });
|
|
|
+
|
|
|
+ // 关闭抽屉
|
|
|
+ const handleClose = () => emit('update:visible', false);
|
|
|
+
|
|
|
+ // 搜索方法
|
|
|
+ const handleGoafSearch = async () => {
|
|
|
+ // 校验:必须选择煤矿
|
|
|
+ if (!selectedMineId.value) {
|
|
|
+ message.warning('请先选择煤矿!');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 调用接口
|
|
|
+ const res = await getGoafList({
|
|
|
+ order: 'desc',
|
|
|
+ mineCode: selectedMineId.value,
|
|
|
+ });
|
|
|
+ goafList.value = res || [];
|
|
|
+ pagination.value.current = 1; // 搜索后重置页码到第一页
|
|
|
+ renderGoafMarkers(goafList.value); // 渲染标记
|
|
|
+ } catch (error) {
|
|
|
+ goafList.value = [];
|
|
|
+ message.error(`查询失败:${(error as Error).message}`);
|
|
|
+ console.error('接口请求失败:', error);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 刷新方法 - 优化:强制重新请求接口
|
|
|
+ const handleRefresh = async () => {
|
|
|
+ searchValue.value = '';
|
|
|
+ pagination.value.current = 1;
|
|
|
+ pagination.value = { ...pagination.value }; // 触发响应式更新
|
|
|
+
|
|
|
+ // 如果已选择煤矿,刷新时重新请求接口(保证数据最新)
|
|
|
+ if (selectedMineId.value) {
|
|
|
+ await handleGoafSearch();
|
|
|
+ } else {
|
|
|
+ goafList.value = []; // 未选煤矿则清空表格
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 表格分页变化
|
|
|
+ const handleTableChange = (pag: any) => {
|
|
|
+ pagination.value = { ...pagination.value, ...pag };
|
|
|
+ };
|
|
|
+
|
|
|
+ // 布点方法 - 优化:布点后主动刷新接口数据
|
|
|
+ const handleDeploy = async (record: any) => {
|
|
|
+ try {
|
|
|
+ const marker = await bindPosition({
|
|
|
+ id: record.id,
|
|
|
+ devicePos: record.devicePos,
|
|
|
+ });
|
|
|
+ if (!marker) {
|
|
|
+ message.warning('布点操作已取消');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 布点成功后刷新接口数据,保证按钮状态同步
|
|
|
+ await handleRefresh();
|
|
|
+ } catch (error) {
|
|
|
+ message.error(`布点失败:${(error as Error).message}`);
|
|
|
+ console.error('布点失败:', error);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 移除后主动刷新接口数据
|
|
|
+ const handleRemove = async (record: any) => {
|
|
|
+ try {
|
|
|
+ const isSuccess = await removePosition(record.sensorId, record.id);
|
|
|
+ if (isSuccess) {
|
|
|
+ // 移除成功后刷新接口数据,保证按钮状态同步
|
|
|
+ await handleRefresh();
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ message.error(`移除失败:${(error as Error).message}`);
|
|
|
+ console.error('移除失败:', error);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 煤矿选择变化
|
|
|
+ const handleMineChange = (mineId: string) => {
|
|
|
+ selectedMineId.value = mineId;
|
|
|
+ };
|
|
|
+
|
|
|
+ watch(
|
|
|
+ () => props.mineCode,
|
|
|
+ (newVal) => {
|
|
|
+ if (newVal) {
|
|
|
+ selectedMineId.value = newVal;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ { immediate: true }
|
|
|
+ );
|
|
|
+
|
|
|
+ // 监听抽屉显隐:打开时刷新数据
|
|
|
+ watch(
|
|
|
+ () => props.visible,
|
|
|
+ async (isVisible) => {
|
|
|
+ if (isVisible) await handleRefresh(); // 异步数据加载
|
|
|
+ },
|
|
|
+ { immediate: true }
|
|
|
+ );
|
|
|
+
|
|
|
+ // 初始化:分页总数同步为接口数据量
|
|
|
+ onMounted(() => {
|
|
|
+ pagination.value.total = goafList.value.length;
|
|
|
+ });
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+ /* 自定义抽屉核心容器 */
|
|
|
+ .custom-drawer {
|
|
|
+ position: fixed;
|
|
|
+ top: 50px;
|
|
|
+ left: 30px;
|
|
|
+ z-index: 999;
|
|
|
+ width: 450px;
|
|
|
+ height: calc(100vh - 50px);
|
|
|
+ background: #ffffff;
|
|
|
+ box-shadow: 2px 0 12px rgba(0, 0, 0, 0.1);
|
|
|
+ transform: translateX(-100%);
|
|
|
+ transition: transform 0.3s cubic-bezier(0.2, 0, 0, 1);
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 抽屉打开状态 - 滑入动画 */
|
|
|
+ .custom-drawer-open {
|
|
|
+ transform: translateX(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 抽屉头部 */
|
|
|
+ .custom-drawer-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ color: #ffffff;
|
|
|
+ background-color: #2d4f82;
|
|
|
+ padding: 14px 20px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .custom-drawer-title {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #ffffff;
|
|
|
+ line-height: 1.5;
|
|
|
+ }
|
|
|
+
|
|
|
+ .close-btn {
|
|
|
+ font-size: 20px;
|
|
|
+ padding: 0;
|
|
|
+ height: 20px;
|
|
|
+ width: 20px;
|
|
|
+ margin-top: -10px;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 抽屉内容区 */
|
|
|
+ .custom-drawer-body {
|
|
|
+ flex: 1;
|
|
|
+ overflow-y: auto;
|
|
|
+ padding: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .drawer-content {
|
|
|
+ padding: 16px 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 搜索区域布局 */
|
|
|
+ .search-section {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 下拉选择区域间距 */
|
|
|
+ .select-section {
|
|
|
+ margin-bottom: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 表格区域宽度适配 */
|
|
|
+ .table-section {
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 表格样式 */
|
|
|
+ :deep(.ant-table) {
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.ant-table-thead > tr > th) {
|
|
|
+ background: #fafafa;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #000;
|
|
|
+ padding: 10px 12px;
|
|
|
+ border-bottom: 1px solid #f0f0f0;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.ant-table-tbody > tr > td) {
|
|
|
+ color: #000 !important;
|
|
|
+ font-family: Source Han Sans SC !important;
|
|
|
+ font-size: 16px !important;
|
|
|
+ font-weight: 400 !important;
|
|
|
+ letter-spacing: 0 !important;
|
|
|
+ }
|
|
|
+ :deep(.ant-table-tbody > .ant-table-row) {
|
|
|
+ &:hover {
|
|
|
+ background-color: #a4d3ee !important;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ :deep(.ant-table-tbody > .ant-table-row > td) {
|
|
|
+ background-color: unset !important;
|
|
|
+ &:hover {
|
|
|
+ background-color: unset !important;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 分页样式 */
|
|
|
+ :deep(.ant-pagination) {
|
|
|
+ margin: 16px 0 0 0;
|
|
|
+ text-align: right;
|
|
|
+ }
|
|
|
+</style>
|