修改热力图播放

This commit is contained in:
冯少康 2026-08-04 15:29:56 +08:00
parent aaab4fc984
commit 324e6302a7
4 changed files with 397 additions and 190 deletions

View File

@ -7,7 +7,7 @@ import { mapRightMenuEvent } from "@/gis/ol/olRightMenu";
import { getGif } from "@/utils/axios/symn"; import { getGif } from "@/utils/axios/symn";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import log from '@/pages/symn/log/index.vue'; import log from "@/pages/symn/log/index.vue";
import { import {
getrwssGifFileData, getrwssGifFileData,
@ -259,7 +259,7 @@ function handleIconClick(item: MapControlItem) {
isShowGif.value = true; isShowGif.value = true;
} }
); );
}else if(item.name=='calendar'){ } else if (item.name == "calendar") {
let falg: any = !item.isActive; let falg: any = !item.isActive;
switchIconActive(item.name, falg); switchIconActive(item.name, falg);
EventBusTool.getEventBus().publish("sjfxCalendarEvent", { EventBusTool.getEventBus().publish("sjfxCalendarEvent", {
@ -328,6 +328,23 @@ const generateGif = () => {
); );
}; };
//
const getFileNameFromDisposition = (
disposition?: string,
defaultName = "download.gif"
) => {
if (!disposition) return defaultName;
const match = disposition.match(/filename=([^;]+)/);
if (match?.[1]) {
try {
return decodeURIComponent(match[1]);
} catch {
return match[1];
}
}
return defaultName;
};
// GIF // GIF
const downGifFile = () => { const downGifFile = () => {
let taskId = JSON.parse(sessionStorage.getItem("ssmnDataItem")).id; let taskId = JSON.parse(sessionStorage.getItem("ssmnDataItem")).id;
@ -338,11 +355,16 @@ const downGifFile = () => {
speciesId, speciesId,
genGifType: downTypeValue.value, genGifType: downTypeValue.value,
}, },
(res: Blob) => { (response) => {
console.log(res, "2222222222222"); console.log(response, "2222222222222");
// res Blobheaders const blob = response.data;
const fileName = "JPX38_region.gif"; const disposition = response.headers["content-disposition"];
const url = URL.createObjectURL(res); const fileName = getFileNameFromDisposition(
disposition,
"JPX38_global.gif"
);
const url = URL.createObjectURL(blob);
const a = document.createElement("a"); const a = document.createElement("a");
a.href = url; a.href = url;
a.download = fileName; a.download = fileName;
@ -495,45 +517,47 @@ onMounted(() => {
style="min-height: 120px" style="min-height: 120px"
@close="isShowGif = false" @close="isShowGif = false"
> >
<el-form :model="form" label-width="auto" style="max-width: 100%"> <el-form
<el-row :gutter="12"> :model="form"
<el-col :span="5"> label-width="auto"
style="max-width: 100%; justify-content: space-between;display: flex;"
>
<el-form-item :label="t('lonmin')"> <el-form-item :label="t('lonmin')">
<el-input v-model="gifFormData.minLon" /> <el-input v-model="gifFormData.minLon" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="5">
<el-form-item :label="t('lonmax')"> <el-form-item :label="t('lonmax')">
<el-input v-model="gifFormData.maxLon" /> <el-input v-model="gifFormData.maxLon" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="5">
<el-form-item :label="t('latmin')"> <el-form-item :label="t('latmin')">
<el-input v-model="gifFormData.minLat" /> <el-input v-model="gifFormData.minLat" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="5">
<el-form-item :label="t('latmax')"> <el-form-item :label="t('latmax')">
<el-input v-model="gifFormData.maxLat" /> <el-input v-model="gifFormData.maxLat" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="2">
<el-button @click="generateGif" type="primary" class="custom-btn" <el-button @click="generateGif" type="primary" class="custom-btn"
>生成GIF</el-button >生成GIF</el-button
></el-col
> >
<el-col :span="2"
><el-button @click="viewLogs" type="primary" class="custom-btn" <el-button @click="viewLogs" type="primary" class="custom-btn"
>查看日志</el-button >查看日志</el-button
></el-col
> >
</el-row>
</el-form> </el-form>
<img v-if="isShowGif" :src="gifSrc" alt="GIF" style="width: 100%" /> <img v-if="isShowGif" :src="gifSrc" alt="GIF" style="width: 100%" />
<div style="width: 100%; display: flex; justify-content: flex-end;margin-top: 15px;"> <div
<div style="width: 25%;display: flex;padding-right: 10px;"> style="
width: 100%;
display: flex;
justify-content: flex-end;
border-top: 1px solid #0c6a66;
margin-top: 10px;
"
>
<div
style="width: 25%; display: flex; margin-top: 15px"
>
<el-select <el-select
v-model="downTypeValue" v-model="downTypeValue"
:options="downTypeOptions" :options="downTypeOptions"
@ -545,7 +569,7 @@ onMounted(() => {
@click="downGifFile" @click="downGifFile"
type="primary" type="primary"
class="custom-btn" class="custom-btn"
style="margin-left: 10px;" style="margin-left: 10px"
>下载</el-button >下载</el-button
> >
</div> </div>

View File

@ -1,20 +1,33 @@
<script lang="ts" setup> <script lang="ts" setup>
import dayjs from 'dayjs'; import dayjs from "dayjs";
import { activeMoudleInf, gisImgOpt, setWeathRequesTime, weathFlag } from '@/gis/ol/index'; import {
import { getClockTimeRange, setcurrentTime, setShouldAnimate, stopPlay } from '@/gis/ol/olClock'; activeMoudleInf,
import { clearGridFeatures } from '@/gis/ol/olGirdHeatmap'; gisImgOpt,
import { clearHeatmapLayer } from '@/gis/ol/olHeatmap'; setWeathRequesTime,
import { playback_EventBusCallback, sendPlaybackPostMassage } from '@/gis/worker/playbackWorkerMa'; weathFlag,
import { playbackSearchData } from '@/utils/axios/tqyb/data/index'; } from "@/gis/ol/index";
import {
getClockTimeRange,
setcurrentTime,
setShouldAnimate,
stopPlay,
} from "@/gis/ol/olClock";
import { clearGridFeatures } from "@/gis/ol/olGirdHeatmap";
import { clearHeatmapLayer } from "@/gis/ol/olHeatmap";
import {
playback_EventBusCallback,
sendPlaybackPostMassage,
} from "@/gis/worker/playbackWorkerMa";
import { playbackSearchData } from "@/utils/axios/tqyb/data/index";
const props = defineProps({ const props = defineProps({
activeMenu: { activeMenu: {
type: String, type: String,
default: '', default: "",
}, },
taskId: { taskId: {
type: String, type: String,
default: '', default: "",
}, },
globalAttr: { globalAttr: {
type: Object, type: Object,
@ -55,10 +68,13 @@ interface TabItem {
isActive: boolean; isActive: boolean;
} }
const tabsList = ref<TabItem[]>([ const tabsList = ref<TabItem[]>([
{ label: '小时', value: 'hour', isActive: true }, { label: "小时", value: "hour", isActive: true },
{ label: '天', value: 'day', isActive: false }, { label: "天", value: "day", isActive: false },
]); ]);
const labelLeft = ref(0)
const labelText = ref('')
// (使) // (使)
const stationValue = ref<any>(null); const stationValue = ref<any>(null);
@ -73,30 +89,34 @@ const isDisabledSlider = ref<boolean>(false);
// //
const isQueryData = ref<boolean>(true); const isQueryData = ref<boolean>(true);
// //
const marskType = ref<string>('hour'); const marskType = ref<string>("hour");
const start = ref<any>(dayjs('2025-09-15 00:00:00')); const start = ref<any>(dayjs("2025-09-15 00:00:00"));
const end = ref<any>(dayjs('2025-09-16 00:00:00')); const end = ref<any>(dayjs("2025-09-16 00:00:00"));
const totalHours = ref<number>(end.value.diff(start.value, marskType.value)); const totalHours = ref<number>(end.value.diff(start.value, marskType.value));
const value = ref<number>(0); const value = ref<number>(0);
const playFalg = ref<boolean>(false); const playFalg = ref<boolean>(false);
const slodtooltip: any = (toolNum: number) => { const slodtooltip: any = (toolNum: number) => {
return start.value.add(toolNum, marskType.value).format('YYYY-MM-DD HH:mm:ss'); return start.value
.add(toolNum, marskType.value)
.format("YYYY-MM-DD HH:mm:ss");
}; };
const active = ref('浓度分布'); const active = ref("浓度分布");
function switchActive(tab: string) { function switchActive(tab: string) {
if (playFalg.value) if (playFalg.value) return;
return;
active.value = tab; active.value = tab;
sendPlaybackPostMassage({ code: 'queryHSJMNType', data: JSON.parse(JSON.stringify(active.value)) }, {}); sendPlaybackPostMassage(
{ code: "queryHSJMNType", data: JSON.parse(JSON.stringify(active.value)) },
{}
);
stopAnimation(); stopAnimation();
} }
// marks6 // marks6
const dataRequestOpt = computed(() => { const dataRequestOpt = computed(() => {
const obj: Record<number, string> = {}; const obj: Record<number, string> = {};
const baseSpeed = marskType.value === 'hour' ? 6 : 1; const baseSpeed = marskType.value === "hour" ? 6 : 1;
const totalPoints = Math.floor(totalHours.value / baseSpeed) + 1; // const totalPoints = Math.floor(totalHours.value / baseSpeed) + 1; //
// const maxShow = 6; // 10 // const maxShow = 6; // 10
@ -107,9 +127,13 @@ const dataRequestOpt = computed(() => {
// 10 // 10
let count = 0; let count = 0;
for (let i = 0; i <= totalHours.value && count < totalPoints; i += baseSpeed) { for (
let i = 0;
i <= totalHours.value && count < totalPoints;
i += baseSpeed
) {
const t = start.value.add(i, marskType.value); const t = start.value.add(i, marskType.value);
obj[i] = t.format('YYYY-MM-DD HH:mm:ss'); obj[i] = t.format("YYYY-MM-DD HH:mm:ss");
count++; count++;
} }
@ -128,8 +152,18 @@ const dataRequestOpt = computed(() => {
function handleChange(val: number) { function handleChange(val: number) {
// //
const currentTime = start.value.add(val, marskType.value); const currentTime = start.value.add(val, marskType.value);
labelText.value = currentTime.format("YYYY-MM-DD HH:mm:ss");
setcurrentTime(currentTime.valueOf()); setcurrentTime(currentTime.valueOf());
console.log(currentTime.format('YYYY-MM-DD HH:mm:ss')); nextTick(() => {
const sliderDom = document.querySelector('.slider .el-slider__runway')
if (!sliderDom) return
const width = sliderDom.offsetWidth;
//
const percent = val / totalHours.value
//
labelLeft.value = percent * width - 60
})
} }
// //
function switchTab(tab: TabItem) { function switchTab(tab: TabItem) {
@ -143,7 +177,7 @@ function switchTab(tab: TabItem) {
// //
function playAnimation() { function playAnimation() {
if (props.activeMenu === '输运模拟' && !playFalg.value && isQueryData.value) { if (props.activeMenu === "输运模拟" && !playFalg.value && isQueryData.value) {
const param = { const param = {
taskId: props.taskId, taskId: props.taskId,
speciesId: JSON.parse(JSON.stringify(speciesValue.value)), speciesId: JSON.parse(JSON.stringify(speciesValue.value)),
@ -153,10 +187,17 @@ function playAnimation() {
}; };
isDisabledSlider.value = true; isDisabledSlider.value = true;
isQueryData.value = false; isQueryData.value = false;
sendPlaybackPostMassage({ code: 'querySYMN', data: JSON.parse(JSON.stringify(param)) }, {}); sendPlaybackPostMassage(
{ code: "querySYMN", data: JSON.parse(JSON.stringify(param)) },
{}
);
return; return;
} }
if (props.activeMenu === '核事件模拟' && !playFalg.value && isQueryData.value) { if (
props.activeMenu === "核事件模拟" &&
!playFalg.value &&
isQueryData.value
) {
const param = { const param = {
taskId: props.taskId, taskId: props.taskId,
hour: 1, hour: 1,
@ -165,12 +206,23 @@ function playAnimation() {
}; };
isDisabledSlider.value = true; isDisabledSlider.value = true;
isQueryData.value = false; isQueryData.value = false;
sendPlaybackPostMassage({ code: 'queryHSJMNType', data: JSON.parse(JSON.stringify(active.value)) }, {}); sendPlaybackPostMassage(
if (active.value === '浓度分布') { {
sendPlaybackPostMassage({ code: 'queryHSJMNndfb', data: JSON.parse(JSON.stringify(param)) }, {}); code: "queryHSJMNType",
} data: JSON.parse(JSON.stringify(active.value)),
else { },
sendPlaybackPostMassage({ code: 'queryHSJMNjlfb', data: JSON.parse(JSON.stringify(param)) }, {}); {}
);
if (active.value === "浓度分布") {
sendPlaybackPostMassage(
{ code: "queryHSJMNndfb", data: JSON.parse(JSON.stringify(param)) },
{}
);
} else {
sendPlaybackPostMassage(
{ code: "queryHSJMNjlfb", data: JSON.parse(JSON.stringify(param)) },
{}
);
} }
return; return;
} }
@ -184,8 +236,8 @@ function stopAnimation() {
// //
stopPlay(); stopPlay();
// //
playback_EventBusCallback.publish('legendUiData', { playback_EventBusCallback.publish("legendUiData", {
key: 'showLengend', key: "showLengend",
value: false, value: false,
}); });
// //
@ -199,7 +251,7 @@ function stopAnimation() {
isQueryData.value = true; isQueryData.value = true;
// 0 // 0
value.value = 0; value.value = 0;
sendPlaybackPostMassage({ code: 'abortSYMN', data: false }, {}); sendPlaybackPostMassage({ code: "abortSYMN", data: false }, {});
} }
// 线 // 线
@ -207,27 +259,33 @@ function updateTimeLabel(ctime: any) {
// //
const startTimestamp = start.value.valueOf(); const startTimestamp = start.value.valueOf();
// //
const currentHourDiff = Math.floor((ctime - startTimestamp) / (3600000)); const currentHourDiff = Math.floor((ctime - startTimestamp) / 3600000);
// marks6 // marks6
const markKeys = Object.keys(dataRequestOpt.value).map(Number); const markKeys = Object.keys(dataRequestOpt.value).map(Number);
const isDifferentValue = value.value !== currentHourDiff; const isDifferentValue = value.value !== currentHourDiff;
const is6HourInterval = props.activeMenu === '输运模拟' ? currentHourDiff % 3 === 0 : currentHourDiff % 1 === 0; const is6HourInterval =
props.activeMenu === "输运模拟"
? currentHourDiff % 3 === 0
: currentHourDiff % 1 === 0;
// currentHourDiffmarks // currentHourDiffmarks
if ( if (
currentHourDiff >= 0 currentHourDiff >= 0 &&
&& currentHourDiff <= totalHours.value currentHourDiff <= totalHours.value &&
// && markKeys.includes(currentHourDiff) // // && markKeys.includes(currentHourDiff) //
&& isDifferentValue // isDifferentValue && //
&& is6HourInterval is6HourInterval
) { ) {
value.value = currentHourDiff; value.value = currentHourDiff;
if (markKeys.includes(currentHourDiff)) { if (markKeys.includes(currentHourDiff)) {
// currentHourDiffmarkKeys // currentHourDiffmarkKeys
const currentIndex = markKeys.indexOf(currentHourDiff); const currentIndex = markKeys.indexOf(currentHourDiff);
if (activeMoudleInf.activeMenu === '天气预报运算') { if (activeMoudleInf.activeMenu === "天气预报运算") {
console.log(`获取第${currentIndex + 1}组数据,当前时间为`, dataRequestOpt.value[currentHourDiff]); console.log(
`获取第${currentIndex + 1}组数据,当前时间为`,
dataRequestOpt.value[currentHourDiff]
);
setWeathRequesTime(dataRequestOpt.value[currentHourDiff]); setWeathRequesTime(dataRequestOpt.value[currentHourDiff]);
// //
const params = { ...gisImgOpt }; const params = { ...gisImgOpt };
@ -238,8 +296,8 @@ function updateTimeLabel(ctime: any) {
playbackSearchData(params, true, (res) => { playbackSearchData(params, true, (res) => {
// //
EventBusTool.getEventBus().publish('playData', { EventBusTool.getEventBus().publish("playData", {
key: 'addyctqjsGis', key: "addyctqjsGis",
data: res.result, data: res.result,
}); });
}); });
@ -275,10 +333,12 @@ const speciesValueChange = () => {
// key: 'speciesId', // key: 'speciesId',
// data: { taskId: props.taskId, speciesId: speciesValue.value }, // data: { taskId: props.taskId, speciesId: speciesValue.value },
// }); // });
console.log(speciesValue.value,"2222") console.log(speciesValue.value, "2222");
sessionStorage.setItem("symnZxHsId", speciesValue.value); sessionStorage.setItem("symnZxHsId", speciesValue.value);
}; };
const ssmnOption = ref({});
// speciesList // speciesList
watch( watch(
() => props.speciesList, () => props.speciesList,
@ -289,16 +349,15 @@ watch(
speciesValue.value = newVal[0].value; speciesValue.value = newVal[0].value;
sessionStorage.setItem("symnZxHsId", newVal[0].value); sessionStorage.setItem("symnZxHsId", newVal[0].value);
EventBusTool.getEventBus().publish('speciesChange', { EventBusTool.getEventBus().publish("speciesChange", {
key: 'speciesId', key: "speciesId",
data: { taskId: props.taskId, speciesId: newVal[0].value }, data: { taskId: props.taskId, speciesId: newVal[0].value },
}); });
} } else {
else {
speciesValue.value = null; speciesValue.value = null;
} }
}, },
{ deep: true }, // / { deep: true } // /
); );
// layer // layer
@ -307,43 +366,64 @@ watch(
(newVal: any) => { (newVal: any) => {
if (newVal.length > 0) { if (newVal.length > 0) {
layerValue.value = newVal[0].value; layerValue.value = newVal[0].value;
} } else {
else {
layerValue.value = null; layerValue.value = null;
} }
}, },
{ deep: true }, { deep: true }
); );
watch(value, (newVal, oldVal) => {
let currentTime = null;
if(ssmnOption.value.taskMode==-1){
currentTime = end.value.clone().subtract(newVal, marskType.value);
}else{
currentTime = start.value.clone().add(newVal, marskType.value);
}
labelText.value = currentTime.format("YYYY-MM-DD HH:mm:ss");
nextTick(() => {
const sliderDom = document.querySelector('.slider .el-slider__runway')
if (!sliderDom) return
const width = sliderDom.offsetWidth;
//
const percent = newVal / totalHours.value
//
labelLeft.value = percent * width - 60
})
}, {
// immediate: true //
})
onMounted(() => { onMounted(() => {
EventBusTool.getEventBus().subscribe('timeSliderUi', (opt: any) => { EventBusTool.getEventBus().subscribe("timeSliderUi", (opt: any) => {
ssmnOption.value = JSON.parse(sessionStorage.getItem("ssmnDataItem"));
switch (opt.key) { switch (opt.key) {
case 'updateUi':// case "updateUi": //
updateTimeLabel(opt.time); updateTimeLabel(opt.time);
break; break;
case 'setTime':// case "setTime": //
setStartAndEndTime(opt); setStartAndEndTime(opt);
isQueryData.value = true; isQueryData.value = true;
break; break;
case 'playFalg':// ui case "playFalg": // ui
playFalg.value = opt.playFalg; playFalg.value = opt.playFalg;
if (!playFalg.value) { if (!playFalg.value) {
isQueryData.value = true; isQueryData.value = true;
} }
break; break;
case 'isQueryData':// ui case "isQueryData": // ui
isQueryData.value = opt.value; isQueryData.value = opt.value;
break; break;
default: default:
break; break;
} }
}); });
playback_EventBusCallback.subscribe('timeSliderUiData', (opt: any) => { playback_EventBusCallback.subscribe("timeSliderUiData", (opt: any) => {
switch (opt.key) { switch (opt.key) {
case 'isDisabledSlider': // case "isDisabledSlider": //
isDisabledSlider.value = opt.value; isDisabledSlider.value = opt.value;
break; break;
case 'playFalg':// ui case "playFalg": // ui
playFalg.value = opt.value; playFalg.value = opt.value;
break; break;
default: default:
@ -354,47 +434,131 @@ onMounted(() => {
</script> </script>
<template> <template>
<div class="sliderDom" <div
:style="{ width: props.widthPx ?? props.activeMenu === '天气预报运算' ? '65vw' : '68vw', left: props.leftPx ?? '320px' }"> class="sliderDom"
:style="{
width:
props.widthPx ?? props.activeMenu === '天气预报运算' ? '65vw' : '68vw',
left: props.leftPx ?? '320px',
}"
>
<div v-if="props.activeMenu === '核事件模拟'" class="switchTabs"> <div v-if="props.activeMenu === '核事件模拟'" class="switchTabs">
<div class="left" :class="{ active: active === '浓度分布', disable: playFalg }" @click="switchActive('浓度分布')"> <div
class="left"
:class="{ active: active === '浓度分布', disable: playFalg }"
@click="switchActive('浓度分布')"
>
浓度分布 浓度分布
</div> </div>
<div class="right" :class="{ active: active === '剂量分布', disable: playFalg }" @click="switchActive('剂量分布')"> <div
class="right"
:class="{ active: active === '剂量分布', disable: playFalg }"
@click="switchActive('剂量分布')"
>
剂量分布 剂量分布
</div> </div>
</div> </div>
<div v-if="isShowSelect" class="selectDom"> <div v-if="isShowSelect" class="selectDom">
<el-select-v2 v-if="props.activeMenu === '核事件模拟'" v-model="layerValue" :disabled="!isQueryData" <el-select-v2
:options="props.layerList" placeholder="请选择图层" style="width: 230px" /> v-if="props.activeMenu === '核事件模拟'"
<el-select-v2 v-if="props.activeMenu === '输运模拟' && speciesValue" v-model="speciesValue" :disabled="!isQueryData" v-model="layerValue"
:options="props.speciesList" placeholder="请选择物种" style="width: 230px" @change="speciesValueChange" /> :disabled="!isQueryData"
:options="props.layerList"
placeholder="请选择图层"
style="width: 230px"
/>
<el-select-v2
v-if="props.activeMenu === '输运模拟' && speciesValue"
v-model="speciesValue"
:disabled="!isQueryData"
:options="props.speciesList"
placeholder="请选择物种"
style="width: 230px"
@change="speciesValueChange"
/>
</div> </div>
<div v-if="isShowTabs" class="tabs"> <div v-if="isShowTabs" class="tabs">
<div v-for="(v, i) in tabsList" :key="i" class="tabItem" :class="{ active: v.isActive }" @click="switchTab(v)"> <div
v-for="(v, i) in tabsList"
:key="i"
class="tabItem"
:class="{ active: v.isActive }"
@click="switchTab(v)"
>
{{ v.label }} {{ v.label }}
</div> </div>
</div> </div>
<div class="icon" @click="playAnimation()"> <div class="icon" @click="playAnimation()">
<SvgIcon :name="!playFalg ? 'playAnimation' : 'zanting'" :title="!playFalg ? '播放' : '暂停'" width="34" height="34" /> <SvgIcon
:name="!playFalg ? 'playAnimation' : 'zanting'"
:title="!playFalg ? '播放' : '暂停'"
width="34"
height="34"
/>
</div> </div>
<div v-if="props.activeMenu === '输运模拟' || props.activeMenu === '核事件模拟'" class="icon" @click="stopAnimation()"> <div
v-if="
props.activeMenu === '输运模拟' || props.activeMenu === '核事件模拟'
"
class="icon"
@click="stopAnimation()"
>
<SvgIcon name="stop" title="停止" width="34" height="34" /> <SvgIcon name="stop" title="停止" width="34" height="34" />
</div> </div>
<div class="slider"> <div class="slider" style="position: relative;">
<!-- <div style="color: white">value:{{ value }} ----- totalHours:{{ totalHours }}</div> --> <!-- <div style="color: white">value:{{ start.format("YYYY-MM-DD HH:mm:ss") }} ----- totalHours:{{ end.format("YYYY-MM-DD HH:mm:ss") }}</div> -->
<el-slider v-model="value" :disabled="isDisabledSlider" <div class="startTimes">{{ ssmnOption.taskMode==-1?ssmnOption.endTime:ssmnOption.startTime }}</div>
:style="{ width: isShowTabs ? (props.sliderWidth ?? '58vw') : '62vw' }" :max="totalHours" <el-slider
:format-tooltip="slodtooltip" :marks="marks" @input="handleChange" /> v-model="value"
:disabled="isDisabledSlider"
:style="{ width: isShowTabs ? props.sliderWidth ?? '58vw' : '62vw' }"
:max="totalHours"
:format-tooltip="slodtooltip"
:show-tooltip="false"
:marks="marks"
@input="handleChange"
/>
<div class="endTimes">{{ ssmnOption.taskMode==-1?ssmnOption.startTime:ssmnOption.endTime }}</div>
<div class="slider-label" :style="{ left: labelLeft + 'px' }" v-if="labelText">
{{ labelText }}
</div>
</div> </div>
</div> </div>
</template> </template>
<style lang="less" scoped> <style lang="less" scoped>
.slider-wrap {
margin-top: 30px; /* 留出标签空间,防止重叠 */
}
.slider-label {
position: absolute;
top: -28px;
background: #409eff;
color: #fff;
padding: 3px 8px;
border-radius: 4px;
font-size: 12px;
white-space: nowrap;
transition: left 0.08s linear;
}
.startTimes{
position: absolute;
left: 0;
bottom: -10px;
color: #fff;
}
.endTimes{
position: absolute;
right: 0;
bottom: -10px;
color: #fff;
}
.switchTabs { .switchTabs {
width: 500px; width: 500px;
height: 52px; height: 52px;
background: url('@/assets/img/tabsBg.png') no-repeat center center; background: url("@/assets/img/tabsBg.png") no-repeat center center;
background-size: 100% 100%; background-size: 100% 100%;
position: fixed; position: fixed;
left: 50%; left: 50%;
@ -409,7 +573,7 @@ onMounted(() => {
.right { .right {
width: 141px; width: 141px;
height: 30px; height: 30px;
background: url('@/assets/img/tabsBtn_default.png') no-repeat center center; background: url("@/assets/img/tabsBtn_default.png") no-repeat center center;
background-size: 100% 100%; background-size: 100% 100%;
text-align: center; text-align: center;
line-height: 30px; line-height: 30px;
@ -424,7 +588,7 @@ onMounted(() => {
} }
.active { .active {
background: url('@/assets/img/tabsBtn_active.png') no-repeat center center; background: url("@/assets/img/tabsBtn_active.png") no-repeat center center;
background-size: 100% 100%; background-size: 100% 100%;
color: rgb(42, 255, 223); color: rgb(42, 255, 223);
} }

View File

@ -1892,49 +1892,7 @@ getStations();
max-height="40vh" max-height="40vh"
class="custom-table" class="custom-table"
> >
<!-- 样品ID --> <ElTableColumn prop="index" :label="t('deviceCode')" width="100">
<ElTableColumn :label="t('sampleId')">
<template #default="scope">
<el-input
v-model="scope.row.sampleId"
type="number"
/>
</template>
</ElTableColumn>
<!-- 样品类型 -->
<ElTableColumn :label="t('sampleType')">
<template #default="scope">
<el-select
v-model="scope.row.sampleType"
>
<el-option
v-for="item in ['B','P']"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</template>
</ElTableColumn>
<!-- 样品级别 -->
<ElTableColumn :label="t('sampleLevel')">
<template #default="scope">
<el-select
v-model="scope.row.sampleCategory"
>
<el-option
v-for="item in [1,2,3,4,5]"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</template>
</ElTableColumn>
<ElTableColumn prop="index" :label="t('deviceCode')" width="130">
<template #default="scope"> <template #default="scope">
<!-- <ElSelect v-if="configForm.taskMode === 1" v-model="scope.row.index" filterable--> <!-- <ElSelect v-if="configForm.taskMode === 1" v-model="scope.row.index" filterable-->
<!-- :placeholder="t('pleaseSelect')" class="config-custom-select" style="color:#fff;"--> <!-- :placeholder="t('pleaseSelect')" class="config-custom-select" style="color:#fff;"-->
@ -1959,8 +1917,8 @@ getStations();
</template> </template>
</ElTableColumn> </ElTableColumn>
<ElTableColumn prop="lon" :label="t('longitude')" /> <ElTableColumn prop="lon" :label="t('longitude')" width="90" />
<ElTableColumn prop="lat" :label="t('latitude')" /> <ElTableColumn prop="lat" :label="t('latitude')" width="90" />
<ElTableColumn <ElTableColumn
v-if="configForm.taskMode === -1" v-if="configForm.taskMode === -1"
prop="index" prop="index"
@ -1991,13 +1949,54 @@ getStations();
/> />
</template> </template>
</ElTableColumn> </ElTableColumn>
<!-- 样品ID -->
<ElTableColumn :label="t('sampleId')" width="80">
<template #default="scope">
<el-input
v-model="scope.row.sampleId"
type="number"
/>
</template>
</ElTableColumn>
<!-- 样品类型 -->
<ElTableColumn :label="t('sampleType')" width="80">
<template #default="scope">
<el-select
v-model="scope.row.sampleType"
>
<el-option
v-for="item in ['B','P']"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</template>
</ElTableColumn>
<!-- 样品级别 -->
<ElTableColumn :label="t('sampleLevel')" width="80">
<template #default="scope">
<el-select
v-model="scope.row.sampleCategory"
>
<el-option
v-for="item in [1,2,3,4,5]"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</template>
</ElTableColumn>
<!-- <ElTableColumn :label="t('releaseAmount')"> <!-- <ElTableColumn :label="t('releaseAmount')">
<template #default="scope"> <template #default="scope">
<el-input v-model="scope.row.releaseAmount" :placeholder="t('enterContent')" /> <el-input v-model="scope.row.releaseAmount" :placeholder="t('enterContent')" />
</template> </template>
</ElTableColumn> --> </ElTableColumn> -->
<ElTableColumn :label="t('operation')"> <ElTableColumn :label="t('operation')" width="90">
<template #default="scope"> <template #default="scope">
<!-- <ElButton type="text" class="custom-text-btn" @click="editTask(scope.row, scope.$index)"> --> <!-- <ElButton type="text" class="custom-text-btn" @click="editTask(scope.row, scope.$index)"> -->
<!-- {{ t('edit') }} --> <!-- {{ t('edit') }} -->

View File

@ -1,7 +1,7 @@
import { baseURL, serverIp } from "@/gis/common/config"; import { baseURL, serverIp } from "@/gis/common/config";
import { ElMessage } from "element-plus"; import { ElLoading, ElMessage } from "element-plus";
import request from "@/utils/request"; // 复用已有的Axios请求实例 import request from "@/utils/request"; // 复用已有的Axios请求实例
import axios from "axios";
/** /**
* GIF文件 * GIF文件
*/ */
@ -31,16 +31,36 @@ export async function downGifSsFile(
params: any, params: any,
callback?: (data: any) => void, callback?: (data: any) => void,
): Promise<any> { ): Promise<any> {
const response = await request({ // 开启Loading和你项目样式保持一致
const loadingInstance = ElLoading.service({
lock: true,
text: "Loading...",
background: "rgba(0, 0, 0, 0.7)",
target: document.querySelector(".base-layout"),
});
try {
const token = localStorage.getItem("token");
const fullResponse = await axios({
baseURL: serverIp,
url: `${serverIp}${baseURL}/transportResult/downloadGif`, url: `${serverIp}${baseURL}/transportResult/downloadGif`,
method: "GET", method: "GET",
params, params,
responseType: "blob", responseType: "blob",
timeout: 300000,
headers: {
"Content-Type": "application/json;charset=utf-8",
...(token ? { "X-Access-Token": token } : {}),
},
}); });
console.log(response, "22222222222222"); console.log(fullResponse, "完整响应");
callback?.(fullResponse);
// HTTP 200 = 文件流正常返回,直接执行下载回调 } catch (err) {
callback?.(response); ElMessage.error("gif下载请求失败");
throw err;
} finally {
// 无论成功失败一定关闭loading
loadingInstance.close();
}
} }
/** /**