Compare commits

...

2 Commits

Author SHA1 Message Date
90b1fe2f7a 补充提交 2025-09-18 17:34:12 +08:00
c414e66e2b fix:修改测试出的问题 2025-09-18 17:23:05 +08:00
13 changed files with 836 additions and 319 deletions

View File

@ -1 +1 @@
{"pathofsave":null,"Filename":"testaa","caijiavgNumber":"1","useSG":false,"usehighpass":false,"Dispatcher":{"isenable":true,"begin":"06:25","end":"23:59"},"sensor_typeforset":"IRIS-IS11"} {"pathofsave":null,"Filename":"testaa","caijiavgNumber":"1","useSG":false,"usehighpass":false,"Dispatcher":{"isenable":true,"begin":"09:28","end":"23:59"},"sensor_typeforset":"IS11"}

View File

@ -13,7 +13,7 @@
</GuiLeftSider> </GuiLeftSider>
<template #content> <template #content>
<a-doption @click="onShowCurvesClick">显示曲线</a-doption> <a-doption @click="onShowCurvesClick">显示曲线</a-doption>
<!-- <a-doption>Option 2</a-doption> --> <a-doption @click="openCurveSaveDialogForSelectedFiles">数据导出</a-doption>
<!-- <a-doption>Option 3</a-doption> --> <!-- <a-doption>Option 3</a-doption> -->
</template> </template>
</a-dropdown> </a-dropdown>
@ -36,6 +36,7 @@ import GuiForDataShow from './vuecomponents/GuiForDataShow.vue';
import GuiLeftSider from './vuecomponents/GuiLeftSider.vue'; import GuiLeftSider from './vuecomponents/GuiLeftSider.vue';
import SaveFileDialog from './vuecomponents/SaveFileDialog.vue'; import SaveFileDialog from './vuecomponents/SaveFileDialog.vue';
import { fs } from '@tauri-apps/api'; import { fs } from '@tauri-apps/api';
import { ElMessage } from 'element-plus';
export default { export default {
name: 'APPDataview', name: 'APPDataview',
@ -171,7 +172,7 @@ export default {
await fs.copyFile(file.path, targetPath) await fs.copyFile(file.path, targetPath)
} }
this.$message.success(`成功保存 ${files.length} 个文件到 ${location}`) ElMessage.success(`成功保存 ${files.length} 个文件到 ${location}`)
} catch (error) { } catch (error) {
console.error('保存文件失败:', error) console.error('保存文件失败:', error)
alert('保存文件失败: ' + error.message) alert('保存文件失败: ' + error.message)
@ -182,13 +183,21 @@ export default {
handleCancelSave() { handleCancelSave() {
this.showSaveDialog = false this.showSaveDialog = false
this.filesToSave = [] this.filesToSave = []
}
}, },
async openCurveSaveDialogForSelectedFiles() {
const paths = (this.selectedFilePaths && this.selectedFilePaths.length > 0)
? this.selectedFilePaths
: (this.selectedFilePath ? [this.selectedFilePath] : []);
if (!paths.length) {
alert('请先选择一个或多个文件后再导出');
return;
} }
this.$refs.GuiForDataShow.openSaveCurveDialogByPaths(paths);
},
},
}
</script> </script>
<style scoped> <style scoped>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@ -49,9 +49,19 @@ export default {
}, },
mounted() { mounted() {
window.addEventListener("keydown", this.handlekeydown) // 仅注册总线,键盘监听放在 activated
EventBus.on('SetMenubutton', this.setbutton); EventBus.on('SetMenubutton', this.setbutton);
}, },
activated() {
window.addEventListener("keydown", this.handlekeydown);
},
deactivated() {
window.removeEventListener("keydown", this.handlekeydown);
},
beforeUnmount() {
window.removeEventListener("keydown", this.handlekeydown);
EventBus.off && EventBus.off('SetMenubutton', this.setbutton);
},
methods: { methods: {
setbutton(command) { setbutton(command) {
if (command.name == "DC") { if (command.name == "DC") {
@ -66,6 +76,15 @@ export default {
showbox() { showbox() {
EventBus.emit('showbox', "hello", "提示11") EventBus.emit('showbox', "hello", "提示11")
}, },
quit() {
EventBus.emit('triggerClearData');
setTimeout(() => {
EventBus.emit('changemainvue');
}, 100);
},
changemainvue() { changemainvue() {
EventBus.emit('changemainvue'); EventBus.emit('changemainvue');
}, },
@ -83,7 +102,20 @@ export default {
// this.$emit("menubalclicked", command) // this.$emit("menubalclicked", command)
}, },
handlekeydown(event) { handlekeydown(event) {
// console.log(event.key); const t = event.target || {};
const tag = (t.tagName || '').toLowerCase();
const isEditable = t.isContentEditable || tag === 'input' || tag === 'textarea' || tag === 'select';
if (isEditable) return;
// 只处理来自 #app 内部的事件,忽略外部悬浮窗/插件
const appRoot = document.getElementById('app');
if (!appRoot || !appRoot.contains(event.target)) return;
// 不劫持系统复制快捷键 Ctrl+C
if (event.ctrlKey && !event.shiftKey && (event.key === 'c' || event.key === 'C')) {
return;
}
if (event.ctrlKey) { if (event.ctrlKey) {
if (event.key == "n" || event.key == "N") { if (event.key == "n" || event.key == "N") {
this.onmenuclick('Set', 'Workmode'); this.onmenuclick('Set', 'Workmode');
@ -94,15 +126,16 @@ export default {
if (event.key == "w" || event.key == "W") { if (event.key == "w" || event.key == "W") {
this.onmenuclick('Set', 'Weavelenth'); this.onmenuclick('Set', 'Weavelenth');
} }
if (event.key == "c" || event.key == "C") { // 与采集页保持一致:定标改为 Ctrl + Shift + C
if (event.shiftKey && (event.key == "c" || event.key == "C")) {
this.onmenuclick('Set', 'Calibrate'); this.onmenuclick('Set', 'Calibrate');
} }
} }
}, },
openFolder() { openFolder() {
// 打开:先清理再打开
EventBus.emit('triggerClearData');
EventBus.emit('triggerOpenFolder'); EventBus.emit('triggerOpenFolder');
}, },
@ -130,27 +163,27 @@ export default {
<BNavbarNav> <BNavbarNav>
<BNavItemDropdown text="文件" right> <BNavItemDropdown text="文件" right>
<BDropdownItem href="#">新建</BDropdownItem> <!-- <BDropdownItem href="#">新建</BDropdownItem> -->
<BDropdownItem href="#" @click="openFolder">打开</BDropdownItem> <BDropdownItem href="#" @click="openFolder">打开</BDropdownItem>
<BDropdownItem href="#" @click="saveFiles">保存</BDropdownItem> <BDropdownItem href="#" @click="saveFiles">保存</BDropdownItem>
<BDropdownItem href="#">另存为</BDropdownItem> <!-- <BDropdownItem href="#">另存为</BDropdownItem> -->
<BDropdownDivider></BDropdownDivider> <BDropdownDivider></BDropdownDivider>
<BDropdownItem href="#">退出</BDropdownItem> <BDropdownItem href="#" @click="quit()">退出</BDropdownItem>
<BDropdownItem href="#" @click="onmenuclick('File', 'Advance')">高级</BDropdownItem> <!-- <BDropdownItem href="#" @click="onmenuclick('File', 'Advance')">高级</BDropdownItem> -->
<BDropdownItem @click="onmenuclick('info', 'help')">帮助</BDropdownItem> <!-- <BDropdownItem @click="onmenuclick('info', 'help')">帮助</BDropdownItem> -->
</BNavItemDropdown> </BNavItemDropdown>
<!-- &lt;!&ndash; Navbar dropdowns &ndash;&gt;--> <!-- &lt;!&ndash; Navbar dropdowns &ndash;&gt;-->
<BNavItemDropdown text="设置" right> <!-- <BNavItemDropdown text="设置" right> -->
<!-- <BDropdownItem @click="onmenuclick('Set','Workmode')">工作模式</BDropdownItem> <!-- <BDropdownItem @click="onmenuclick('Set','Workmode')">工作模式</BDropdownItem>
<BDropdownItem @click="onmenuclick('Set','DevInfo')">设备信息</BDropdownItem> --> <BDropdownItem @click="onmenuclick('Set','DevInfo')">设备信息</BDropdownItem> -->
<!-- <BDropdownItem @click="onmenuclick('Set','Weavelenth')">波长系数</BDropdownItem> --> <!-- <BDropdownItem @click="onmenuclick('Set','Weavelenth')">波长系数</BDropdownItem> -->
<!-- <BDropdownItem @click="onmenuclick('Set','Weavelenthcoeff')">波长设定</BDropdownItem> <!-- <BDropdownItem @click="onmenuclick('Set','Weavelenthcoeff')">波长设定</BDropdownItem>
<BDropdownItem @click="onmenuclick('Set','Calibrate')">定标</BDropdownItem> <BDropdownItem @click="onmenuclick('Set','Calibrate')">定标</BDropdownItem>
<BDropdownItem @click="onmenuclick('Set','CalibrateHH3')">HH3定标</BDropdownItem> --> <BDropdownItem @click="onmenuclick('Set','CalibrateHH3')">HH3定标</BDropdownItem> -->
</BNavItemDropdown> <!-- </BNavItemDropdown> -->
<BNavItemDropdown text="窗口" right> <BNavItemDropdown text="窗口" right>

View File

@ -5,7 +5,7 @@
justify-content: space-between;"> justify-content: space-between;">
<el-row class="secondhang"> <el-row class="secondhang">
<GuiForPlotShow @onComBox1="onComBox1" @onComBox2="onComBox2" @legendselectchanged="legendselectchanged" <GuiForPlotShow @onComBox1="onComBox1" @onComBox2="onComBox2" @legendselectchanged="legendselectchanged"
ref="ASDPlotShow" class="plotcontainer"> @useDarkDnChanged="onUseDarkDnChanged" ref="ASDPlotShow" class="plotcontainer">
</GuiForPlotShow> </GuiForPlotShow>
</el-row> </el-row>
<el-row class="firsthang"> <el-row class="firsthang">
@ -30,9 +30,11 @@
import GuiForPlotShow from "./GuiForPlotShow.vue"; import GuiForPlotShow from "./GuiForPlotShow.vue";
import GuiForDivesInfo from "./GuiForDivesInfo.vue"; import GuiForDivesInfo from "./GuiForDivesInfo.vue";
import PictureDisplayInterface from "./PictureDisplayInterface.vue"; import PictureDisplayInterface from "./PictureDisplayInterface.vue";
import { ref } from 'vue'; import { ref, onMounted, onBeforeUnmount } from 'vue';
import { spectralTypeList } from '../../utils/irisDataDispose'; import { spectralTypeList, spectralProcessTypeList, getIrisDataDispose } from '../../utils/irisDataDispose';
import { SpectralDataService } from '../../utils/spectralDataService'; import { SpectralDataService } from '../../utils/spectralDataService';
import { ElMessage } from 'element-plus';
import EventBus from "../../eventBus.js";
defineOptions({ defineOptions({
name: "GuiForDataShow" name: "GuiForDataShow"
@ -42,20 +44,21 @@ const fromData = ref({
comBox1: spectralTypeList[0].value, comBox1: spectralTypeList[0].value,
comBox2: '', comBox2: '',
}); });
const useDarkDn = ref(true);
const ASDPlotShow = ref(null); const ASDPlotShow = ref(null);
const GuiForDivesInforef = ref(null); const GuiForDivesInforef = ref(null);
const PictureDisplayInterfaceRef = ref(null); const PictureDisplayInterfaceRef = ref(null);
const spectralDataList = ref([]); const spectralDataList = ref([]);
const spectralDataForInfo = ref([]); // 新增:专供 Info/图片使用的数据
const imgeList = ref([]); const imgeList = ref([]);
const fileData = ref([]); const fileData = ref([]);
async function onloaddata(data) { async function onloaddata(data) {
// 重置数据 // 重置数据
spectralDataList.value = []; spectralDataList.value = [];
spectralDataForInfo.value = []; // 新增:同步清空
imgeList.value = []; imgeList.value = [];
fileData.value = []; fileData.value = [];
if (!data || data.length === 0) { if (!data || data.length === 0) {
updateChildComponents([], [], []); updateChildComponents([], [], []);
return; return;
@ -67,6 +70,11 @@ async function onloaddata(data) {
// 处理数据 // 处理数据
await processSpectralData(); await processSpectralData();
if (!spectralDataList.value || spectralDataList.value.length === 0) {
const typeLabel = spectralTypeList.find(i => i.value === fromData.value.comBox1)?.label || fromData.value.comBox1;
ElMessage.warning(`当前数据没有${typeLabel}数据`);
}
} catch (error) { } catch (error) {
console.error('加载数据失败:', error); console.error('加载数据失败:', error);
updateChildComponents([], [], []); updateChildComponents([], [], []);
@ -78,15 +86,43 @@ async function processSpectralData() {
const result = SpectralDataService.processSpectralData( const result = SpectralDataService.processSpectralData(
fileData.value, fileData.value,
fromData.value.comBox1, fromData.value.comBox1,
fromData.value.comBox2 fromData.value.comBox2,
useDarkDn.value
); );
spectralDataList.value = result.spectralDataList; spectralDataList.value = result.spectralDataList;
imgeList.value = result.imageList; imgeList.value = result.imageList;
// 新增:构造独立于 spectralDataList 的 spectralDataForInfo
if (Array.isArray(result.spectralDataList) && result.spectralDataList.length > 0) {
spectralDataForInfo.value = result.spectralDataList;
} else {
// fallback基于 fileData 提取 environmentData 作为占位项
const envOnlyList = [];
for (const item of fileData.value) {
try {
const dispose = new getIrisDataDispose(item.data, fromData.value.comBox1, useDarkDn.value);
const env = dispose?.environmentData;
if (env) {
envOnlyList.push({
name: item.name || '',
datax: [],
datay: [],
environmentData: { ...env, fileName: item.name },
isEnvironmentOnly: true
});
}
} catch (e) {
console.warn('提取环境信息失败:', e);
}
}
spectralDataForInfo.value = envOnlyList;
}
updateChildComponents( updateChildComponents(
result.processedData, result.processedData,
result.spectralDataList, spectralDataForInfo.value,
result.imageList result.imageList
); );
} catch (error) { } catch (error) {
@ -95,20 +131,33 @@ async function processSpectralData() {
} }
function updateChildComponents(processedData, spectralData, imageData) { function updateChildComponents(processedData, spectralData, imageData) {
ASDPlotShow.value?.onloaddata(processedData, fileData.value); ASDPlotShow.value?.onloaddata(processedData, fileData.value);
GuiForDivesInforef.value?.onloaddata(spectralData); GuiForDivesInforef.value?.onloaddata(spectralData);
PictureDisplayInterfaceRef.value?.onloaddata(imageData, spectralData); PictureDisplayInterfaceRef.value?.onloaddata(imageData, spectralData);
} }
const onComBox1 = (e) => { // 光谱类型
const onComBox1 = async (e) => {
fromData.value.comBox1 = e; fromData.value.comBox1 = e;
processSpectralData(); await processSpectralData();
if (!spectralDataList.value || spectralDataList.value.length === 0) {
const typeLabel = spectralTypeList.find(i => i.value === fromData.value.comBox1)?.label || fromData.value.comBox1;
ElMessage.warning(`当前数据没有${typeLabel}数据`);
}
}; };
const onComBox2 = (val) => { // 处理方式
const onComBox2 = async (val) => {
fromData.value.comBox2 = val; fromData.value.comBox2 = val;
if (fromData.value.comBox1) { if (fromData.value.comBox1) {
processSpectralData(); await processSpectralData();
if (!spectralDataList.value || spectralDataList.value.length === 0) {
const typeLabel = spectralTypeList.find(i => i.value === fromData.value.comBox1)?.label || fromData.value.comBox1;
ElMessage.warning(`当前数据没有${typeLabel}数据`);
}
} }
}; };
@ -118,10 +167,10 @@ const legendselectchanged = (nameTable) => {
if (!element || element.length === 0) return false; if (!element || element.length === 0) return false;
return element.some(item => { return element.some(item => {
const str = item.name.split('.')[0]; const str = item.name.split('.')[0];
return nameTable.includes(str); const str1 = (str || '').toString()?.split('_')[0];
return nameTable.split('_')[0] === str1;
}); });
}); });
const selectedSpectral = spectralDataList.value.filter(e => const selectedSpectral = spectralDataList.value.filter(e =>
nameTable.includes(e.name) nameTable.includes(e.name)
); );
@ -131,14 +180,53 @@ const legendselectchanged = (nameTable) => {
PictureDisplayInterfaceRef.value?.onloaddata(filteredImages, selectedSpectral); PictureDisplayInterfaceRef.value?.onloaddata(filteredImages, selectedSpectral);
} }
} else { } else {
GuiForDivesInforef.value?.onloaddata(spectralDataList.value); GuiForDivesInforef.value?.onloaddata(spectralDataForInfo.value);
PictureDisplayInterfaceRef.value?.onloaddata(imgeList.value, spectralDataList.value); PictureDisplayInterfaceRef.value?.onloaddata(imgeList.value, spectralDataForInfo.value);
} }
}; };
function openSaveCurveDialog(selectedPaths) {
const selectedNames = Array.isArray(selectedPaths)
? selectedPaths.map(p => (p || '').toString().split(/[\\\/]/).pop()).filter(Boolean)
: [];
ASDPlotShow.value?.openSaveCurveDialog(selectedNames);
}
function openSaveCurveDialogByPaths(selectedPaths) {
ASDPlotShow.value?.openSaveCurveDialogByPaths(selectedPaths || []);
}
defineExpose({ defineExpose({
onloaddata onloaddata,
openSaveCurveDialog,
openSaveCurveDialogByPaths
}); });
// 新增:统一清理函数,响应 triggerClearData
function clearAll() {
// 清空本组件状态
spectralDataList.value = [];
spectralDataForInfo.value = []; // 新增:同步清空
imgeList.value = [];
fileData.value = [];
// 通知子组件清空
ASDPlotShow.value?.onloaddata([], []); // 清空图表
GuiForDivesInforef.value?.onloaddata([]); // 清空设备信息
PictureDisplayInterfaceRef.value?.clear?.(); // 清空图片显示
}
onMounted(() => {
EventBus.on('triggerClearData', clearAll);
});
onBeforeUnmount(() => {
EventBus.off('triggerClearData', clearAll);
});
// 新增:接收子组件复选框切换事件
const onUseDarkDnChanged = async (val) => {
useDarkDn.value = !!val;
await processSpectralData();
};
</script> </script>
<style scoped> <style scoped>

View File

@ -8,6 +8,8 @@
@change="onComBox2"> @change="onComBox2">
<el-option v-for="item in spectralProcessTypeList" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in spectralProcessTypeList" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
<el-checkbox class="blue-checkbox" v-model="fromDataPlot.useDarkDn"
@change="onUseDarkDnChanged">启用暗噪校正</el-checkbox>
<!-- <el-button class="plotbutton">求导</el-button> <!-- <el-button class="plotbutton">求导</el-button>
<el-checkbox v-model="Prameter.smooth" @change="singleshowclicked($event, 'Smooth')">平滑</el-checkbox> <el-checkbox v-model="Prameter.smooth" @change="singleshowclicked($event, 'Smooth')">平滑</el-checkbox>
@ -56,21 +58,37 @@
<div class="save-select-group"> <div class="save-select-group">
<div class="save-select-item"> <div class="save-select-item">
<span class="save-label">光谱类型</span> <span class="save-label">光谱类型</span>
<el-select v-model="saveOptions.comBox1" placeholder="请选择" class="save-blue-select" style="width: 73%" <el-select
:rules="[{ required: true, message: '请选择光谱类型', trigger: 'change' }]"> v-model="saveOptions.comBox1"
placeholder="请选择"
class="save-blue-select"
style="width: 73%"
:rules="[{ required: true, message: '请选择光谱类型', trigger: 'change' }]"
@change="onSaveComBox1"
>
<el-option v-for="item in spectralTypeList" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in spectralTypeList" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
</div> </div>
<div class="save-select-item"> <div class="save-select-item">
<span class="save-label">处理方式</span> <span class="save-label">处理方式</span>
<el-select clearable v-model="saveOptions.comBox2" placeholder="请选择" class="save-blue-select" <el-select
style="width: 73%" :rules="[{ required: true, message: '请选择处理方式', trigger: 'change' }]"> clearable
<el-option v-for="item in spectralProcessTypeList" :key="item.value" :label="item.label" v-model="saveOptions.comBox2"
:value="item.value" /> placeholder="请选择"
class="save-blue-select"
style="width: 73%"
:rules="[{ required: true, message: '请选择处理方式', trigger: 'change' }]"
@change="onSaveComBox2"
>
<el-option v-for="item in spectralProcessTypeList" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
</div> </div>
</div> </div>
<div class="save-setting" style="margin: 8px 0 12px 0; width: 104px;">
<el-checkbox v-model="saveOptions.useDarkDn" class="blue-checkbox">启用暗噪校正</el-checkbox>
</div>
<!-- 文件选择 --> <!-- 文件选择 -->
<div class="file-selection"> <div class="file-selection">
<div class="selection-header"> <div class="selection-header">
@ -129,11 +147,12 @@ defineOptions({
inheritAttrs: false inheritAttrs: false
}); });
const emit = defineEmits(['onComBox1', 'legendselectchanged']) const emit = defineEmits(['onComBox1', 'onComBox2', 'legendselectchanged', 'useDarkDnChanged'])
const images = import.meta.glob('../assets/*.png', { eager: true, import: 'default' }) const images = import.meta.glob('../assets/*.png', { eager: true, import: 'default' })
const fromDataPlot = ref({ const fromDataPlot = ref({
comBox1: spectralTypeList[0].value, comBox1: spectralTypeList[0].value,
comBox2: '', comBox2: '',
useDarkDn: true,
}) })
const dialogVisible = ref(false); const dialogVisible = ref(false);
const colorList = [ const colorList = [
@ -148,6 +167,11 @@ const onComBox1 = (val) => {
emit('onComBox1', val); emit('onComBox1', val);
}; };
// 暗噪开关变更事件
const onUseDarkDnChanged = (val) => {
emit('useDarkDnChanged', !!val);
};
const echartsMenulist = ref([ const echartsMenulist = ref([
{ {
@ -179,10 +203,63 @@ const saveOptions = reactive({
selectedFiles: [], selectedFiles: [],
selectAllFiles: false, selectAllFiles: false,
fileName: '', fileName: '',
savePath: '' savePath: '',
useDarkDn: true
}); });
// 添加半选状态 // 添加半选状态
function openSaveCurveDialog(selectedNames) {
try {
if (!fileData.value || fileData.value.length === 0) {
alert('暂无有效的曲线数据!');
return;
}
// 打开弹窗并初始化默认项
saveDialogVisible.value = true;
initSaveOptions();
// 按照外部传入的文件名进行预选(文件名需与 fileData.value[*].name 匹配)
if (Array.isArray(selectedNames) && selectedNames.length > 0) {
const onlyNames = selectedNames.map(n => (n || '').toString().split(/[\\\/]/).pop());
const allNames = fileData.value.map(f => f.name);
saveOptions.selectedFiles = allNames.filter(n => onlyNames.includes(n));
updateSelectAllState();
}
} catch (error) {
alert('打开保存对话框失败: ' + error);
}
}
async function openSaveCurveDialogByPaths(filePaths) {
try {
const paths = Array.isArray(filePaths) ? filePaths.filter(Boolean) : [];
if (paths.length === 0) {
alert('请选择要导出的文件');
return;
}
// 仅为保存弹窗临时加载数据,不更新图表
const loaded = await SpectralDataService.loadFileData(paths);
if (!loaded || loaded.length === 0) {
alert('未能加载到有效的文件数据');
return;
}
fileData.value = loaded;
// 打开并初始化弹窗
saveDialogVisible.value = true;
initSaveOptions();
// 预勾选当前传入的文件
const onlyNames = paths.map(p => (p || '').toString().split(/[\\\/]/).pop());
const allNames = fileData.value.map(f => f.name);
saveOptions.selectedFiles = allNames.filter(n => onlyNames.includes(n));
updateSelectAllState();
} catch (error) {
alert('打开保存对话框失败: ' + error);
}
}
const isIndeterminate = ref(false); const isIndeterminate = ref(false);
// 处理保存对话框关闭 // 处理保存对话框关闭
@ -225,6 +302,7 @@ function updateSelectAllState() {
function initSaveOptions() { function initSaveOptions() {
saveOptions.comBox1 = fromDataPlot.value.comBox1; saveOptions.comBox1 = fromDataPlot.value.comBox1;
saveOptions.comBox2 = fromDataPlot.value.comBox2; saveOptions.comBox2 = fromDataPlot.value.comBox2;
saveOptions.useDarkDn = fromDataPlot.value.useDarkDn;
// 默认选中所有文件 // 默认选中所有文件
if (fileData.value && fileData.value.length > 0) { if (fileData.value && fileData.value.length > 0) {
@ -337,7 +415,7 @@ async function saveCurveData() {
await fs.writeTextFile(filePath, bom + content); await fs.writeTextFile(filePath, bom + content);
console.log("文件已成功保存到: " + filePath); console.log("文件已成功保存到: " + filePath);
this.$message.success(`文件已成功保存到 ${filePath}`) ElMessage.success(`文件已成功保存到 ${filePath}`)
saveDialogVisible.value = false; saveDialogVisible.value = false;
} catch (error) { } catch (error) {
@ -345,6 +423,38 @@ async function saveCurveData() {
} }
} }
// 保存弹窗:光谱类型选择变更
function onSaveComBox1(val) {
try {
saveOptions.comBox1 = val;
const targets = getPitchOnData(saveOptions);
if (!targets || !Array.isArray(targets) || targets.length === 0) {
const typeLabel = spectralTypeList.find(i => i.value === saveOptions.comBox1)?.label || saveOptions.comBox1;
ElMessage.warning(`当前数据没有${typeLabel}数据`);
}
} catch (error) {
console.error('保存弹窗光谱类型切换处理失败:', error);
}
}
// 保存弹窗:处理方式选择变更
function onSaveComBox2(val) {
try {
saveOptions.comBox2 = val;
if (saveOptions.comBox1) {
const targets = getPitchOnData(saveOptions);
if (!targets || !Array.isArray(targets) || targets.length === 0) {
const typeLabel = spectralTypeList.find(i => i.value === saveOptions.comBox1)?.label || saveOptions.comBox1;
ElMessage.warning(`当前数据没有${typeLabel}数据`);
}
}
} catch (error) {
console.error('保存弹窗处理方式切换处理失败:', error);
}
}
// 文件数据处理 // 文件数据处理
function getPitchOnData(saveOptions) { function getPitchOnData(saveOptions) {
try { try {
@ -352,7 +462,8 @@ function getPitchOnData(saveOptions) {
fileData.value, fileData.value,
saveOptions.selectedFiles, saveOptions.selectedFiles,
saveOptions.comBox1, saveOptions.comBox1,
saveOptions.comBox2 saveOptions.comBox2,
saveOptions.useDarkDn
); );
return result.processedData; return result.processedData;
} catch (error) { } catch (error) {
@ -462,11 +573,15 @@ function onloaddata(data, files) {
min: null, min: null,
max: null max: null
}; };
if (Array.isArray(option.value.yAxis)) {
option.value.yAxis = option.value.yAxis.map(ax => ({ ...ax, min: null, max: null }));
} else {
option.value.yAxis = { option.value.yAxis = {
...option.value.yAxis, ...option.value.yAxis,
min: null, min: null,
max: null max: null
}; };
};
// 遍历数据创建多条折线 // 遍历数据创建多条折线
data.forEach((item, index) => { data.forEach((item, index) => {
@ -505,11 +620,15 @@ function onloaddata(data, files) {
min: -100, min: -100,
max: 100 max: 100
}; };
if (Array.isArray(option.value.yAxis)) {
option.value.yAxis = option.value.yAxis.map(ax => ({ ...ax, min: -100, max: 100 }));
} else {
option.value.yAxis = { option.value.yAxis = {
...option.value.yAxis, ...option.value.yAxis,
min: -100, min: -100,
max: 100 max: 100
}; };
};
option.value.series = []; option.value.series = [];
option.value.legend.data = []; option.value.legend.data = [];
} }
@ -532,12 +651,16 @@ function initChart() {
color: colorList, color: colorList,
grid: { grid: {
left: 10, left: 10,
right: 40, right: 30,
bottom: 0, bottom: 30,
containLabel: true containLabel: true
}, },
toolbox: { toolbox: {
left: 'center', left: 'center',
feature: {
dataZoom: {},
restore: {}
}
}, },
animation: false, animation: false,
xAxis: { xAxis: {
@ -549,14 +672,11 @@ function initChart() {
color: 'rgba(0, 0, 0, 0.2)' color: 'rgba(0, 0, 0, 0.2)'
} }
}, },
axisTick: { axisTick: { show: false },
show: false axisLabel: { color: 'rgba(0, 0, 0, 0.70)' }
}, },
axisLabel: { yAxis: [
color: 'rgba(0, 0, 0, 0.70)' {
}
},
yAxis: {
type: 'value', type: 'value',
min: -100, min: -100,
max: 100, max: 100,
@ -565,20 +685,30 @@ function initChart() {
color: 'rgba(0, 0, 0, 0.2)' color: 'rgba(0, 0, 0, 0.2)'
} }
}, },
axisTick: { axisTick: { show: false },
show: false axisLabel: { color: 'rgba(0, 0, 0, 0.70)' },
position: 'left'
}, },
axisLabel: { {
color: 'rgba(0, 0, 0, 0.70)' type: 'value',
min: -100,
max: 100,
axisLine: {
lineStyle: {
color: 'rgba(0, 0, 0, 0.2)'
} }
}, },
axisTick: { show: false },
axisLabel: { color: 'rgba(0, 0, 0, 0.70)' },
position: 'right' // 右侧轴
}
],
dataZoom: [ dataZoom: [
{ // 显式绑定到 x/y 轴,支持框选缩放
type: 'inside', { type: 'inside', xAxisIndex: [0], filterMode: 'none' },
}, { type: 'inside', yAxisIndex: [0], filterMode: 'none' },
{ { type: 'slider', xAxisIndex: [0], filterMode: 'none', height: 35, bottom: 15 },
type: 'inside', { type: 'slider', yAxisIndex: [0], filterMode: 'none', width: 35, right: 25 }
}
], ],
legend: { legend: {
itemHeight: 2, itemHeight: 2,
@ -592,14 +722,10 @@ function initChart() {
height: 30, height: 30,
width: 400, width: 400,
pageIconColor: '#4271EE', pageIconColor: '#4271EE',
pageTextStyle: { pageTextStyle: { color: '#4271EE' },
color: '#4271EE'
},
itemWidth: 14, itemWidth: 14,
itemHeight: 10, itemHeight: 10,
textStyle: { textStyle: { color: 'rgba(0, 0, 0, 0.70)' },
color: 'rgba(0, 0, 0, 0.70)'
},
selectedMode: 'multiple' selectedMode: 'multiple'
}, },
series: [ series: [
@ -607,13 +733,21 @@ function initChart() {
data: [], data: [],
type: 'line', type: 'line',
symbol: 'none', symbol: 'none',
smooth: true, smooth: true
} }
] ]
}; };
let selectedLegend = null; let selectedLegend = null;
chart.setOption(option.value, true); chart.setOption(option.value, true);
// 启用“左键框选缩放”模式
chart.dispatchAction({
type: 'takeGlobalCursor',
key: 'dataZoomSelect',
dataZoomSelectActive: true
});
window.addEventListener('resize', echartresize); window.addEventListener('resize', echartresize);
// 监听图例点击事件,控制单条显示与恢复全部 // 监听图例点击事件,控制单条显示与恢复全部
@ -623,7 +757,6 @@ function initChart() {
if (selectedLegend === clickedName) { if (selectedLegend === clickedName) {
emit("legendselectchanged", '') emit("legendselectchanged", '')
// 恢复全部
selectedLegend = null; selectedLegend = null;
option.value.series.forEach(item => { option.value.series.forEach(item => {
chart.dispatchAction({ type: 'legendSelect', name: item.name }); chart.dispatchAction({ type: 'legendSelect', name: item.name });
@ -641,7 +774,13 @@ function initChart() {
} }
}); });
// 双击恢复缩放到初始范围
chart.getZr().off('dblclick');
chart.getZr().on('dblclick', () => {
(option.value.dataZoom || []).forEach((_, idx) => {
chart.dispatchAction({ type: 'dataZoom', dataZoomIndex: idx, start: 0, end: 100 });
});
});
} }
@ -676,6 +815,13 @@ function flushplot() {
start: 0, start: 0,
end: 100 end: 100
}); });
chart.dispatchAction({
type: 'takeGlobalCursor',
key: 'dataZoomSelect',
dataZoomSelectActive: true
});
chart.resize();
}, 0); }, 0);
} }
} }
@ -709,7 +855,9 @@ onBeforeUnmount(() => {
defineExpose({ defineExpose({
onloaddata, onloaddata,
Prameter, Prameter,
fromDataPlot fromDataPlot,
openSaveCurveDialog,
openSaveCurveDialogByPaths
}); });
</script> </script>
@ -755,8 +903,17 @@ defineExpose({
.blue-select :deep(.el-input__wrapper.is-focus) {} .blue-select :deep(.el-input__wrapper.is-focus) {}
.blue-select:nth-child(2) { .blue-select {
margin-left: 20px; margin-right: 20px;
}
.blue-checkbox :deep(.el-checkbox__input.is-checked .el-checkbox__inner) {
background-color: rgba(66, 113, 238, 1);
border-color: rgba(66, 113, 238, 1);
}
.blue-checkbox :deep(.el-checkbox__input.is-checked+.el-checkbox__label) {
color: #4271EE;
} }
.save-blue-select:deep(.el-select__wrapper) { .save-blue-select:deep(.el-select__wrapper) {

View File

@ -54,14 +54,27 @@ export default {
async mounted() { async mounted() {
window.addEventListener("keydown", this.handleKeyDown); window.addEventListener("keydown", this.handleKeyDown);
window.addEventListener("keyup", this.handleKeyUp); window.addEventListener("keyup", this.handleKeyUp);
// 额外增加:用鼠标事件同步按键状态,防止 keyup 丢失导致“多选卡住”
window.addEventListener("mousedown", this.handleMouseDown, true); // 捕获阶段更稳妥
window.addEventListener("mouseup", this.handleMouseUp, true);
window.addEventListener("blur", this.resetModifierKeys); // 窗口失焦时重置
document.addEventListener("visibilitychange", this.handleVisibilityChange);
// 事件总线
EventBus.on('triggerOpenFolder', this.onopendata); EventBus.on('triggerOpenFolder', this.onopendata);
EventBus.on('triggerSaveFiles', this.handleSaveFiles); EventBus.on('triggerSaveFiles', this.handleSaveFiles);
EventBus.on('triggerClearData', this.clearData);
}, },
beforeUnmount() { beforeUnmount() {
window.removeEventListener("keydown", this.handleKeyDown); window.removeEventListener("keydown", this.handleKeyDown);
window.removeEventListener("keyup", this.handleKeyUp); window.removeEventListener("keyup", this.handleKeyUp);
// 配套移除新增的监听
window.removeEventListener("mousedown", this.handleMouseDown, true);
window.removeEventListener("mouseup", this.handleMouseUp, true);
window.removeEventListener("blur", this.resetModifierKeys);
document.removeEventListener("visibilitychange", this.handleVisibilityChange);
EventBus.off('triggerOpenFolder', this.onopendata); EventBus.off('triggerOpenFolder', this.onopendata);
EventBus.off('triggerSaveFiles', this.handleSaveFiles); EventBus.off('triggerSaveFiles', this.handleSaveFiles);
EventBus.off('triggerClearData', this.clearData);
}, },
methods: { methods: {
handleKeyDown(event) { handleKeyDown(event) {
@ -80,6 +93,26 @@ export default {
this.shiftKeyPressed = false; this.shiftKeyPressed = false;
} }
}, },
// 新增:鼠标按下/松开时同步 Ctrl/Shift 状态(点击流程更可靠)
handleMouseDown(e) {
this.ctrlKeyPressed = !!e.ctrlKey;
this.shiftKeyPressed = !!e.shiftKey;
},
handleMouseUp(e) {
// 鼠标抬起时再次以实际状态为准(若用户已松开 Ctrl/Shift这里会回到 false
this.ctrlKeyPressed = !!e.ctrlKey;
this.shiftKeyPressed = !!e.shiftKey;
},
// 新增:窗口不可见/失焦时,重置修饰键,避免卡住
handleVisibilityChange() {
if (document.visibilityState !== 'visible') {
this.resetModifierKeys();
}
},
resetModifierKeys() {
this.ctrlKeyPressed = false;
this.shiftKeyPressed = false;
},
collectAllFiles(node) { collectAllFiles(node) {
const files = []; const files = [];
@ -295,29 +328,84 @@ export default {
this.$emit("reset"); this.$emit("reset");
this.data = [] this.data = []
const folderTree = await this.$tauriApi.getFolderList(this.DefualtPath); const folderTree = await this.$tauriApi.getFolderList(this.DefualtPath);
// 添加唯一ID
const getComparableLabel = (node) => {
if (typeof node?.label !== "string") return "";
if (node.isLeaf) {
return node.label.replace(/\.[^/.]+$/, "");
}
return node.label;
};
// 工具从名称中提取日期YYYY[_-]M[M]?[_-]D[D]?),返回时间戳,未匹配返回 null
const extractDateStamp = (node) => {
const base = getComparableLabel(node);
// 支持 2025_9_3、2025-9-3、2025_09_03、2025-09-03
const m = base.match(/(\d{4})[_-](\d{1,2})[_-](\d{1,2})/);
if (!m) return null;
const y = parseInt(m[1], 10);
const M = parseInt(m[2], 10);
const d = parseInt(m[3], 10);
const dt = new Date(y, M - 1, d);
if (
Number.isNaN(dt.getTime()) ||
dt.getFullYear() !== y ||
dt.getMonth() !== (M - 1) ||
dt.getDate() !== d
) {
return null;
}
return dt.getTime();
};
// 添加唯一ID并进行过滤 + 排序(同级文件夹与文件按日期由近到远,无日期排后且保持原序)
let idCounter = 1; let idCounter = 1;
const addUniqueIdsAndFilter = (node) => { const addUniqueIdsAndFilter = (node) => {
node.id = idCounter++; node.id = idCounter++;
if (node.isFolder) { if (node.isFolder) {
if (Array.isArray(node.children) && node.children.length) { if (Array.isArray(node.children) && node.children.length) {
// 过滤:仅保留文件夹与 .iris 文件
node.children = node.children.filter(child => { node.children = node.children.filter(child => {
if (child.isFolder) return true; if (child.isFolder) return true;
if (child.isLeaf && typeof child.label === 'string') { if (child.isLeaf && typeof child.label === "string") {
return child.label.endsWith('.iris'); return child.label.endsWith(".iris");
} }
return false; return false;
}); });
// 排序:按包含的日期(忽略后缀)由近到远;无日期排在后面并保持原有顺序
const decorated = node.children.map((child, idx) => ({
child,
idx,
stamp: extractDateStamp(child) // number | null
}));
decorated.sort((a, b) => {
const aHas = typeof a.stamp === "number";
const bHas = typeof b.stamp === "number";
if (aHas && bHas) {
return b.stamp - a.stamp; // 近(新) -> 远(旧)
}
if (aHas && !bHas) return -1; // 有日期在前
if (!aHas && bHas) return 1; // 无日期在后
// 都没有日期:保持原有顺序(稳定)
return a.idx - b.idx;
});
node.children = decorated.map(d => d.child);
// 递归处理
node.children.forEach(child => addUniqueIdsAndFilter(child)); node.children.forEach(child => addUniqueIdsAndFilter(child));
} }
} else { } else {
// 非文件夹无需处理子项
} }
}; };
addUniqueIdsAndFilter(folderTree); addUniqueIdsAndFilter(folderTree);
if (folderTree && folderTree.label != "请选择") { if (folderTree && folderTree.label != "请选择") {
this.data = [folderTree]; this.data = [folderTree];
} }
// 收集所有id用于默认展开 // 收集所有id用于默认展开
const expandedKeys = []; const expandedKeys = [];
this.collectAllNodeIds(folderTree, expandedKeys); this.collectAllNodeIds(folderTree, expandedKeys);
@ -366,8 +454,16 @@ export default {
return allFiles; return allFiles;
}, },
// 清空数据
clearData() {
this.$emit("reset");
this.data = []
} }
} }
}
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
@ -388,7 +484,7 @@ el-tree {
.el-treecontain { .el-treecontain {
width: 100%; width: 100%;
text-align: left; text-align: left;
max-height: 96vh; max-height: 88vh;
overflow-y: auto; overflow-y: auto;
} }

View File

@ -172,10 +172,21 @@ const fullscreenChangeHandler = () => {
isFullscreen.value = !!document.fullscreenElement; isFullscreen.value = !!document.fullscreenElement;
}; };
// 新增:清空地图矢量图层的方法
const clearMap = () => {
if (vectorLayer.value && vectorLayer.value.getSource()) {
vectorLayer.value.getSource().clear();
}
};
watch( watch(
() => props.dataListMap, () => props.dataListMap,
(newVal) => { (newVal) => {
if (!Array.isArray(newVal) || newVal.length === 0) return; // 当传入空数组或非法数据时,清空图层中的点
if (!Array.isArray(newVal) || newVal.length === 0) {
clearMap();
return;
}
const tryAdd = () => { const tryAdd = () => {
if (isMapReady.value) { if (isMapReady.value) {
@ -205,6 +216,10 @@ onBeforeUnmount(() => {
document.removeEventListener('fullscreenchange', fullscreenChangeHandler); document.removeEventListener('fullscreenchange', fullscreenChangeHandler);
}); });
// 对外暴露清空方法,供父组件调用
defineExpose({
clearMap
});
</script> </script>
<style scoped> <style scoped>

View File

@ -2,14 +2,13 @@
<div class="maincontainer"> <div class="maincontainer">
<div class="container_item"> <div class="container_item">
<!-- 文件名显示 --> <!-- 文件名显示 -->
<div class="filename_display" v-if="!isLastPage && currentItem?.url"> <div class="filename_display" v-if="!isLastPage">
<img src="../assets/文件图标-面.png"> <img src="../assets/文件图标-面.png">
{{ currentItem?.name || '暂无文件' }} {{ currentItem?.name || '暂无文件' }}
</div> </div>
<div class="filename_display" v-else> <div class="filename_display" v-else>
地图 地图
</div> </div>
<!-- 轮播内容区域 --> <!-- 轮播内容区域 -->
<div class="carousel-container"> <div class="carousel-container">
<!-- 左侧导航按钮 --> <!-- 左侧导航按钮 -->
@ -22,9 +21,13 @@
</svg> </svg>
</button> </button>
<div class="contemer_content"> <div class="contemer_content">
<img v-if="!isLastPage && currentItem?.url" :src="currentItem.url" /> <div class="jzsb" v-if="!isLastPage && currentItem.url == 'jzsb'">
<img src="../assets/加载失败.svg"></img>
<span>图片加载失败</span>
</div>
<img v-else-if="!isLastPage" :src="currentItem.url" />
<div v-else class="last-page-box"> <div v-else class="last-page-box">
<MapContainer :dataListMap="dataListMap"></MapContainer> <MapContainer ref="mapRef" :dataListMap="dataListMap"></MapContainer>
</div> </div>
</div> </div>
@ -50,11 +53,12 @@ import MapContainer from "./MapContainer.vue";
const imgeList = ref([]) const imgeList = ref([])
const currentIndex = ref(0) const currentIndex = ref(0)
const dataListMap = ref([]) const dataListMap = ref([])
const mapRef = ref(null)
const isLastPage = computed(() => currentIndex.value === imgeList.value.length) const isLastPage = computed(() => currentIndex.value === imgeList.value.length)
const currentItem = computed(() => { const currentItem = computed(() => {
if (isLastPage.value) { if (isLastPage.value) {
return null return {}
} }
return imgeList.value[currentIndex.value] || {} return imgeList.value[currentIndex.value] || {}
}) })
@ -68,6 +72,14 @@ const onloaddata = async (jsondata, dataList) => {
} }
} }
// 新增:清空方法,确保图片与地图点都能被清理
const clear = () => {
imgeList.value = []
dataListMap.value = []
currentIndex.value = 0
mapRef.value?.clearMap()
}
// 上一项 // 上一项
const prevItem = () => { const prevItem = () => {
@ -91,7 +103,8 @@ const goToItem = (index) => {
} }
defineExpose({ defineExpose({
onloaddata onloaddata,
clear
}) })
</script> </script>
@ -144,7 +157,7 @@ defineExpose({
width: 100%; width: 100%;
height: 30vh; height: 30vh;
display: flex; display: flex;
padding-top: 20px; // padding-top: 20px;
&>img { &>img {
width: 100%; width: 100%;
@ -157,6 +170,23 @@ defineExpose({
height: 100%; height: 100%;
} }
& > .jzsb {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
&>img {
width: 70%;
height: 70%;
}
&>span {
font-size: 14px;
color: #6B7181;
}
}
} }
.nav-button { .nav-button {

View File

@ -49,9 +49,22 @@ export default {
}, },
mounted() { mounted() {
window.addEventListener("keydown",this.handlekeydown) // 仅在挂载时注册总线,不在这里绑定全局键盘事件(避免 KeepAlive 导致的重复/遗留绑定)
EventBus.on('SetMenubutton',this.setbutton); EventBus.on('SetMenubutton',this.setbutton);
}, },
activated() {
// 仅在当前页面处于激活状态时绑定
window.addEventListener("keydown", this.handlekeydown);
},
deactivated() {
// 从可见切换为缓存(隐藏)时,解绑,避免隐藏页误触发
window.removeEventListener("keydown", this.handlekeydown);
},
beforeUnmount() {
// 彻底卸载时,兜底解绑
window.removeEventListener("keydown", this.handlekeydown);
EventBus.off && EventBus.off('SetMenubutton', this.setbutton);
},
methods: { methods: {
setbutton(command){ setbutton(command){
if (command.name == "DC"){ if (command.name == "DC"){
@ -83,7 +96,21 @@ export default {
this.$emit("menubalclicked", command) this.$emit("menubalclicked", command)
}, },
handlekeydown(event) { handlekeydown(event) {
// console.log(event.key); // 在可编辑环境中不触发应用快捷键
const t = event.target || {};
const tag = (t.tagName || '').toLowerCase();
const isEditable = t.isContentEditable || tag === 'input' || tag === 'textarea' || tag === 'select';
if (isEditable) return;
// 只处理来自本应用根节点(#app)内的事件,忽略外部悬浮窗/插件
const appRoot = document.getElementById('app');
if (!appRoot || !appRoot.contains(event.target)) return;
// 不劫持系统复制快捷键 Ctrl+C
if (event.ctrlKey && !event.shiftKey && (event.key === 'c' || event.key === 'C')) {
return;
}
if (event.ctrlKey) { if (event.ctrlKey) {
if (event.key == "n" || event.key == "N") { if (event.key == "n" || event.key == "N") {
this.onmenuclick('Set', 'Workmode'); this.onmenuclick('Set', 'Workmode');
@ -94,11 +121,10 @@ export default {
if (event.key == "w" || event.key == "W") { if (event.key == "w" || event.key == "W") {
this.onmenuclick('Set', 'Weavelenth'); this.onmenuclick('Set', 'Weavelenth');
} }
if (event.key == "c" || event.key == "C") { // 将“定标”快捷键改为 Ctrl + Shift + C避免与系统复制冲突
if (event.shiftKey && (event.key == "c" || event.key == "C")) {
this.onmenuclick('Set', 'Calibrate'); this.onmenuclick('Set', 'Calibrate');
} }
} }
} }
} }

View File

@ -7,11 +7,12 @@ class getIrisDataDispose {
devinfoData; devinfoData;
environmentData; environmentData;
constructor(irisData, spectralName) { constructor(irisData, spectralName, useDarkDn = true) {
this.irisData = irisData; this.irisData = irisData;
this.spectralName = spectralName; this.spectralName = spectralName;
this.spectral_data = irisData.spectral_data_section; this.spectral_data = irisData.spectral_data_section;
this.image_info = irisData.image_info_section; this.image_info = irisData.image_info_section;
this.useDarkDn = useDarkDn;
for (const element of irisData.spectral_info_section) { for (const element of irisData.spectral_info_section) {
if (element.info_type == "devinfo") { if (element.info_type == "devinfo") {
@ -40,10 +41,79 @@ class getIrisDataDispose {
//获取一般后端直接返回的类型 //获取一般后端直接返回的类型
getFileSpectralData() { getFileSpectralData() {
// 基础类型适配暗噪开关ground_dn / flat_dn 在启用暗噪时做 “- dark_dn”
const nameLower = (this.spectralName || '').toLowerCase();
const bands = this.devinfoData?.bandnum ?? 0;
const needDarkCorr =
this.useDarkDn && (nameLower === 'ground_dn' || nameLower === 'flat_dn');
if (needDarkCorr) {
let mainEl = null; // ground_dn 或 flat_dn 的原始 element
let darkEl = null; // dark_dn 的原始 element
for (const element of this.spectral_data) {
const lower = (element.name || '').toLowerCase();
if (!mainEl && lower.includes(nameLower)) {
mainEl = element;
} else if (!darkEl && lower.includes('dark_dn')) {
darkEl = element;
}
if (mainEl && darkEl) break;
}
if (!mainEl) {
console.error(`未找到 ${nameLower} 数据,无法计算`);
return undefined;
}
const mainTyped = manageSpectralData(mainEl, this.devinfoData);
const main = Array.isArray(mainTyped) ? mainTyped : Array.from(mainTyped || []);
const darkTyped = darkEl ? manageSpectralData(darkEl, this.devinfoData) : null;
const dark = darkTyped ? (Array.isArray(darkTyped) ? darkTyped : Array.from(darkTyped)) : null;
const corrected = [];
const invalidCount = { missing: 0, invalidResult: 0 };
for (let i = 0; i < bands; i++) {
const mv = main[i];
const dv = dark ? (dark[i] ?? 0) : 0;
if (mv === undefined) {
corrected.push(0);
invalidCount.missing++;
continue;
}
const v = mv - dv;
if (Number.isFinite(v) && !Number.isNaN(v)) {
corrected.push(v);
} else {
corrected.push(0);
invalidCount.invalidResult++;
}
}
if (!dark) {
console.warn(`${nameLower} 去暗噪: 未找到 dark_dn按 0 处理`);
} else if (dark.length !== bands) {
console.warn(
`${nameLower} 去暗噪: dark_dn 长度(${dark.length})与波段数(${bands})不一致,按可用索引减,缺失部分按 0`
);
}
if (invalidCount.missing > 0 || invalidCount.invalidResult > 0) {
console.warn(
`${nameLower} 去暗噪: 缺失值 ${invalidCount.missing} 个,无效结果 ${invalidCount.invalidResult} 个,有效数据 ${corrected.length}`
);
}
return { ...mainEl, normalArray: corrected };
}
// 默认路径:保持原逻辑(未启用暗噪或其它基础类型)
for (const element of this.spectral_data) { for (const element of this.spectral_data) {
const typedArray = manageSpectralData(element, this.devinfoData); const typedArray = manageSpectralData(element, this.devinfoData);
const normalArray = Array.from(typedArray); const normalArray = Array.from(typedArray);
if (element.name.toLowerCase().includes(this.spectralName)) { if ((element.name || '').toLowerCase().includes(nameLower)) {
return { ...element, normalArray }; return { ...element, normalArray };
} }
} }
@ -75,43 +145,22 @@ class getIrisDataDispose {
} }
} }
if ( // 分支依赖校验与辅助函数
spectralDataMap.get("ground_dn") && const has = (key) => !!spectralDataMap.get(key);
spectralDataMap.get("flat_dn") && const requireDeps = (deps) => deps.every((k) => has(k));
spectralDataMap.get("dark_dn") && const buildArrAll = (keys) => {
spectralDataMap.get("gain") const obj = {};
) { for (const k of keys) obj[k] = spectralDataMap.get(k).normalArray;
const obj1 = { return mergeObjectArrays(obj);
ground_dn: spectralDataMap.get("ground_dn").normalArray,
flat_dn: spectralDataMap.get("flat_dn").normalArray,
dark_dn: spectralDataMap.get("dark_dn").normalArray,
gain: spectralDataMap.get("gain").normalArray,
}; };
const baseName = (...preferredKeys) => {
const arrAll = mergeObjectArrays(obj1); for (const k of preferredKeys) {
const name = spectralDataMap.get("ground_dn").name.split("_")[0]; if (has(k)) return spectralDataMap.get(k).name.split("_")[0];
// 通用的数值验证函数
const validateAndPush = (array, value, type, invalidCount) => {
if (isFinite(value) && !isNaN(value)) {
array.push(value);
return true;
} else {
invalidCount.invalidResult++;
return false;
} }
return "unknown";
}; };
// 通用的除零检查函数 // 结果验证(依赖不够时不会走到这里)
const checkDivision = (numerator, denominator, type, invalidCount) => {
if (Math.abs(denominator) < 1e-10) {
invalidCount.zeroDiv++;
return null;
}
return numerator / denominator;
};
// 通用的结果验证和返回函数
const validateResult = (array, name, type) => { const validateResult = (array, name, type) => {
if (array.length === 0) { if (array.length === 0) {
console.error(`${type}计算错误: 没有有效的数据点,无法生成图表`); console.error(`${type}计算错误: 没有有效的数据点,无法生成图表`);
@ -121,6 +170,11 @@ class getIrisDataDispose {
}; };
if (this.spectralName == "radiance_ground") { if (this.spectralName == "radiance_ground") {
const deps = ["gain", "ground_dn"].concat(this.useDarkDn ? ["dark_dn"] : []);
if (!requireDeps(deps)) return undefined; // 依赖不够,直接返回空,保持原逻辑
const arrAll = buildArrAll(deps);
const name = baseName("ground_dn", "gain");
const radiance_ground = []; const radiance_ground = [];
const invalidCount = { zeroDiv: 0, invalidResult: 0 }; const invalidCount = { zeroDiv: 0, invalidResult: 0 };
@ -128,7 +182,6 @@ class getIrisDataDispose {
const gainExposure = spectralDataMap.get("gain").exposure; const gainExposure = spectralDataMap.get("gain").exposure;
const groundExposure = spectralDataMap.get("ground_dn").exposure; const groundExposure = spectralDataMap.get("ground_dn").exposure;
// 检查曝光时间除零 - 改为补充0值
if (Math.abs(groundExposure) < 1e-10) { if (Math.abs(groundExposure) < 1e-10) {
invalidCount.zeroDiv++; invalidCount.zeroDiv++;
radiance_ground.push(0); radiance_ground.push(0);
@ -136,10 +189,9 @@ class getIrisDataDispose {
} }
const exposureRatio = gainExposure / groundExposure; const exposureRatio = gainExposure / groundExposure;
const dnDiff = element.ground_dn - element.dark_dn; const dnDiff = element.ground_dn - (this.useDarkDn ? element.dark_dn : 0);
const a = exposureRatio * (element.gain * dnDiff); const a = exposureRatio * (element.gain * dnDiff);
// 验证结果无效时补充0值
if (isFinite(a) && !isNaN(a)) { if (isFinite(a) && !isNaN(a)) {
radiance_ground.push(a); radiance_ground.push(a);
} else { } else {
@ -147,14 +199,17 @@ class getIrisDataDispose {
radiance_ground.push(0); radiance_ground.push(0);
} }
} }
// 记录统计信息
if (invalidCount.zeroDiv > 0 || invalidCount.invalidResult > 0) { if (invalidCount.zeroDiv > 0 || invalidCount.invalidResult > 0) {
console.warn(`radiance_ground计算统计: 除零错误 ${invalidCount.zeroDiv} 个,无效结果 ${invalidCount.invalidResult} 个,有效数据 ${radiance_ground.length}`); console.warn(`radiance_ground计算统计: 除零错误 ${invalidCount.zeroDiv} 个,无效结果 ${invalidCount.invalidResult} 个,有效数据 ${radiance_ground.length}`);
} }
return validateResult(radiance_ground, name + "_radiance_ground", "radiance_ground");
return validateResult(radiance_ground, name + "_radiance_ground", 'radiance_ground');
} else if (this.spectralName == "radiance_flat") { } else if (this.spectralName == "radiance_flat") {
const deps = ["gain", "flat_dn"].concat(this.useDarkDn ? ["dark_dn"] : []);
if (!requireDeps(deps)) return undefined; // 依赖不够,直接返回空
const arrAll = buildArrAll(deps);
const name = baseName("flat_dn", "gain");
const radiance_flat = []; const radiance_flat = [];
const invalidCount = { zeroDiv: 0, invalidResult: 0 }; const invalidCount = { zeroDiv: 0, invalidResult: 0 };
@ -162,7 +217,6 @@ class getIrisDataDispose {
const gainExposure = spectralDataMap.get("gain").exposure; const gainExposure = spectralDataMap.get("gain").exposure;
const flatExposure = spectralDataMap.get("flat_dn").exposure; const flatExposure = spectralDataMap.get("flat_dn").exposure;
// 检查曝光时间除零 - 改为补充0值
if (Math.abs(flatExposure) < 1e-10) { if (Math.abs(flatExposure) < 1e-10) {
invalidCount.zeroDiv++; invalidCount.zeroDiv++;
radiance_flat.push(0); radiance_flat.push(0);
@ -170,10 +224,9 @@ class getIrisDataDispose {
} }
const exposureRatio = gainExposure / flatExposure; const exposureRatio = gainExposure / flatExposure;
const dnDiff = element.flat_dn - element.dark_dn; const dnDiff = element.flat_dn - (this.useDarkDn ? element.dark_dn : 0);
const b = exposureRatio * (element.gain * dnDiff); const b = exposureRatio * (element.gain * dnDiff);
// 验证结果无效时补充0值
if (isFinite(b) && !isNaN(b)) { if (isFinite(b) && !isNaN(b)) {
radiance_flat.push(b); radiance_flat.push(b);
} else { } else {
@ -181,14 +234,17 @@ class getIrisDataDispose {
radiance_flat.push(0); radiance_flat.push(0);
} }
} }
// 记录统计信息
if (invalidCount.zeroDiv > 0 || invalidCount.invalidResult > 0) { if (invalidCount.zeroDiv > 0 || invalidCount.invalidResult > 0) {
console.warn(`radiance_flat计算统计: 除零错误 ${invalidCount.zeroDiv} 个,无效结果 ${invalidCount.invalidResult} 个,有效数据 ${radiance_flat.length}`); console.warn(`radiance_flat计算统计: 除零错误 ${invalidCount.zeroDiv} 个,无效结果 ${invalidCount.invalidResult} 个,有效数据 ${radiance_flat.length}`);
} }
return validateResult(radiance_flat, name + "_radiance_flat", "radiance_flat");
return validateResult(radiance_flat, name + "_radiance_flat", 'radiance_flat');
} else if (this.spectralName == "refrad") { } else if (this.spectralName == "refrad") {
const deps = ["gain", "ground_dn", "flat_dn"].concat(this.useDarkDn ? ["dark_dn"] : []);
if (!requireDeps(deps)) return undefined; // 依赖不够,直接返回空
const arrAll = buildArrAll(deps);
const name = baseName("ground_dn", "flat_dn", "gain");
const refrad = []; const refrad = [];
const invalidCount = { zeroDiv: 0, invalidResult: 0 }; const invalidCount = { zeroDiv: 0, invalidResult: 0 };
@ -197,7 +253,6 @@ class getIrisDataDispose {
const groundExposure = spectralDataMap.get("ground_dn").exposure; const groundExposure = spectralDataMap.get("ground_dn").exposure;
const flatExposure = spectralDataMap.get("flat_dn").exposure; const flatExposure = spectralDataMap.get("flat_dn").exposure;
// 检查曝光时间除零 - 改为补充0值
if (Math.abs(groundExposure) < 1e-10 || Math.abs(flatExposure) < 1e-10) { if (Math.abs(groundExposure) < 1e-10 || Math.abs(flatExposure) < 1e-10) {
invalidCount.zeroDiv++; invalidCount.zeroDiv++;
refrad.push(0); refrad.push(0);
@ -207,13 +262,12 @@ class getIrisDataDispose {
const groundRatio = gainExposure / groundExposure; const groundRatio = gainExposure / groundExposure;
const flatRatio = gainExposure / flatExposure; const flatRatio = gainExposure / flatExposure;
const groundDnDiff = element.ground_dn - element.dark_dn; const groundDnDiff = element.ground_dn - (this.useDarkDn ? element.dark_dn : 0);
const flatDnDiff = element.flat_dn - element.dark_dn; const flatDnDiff = element.flat_dn - (this.useDarkDn ? element.dark_dn : 0);
const a = groundRatio * (element.gain * groundDnDiff); const a = groundRatio * (element.gain * groundDnDiff);
const b = flatRatio * (element.gain * flatDnDiff); const b = flatRatio * (element.gain * flatDnDiff);
// 检查分母b是否为零 - 改为补充0值
if (Math.abs(b) < 1e-10) { if (Math.abs(b) < 1e-10) {
invalidCount.zeroDiv++; invalidCount.zeroDiv++;
refrad.push(0); refrad.push(0);
@ -227,23 +281,24 @@ class getIrisDataDispose {
} }
} }
} }
// 记录统计信息
if (invalidCount.zeroDiv > 0 || invalidCount.invalidResult > 0) { if (invalidCount.zeroDiv > 0 || invalidCount.invalidResult > 0) {
console.warn(`refrad计算统计: 除零错误 ${invalidCount.zeroDiv} 个,无效结果 ${invalidCount.invalidResult} 个,有效数据 ${refrad.length}`); console.warn(`refrad计算统计: 除零错误 ${invalidCount.zeroDiv} 个,无效结果 ${invalidCount.invalidResult} 个,有效数据 ${refrad.length}`);
} }
return validateResult(refrad, name + "_refrad", "refrad");
return validateResult(refrad, name + "_refrad", 'refrad');
} else if (this.spectralName == "flat_ref") { } else if (this.spectralName == "flat_ref") {
const deps = ["ground_dn", "flat_dn"].concat(this.useDarkDn ? ["dark_dn"] : []);
if (!requireDeps(deps)) return undefined; // 依赖不够,直接返回空
const arrAll = buildArrAll(deps);
const name = baseName("ground_dn", "flat_dn");
const validData = []; const validData = [];
const invalidCount = { zeroDiv: 0, invalidResult: 0 }; const invalidCount = { zeroDiv: 0, invalidResult: 0 };
for (const element of arrAll) { for (const element of arrAll) {
const denominator = element.flat_dn - element.dark_dn; const denominator = element.flat_dn - (this.useDarkDn ? element.dark_dn : 0);
const numerator = element.ground_dn - element.dark_dn; const numerator = element.ground_dn - (this.useDarkDn ? element.dark_dn : 0);
// 检查分母是否为零或接近零 - 改为补充0值
if (Math.abs(denominator) < 1e-10) { if (Math.abs(denominator) < 1e-10) {
invalidCount.zeroDiv++; invalidCount.zeroDiv++;
validData.push(0); validData.push(0);
@ -257,13 +312,10 @@ class getIrisDataDispose {
} }
} }
} }
// 记录统计信息
if (invalidCount.zeroDiv > 0 || invalidCount.invalidResult > 0) { if (invalidCount.zeroDiv > 0 || invalidCount.invalidResult > 0) {
console.warn(`flat_ref计算统计: 除零错误 ${invalidCount.zeroDiv} 个,无效结果 ${invalidCount.invalidResult} 个,有效数据 ${validData.length}`); console.warn(`flat_ref计算统计: 除零错误 ${invalidCount.zeroDiv} 个,无效结果 ${invalidCount.invalidResult} 个,有效数据 ${validData.length}`);
} }
return validateResult(validData, name + "_flat_ref", 'flat_ref'); return validateResult(validData, name + "_flat_ref", "flat_ref");
}
} }
} }
@ -399,22 +451,22 @@ const spectralTypeList = [
value: "radiance_flat", value: "radiance_flat",
label: "参考辐射亮度", label: "参考辐射亮度",
}, },
{ // {
value: "refrad", // value: "refrad",
label: "反射率能量", // label: "反射率能量",
}, // },
{ // {
value: "jdfs", // value: "jdfs",
label: "绝对反射率", // label: "绝对反射率",
}, // },
{ // {
value: "ckbzwj", // value: "ckbzwj",
label: "参考校准文件", // label: "参考校准文件",
}, // },
{ // {
value: "fszd", // value: "fszd",
label: "辐射照度", // label: "辐射照度",
}, // },
]; ];
const spectralProcessTypeList = [ const spectralProcessTypeList = [

View File

@ -33,7 +33,7 @@ export class SpectralDataService {
/** /**
* 处理光谱数据 * 处理光谱数据
*/ */
static processSpectralData(fileData, spectralType, processType = '') { static processSpectralData(fileData, spectralType, processType = '', useDarkDn = true) {
const spectralDataList = []; const spectralDataList = [];
const imageList = []; const imageList = [];
@ -41,12 +41,20 @@ export class SpectralDataService {
if (!element.data) continue; if (!element.data) continue;
try { try {
const dispose = new getIrisDataDispose(element.data, spectralType); // 传入暗噪开关
const dispose = new getIrisDataDispose(element.data, spectralType, useDarkDn);
const datay = dispose.initData(); const datay = dispose.initData();
const datax = dispose.getSpectralInfoData(); const datax = dispose.getSpectralInfoData();
const environmentData = dispose.environmentData; const environmentData = dispose.environmentData;
const img = dispose.parseImageData(element.data.image_info_section); const img = dispose.parseImageData(element.data.image_info_section);
if (img && img.length) {
imageList.push(img);
} else {
imageList.push([{
name: element.name,
url: 'jzsb'
}]);
}
if (datay?.normalArray && datax) { if (datay?.normalArray && datax) {
spectralDataList.push({ spectralDataList.push({
name: datay?.name || '', name: datay?.name || '',
@ -54,8 +62,8 @@ export class SpectralDataService {
datay: datay.normalArray, datay: datay.normalArray,
environmentData: { ...environmentData, fileName: element.name } environmentData: { ...environmentData, fileName: element.name }
}); });
imageList.push(img);
} }
} catch (error) { } catch (error) {
console.error(`处理光谱数据失败: ${element.name}`, error); console.error(`处理光谱数据失败: ${element.name}`, error);
} }
@ -70,6 +78,7 @@ export class SpectralDataService {
/** /**
* 应用数据处理D1/D2等 * 应用数据处理D1/D2等
* 注意:该方法需要在类内部,避免顶层出现 static 关键字导致语法错误
*/ */
static applyProcessing(spectralDataList, processType) { static applyProcessing(spectralDataList, processType) {
if (!processType) return spectralDataList; if (!processType) return spectralDataList;
@ -97,10 +106,11 @@ export class SpectralDataService {
/** /**
* 批量处理选定文件的光谱数据 * 批量处理选定文件的光谱数据
*/ */
static processSelectedFiles(fileData, selectedFileNames, spectralType, processType = '') { static processSelectedFiles(fileData, selectedFileNames, spectralType, processType = '', useDarkDn = true) {
const filteredData = fileData.filter(file => const filteredData = fileData.filter(file =>
selectedFileNames.includes(file.name) selectedFileNames.includes(file.name)
); );
return this.processSpectralData(filteredData, spectralType, processType); // 透传暗噪开关
return this.processSpectralData(filteredData, spectralType, processType, useDarkDn);
} }
} }