|  | @@ -16,7 +16,7 @@
 | 
	
		
			
				|  |  |      <div
 | 
	
		
			
				|  |  |        class="classtable"
 | 
	
		
			
				|  |  |        style="margin-top: 10px; "
 | 
	
		
			
				|  |  | -      v-if="currentTab2 == '0'"
 | 
	
		
			
				|  |  | +      v-show="currentTab2 == '0'"
 | 
	
		
			
				|  |  |      >
 | 
	
		
			
				|  |  |        <el-form label-position="left">
 | 
	
		
			
				|  |  |          <el-form-item label="网格文件:" :label-width="formLabelWidth120">
 | 
	
	
		
			
				|  | @@ -46,8 +46,10 @@
 | 
	
		
			
				|  |  |            </el-row>
 | 
	
		
			
				|  |  |          </el-form-item>
 | 
	
		
			
				|  |  |        </el-form>
 | 
	
		
			
				|  |  | -      <div style="flex-grow: 1;">
 | 
	
		
			
				|  |  | -        <cloudChart :data="bdfData" />
 | 
	
		
			
				|  |  | +      <div style="flex-grow: 1;"
 | 
	
		
			
				|  |  | +        v-loading="isLoading"
 | 
	
		
			
				|  |  | +        element-loading-text="拼命加载中...">
 | 
	
		
			
				|  |  | +        <cloudChart :data="bdfData" :height=canvasHeight />
 | 
	
		
			
				|  |  |        </div>
 | 
	
		
			
				|  |  |      </div>
 | 
	
		
			
				|  |  |      <!-- 设置参数 -->
 | 
	
	
		
			
				|  | @@ -396,6 +398,19 @@ let uploadStatus = ref('')
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  // 控制进度条显隐
 | 
	
		
			
				|  |  |  const showProgress = computed(() => percentage.value > 0 && percentage.value <= 100);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +let canvasHeight = ref("400px");
 | 
	
		
			
				|  |  | +let isLoading = ref(false); // 控制 loading 状态
 | 
	
		
			
				|  |  | +let websock = shallowRef(null);
 | 
	
		
			
				|  |  | +let times = ref({
 | 
	
		
			
				|  |  | +  lockReconnect: false, //是否真正建立连接
 | 
	
		
			
				|  |  | +  timeout: 60 * 1000, //30秒一次心跳
 | 
	
		
			
				|  |  | +  heartBeatInterval: 30 * 1000, // 添加心跳发送间隔(30秒发一次)
 | 
	
		
			
				|  |  | +  timeoutObj: null, //心跳倒计时
 | 
	
		
			
				|  |  | +  serverTimeoutObj: null, //
 | 
	
		
			
				|  |  | +  timeoutnum: null, //断开重连倒计时
 | 
	
		
			
				|  |  | +})
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  // 更新进度条
 | 
	
		
			
				|  |  |  const updatePercentage = (newValue) => {
 | 
	
		
			
				|  |  |    percentage.value = newValue
 | 
	
	
		
			
				|  | @@ -437,6 +452,10 @@ const gettacs = (id,nowid) => {
 | 
	
		
			
				|  |  |      if (res.hasOwnProperty("tacsid")) {
 | 
	
		
			
				|  |  |        gettacsAssign(res);
 | 
	
		
			
				|  |  |        emitter.emit('tacsidFromTACS', tacsid);
 | 
	
		
			
				|  |  | +      // 默认加载cgns文件
 | 
	
		
			
				|  |  | +      if (res.fid) {
 | 
	
		
			
				|  |  | +        openWebSocket(res.fid);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    })
 | 
	
		
			
				|  |  |    .catch((err) => {
 | 
	
	
		
			
				|  | @@ -585,19 +604,198 @@ const gettacssave = (id,nowid) => {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  defineExpose({ gettacs, gettacsAssign, gettacssave })
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +const fetchBdfData = async (fpid) =>{
 | 
	
		
			
				|  |  | +  isLoading.value = true;
 | 
	
		
			
				|  |  | +  try {
 | 
	
		
			
				|  |  | +    const response = await fetch('https://www.adicn.com/airopt/TransServlet', {
 | 
	
		
			
				|  |  | +      method: 'POST',
 | 
	
		
			
				|  |  | +      headers: {
 | 
	
		
			
				|  |  | +        'Content-Type': 'application/json',
 | 
	
		
			
				|  |  | +      },
 | 
	
		
			
				|  |  | +      body: JSON.stringify({
 | 
	
		
			
				|  |  | +        channelNo: 'service',
 | 
	
		
			
				|  |  | +        clientToken: 'e47b87eec69545559d1e81e56626da68',
 | 
	
		
			
				|  |  | +        transCode: 'MDO0072',
 | 
	
		
			
				|  |  | +        userId: '5f06c8bc77234f969d13e160b54c27e3',
 | 
	
		
			
				|  |  | +        fid: fpid
 | 
	
		
			
				|  |  | +      }),
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +  }catch (error) {
 | 
	
		
			
				|  |  | +    isLoading.value = false;
 | 
	
		
			
				|  |  | +    console.error("请求失败:", error.response || error);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +const getBdfData = async (fpid) =>{
 | 
	
		
			
				|  |  | +  try {
 | 
	
		
			
				|  |  | +    const response = await fetch('https://www.adicn.com/airopt/TransServlet', {
 | 
	
		
			
				|  |  | +      method: 'POST',
 | 
	
		
			
				|  |  | +      headers: {
 | 
	
		
			
				|  |  | +        'Content-Type': 'application/json',
 | 
	
		
			
				|  |  | +      },
 | 
	
		
			
				|  |  | +      body: JSON.stringify({
 | 
	
		
			
				|  |  | +        channelNo: 'service',
 | 
	
		
			
				|  |  | +        clientToken: 'e47b87eec69545559d1e81e56626da68',
 | 
	
		
			
				|  |  | +        transCode: 'MDO0062',
 | 
	
		
			
				|  |  | +        userId: '5f06c8bc77234f969d13e160b54c27e3',
 | 
	
		
			
				|  |  | +        fid: fpid
 | 
	
		
			
				|  |  | +      }),
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +    // 解析 JSON 数据
 | 
	
		
			
				|  |  | +  const data = await response.json(); //
 | 
	
		
			
				|  |  | +  console.log('接口返回的数据:', data); // 正确打印数据
 | 
	
		
			
				|  |  | +  bdfData.value = data;
 | 
	
		
			
				|  |  | +  isLoading.value = false;
 | 
	
		
			
				|  |  | +  }catch (error) {
 | 
	
		
			
				|  |  | +    isLoading.value = false;
 | 
	
		
			
				|  |  | +    console.error("请求失败:", error.response || error);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  const handleFileUploadSuccess = (data) => {
 | 
	
		
			
				|  |  | +  //隐藏进度条
 | 
	
		
			
				|  |  | +  setTimeout(() => {
 | 
	
		
			
				|  |  | +    percentage.value = 0;
 | 
	
		
			
				|  |  | +  }, 1000);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    fname.value = data.fname
 | 
	
		
			
				|  |  |    fid.value = data.bfid
 | 
	
		
			
				|  |  |    console.log("文件上传成功,bfid:", data.bfid, "fname:", data.fname)
 | 
	
		
			
				|  |  | -  bdfData.value = {
 | 
	
		
			
				|  |  | -  "data": {
 | 
	
		
			
				|  |  | -    "datasetType": 'bdf',
 | 
	
		
			
				|  |  | +  // 开启websocket
 | 
	
		
			
				|  |  | +  openWebSocket(data.bfid);
 | 
	
		
			
				|  |  | +  
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//websockct的连接
 | 
	
		
			
				|  |  | +const openWebSocket = (fid) => {
 | 
	
		
			
				|  |  | +  if (websock.value?.readyState === 1) return; // 避免重复创建
 | 
	
		
			
				|  |  | +  const wsurl = import.meta.env.VITE_WEBSOCKET_URL + fid;
 | 
	
		
			
				|  |  | +  const ws = new WebSocket(wsurl);
 | 
	
		
			
				|  |  | +  websock.value = ws;
 | 
	
		
			
				|  |  | +  ws.onopen = websocketonopen;
 | 
	
		
			
				|  |  | +  ws.onmessage = websocketonmessage;
 | 
	
		
			
				|  |  | +  ws.onerror = websocketonerror;
 | 
	
		
			
				|  |  | +  ws.onclose = websocketclose;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// Websoket连接成功事件
 | 
	
		
			
				|  |  | +const websocketonopen = (res) => {
 | 
	
		
			
				|  |  | +  console.log("bdfWebSocket连接成功", res);
 | 
	
		
			
				|  |  | +  // 开启心跳
 | 
	
		
			
				|  |  | +  start();
 | 
	
		
			
				|  |  | +  // 调用文件解析
 | 
	
		
			
				|  |  | +  fetchBdfData(fid.value);
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// Websoket接收消息事件
 | 
	
		
			
				|  |  | +const websocketonmessage = (res) => {
 | 
	
		
			
				|  |  | +  try {
 | 
	
		
			
				|  |  | +    const receivedData = JSON.parse(res.data);
 | 
	
		
			
				|  |  | +    console.log('receivedData', receivedData);
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    if (receivedData.status === 0) {
 | 
	
		
			
				|  |  | +      console.log("转换成功,准备关闭");
 | 
	
		
			
				|  |  | +      
 | 
	
		
			
				|  |  | +      // 1. 清除所有计时器
 | 
	
		
			
				|  |  | +      clearAllTimers();
 | 
	
		
			
				|  |  | +      
 | 
	
		
			
				|  |  | +      // 2. 解除事件监听
 | 
	
		
			
				|  |  | +      websock.value.onclose = null;
 | 
	
		
			
				|  |  | +      websock.value.onerror = null;
 | 
	
		
			
				|  |  | +      
 | 
	
		
			
				|  |  | +      // 3. 主动关闭(code 1000)
 | 
	
		
			
				|  |  | +      websock.value.close(1000, "Normal closure");
 | 
	
		
			
				|  |  | +      
 | 
	
		
			
				|  |  | +      // 4. 置空引用
 | 
	
		
			
				|  |  | +      websock.value = null;
 | 
	
		
			
				|  |  | +      
 | 
	
		
			
				|  |  | +      // 5. 获取数据
 | 
	
		
			
				|  |  | +      getBdfData(fid.value);
 | 
	
		
			
				|  |  | +      return; // 直接返回
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  } catch (e) {
 | 
	
		
			
				|  |  | +    // 非JSON消息(如连接成功的文本提示或心跳回复)
 | 
	
		
			
				|  |  | +    if (res.data === "建立服务端连接成功!") {
 | 
	
		
			
				|  |  | +      console.log("WebSocket连接已建立");
 | 
	
		
			
				|  |  | +    } 
 | 
	
		
			
				|  |  | +    else if (res.data === "服务端已经接收到消息,msg=heartCheck") {
 | 
	
		
			
				|  |  | +      console.log("心跳确认");
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    else {
 | 
	
		
			
				|  |  | +      console.warn("未知的非JSON消息:", res.data);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  reset();
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +// Websoket连接错误事件
 | 
	
		
			
				|  |  | +const websocketonerror = (res) => {
 | 
	
		
			
				|  |  | +  console.log("连接错误", res);
 | 
	
		
			
				|  |  | +  websock.close();
 | 
	
		
			
				|  |  | +  reconnect();
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +// Websoket断开事件
 | 
	
		
			
				|  |  | +const websocketclose = (res) => {
 | 
	
		
			
				|  |  | +  console.log("断开连接", res);
 | 
	
		
			
				|  |  | +  // 只有当非正常关闭时才重连(code 1000=正常关闭)
 | 
	
		
			
				|  |  | +  if (res.code !== 1000) {
 | 
	
		
			
				|  |  | +    reconnect();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 心跳包
 | 
	
		
			
				|  |  | +const reconnect = () => {
 | 
	
		
			
				|  |  | +  // 增加多个防护条件
 | 
	
		
			
				|  |  | +  if (
 | 
	
		
			
				|  |  | +    times.value.lockReconnect ||
 | 
	
		
			
				|  |  | +    websock.value?.readyState === 1 ||
 | 
	
		
			
				|  |  | +    !adflowvalue.value?.fid
 | 
	
		
			
				|  |  | +  ) return;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  console.log("尝试重连...");
 | 
	
		
			
				|  |  | +  times.value.lockReconnect = true;
 | 
	
		
			
				|  |  |    
 | 
	
		
			
				|  |  | +  clearTimeout(times.value.timeoutnum);
 | 
	
		
			
				|  |  | +  times.value.timeoutnum = setTimeout(() => {
 | 
	
		
			
				|  |  | +    if (!websock.value || websock.value?.readyState > 1) {
 | 
	
		
			
				|  |  | +      openWebSocket(fid.value);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    times.value.lockReconnect = false;
 | 
	
		
			
				|  |  | +  }, 10000);
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const reset = () => {
 | 
	
		
			
				|  |  | +  //重置心跳
 | 
	
		
			
				|  |  | +  clearTimeout(times.value.timeoutObj);
 | 
	
		
			
				|  |  | +  clearTimeout(times.value.serverTimeoutObj);
 | 
	
		
			
				|  |  | +  start();
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const start = () => {
 | 
	
		
			
				|  |  | +  clearTimeout(times.value.timeoutObj);
 | 
	
		
			
				|  |  | +  clearTimeout(times.value.serverTimeoutObj);
 | 
	
		
			
				|  |  |    
 | 
	
		
			
				|  |  | +  // 增加连接状态检查
 | 
	
		
			
				|  |  | +  if (!websock.value || websock.value.readyState !== 1) return;
 | 
	
		
			
				|  |  | +  
 | 
	
		
			
				|  |  | +  times.value.timeoutObj = setTimeout(() => {
 | 
	
		
			
				|  |  | +    if (websock.value?.readyState === 1) {
 | 
	
		
			
				|  |  | +      websock.value.send("heartCheck");
 | 
	
		
			
				|  |  | +      
 | 
	
		
			
				|  |  | +      times.value.serverTimeoutObj = setTimeout(() => {
 | 
	
		
			
				|  |  | +        if (websock.value?.readyState === 1) {
 | 
	
		
			
				|  |  | +          websock.value.close(1006, "Heartbeat timeout");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }, times.value.timeout);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }, times.value.heartBeatInterval);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +const clearAllTimers = () => {
 | 
	
		
			
				|  |  | +  clearTimeout(times.value.timeoutObj);
 | 
	
		
			
				|  |  | +  clearTimeout(times.value.serverTimeoutObj);
 | 
	
		
			
				|  |  | +  clearTimeout(times.value.timeoutnum);
 | 
	
		
			
				|  |  | +  times.value.lockReconnect = true; // 永久锁定重连
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  </script>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  <style scoped lang="scss">
 |