弹窗拖动+过鱼设施-过鱼总量-弹框添加

This commit is contained in:
王兴凯 2026-07-07 10:33:29 +08:00
parent 9473a87a1d
commit 5465ef72d6
61 changed files with 2406 additions and 1273 deletions

View File

@ -12,7 +12,7 @@ VITE_APP_BASE_API = '/dev-api'
# VITE_APP_BASE_URL = 'http://172.16.21.142:8093' # VITE_APP_BASE_URL = 'http://172.16.21.142:8093'
# VITE_APP_BASE_URL = 'http://172.16.21.142:8096' # VITE_APP_BASE_URL = 'http://172.16.21.142:8096'
# 汤伟 # 汤伟
VITE_APP_BASE_URL = 'http://10.84.121.127:8093' VITE_APP_BASE_URL = 'http://10.84.111.235:8093'
# 李林 # 李林
# VITE_APP_BASE_URL = 'http://10.84.121.43:8093' # VITE_APP_BASE_URL = 'http://10.84.121.43:8093'
# VITE_APP_BASE_URL = 'http://192.168.1.162:8093' # VITE_APP_BASE_URL = 'http://192.168.1.162:8093'

View File

@ -177,7 +177,84 @@
</a-select> </a-select>
</a-form-item-rest> </a-form-item-rest>
</div> </div>
<!-- 基地电站下拉框 -->
<div
class="flex gap-[10px]"
v-else-if="item.type === 'jidiData'"
>
<a-form-item-rest>
<!-- 基地下拉框 -->
<a-select
:value="formData[item.name]"
placeholder="请选择"
@change="val => dataDimensionDataChange(val, item.name)"
show-search
allow-clear
:loading="shuJuTianBaoStore.baseLoading"
:filter-option="filterOption"
style="width: 135px"
>
<a-select-option
v-for="opt in shuJuTianBaoStore.baseOption"
:key="opt.baseid"
:value="opt.baseid"
:label="opt.basename"
>
{{ opt.basename }}
</a-select-option>
</a-select>
<!-- 电站下拉框 -->
<a-select
v-if="props.zhujianfujian == 'fu'"
:value="formData.rstcd"
placeholder="请选择电站"
@change="stcdIdChange"
show-search
allow-clear
:loading="shuJuTianBaoStore.engLoading"
:filter-option="filterOption"
style="width: 135px"
:dropdown-style="{
maxHeight: '400px',
overflow: 'auto',
minWidth: '300px'
}"
>
<a-select-option
v-for="opt in shuJuTianBaoStore.engOption"
:key="opt.stcd"
:value="opt.stcd"
:label="opt.ennm"
:title="opt.ennm + ',' + opt.reachcdName"
:reachcdName="opt.reachcdName"
>
{{ opt.ennm }},{{ opt.reachcdName }}
</a-select-option>
</a-select>
<!-- 电站下拉框 -->
<a-select
v-if="props.zhujianfujian == 'zhu'"
:value="formData.stcd"
placeholder="请选择电站"
@change="stcdIdChange"
show-search
allow-clear
:loading="shuJuTianBaoStore.engLoading"
:filter-option="filterOption"
style="width: 135px"
>
<a-select-option
v-for="opt in shuJuTianBaoStore.engOption"
:key="opt.stcd"
:value="opt.stcd"
:label="opt.ennm"
>
{{ opt.ennm }}
</a-select-option>
</a-select>
</a-form-item-rest>
</div>
<!-- 下拉选择 --> <!-- 下拉选择 -->
<!-- <div v-else-if="item.type === 'Select'"> <!-- <div v-else-if="item.type === 'Select'">
<div v-for="i in item.options"> {{ i[item.values?.name] }} {{ i[item.values?.value] }}</div> <div v-for="i in item.options"> {{ i[item.values?.name] }} {{ i[item.values?.value] }}</div>
@ -362,9 +439,13 @@ const initForm = () => {
validSearchList.value.forEach(item => { validSearchList.value.forEach(item => {
if (item.type == 'waterStation') { if (item.type == 'waterStation') {
// //
// shuJuTianBaoStore.getBaseOption(); shuJuTianBaoStore.getBaseOption();
shuJuTianBaoStore.getSelectForOption(); shuJuTianBaoStore.getSelectForOption();
shuJuTianBaoStore.getEngOption(formData.rvcd); shuJuTianBaoStore.getEngOption(formData.rvcd,'rvcd');
}
if (item.type == 'jidiData') {
shuJuTianBaoStore.getBaseOption();
shuJuTianBaoStore.getEngOption(formData[item.name] || 'all','baseId');
} }
if (item.fieldProps?.required) { if (item.fieldProps?.required) {
rules[item.name] = [ rules[item.name] = [
@ -387,19 +468,19 @@ const triggerManualValuesChange = (changedKey: string, newValue: any) => {
emit('valuesChange', changedValues, { ...formData }); emit('valuesChange', changedValues, { ...formData });
}; };
// const dataDimensionDataChange = (value: any) => { const dataDimensionDataChange = (value: any, fieldName: string = 'baseId') => {
// formData.baseId = value; formData[fieldName] = value;
// formData.rstcd = ""; formData.rstcd = "";
// shuJuTianBaoStore.getEngOption(formData.baseId); shuJuTianBaoStore.getEngOption(value,'baseId');
triggerManualValuesChange('baseId', formData.baseId);
// // valuesChange a-form-item-rest //
// triggerManualValuesChange("baseId", formData.baseId); // emit('valuesChange', { [fieldName]: value, rstcd: "" }, { ...formData });
// }; };
const lyChange = (value: any) => { const lyChange = (value: any) => {
formData.rvcd = value; formData.rvcd = value;
formData.rstcd = ''; formData.rstcd = '';
shuJuTianBaoStore.getEngOption(formData.rvcd); shuJuTianBaoStore.getEngOption(formData.rvcd,'rvcd');
// valuesChange a-form-item-rest // valuesChange a-form-item-rest
triggerManualValuesChange('rvcd', formData.rvcd); triggerManualValuesChange('rvcd', formData.rvcd);
@ -408,12 +489,12 @@ const lyChange = (value: any) => {
const stcdIdChange = (value: any) => { const stcdIdChange = (value: any) => {
if (props.zhujianfujian == 'fu') { if (props.zhujianfujian == 'fu') {
formData.rstcd = value; formData.rstcd = value;
shuJuTianBaoStore.getFpssOption(formData.rvcd, value); shuJuTianBaoStore.getFpssOption(formData.baseId, value);
// valuesChange // valuesChange
triggerManualValuesChange('rstcd', formData.rstcd); triggerManualValuesChange('rstcd', formData.rstcd);
} else { } else {
formData.stcd = value; formData.stcd = value;
shuJuTianBaoStore.getFpssOption(formData.rvcd, value); shuJuTianBaoStore.getFpssOption(formData.baseId, value);
// valuesChange // valuesChange
triggerManualValuesChange('stcd', formData.stcd); triggerManualValuesChange('stcd', formData.stcd);
} }

View File

@ -0,0 +1,282 @@
<template>
<div class="approval-search">
<BasicSearch
ref="basicSearchRef"
:searchList="searchList"
:initial-values="initSearchData"
:zhujianfujian="'fu'"
@reset="handleResetWrapper"
@finish="onSearchFinish"
@values-change="onValuesChange"
><template #jcdt>
<a-date-picker
class="w-[120px]"
v-model:value="jcdt.min"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="起始时间"
:showToday="false"
>
<template #renderExtraFooter>
<div class="flex items-center flex-wrap px-2">
<span
v-for="item in DateSetting.RangeButton.days1"
:key="item"
@click="handleRangeClick(item)"
>
<a class="text-[#1890ff] mr-1"> {{ item.label }}</a>
</span>
</div>
</template>
</a-date-picker>
<a-form-item-rest>
<a-date-picker
class="w-[120px]"
v-model:value="jcdt.max"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD HH:mm:ss"
:disabledDate="disabledEndDate"
placeholder="结束时间"
:showToday="false"
>
<template #renderExtraFooter>
<div class="flex items-center flex-wrap px-2">
<span
v-for="item in DateSetting.RangeButton.days1"
:key="item"
@click="handleRangeClick(item)"
>
<a class="text-[#1890ff] mr-1"> {{ item.label }}</a>
</span>
</div>
</template>
</a-date-picker>
</a-form-item-rest>
</template>
<template #actions>
<a-button :loading="exportLoading" @click="exportBtn">导出</a-button>
</template>
</BasicSearch>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, onMounted } from 'vue';
import dayjs from 'dayjs';
import BasicSearch from '@/components/BasicSearch/index.vue';
import { DateSetting } from '@/utils/enumeration';
import { useTimeScale } from '@/store/composables/useTimeScale';
import { getFishReleaseMonitorSectionList } from '@/api/DataQueryMenuModule';
const emit = defineEmits<{
(e: 'export-btn'): void;
(e: 'reset', values: any): void;
(e: 'search-finish', values: any): void;
}>();
const basicSearchRef = ref<any>();
const btnLoading = ref<boolean>(false);
const props = defineProps<{
exportLoading?: boolean;
modalData: any;
}>();
const initSearchData = {
baseId: props.modalData.baseid ?? 'all',
rstcd: null,
stcd: '',
mway: '1'
};
const searchData = ref<any>({ ...initSearchData });
const {
jcdt,
currentTimeScale,
handleRangeClick,
disabledEndDate,
handleSearchFinish,
handleValuesChange,
init,
setDefaultTimeRange
} = useTimeScale({
defaultTimeScale: initSearchData.timeScale,
onSearchFinish: values => emit('search-finish', values),
onReset: () => emit('reset', initSearchData)
});
const crossSectionListLoading = ref<any>(false);
const crossSectionList = ref<any>([]);
const searchList: any = computed(() => [
// {
// type: 'waterStation',
// name: 'rvcd',
// label: '',
// placeholder: '',
// fieldProps: {
// allowClear: true
// },
// options: []
// },
{
type: 'jidiData',
name: 'baseId',
label: '水电基地',
placeholder: '请输入水电基地名称',
fieldProps: {
allowClear: true
},
options: []
},
{
type: 'Select',
name: 'stcd',
label: '过鱼设施名称',
width: 200,
placeholder: '请选择过鱼设施名称',
fieldProps: {
allowClear: true
},
loading: crossSectionListLoading.value,
options: crossSectionList.value.map(item => ({
label: item.stnm,
value: item.stcd
}))
},
{
type: 'Radio',
name: 'mway',
label: '数据类型',
width: 140,
options: [
{
label: '人工',
value: '1'
},
{
label: '自动',
value: '2'
}
]
},
{
type: 'custom',
name: 'jcdt',
label: '时间',
fieldProps: {
allowClear: false
}
}
]);
const onSearchFinish = (values: any) => {
handleSearchFinish(values);
};
const exportBtn = () => {
emit('export-btn');
};
const initCrossSectionList = params => {
const filters = [];
if (params) {
if (params.baseId != '' && params.baseId != 'all') {
filters.push({
field: 'baseId',
operator: 'contains',
dataType: 'string',
value: params.baseId
});
}
if (params.rstcd != '' && params.rstcd != null) {
filters.push({
field: 'rstcd',
operator: 'contains',
dataType: 'string',
value: params.rstcd
});
}
}
crossSectionListLoading.value = true;
getFishReleaseMonitorSectionList({
filter: {
logic: 'and',
filters: filters
},
select: ['stcd', 'stnm', 'wtDeviceType', 'dtinType', 'mway']
}).then(res => {
if (res.data?.data) {
crossSectionList.value = res.data?.data;
}
crossSectionListLoading.value = false;
});
};
const onValuesChange = (changedValues: any, allValues: any) => {
//
if ('baseId' in changedValues || 'rstcd' in changedValues) {
allValues.stcd = null;
if (basicSearchRef.value?.formData) {
basicSearchRef.value.formData.stcd = null;
}
initCrossSectionList(allValues);
}
handleValuesChange(changedValues, allValues);
searchData.value = { ...searchData.value, ...allValues };
};
const handleResetWrapper = () => {
//
currentTimeScale.value = initSearchData.timeScale;
const now = dayjs();
if (props.modalData.year) {
jcdt.value = {
min: `${props.modalData.year}-01-01 00:00:00`,
max: `${props.modalData.year}-12-31 23:59:59`
};
} else {
jcdt.value = {
min: `${now
.subtract(5, 'year')
.startOf('year')
.format('YYYY-MM-DD')} 00:00:00`,
max: `${now.endOf('year').format('YYYY-MM-DD')} 23:59:59`
};
}
setDefaultTimeRange(initSearchData.timeScale);
// 使 initSearchData
handleSearchFinish({
...initSearchData
});
};
defineExpose({
btnLoading,
searchData
});
onMounted(() => {
init();
//
const now = dayjs();
if (props.modalData.year) {
jcdt.value = {
min: `${props.modalData.year}-01-01 00:00:00`,
max: `${props.modalData.year}-12-31 23:59:59`
};
} else {
jcdt.value = {
min: `${now.subtract(5, 'year').format('YYYY-MM-DD')} 00:00:00`,
max: `${now.format('YYYY-MM-DD')} 23:59:59`
};
}
initCrossSectionList();
// 使 handleSearchFinish jcdt
handleSearchFinish({ ...initSearchData });
});
</script>
<style lang="scss"></style>

View File

@ -0,0 +1,554 @@
<template>
<div class="w-full h-full flex flex-col" style="height:calc(60vh)">
<!-- 搜索组件 -->
<FishDataSearch
@export-btn="exportBtn"
@search-finish="onSearchFinish"
@reset="onReset"
:exportLoading="exportLoading"
:modalData = "props.modalData"
ref="searchRef"
/>
<!-- 表格组件 -->
<BasicTable
ref="tableRef"
:scrollX="tableScrollX"
:scrollY="tableScrollY"
:columns="tableColumns"
:list-url="getFishReleaseMonitorList"
:searchParams="{
sort: sort
}"
>
</BasicTable>
<!-- 图片预览弹框 -->
<a-modal
v-model:open="imagePreviewVisible"
title="图片预览"
:footer="null"
width="800px"
>
<div style="text-align: center">
<img :src="previewImageUrl" style="width: 100%; height: 600px" />
</div>
</a-modal>
<!-- 视频预览弹框 -->
<a-modal
v-model:open="videoPreviewVisible"
title="视频预览"
:footer="null"
width="800px"
>
<div style="text-align: center">
<video
:src="previewVideoUrl"
controls
style="width: 100%; height: 600px"
></video>
</div>
</a-modal>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted, nextTick, h } from 'vue';
import dayjs from 'dayjs';
import { Button } from 'ant-design-vue';
import FishDataSearch from './FishResourceSearch.vue';
import BasicTable from '@/components/BasicTable/index.vue';
import { getFishReleaseMonitorList } from '@/api/DataQueryMenuModule';
import { calcTableScrollY } from '@/utils/index';
import { useDraggable } from '@/utils/drag';
const props = defineProps<{
modalData?: any;
}>();
const sort = ref<any>([
{
field: 'baseStepSort',
dir: 'asc'
},
{
field: 'rvcdStepSort',
dir: 'asc'
},
{
field: 'rstcdStepSort',
dir: 'asc'
},
{
field: 'ttpwr',
dir: 'asc'
},
{
field: 'tm',
dir: 'desc'
}
]);
const tableRef = ref();
const searchRef = ref();
const tableScrollY = ref<string | number>(0);
const currentSearchParams = ref<any>({});
const exportLoading = ref(false);
//
const imagePreviewVisible = ref(false);
const previewImageUrl = ref('');
//
const videoPreviewVisible = ref(false);
const previewVideoUrl = ref('');
useDraggable(imagePreviewVisible, { boundary: true, resetOnOpen: true });
useDraggable(videoPreviewVisible, { boundary: true, resetOnOpen: true });
const openImagePreview = (url: string) => {
previewImageUrl.value = import.meta.env.VITE_APP_ATTACHMENT_URL + '/?' + url;
imagePreviewVisible.value = true;
};
const openVideoPreview = (url: string) => {
previewVideoUrl.value = import.meta.env.VITE_APP_ATTACHMENT_URL + '/?' + url;
videoPreviewVisible.value = true;
};
const tableScrollX = computed(() =>
Math.max(
tableColumns.value.reduce(
(sum: number, col: any) => sum + (col.width || 180),
0
),
600
)
);
//
const columnsManual: any[] = [
{
key: 'stnm',
title: '电站名称',
dataIndex: 'stnm',
visible: true,
width: 200,
sort: true,
merge: true
},
{
key: 'baseName',
title: '所属基地',
dataIndex: 'baseName',
sort: true,
width: 120
},
{
key: 'stnm',
title: '过鱼设施名称',
dataIndex: 'stnm',
sort: true,
width: 200
},
{
key: 'strdt',
title: '开始时间',
dataIndex: 'strdt',
sort: true,
width: 100,
customRender: ({ text }) => dayjs(text).format('YYYY-MM-DD') || '-'
},
{
key: 'enddt',
title: '结束时间',
dataIndex: 'enddt',
sort: true,
width: 100,
customRender: ({ text }) => dayjs(text).format('YYYY-MM-DD') || '-'
},
{
key: 'tm',
title: '填报时间',
dataIndex: 'tm',
sort: true,
width: 160
},
{
key: 'ftp',
title: '鱼种类',
dataIndex: 'ftp',
sort: true,
width: 120
},
{
key: 'fcnt',
title: '过鱼数量(尾)',
dataIndex: 'fcnt',
sort: true,
width: 120
},
{
key: 'directionName',
title: '鱼游向',
dataIndex: 'directionName',
sort: true,
width: 120
},
{
key: 'fsz',
title: '鱼类规格',
dataIndex: 'fsz',
sort: true,
width: 160
},
{
key: 'firstimgurl',
title: '图片',
dataIndex: 'firstimgurl',
align: 'center',
width: 110,
customRender: ({ text }: any) => {
const hasValidUrl =
text &&
text !== '-' &&
text.trim() !== '' &&
text !== 'null' &&
text !== 'undefined';
return h(
Button,
{
type: 'link',
disabled: !hasValidUrl,
style: {
color: !hasValidUrl ? '#ccc' : '#1890ff',
cursor: !hasValidUrl ? 'not-allowed' : 'pointer'
},
onClick: () => {
if (hasValidUrl) {
openImagePreview(text);
}
}
},
() => '查看图片'
);
}
},
{
key: 'videourl',
title: '视频',
dataIndex: 'videourl',
align: 'center',
width: 110,
customRender: ({ text }: any) => {
const hasValidUrl =
text &&
text !== '-' &&
text.trim() !== '' &&
text !== 'null' &&
text !== 'undefined';
return h(
Button,
{
type: 'link',
disabled: !hasValidUrl,
style: {
color: !hasValidUrl ? '#ccc' : '#1890ff',
cursor: !hasValidUrl ? 'not-allowed' : 'pointer'
},
onClick: () => {
if (hasValidUrl) {
openVideoPreview(text);
}
}
},
() => '查看视频'
);
}
}
];
//
const columnsAuto: any[] = [
{
key: 'stnm',
title: '电站名称',
dataIndex: 'stnm',
visible: true,
width: 200,
sort: true,
merge: true
},
{
key: 'baseName',
title: '所属基地',
dataIndex: 'baseName',
sort: true,
width: 120
},
{
key: 'stnm',
title: '过鱼设施名称',
dataIndex: 'stnm',
sort: true,
width: 200
},
{
key: 'tm',
title: '时间',
dataIndex: 'tm',
sort: true,
width: 160
},
{
key: 'ftp',
title: '鱼种类',
dataIndex: 'ftp',
sort: true,
width: 120
},
{
key: 'length',
title: '鱼长度(cm)',
dataIndex: 'length',
sort: true,
width: 120
},
{
key: 'width',
title: '鱼宽度(cm)',
dataIndex: 'width',
sort: true,
width: 120,
customRender: ({ text }: any) => {
const num = parseFloat(text);
return isNaN(num) ? '-' : num.toFixed(2);
}
},
{
key: 'fishspeed',
title: '鱼速度(m/s)',
dataIndex: 'fishspeed',
sort: true,
width: 80,
customRender: ({ text }: any) => {
const num = parseFloat(text);
return isNaN(num) ? '-' : num.toFixed(2);
}
},
{
key: 'directionName',
title: '鱼游向',
dataIndex: 'directionName',
sort: true,
width: 160
},
{
key: 'temperature',
title: '水温(℃)',
dataIndex: 'temperature',
sort: true,
width: 160,
customRender: ({ text }: any) => {
const num = parseFloat(text);
return isNaN(num) ? '-' : num.toFixed(1);
}
},
{
key: 'speed',
title: '流速(m/s)',
dataIndex: 'speed',
sort: true,
width: 160,
customRender: ({ text }: any) => {
const num = parseFloat(text);
return isNaN(num) ? '-' : num.toFixed(2);
}
},
{
key: 'fcnt',
title: '过鱼数量(尾)',
dataIndex: 'fcnt',
sort: true,
width: 120
},
{
key: 'channelno',
title: '过鱼通道',
dataIndex: 'channelno',
sort: true,
width: 140
},
{
key: 'firstimgurl',
title: '轮廓图',
dataIndex: 'firstimgurl',
align: 'center',
width: 110,
customRender: ({ text }: any) => {
const hasValidUrl =
text &&
text !== '-' &&
text.trim() !== '' &&
text !== 'null' &&
text !== 'undefined';
return h(
Button,
{
type: 'link',
disabled: !hasValidUrl,
style: {
color: !hasValidUrl ? '#ccc' : '#1890ff',
cursor: !hasValidUrl ? 'not-allowed' : 'pointer'
},
onClick: () => {
if (hasValidUrl) {
openImagePreview(text);
}
}
},
() => '查看图片'
);
}
},
{
key: 'videourl',
title: '短视频',
dataIndex: 'videourl',
align: 'center',
width: 110,
customRender: ({ text }: any) => {
const hasValidUrl =
text &&
text !== '-' &&
text.trim() !== '' &&
text !== 'null' &&
text !== 'undefined';
return h(
Button,
{
type: 'link',
disabled: !hasValidUrl,
style: {
color: !hasValidUrl ? '#ccc' : '#1890ff',
cursor: !hasValidUrl ? 'not-allowed' : 'pointer'
},
onClick: () => {
if (hasValidUrl) {
openVideoPreview(text);
}
}
},
() => '查看视频'
);
}
}
];
//
const tableColumns = computed(() => {
const mway = currentSearchParams.value.mway;
return mway === '2' ? columnsAuto : columnsManual;
});
const onSearchFinish = async (values: any) => {
currentSearchParams.value = values;
// prop getList
await nextTick();
initTable(values);
};
const onReset = async (values: any) => {
currentSearchParams.value = values;
await nextTick();
initTable(values);
};
const exportBtn = () => {
if (exportLoading.value) return;
exportLoading.value = true;
searchRef.value.btnLoading = true;
tableRef.value
.exportTable({
fileName: `过鱼监测数据_${dayjs().format('YYYY-MM-DD HH-mm-ss')}`
})
.finally(() => {
exportLoading.value = false;
searchRef.value.btnLoading = false;
});
};
const initTable = (values: any) => {
console.log(values);
const filters = [
values.baseId && values.baseId !== 'all'
? {
field: 'baseId',
operator: 'contains',
dataType: 'string',
value: values.baseId
}
: null,
values.rstcd
? {
field: 'rstcd',
operator: 'eq',
dataType: 'string',
value: values.rstcd
}
: null,
values.mway
? {
field: 'mway',
operator: 'eq',
dataType: 'string',
value: values.mway
}
: null
].filter(Boolean); //
if (values.stcd) {
filters.push({
logic: 'or',
filters: [
{
field: 'stcd',
operator: 'eq',
dataType: 'string',
value: values.stcd
},
{
field: 'stcode',
operator: 'eq',
dataType: 'string',
value: values.stcd
}
]
});
}
if (values.jcdt) {
filters.push(
{
field: 'tm',
operator: 'gte',
dataType: 'date',
value: dayjs(values.jcdt.min).format('YYYY-MM-DD HH:mm:ss')
},
{
field: 'tm',
operator: 'lte',
dataType: 'date',
value: dayjs(values.jcdt.max).format('YYYY-MM-DD HH:mm:ss')
}
);
}
const params = {
logic: 'and',
filters
};
tableRef.value.getList(params);
};
onMounted(() => {
nextTick(() => {
tableScrollY.value = calcTableScrollY();
});
});
</script>
<style scoped lang="scss"></style>

View File

@ -245,6 +245,7 @@ import { useModelStore } from '@/store/modules/model';
import videoCover from '@/assets/images/videFm.jpg'; import videoCover from '@/assets/images/videFm.jpg';
import MediaViewer from './MediaViewer.vue'; import MediaViewer from './MediaViewer.vue';
import AttachmentPreview from './AttachmentPreview.vue'; import AttachmentPreview from './AttachmentPreview.vue';
import { useDraggable } from '@/utils/drag';
const modelStore = useModelStore(); const modelStore = useModelStore();
@ -875,7 +876,8 @@ const notRunningMediaViewerRef = ref();
// //
const attachmentModalVisible = ref(false); const attachmentModalVisible = ref(false);
const currentAttachmentFid = ref(''); const currentAttachmentFid = ref('');
useDraggable(detailModalVisible, { boundary: true, resetOnOpen: true });
useDraggable(attachmentModalVisible, { boundary: true, resetOnOpen: true });
// //
const handleViewAttachment = (record: any) => { const handleViewAttachment = (record: any) => {
if (!record.fid) { if (!record.fid) {

View File

@ -152,7 +152,7 @@ import { getStcdDetail } from '@/api/mapModal';
const baseUrl = import.meta.env.VITE_APP_ATTACHMENT_URL; const baseUrl = import.meta.env.VITE_APP_ATTACHMENT_URL;
const modelStore = useModelStore(); const modelStore = useModelStore();
const hasLoaded = ref(false); // const hasLoaded = ref(false); //
import { useDraggable } from '@/utils/drag';
const props = defineProps({ const props = defineProps({
url: { url: {
type: String, type: String,
@ -168,6 +168,7 @@ const isLogo = ref(false);
const loading = ref(false); const loading = ref(false);
const data2: any = ref({}); const data2: any = ref({});
const tabledata = ref([]); const tabledata = ref([]);
useDraggable(visible, { boundary: true, resetOnOpen: true });
const columnsConfig = ref([ const columnsConfig = ref([
{ {
type: 'ENG', type: 'ENG',

View File

@ -56,6 +56,7 @@ import { getMonitorDataFpq, getMonitorDataOnline } from '@/api/mapModal';
import { useModelStore } from '@/store/modules/model'; import { useModelStore } from '@/store/modules/model';
import { DateSetting } from '@/utils/enumeration'; import { DateSetting } from '@/utils/enumeration';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { useDraggable } from '@/utils/drag';
const loading = ref(false); const loading = ref(false);
const modelStore = useModelStore(); const modelStore = useModelStore();
@ -72,7 +73,8 @@ const previewImageUrl = ref('');
// //
const videoPreviewVisible = ref(false); const videoPreviewVisible = ref(false);
const previewVideoUrl = ref(''); const previewVideoUrl = ref('');
useDraggable(imagePreviewVisible, { boundary: true, resetOnOpen: true });
useDraggable(videoPreviewVisible, { boundary: true, resetOnOpen: true });
const openImagePreview = (url: string) => { const openImagePreview = (url: string) => {
previewImageUrl.value = import.meta.env.VITE_APP_ATTACHMENT_URL + '/?' + url; previewImageUrl.value = import.meta.env.VITE_APP_ATTACHMENT_URL + '/?' + url;
imagePreviewVisible.value = true; imagePreviewVisible.value = true;

View File

@ -102,6 +102,7 @@ import { getDictItemsByCode } from '@/api/dict';
import { getFishDictoryDropdown } from '@/api/select'; import { getFishDictoryDropdown } from '@/api/select';
import { useModelStore } from '@/store/modules/model'; import { useModelStore } from '@/store/modules/model';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { useDraggable } from '@/utils/drag';
const loading = ref(false); const loading = ref(false);
const modelStore = useModelStore(); const modelStore = useModelStore();
@ -125,7 +126,8 @@ const previewImageUrl = ref('');
// //
const videoPreviewVisible = ref(false); const videoPreviewVisible = ref(false);
const currentVideoUrl = ref(''); const currentVideoUrl = ref('');
useDraggable(imagePreviewVisible, { boundary: true, resetOnOpen: true });
useDraggable(videoPreviewVisible, { boundary: true, resetOnOpen: true });
// //
const filterFtpOption = (input: string, option: any) => { const filterFtpOption = (input: string, option: any) => {
console.log('filterOption', input, option); console.log('filterOption', input, option);

View File

@ -79,6 +79,7 @@ import { queryPostUrlList } from '@/api/mapModal';
import { useModelStore } from '@/store/modules/model'; import { useModelStore } from '@/store/modules/model';
import BasicTable from '@/components/BasicTable/index.vue'; import BasicTable from '@/components/BasicTable/index.vue';
import { DateSetting } from '@/utils/enumeration'; import { DateSetting } from '@/utils/enumeration';
import { useDraggable } from '@/utils/drag';
const modelStore = useModelStore(); const modelStore = useModelStore();
@ -102,7 +103,7 @@ let chartInstance: echarts.ECharts | null = null;
const videoModalVisible = ref(false); const videoModalVisible = ref(false);
const videoModalTitle = ref(''); const videoModalTitle = ref('');
const currentVideoUrl = ref(''); const currentVideoUrl = ref('');
useDraggable(videoModalVisible, { boundary: true, resetOnOpen: true });
const tabsList = [{ name: '流量监测', key: 'flowMeasure' }]; const tabsList = [{ name: '流量监测', key: 'flowMeasure' }];
const activeTabKey = ref('flowMeasure'); const activeTabKey = ref('flowMeasure');

View File

@ -110,6 +110,7 @@ import {
type OperationFilterField, type OperationFilterField,
type OperationTableItem type OperationTableItem
} from './operationConfig'; } from './operationConfig';
import { useDraggable } from '@/utils/drag';
const props = defineProps({ const props = defineProps({
isActive: { type: Boolean, default: false } isActive: { type: Boolean, default: false }
@ -141,6 +142,7 @@ const loadYear = ref(false);
const loadFtp = ref(false); const loadFtp = ref(false);
const tableRef = ref(); const tableRef = ref();
const attachmentModalVisible = ref(false); const attachmentModalVisible = ref(false);
useDraggable(attachmentModalVisible, { boundary: true, resetOnOpen: true });
const currentAttachmentFid = ref(''); const currentAttachmentFid = ref('');
const fieldOptionsMap = reactive<Record<string, OperationFilterOption[]>>({}); const fieldOptionsMap = reactive<Record<string, OperationFilterOption[]>>({});
const selectLoadingMap = reactive<Record<string, boolean>>({}); const selectLoadingMap = reactive<Record<string, boolean>>({});

View File

@ -28,7 +28,7 @@ import * as echarts from 'echarts';
import { getVmsstbprptKendoList } from '@/api/home'; import { getVmsstbprptKendoList } from '@/api/home';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import ShuiDianKaiFQKTwoLayer from '@/modules/shuidianhuangjingjieruMod/TwoLayer/ShuiDianKaiFQKTwoLayer.vue'; import ShuiDianKaiFQKTwoLayer from '@/modules/shuidianhuangjingjieruMod/TwoLayer/ShuiDianKaiFQKTwoLayer.vue';
import { useDraggable } from '@/utils/drag';
defineOptions({ defineOptions({
name: 'developStatusChart' name: 'developStatusChart'
}); });
@ -41,7 +41,7 @@ const dataLoading = ref(false);
const modalVisible = ref(false); const modalVisible = ref(false);
const modalProps = ref<any>({}); const modalProps = ref<any>({});
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
function openModal(props: any) { function openModal(props: any) {
modalProps.value = props; modalProps.value = props;
modalVisible.value = true; modalVisible.value = true;

View File

@ -60,7 +60,7 @@ import { ref, watch } from 'vue';
import { getVmsstbprptKendoList } from '@/api/home'; import { getVmsstbprptKendoList } from '@/api/home';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import HuanJingSJJRQK from '@/modules/shuidianhuangjingjieruMod/TwoLayer/HuanJingSJJRQK.vue'; import HuanJingSJJRQK from '@/modules/shuidianhuangjingjieruMod/TwoLayer/HuanJingSJJRQK.vue';
import { useDraggable } from '@/utils/drag';
defineOptions({ defineOptions({
name: 'EngEnvironmentData' name: 'EngEnvironmentData'
}); });
@ -72,7 +72,7 @@ const data = ref<Record<string, number>>({ one: 0, two: 0, three: 0 });
const modalVisible = ref(false); const modalVisible = ref(false);
const modalProps = ref<any>({}); const modalProps = ref<any>({});
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
function openModal(props: any) { function openModal(props: any) {
modalProps.value = props; modalProps.value = props;
modalVisible.value = true; modalVisible.value = true;

View File

@ -63,6 +63,7 @@ import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { vpcGetKendoListCust } from '@/api/zxdzw'; import { vpcGetKendoListCust } from '@/api/zxdzw';
import ArtsDetail from '@/components/carouselIntroduce/ArtsDetail.vue'; import ArtsDetail from '@/components/carouselIntroduce/ArtsDetail.vue';
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
@ -83,7 +84,7 @@ const baseid = ref('');
// //
const modalVisible = ref(false); const modalVisible = ref(false);
const currentItem = ref<any>(null); const currentItem = ref<any>(null);
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// //
const loading = ref(false); const loading = ref(false);

View File

@ -109,6 +109,7 @@ import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'
import BasicTable from '@/components/BasicTable/index.vue' import BasicTable from '@/components/BasicTable/index.vue'
import { wqGetKendoList } from '@/api/sz' import { wqGetKendoList } from '@/api/sz'
import HJMZDTwoLays from "./HJMZDTwoLays.vue" import HJMZDTwoLays from "./HJMZDTwoLays.vue"
import { useDraggable } from '@/utils/drag';
// dayjs // dayjs
dayjs.extend(isSameOrAfter) dayjs.extend(isSameOrAfter)
@ -155,7 +156,7 @@ const detailModalVisible = ref(false)
const detailData = ref<any>({}) const detailData = ref<any>({})
const mapModalVisible = ref(false) const mapModalVisible = ref(false)
const mapModalData = ref<any>({}) const mapModalData = ref<any>({})
useDraggable(detailModalVisible, { boundary: true, resetOnOpen: true });
// //
const sortConfig = computed(() => [ const sortConfig = computed(() => [
{ field: 'rstcdStepSort', dir: 'asc' }, { field: 'rstcdStepSort', dir: 'asc' },

View File

@ -36,6 +36,8 @@ import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { wqGetKendoListCust } from '@/api/sz' import { wqGetKendoListCust } from '@/api/sz'
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent"; import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
import EnvironmentalQualityTwoLayers from "./TwoLayers/EnvironmentalQualityTwoLayers.vue" import EnvironmentalQualityTwoLayers from "./TwoLayers/EnvironmentalQualityTwoLayers.vue"
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
name: 'EnvironmentalQuality' name: 'EnvironmentalQuality'
@ -774,7 +776,7 @@ onUnmounted(() => {
// //
const modalVisible = ref(false); const modalVisible = ref(false);
const clickedBarData = ref<{ name: string; current: number | null; lastYear: number | null; selectedId?: string } | null>(null); const clickedBarData = ref<{ name: string; current: number | null; lastYear: number | null; selectedId?: string } | null>(null);
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
</script> </script>

View File

@ -1,6 +1,10 @@
<!-- SidePanelItem.vue --> <!-- SidePanelItem.vue -->
<template> <template>
<SidePanelItem :title="title" :datetimePicker="datetimePicker" @update-values="handlePanelChange1"> <SidePanelItem
:title="title"
:datetimePicker="datetimePicker"
@update-values="handlePanelChange1"
>
<!-- 加载状态 --> <!-- 加载状态 -->
<div v-if="loading" class="loading-container"> <div v-if="loading" class="loading-container">
<a-spin tip="加载中..." /> <a-spin tip="加载中..." />
@ -12,12 +16,24 @@
</div> </div>
<!-- 正常显示图表 --> <!-- 正常显示图表 -->
<div v-else class="container" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave"> <div
v-else
class="container"
@mouseenter="handleMouseEnter"
@mouseleave="handleMouseLeave"
>
<!-- 跑马灯轨道容器 --> <!-- 跑马灯轨道容器 -->
<div class="carousel-track" :class="{ 'no-transition': isTransitioning }" <div
:style="{ transform: `translateX(-${currentIndex * 100}%)` }"> class="carousel-track"
:class="{ 'no-transition': isTransitioning }"
:style="{ transform: `translateX(-${currentIndex * 100}%)` }"
>
<!-- 遍历所有图表项包含克隆项 --> <!-- 遍历所有图表项包含克隆项 -->
<div v-for="(item, index) in renderChartData" :key="index" class="carousel-item"> <div
v-for="(item, index) in renderChartData"
:key="index"
class="carousel-item"
>
<div class="pie-chart-container"> <div class="pie-chart-container">
<!-- 图表区域 --> <!-- 图表区域 -->
<div :ref="el => setChartRef(el, index)" class="chart"></div> <div :ref="el => setChartRef(el, index)" class="chart"></div>
@ -31,45 +47,12 @@
<!-- 详情弹框 --> <!-- 详情弹框 -->
<a-modal <a-modal
v-model:open="modalVisible" v-model:open="modalVisible"
:title="modalTitle" :title="'过鱼监测数据'"
width="1650px" width="1650px"
:footer="null" :footer="null"
@cancel="handleModalClose" @cancel="handleModalClose"
> >
<div class="modal-content"> <FishResource v-if="modalVisible" :modalData = "modalData" />
<a-descriptions bordered :column="2" size="small">
<a-descriptions-item label="年份">
{{ modalData.year }}
</a-descriptions-item>
<a-descriptions-item label="流域/设施">
{{ modalData.basinName }}
</a-descriptions-item>
<a-descriptions-item label="鱼类总数">
<span style="color: #1890ff; font-weight: bold;">
{{ modalData.totalCount }} {{ getUnit() }}
</span>
</a-descriptions-item>
<a-descriptions-item label="">
{{ modalData.baseid }}
</a-descriptions-item>
</a-descriptions>
<a-divider orientation="left">鱼类分布详情</a-divider>
<a-table
:columns="fishColumns"
:data-source="modalData.fishList"
:pagination="false"
size="small"
:scroll="{ y: 300 }"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'percentage'">
{{ record.percentage }}%
</template>
</template>
</a-table>
</div>
</a-modal> </a-modal>
</SidePanelItem> </SidePanelItem>
</template> </template>
@ -80,8 +63,10 @@ import * as echarts from 'echarts';
import type { ECharts } from 'echarts'; import type { ECharts } from 'echarts';
import SidePanelItem from '@/components/SidePanelItem/index.vue'; import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { yearGetYearFpStatistics } from '@/api/gyss'; import { yearGetYearFpStatistics } from '@/api/gyss';
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent"; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import type { ColumnsType } from 'ant-design-vue/es/table/Table'; import type { ColumnsType } from 'ant-design-vue/es/table/Table';
import { useDraggable } from '@/utils/drag';
import FishResource from '@/components/FishResource/index.vue';
// API // API
interface FpFtpStatisticsVo { interface FpFtpStatisticsVo {
@ -108,10 +93,11 @@ const JidiSelectEventStore = useJidiSelectEventStore();
const baseid = ref(''); const baseid = ref('');
const props = defineProps({ const props = defineProps({
title: { // title: {
//
type: String, type: String,
default: '过鱼总量' default: '过鱼总量'
}, }
}); });
const datetimePicker = ref({ const datetimePicker = ref({
@ -134,7 +120,7 @@ const currentYear = ref<string>(''); // 当前选中的年份
interface ChartDataItem { interface ChartDataItem {
title: string; title: string;
baseid?: string; // ID baseid?: string; // ID
data: Array<{ name: string; value: number; baseId?: string }>; // ID data: Array<{ name: string; value: number; baseId?: string; ftp?: string }>;
} }
// //
@ -151,13 +137,16 @@ let timer: any = null;
// //
const modalVisible = ref(false); const modalVisible = ref(false);
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
const modalTitle = ref(''); const modalTitle = ref('');
const modalData = ref<{ const modalData = ref<{
year: string; year: string;
basinName: string; basinName: string;
baseid?: string; // ID baseid?: string;
totalCount: number; totalCount: number;
fishTypes: number; fishTypes: number;
fishName?: string;
ftp?: string;
fishList: Array<{ fishList: Array<{
name: string; name: string;
value: number; value: number;
@ -169,6 +158,8 @@ const modalData = ref<{
baseid: '', baseid: '',
totalCount: 0, totalCount: 0,
fishTypes: 0, fishTypes: 0,
fishName: '',
ftp: '',
fishList: [] fishList: []
}); });
@ -351,12 +342,12 @@ const updateChart = (index: number) => {
textStyle: { textStyle: {
fontSize: 24, fontSize: 24,
fontWeight: 'bold', fontWeight: 'bold',
color: '#333', color: '#333'
}, },
subtextStyle: { subtextStyle: {
fontSize: 12, fontSize: 12,
color: '#999', color: '#999',
align: 'center', align: 'center'
} }
} }
], ],
@ -377,7 +368,8 @@ const updateChart = (index: number) => {
const found = chartData.data.find(item => item.name === name); const found = chartData.data.find(item => item.name === name);
const value = found ? found.value : '-'; const value = found ? found.value : '-';
const maxLength = 7; const maxLength = 7;
const truncatedName = name.length > maxLength ? name.substring(0, maxLength) + '...' : name; const truncatedName =
name.length > maxLength ? name.substring(0, maxLength) + '...' : name;
return `${truncatedName} ${value}${unit}`; return `${truncatedName} ${value}${unit}`;
}, },
textStyle: { textStyle: {
@ -538,13 +530,17 @@ onUnmounted(() => {
/** /**
* 构建单一流域的图表数据 * 构建单一流域的图表数据
*/ */
const buildSingleBasinChartData = (basin: BasinData, year: string): ChartDataItem => { const buildSingleBasinChartData = (
basin: BasinData,
year: string
): ChartDataItem => {
return { return {
title: `${basin.baseName}`, title: `${basin.baseName}`,
baseid: basin.baseId, // ID baseid: basin.baseId, // ID
data: basin.fpFtpStatitcsVos.map((fish: FpFtpStatisticsVo) => ({ data: basin.fpFtpStatitcsVos.map((fish: FpFtpStatisticsVo) => ({
name: fish.fishName, name: fish.fishName,
value: fish.fcnt value: fish.fcnt,
ftp: fish.ftp
})) }))
}; };
}; };
@ -552,12 +548,17 @@ const buildSingleBasinChartData = (basin: BasinData, year: string): ChartDataIte
/** /**
* 构建全部流域的图表数据包含流域对比图和各流域鱼类分布图 * 构建全部流域的图表数据包含流域对比图和各流域鱼类分布图
*/ */
const buildAllBasinsChartData = (apiData: BasinData[], year: string): ChartDataItem[] => { const buildAllBasinsChartData = (
apiData: BasinData[],
year: string
): ChartDataItem[] => {
const charts: ChartDataItem[] = []; const charts: ChartDataItem[] = [];
// 1 使 fpCount // 1 使 fpCount
const basinComparisonData = apiData const basinComparisonData = apiData
.filter(basin => basin.fpFtpStatitcsVos && basin.fpFtpStatitcsVos.length > 0) .filter(
basin => basin.fpFtpStatitcsVos && basin.fpFtpStatitcsVos.length > 0
)
.map(basin => ({ .map(basin => ({
name: basin.baseName, name: basin.baseName,
value: basin.fpCount, value: basin.fpCount,
@ -613,7 +614,8 @@ const rebuildCharts = async () => {
*/ */
const controlCarousel = () => { const controlCarousel = () => {
// //
const shouldStop = baseid.value !== 'all' || originalChartData.value.length <= 1; const shouldStop =
baseid.value !== 'all' || originalChartData.value.length <= 1;
if (shouldStop) { if (shouldStop) {
stopAutoPlay(); // currentIndex stopAutoPlay(); // currentIndex
@ -636,12 +638,21 @@ const updateChartByBaseid = () => {
if (baseid.value === 'all') { if (baseid.value === 'all') {
// === === // === ===
originalChartData.value = buildAllBasinsChartData(cachedApiData.value, currentYear.value); originalChartData.value = buildAllBasinsChartData(
cachedApiData.value,
currentYear.value
);
} else { } else {
// === === // === ===
const targetBasin = cachedApiData.value.find(item => item.baseId === baseid.value); const targetBasin = cachedApiData.value.find(
item => item.baseId === baseid.value
);
if (!targetBasin || !targetBasin.fpFtpStatitcsVos || targetBasin.fpFtpStatitcsVos.length === 0) { if (
!targetBasin ||
!targetBasin.fpFtpStatitcsVos ||
targetBasin.fpFtpStatitcsVos.length === 0
) {
hasData.value = false; hasData.value = false;
originalChartData.value = []; originalChartData.value = [];
renderChartData.value = []; // renderChartData.value = []; //
@ -649,7 +660,9 @@ const updateChartByBaseid = () => {
return; return;
} }
originalChartData.value = [buildSingleBasinChartData(targetBasin, currentYear.value)]; originalChartData.value = [
buildSingleBasinChartData(targetBasin, currentYear.value)
];
} }
// //
@ -720,7 +733,6 @@ const getechartsdata = async (yearOne: string) => {
currentYear.value = yearOne; currentYear.value = yearOne;
// baseid // baseid
updateChartByBaseid(); updateChartByBaseid();
} catch (error) { } catch (error) {
console.error('获取过鱼统计数据失败:', error); console.error('获取过鱼统计数据失败:', error);
hasData.value = false; hasData.value = false;
@ -755,40 +767,43 @@ const handlePanelChange1 = (data: any) => {
* @param params ECharts 点击事件参数可选 * @param params ECharts 点击事件参数可选
*/ */
const handleChartClick = (item: ChartDataItem, index: number, params?: any) => { const handleChartClick = (item: ChartDataItem, index: number, params?: any) => {
//
const totalCount = getTotalAmount(item.data); const totalCount = getTotalAmount(item.data);
const fishList = item.data.map(fish => ({ const fishList = item.data.map(fish => ({
name: fish.name, name: fish.name,
value: fish.value, value: fish.value,
percentage: totalCount > 0 ? ((fish.value / totalCount) * 100).toFixed(2) : '0.00' percentage:
totalCount > 0 ? ((fish.value / totalCount) * 100).toFixed(2) : '0.00'
})); }));
// ID
let clickedBaseId: string | undefined; let clickedBaseId: string | undefined;
let fishName = '';
let ftp = '';
if (params && params.data && params.data.baseId) { if (params && params.data && params.data.baseId) {
// 1
clickedBaseId = params.data.baseId; clickedBaseId = params.data.baseId;
} else if (item.baseid && item.baseid !== 'all') { } else if (item.baseid && item.baseid !== 'all') {
// 2使 baseid
clickedBaseId = item.baseid; clickedBaseId = item.baseid;
} else { } else {
// 3 baseId
clickedBaseId = item.baseid; clickedBaseId = item.baseid;
} }
// if (item.baseid !== 'all' && params && params.data) {
fishName = params.data.name || '';
ftp = params.data.ftp || '';
}
modalTitle.value = `${item.title} - 详情`; modalTitle.value = `${item.title} - 详情`;
modalData.value = { modalData.value = {
year: currentYear.value || '-', year: currentYear.value || '-',
basinName: params?.name || item.title, // 使 basinName: params?.name || item.title,
baseid: clickedBaseId, // ID baseid: clickedBaseId,
totalCount: totalCount, totalCount: totalCount,
fishTypes: item.data.length, fishTypes: item.data.length,
fishName,
ftp,
fishList: fishList fishList: fishList
}; };
//
modalVisible.value = true; modalVisible.value = true;
}; };
@ -801,7 +816,7 @@ const handleModalClose = () => {
watch( watch(
() => JidiSelectEventStore.selectedItem, () => JidiSelectEventStore.selectedItem,
(newVal) => { newVal => {
if (newVal && newVal.wbsCode) { if (newVal && newVal.wbsCode) {
baseid.value = newVal.wbsCode; baseid.value = newVal.wbsCode;
@ -813,7 +828,6 @@ watch(
}, },
{ deep: true, immediate: true } { deep: true, immediate: true }
); );
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -32,6 +32,7 @@ import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { vpcGetKendoListCust } from '@/api/zxdzw'; import { vpcGetKendoListCust } from '@/api/zxdzw';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import ZhiWuYuanDetailTable from './ZhiWuYuanDetailTable.vue'; import ZhiWuYuanDetailTable from './ZhiWuYuanDetailTable.vue';
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
@ -50,7 +51,7 @@ const loading = ref(false);
// //
const modalVisible = ref(false); const modalVisible = ref(false);
const modalJidi = ref('all'); const modalJidi = ref('all');
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// //
const jidiOptions = ref<any[]>([]); const jidiOptions = ref<any[]>([]);

View File

@ -54,6 +54,7 @@ import Yanchengyulei from './TwoLayers/Yanchengyulei.vue';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { wbsbGetKendoList, getDftYear, fishChanges2 } from '@/api/stdc'; import { wbsbGetKendoList, getDftYear, fishChanges2 } from '@/api/stdc';
import moment from 'moment'; import moment from 'moment';
import { useDraggable } from '@/utils/drag';
defineOptions({ defineOptions({
name: 'alongFishMod' name: 'alongFishMod'
@ -108,7 +109,7 @@ const modalHbrvcd = ref('');
const modalStateName = ref(''); const modalStateName = ref('');
const modalSectionName = ref(''); const modalSectionName = ref('');
const modalStcd = ref(''); const modalStcd = ref('');
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// ==================== ==================== // ==================== ====================
/** /**

View File

@ -53,6 +53,8 @@ import { getVmsstbprpt, inOutOneGetKendoListCust } from '@/api/sw';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import churukushuiwen from './churukushuiwen.vue'; import churukushuiwen from './churukushuiwen.vue';
import { MapClass } from '@/components/gis/map.class'; import { MapClass } from '@/components/gis/map.class';
import { useDraggable } from '@/utils/drag';
// ==================== ==================== // ==================== ====================
// (便) // (便)
defineOptions({ defineOptions({
@ -96,7 +98,7 @@ const modalVisible = ref(false); // 弹框显示状态
const clickDataInfo = ref<any>(null); // const clickDataInfo = ref<any>(null); //
const stationName = ref(''); // const stationName = ref(''); //
// ==================== ==================== // ==================== ====================
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
/** /**
* 转换图表数据格式 * 转换图表数据格式
* 将后端返回的扁平数据结构转换为ECharts所需的双线数据格式 * 将后端返回的扁平数据结构转换为ECharts所需的双线数据格式

View File

@ -53,7 +53,7 @@
</SidePanelItem> </SidePanelItem>
<!-- 设施详情弹框 --> <!-- 设施详情弹框 -->
<a-modal v-model:open="modalVisible" :title="'设施详情'" width="1536px" :footer="null"> <a-modal v-model:open="modalVisibleone" :title="'设施详情'" width="1536px" :footer="null">
<div v-if="currentItem" class="detail-container"> <div v-if="currentItem" class="detail-container">
<ArtsDetail :dataSource="currentItem" :index="getCurrentRealIndex()" /> <ArtsDetail :dataSource="currentItem" :index="getCurrentRealIndex()" />
</div> </div>
@ -66,6 +66,7 @@ import SidePanelItem from '@/components/SidePanelItem/index.vue';
import ArtsDetail from '@/components/carouselIntroduce/ArtsDetail.vue'; import ArtsDetail from '@/components/carouselIntroduce/ArtsDetail.vue';
import { getMsstbprptKendoList } from '@/api/home'; import { getMsstbprptKendoList } from '@/api/home';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
@ -84,9 +85,9 @@ interface MediaItem {
} }
// //
const modalVisible = ref(false); const modalVisibleone = ref(false);
const currentItem = ref<any>(null); const currentItem = ref<any>(null);
useDraggable(modalVisibleone, { boundary: true, resetOnOpen: true });
// //
const loading = ref(false); const loading = ref(false);
@ -217,7 +218,7 @@ const handleItemClick = () => {
description: item.description || '', description: item.description || '',
title: item.title || '' title: item.title || ''
})); }));
modalVisible.value = true; modalVisibleone.value = true;
}; };
// //

View File

@ -36,6 +36,8 @@ import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { dwInfoGetKendoListCust } from "@/api/sw"; import { dwInfoGetKendoListCust } from "@/api/sw";
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent"; import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
import DiwenshuijianhuansheshileixingzuchengjijieruqingkuangTwoLayers from "./TwoLayers/diwenshuijianhuansheshileixingzuchengjijieruqingkuangTwoLayers.vue" import DiwenshuijianhuansheshileixingzuchengjijieruqingkuangTwoLayers from "./TwoLayers/diwenshuijianhuansheshileixingzuchengjijieruqingkuangTwoLayers.vue"
import { useDraggable } from '@/utils/drag';
const JidiSelectEventStore = useJidiSelectEventStore(); const JidiSelectEventStore = useJidiSelectEventStore();
// 便 // 便
defineOptions({ defineOptions({
@ -73,7 +75,7 @@ const baseid = ref('')
const modalVisible = ref(false); const modalVisible = ref(false);
const selectedItem: any = ref<DataString | null>(null); const selectedItem: any = ref<DataString | null>(null);
const twoLayersRef = ref(); const twoLayersRef = ref();
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
const getListData = async () => { const getListData = async () => {
loading.value = true; loading.value = true;

View File

@ -68,6 +68,8 @@ import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { fishDicGetKendoList, wbsbGetKendoList } from '@/api/yldc'; import { fishDicGetKendoList, wbsbGetKendoList } from '@/api/yldc';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import ArtsDetail from '@/components/carouselIntroduce/ArtsDetail.vue'; import ArtsDetail from '@/components/carouselIntroduce/ArtsDetail.vue';
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
name: 'zengZhiZhanJieShaoMod' name: 'zengZhiZhanJieShaoMod'
@ -87,7 +89,7 @@ let rvcd = ref('');
// //
const modalVisible = ref(false); const modalVisible = ref(false);
const currentItem = ref<any>(null); const currentItem = ref<any>(null);
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// //
const loading = ref(false); const loading = ref(false);

View File

@ -62,6 +62,8 @@ import { ref, onMounted, onUnmounted, computed } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue'; import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { msstbprptGetKendoList } from '@/api/yldc'; import { msstbprptGetKendoList } from '@/api/yldc';
import ArtsDetail from '@/components/carouselIntroduce/ArtsDetail.vue'; import ArtsDetail from '@/components/carouselIntroduce/ArtsDetail.vue';
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
name: 'zengZhiZhanJieShaoMod' name: 'zengZhiZhanJieShaoMod'
@ -79,7 +81,7 @@ const baseUrl = import.meta.env.VITE_APP_ATTACHMENT_URL;
// //
const modalVisible = ref(false); const modalVisible = ref(false);
const currentItem = ref<any>(null); const currentItem = ref<any>(null);
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// //
const loading = ref(false); const loading = ref(false);

View File

@ -36,6 +36,8 @@ import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { vmsstbprptGetKendoList } from '@/api/gyss' import { vmsstbprptGetKendoList } from '@/api/gyss'
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent"; import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
import FPVDDetailMD from './components/FPVDDetailMD.vue' import FPVDDetailMD from './components/FPVDDetailMD.vue'
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
name: 'guoyusheshijiansheqingkuang' name: 'guoyusheshijiansheqingkuang'
@ -81,6 +83,7 @@ const loading = ref(false);
const modalVisible = ref(false); const modalVisible = ref(false);
const selectedFacility = ref<any>(null); const selectedFacility = ref<any>(null);
const title = ref(''); const title = ref('');
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// //
const handleCardClick = (facility: any) => { const handleCardClick = (facility: any) => {
selectedFacility.value = facility; selectedFacility.value = facility;

View File

@ -3,25 +3,49 @@
<SidePanelItem title="过鱼设施"> <SidePanelItem title="过鱼设施">
<a-spin :spinning="loading" tip="加载中..."> <a-spin :spinning="loading" tip="加载中...">
<div class="facility-grid"> <div class="facility-grid">
<div v-for="facility in facilities" :key="facility.name" class="facility-card" <div
@click="handleFacilityClick(facility)"> v-for="facility in facilities"
<div style="width: 60px;height: 62px;display: flex;align-items: center;justify-content: center;"> :key="facility.name"
class="facility-card"
@click="handleFacilityClick(facility)"
>
<div
style="
width: 60px;
height: 62px;
display: flex;
align-items: center;
justify-content: center;
"
>
<div class="facility-icon"> <div class="facility-icon">
<i style="color: #fff;" :class="facility.icon" type="icon-shengtailiuliang2"></i> <i
style="color: #fff"
:class="facility.icon"
type="icon-shengtailiuliang2"
></i>
</div> </div>
</div> </div>
<div class="facility-info"> <div class="facility-info">
<div class="facility-name">{{ facility.name }}</div> <div class="facility-name">{{ facility.name }}</div>
<div style="font-size: 16px;"> <span class="facility-count">{{ facility.count <div style="font-size: 16px">
}}</span><span></span></div> <span class="facility-count">{{ facility.count }}</span
><span></span>
</div>
</div> </div>
</div> </div>
</div> </div>
</a-spin> </a-spin>
</SidePanelItem> </SidePanelItem>
<!-- 弹框 --> <!-- 弹框 -->
<a-modal v-model:open="modalVisible" :title="'过鱼设施'" :footer="null" width="1536px" @cancel="handleCloseModal"> <a-modal
v-model:open="modalVisible"
:title="'过鱼设施'"
:footer="null"
width="1536px"
@cancel="handleCloseModal"
>
<ModalPage v-if="currentFacility" :data="currentFacility" :jdId="'all'" /> <ModalPage v-if="currentFacility" :data="currentFacility" :jdId="'all'" />
</a-modal> </a-modal>
</template> </template>
@ -29,9 +53,11 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue'; import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue'; import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent"; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { buildGetKendoListCust } from '@/api/gyss'; import { buildGetKendoListCust } from '@/api/gyss';
import ModalPage from './ModalPage/index.vue' import ModalPage from './ModalPage/index.vue';
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
name: 'qixidibaohugongzuokaizhanQK' name: 'qixidibaohugongzuokaizhanQK'
@ -64,23 +90,23 @@ const facilities = ref([
count: 0, count: 0,
icon: 'icon iconfont icon-map-gyssQita', icon: 'icon iconfont icon-map-gyssQita',
key: 'FP_5' key: 'FP_5'
}, }
]); ]);
const baseid = ref('') const baseid = ref('');
// //
const modalVisible = ref(false); const modalVisible = ref(false);
const currentFacility = ref<any>(null); const currentFacility = ref<any>(null);
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// //
const getData = async () => { const getData = async () => {
loading.value = true; loading.value = true;
try { try {
let params = { let params = {
"filter": { filter: {
"logic": "and", logic: 'and',
"filters": [] filters: []
}
} }
};
const res = await buildGetKendoListCust(params); //-VD const res = await buildGetKendoListCust(params); //-VD
let data = res?.data?.data || res?.data || []; let data = res?.data?.data || res?.data || [];
@ -91,15 +117,21 @@ const getData = async () => {
// //
data.forEach(item => { data.forEach(item => {
const matchedFacility = facilities.value.find(facility => facility.key === item.sttpCode); const matchedFacility = facilities.value.find(
facility => facility.key === item.sttpCode
);
if (matchedFacility) { if (matchedFacility) {
// facilitieskey // facilitieskey
matchedFacility.count += Number(item.built) + Number(item.building) || 0; matchedFacility.count +=
Number(item.built) + Number(item.building) || 0;
} else { } else {
// keyFP_5 // keyFP_5
const otherFacility = facilities.value.find(facility => facility.key === 'FP_5'); const otherFacility = facilities.value.find(
facility => facility.key === 'FP_5'
);
if (otherFacility) { if (otherFacility) {
otherFacility.count += Number(item.built) + Number(item.building) || 0; otherFacility.count +=
Number(item.built) + Number(item.building) || 0;
} }
} }
}); });
@ -108,13 +140,11 @@ const getData = async () => {
} finally { } finally {
loading.value = false; loading.value = false;
} }
} };
// //
const handleFacilityClick = (facility: any) => { const handleFacilityClick = (facility: any) => {
currentFacility.value = facility; currentFacility.value = facility;
modalVisible.value = true; modalVisible.value = true;
}; };
// //
const handleCloseModal = () => { const handleCloseModal = () => {
@ -124,22 +154,19 @@ const handleCloseModal = () => {
watch( watch(
() => JidiSelectEventStore.selectedItem, () => JidiSelectEventStore.selectedItem,
(newVal) => { newVal => {
baseid.value = newVal.wbsCode; baseid.value = newVal.wbsCode;
getData() getData();
}, },
{ deep: true, immediate: true } { deep: true, immediate: true }
); );
// //
onMounted(() => { onMounted(() => {
// //
}); });
// //
onUnmounted(() => { onUnmounted(() => {});
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -148,7 +175,9 @@ onUnmounted(() => {
flex-flow: wrap; flex-flow: wrap;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji,
Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
} }
.facility-card { .facility-card {

View File

@ -3,13 +3,25 @@
<SidePanelItem title="过鱼设施介绍"> <SidePanelItem title="过鱼设施介绍">
<!-- Loading 和空状态容器 --> <!-- Loading 和空状态容器 -->
<a-spin :spinning="loading" class="carousel-container-wrapper"> <a-spin :spinning="loading" class="carousel-container-wrapper">
<div v-if="hasData" class="container" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave"> <div
v-if="hasData"
class="container"
@mouseenter="handleMouseEnter"
@mouseleave="handleMouseLeave"
>
<!-- 跑马灯轨道容器 --> <!-- 跑马灯轨道容器 -->
<div class="carousel-track" :class="{ 'no-transition': isTransitioning }" <div
:style="{ transform: `translateX(-${currentIndex * 100}%)` }"> class="carousel-track"
:class="{ 'no-transition': isTransitioning }"
:style="{ transform: `translateX(-${currentIndex * 100}%)` }"
>
<!-- 遍历所有媒体项包含克隆项 --> <!-- 遍历所有媒体项包含克隆项 -->
<div v-for="(item, index) in renderMediaData" :key="index" class="carousel-item" <div
@click="handleItemClick(originalMediaData)"> v-for="(item, index) in renderMediaData"
:key="index"
class="carousel-item"
@click="handleItemClick(originalMediaData)"
>
<!-- 图片 --> <!-- 图片 -->
<img :src="item.url" :alt="item.stnm" loading="lazy" /> <img :src="item.url" :alt="item.stnm" loading="lazy" />
<!-- 说明文字随媒体项移动 --> <!-- 说明文字随媒体项移动 -->
@ -19,36 +31,50 @@
<!-- 面板指示器固定在底部右侧 --> <!-- 面板指示器固定在底部右侧 -->
<div class="pagination-dots-fixed"> <div class="pagination-dots-fixed">
<span v-for="(dot, index) in originalMediaData" :key="index" class="dot" <span
:class="{ active: currentRealIndex === index }" @click="goToSlide(index)"></span> v-for="(dot, index) in originalMediaData"
:key="index"
class="dot"
:class="{ active: currentRealIndex === index }"
@click="goToSlide(index)"
></span>
</div> </div>
</div> </div>
<!-- 暂无数据状态 --> <!-- 暂无数据状态 -->
<!-- 独立的文字说明区域随跑马灯切换而变化 --> <!-- 独立的文字说明区域随跑马灯切换而变化 -->
<div v-if="hasData" class="description-text" @click="handleItemClick(originalMediaData)"> <div
v-if="hasData"
class="description-text"
@click="handleItemClick(originalMediaData)"
>
{{ currentDescription }} {{ currentDescription }}
</div> </div>
<a-empty v-else description="暂无数据" :image="simpleImage" /> <a-empty v-else description="暂无数据" :image="simpleImage" />
</a-spin> </a-spin>
</SidePanelItem> </SidePanelItem>
<!-- 设施详情弹框 --> <!-- 设施详情弹框 -->
<a-modal v-model:open="modalVisible" :title="'设施类型介绍'" width="1536px" :footer="null"> <a-modal
v-model:open="modalVisible"
:title="'设施类型介绍'"
width="1536px"
:footer="null"
>
<!-- 你在这里编写弹框内容 --> <!-- 你在这里编写弹框内容 -->
<div v-if="currentItem"> <div v-if="currentItem">
<ArtsDetail :dataSource='currentItem' :index="getCurrentRealIndex()" /> <ArtsDetail :dataSource="currentItem" :index="getCurrentRealIndex()" />
</div> </div>
</a-modal> </a-modal>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted, onUnmounted, computed, watch } from 'vue'; import { ref, onMounted, onUnmounted, computed, watch } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue'; import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent"; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { fpVmsstbprptGetKendoList } from '@/api/gyss'; import { fpVmsstbprptGetKendoList } from '@/api/gyss';
import ArtsDetail from '@/components/carouselIntroduce/ArtsDetail.vue'; import ArtsDetail from '@/components/carouselIntroduce/ArtsDetail.vue';
import { Empty } from 'ant-design-vue'; import { Empty } from 'ant-design-vue';
import { useDraggable } from '@/utils/drag';
// ==================== ==================== // ==================== ====================
interface MediaItem { interface MediaItem {
@ -79,6 +105,7 @@ const baseUrl = import.meta.env.VITE_APP_ATTACHMENT_URL;
// //
const modalVisible = ref(false); const modalVisible = ref(false);
const currentItem = ref<any>(null); const currentItem = ref<any>(null);
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// ==================== ==================== // ==================== ====================
// //
const loading = ref(false); const loading = ref(false);
@ -247,12 +274,14 @@ const getCarouselData = async () => {
operator: 'isnotnull', operator: 'isnotnull',
dataType: 'string' dataType: 'string'
}, },
baseid.value !== 'all' ? { baseid.value !== 'all'
? {
field: 'baseId', field: 'baseId',
operator: 'eq', operator: 'eq',
dataType: 'string', dataType: 'string',
value: baseid.value value: baseid.value
} : null }
: null
].filter(Boolean) ].filter(Boolean)
}, },
select: ['introduce', 'logo', 'stnm', 'precis'], select: ['introduce', 'logo', 'stnm', 'precis'],
@ -298,7 +327,7 @@ onUnmounted(() => {
// ==================== ==================== // ==================== ====================
watch( watch(
() => JidiSelectEventStore.selectedItem, () => JidiSelectEventStore.selectedItem,
(newVal) => { newVal => {
if (newVal?.wbsCode) { if (newVal?.wbsCode) {
baseid.value = newVal.wbsCode; baseid.value = newVal.wbsCode;
} else { } else {
@ -391,7 +420,7 @@ const handleItemClick = (item: any) => {
width: 5px; width: 5px;
height: 5px; height: 5px;
border-radius: 50%; border-radius: 50%;
background-color: #D8D8D8; background-color: #d8d8d8;
cursor: pointer; cursor: pointer;
transition: background-color 0.3s ease; transition: background-color 0.3s ease;

View File

@ -49,6 +49,7 @@ import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { environmentalProtectionConstruction } from '@/api/home'; import { environmentalProtectionConstruction } from '@/api/home';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import HuanbaoModTwoLayers from './TwoLayers/HuanbaoModTwoLayers.vue'; import HuanbaoModTwoLayers from './TwoLayers/HuanbaoModTwoLayers.vue';
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
@ -82,7 +83,7 @@ const modalRes = ref({
bldstt: '', bldstt: '',
hydrodtin: '1' hydrodtin: '1'
}); });
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// //
const getData = async () => { const getData = async () => {
if (!baseid.value) return; if (!baseid.value) return;

View File

@ -68,6 +68,7 @@ import svg_liuliangjiancezhan from '@/assets/svg/liuliangjiancezhan.svg';
import svg_shuizhijiancezhan from '@/assets/svg/shuizhijiancezhan.svg'; import svg_shuizhijiancezhan from '@/assets/svg/shuizhijiancezhan.svg';
import svg_zengzhizhanshuizhizhan from '@/assets/svg/zengzhizhanshuizhizhan.svg'; import svg_zengzhizhanshuizhizhan from '@/assets/svg/zengzhizhanshuizhizhan.svg';
import svg_qixidi from '@/assets/svg/qixidi.svg'; import svg_qixidi from '@/assets/svg/qixidi.svg';
import { useDraggable } from '@/utils/drag';
defineOptions({ defineOptions({
name: 'huanbaoMod' name: 'huanbaoMod'
@ -103,7 +104,7 @@ const baseid = ref('');
// //
const modalVisible = ref(false); const modalVisible = ref(false);
const currentFacility = ref<IFacility | null>(null); const currentFacility = ref<IFacility | null>(null);
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
const fetchData = () => { const fetchData = () => {
let params = { let params = {
filter: { filter: {

View File

@ -316,7 +316,8 @@ import { postIdUrl } from '@/api/mapModal';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import videoCover from '@/assets/images/videFm.jpg'; import videoCover from '@/assets/images/videFm.jpg';
import { useDraggable } from '@/utils/drag';
;
const baseUrl = import.meta.env.VITE_APP_ATTACHMENT_URL; const baseUrl = import.meta.env.VITE_APP_ATTACHMENT_URL;
// ==================== Props ==================== // ==================== Props ====================
@ -397,7 +398,7 @@ const calendarValue = ref(searchData.value.month);
const detailModalVisible = ref(false); const detailModalVisible = ref(false);
const detailActiveKey = ref('2'); const detailActiveKey = ref('2');
const detailDate = ref(''); const detailDate = ref('');
useDraggable(detailModalVisible, { boundary: true, resetOnOpen: true })
// / // /
const calendarStatusMap: Record< const calendarStatusMap: Record<
string, string,

View File

@ -51,6 +51,7 @@ import SidePanelItem from '@/components/SidePanelItem/index.vue';
import AISPTK from './AISPTK.vue'; import AISPTK from './AISPTK.vue';
import { getAiGyssList } from '@/api/zngj'; import { getAiGyssList } from '@/api/zngj';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
@ -65,7 +66,7 @@ const panelDetail = ref<any>({});
// ==================== ==================== // ==================== ====================
const modalVisible = ref(false); const modalVisible = ref(false);
const currentAction = ref('AI_5006'); const currentAction = ref('AI_5006');
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
const lyName = computed(() => baseid.value === '02' ? '升鱼斗运行' : '升鱼机运行'); const lyName = computed(() => baseid.value === '02' ? '升鱼斗运行' : '升鱼机运行');
// ==================== ==================== // ==================== ====================

View File

@ -40,6 +40,7 @@ import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import SidePanelItem from "@/components/SidePanelItem/index.vue"; import SidePanelItem from "@/components/SidePanelItem/index.vue";
import { getStllGaojingList } from '@/api/zngj'; import { getStllGaojingList } from '@/api/zngj';
import ModeGaoJing from './ModeGaoJing.vue'; import ModeGaoJing from './ModeGaoJing.vue';
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
@ -51,7 +52,7 @@ const baseid = ref('');
const dataLoading = ref(false); const dataLoading = ref(false);
const isModalOpen = ref(false); const isModalOpen = ref(false);
const currentWarnState = ref(''); const currentWarnState = ref('');
useDraggable(isModalOpen, { boundary: true, resetOnOpen: true });
const data = ref([ const data = ref([
{ {
name:'正常', name:'正常',

View File

@ -38,6 +38,7 @@ import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import SidePanelItem from "@/components/SidePanelItem/index.vue"; import SidePanelItem from "@/components/SidePanelItem/index.vue";
import { getShuizhiGaojingList } from '@/api/zngj'; import { getShuizhiGaojingList } from '@/api/zngj';
import ModeGaoJing from './ModeGaoJing.vue'; import ModeGaoJing from './ModeGaoJing.vue';
import { useDraggable } from '@/utils/drag';
defineOptions({ defineOptions({
name: "shuizhijianceshuju", name: "shuizhijianceshuju",
@ -51,7 +52,7 @@ const defaultValue = ref<string>('0');
// //
const modalVisible = ref(false); const modalVisible = ref(false);
const currentWarnState = ref(''); const currentWarnState = ref('');
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
const handleCardClick = (warnState: string) => { const handleCardClick = (warnState: string) => {
currentWarnState.value = warnState; currentWarnState.value = warnState;
modalVisible.value = true; modalVisible.value = true;

View File

@ -68,6 +68,7 @@ import SidePanelItem from '@/components/SidePanelItem/index.vue';
import LsstjkTk from './LsstjkTk.vue'; import LsstjkTk from './LsstjkTk.vue';
import { wbsbGetKendoList, getEvnmAutoMonitor } from '@/api/stdc'; import { wbsbGetKendoList, getEvnmAutoMonitor } from '@/api/stdc';
import moment from 'moment'; import moment from 'moment';
import { useDraggable } from '@/utils/drag';
// //
defineOptions({ defineOptions({
@ -81,7 +82,7 @@ const dataLoading = ref(false);
// ==================== ==================== // ==================== ====================
const modalVisible = ref(false); const modalVisible = ref(false);
const currentOrderIndex = ref('16'); const currentOrderIndex = ref('16');
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// ==================== ==================== // ==================== ====================
// //
const select = ref({ const select = ref({

View File

@ -70,6 +70,7 @@ import dayjs from 'dayjs';
import { ZoomInOutlined } from '@ant-design/icons-vue'; import { ZoomInOutlined } from '@ant-design/icons-vue';
import type { Dayjs } from 'dayjs'; import type { Dayjs } from 'dayjs';
import MonthlyAverage from '../monthlyAverage.vue'; import MonthlyAverage from '../monthlyAverage.vue';
import { useDraggable } from '@/utils/drag';
defineOptions({ defineOptions({
name: 'MonthlyAverageMaxModal' name: 'MonthlyAverageMaxModal'
@ -101,7 +102,7 @@ const detailModalData = ref<any>(null);
// - // -
const selectValue = ref(''); const selectValue = ref('');
const selectOptions = ref<any[]>([]); const selectOptions = ref<any[]>([]);
useDraggable(detailModalVisible, { boundary: true, resetOnOpen: true });
// //
const treeExpandedKeys = ref<string[]>([]) const treeExpandedKeys = ref<string[]>([])
const nodeMap = new Map<string, { node: any; parentKey: string | null }>() const nodeMap = new Map<string, { node: any; parentKey: string | null }>()

View File

@ -41,6 +41,7 @@ import dayjs from 'dayjs'
import { import {
ZoomInOutlined ZoomInOutlined
} from '@ant-design/icons-vue'; } from '@ant-design/icons-vue';
import { useDraggable } from '@/utils/drag';
defineOptions({ defineOptions({
name: 'monthlyAvgWaterTemCompareHistory' name: 'monthlyAvgWaterTemCompareHistory'
@ -68,7 +69,8 @@ const stationName = ref('');
// //
const zoomModalVisible = ref(false); const zoomModalVisible = ref(false);
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
useDraggable(zoomModalVisible, { boundary: true, resetOnOpen: true });
// //
const select = ref({ const select = ref({
show: true, show: true,

View File

@ -3,36 +3,66 @@
<SidePanelItem title="栖息地保护工作开展情况"> <SidePanelItem title="栖息地保护工作开展情况">
<a-spin :spinning="loading" tip="加载中..."> <a-spin :spinning="loading" tip="加载中...">
<div class="facility-grid"> <div class="facility-grid">
<div v-for="facility in facilities" :key="facility.name" class="facility-card" <div
@click="handleFacilityClick(facility)"> v-for="facility in facilities"
<div style="width: 60px;height: 62px;display: flex;align-items: center;justify-content: center;"> :key="facility.name"
class="facility-card"
@click="handleFacilityClick(facility)"
>
<div
style="
width: 60px;
height: 62px;
display: flex;
align-items: center;
justify-content: center;
"
>
<div class="facility-icon"> <div class="facility-icon">
<i style="color: #fff;" :class="facility.icon" type="icon-shengtailiuliang2"></i> <i
style="color: #fff"
:class="facility.icon"
type="icon-shengtailiuliang2"
></i>
</div> </div>
</div> </div>
<div class="facility-info"> <div class="facility-info">
<div class="facility-name">{{ facility.name }}</div> <div class="facility-name">{{ facility.name }}</div>
<div style="font-size: 16px;"> <span class="facility-count">{{ facility.count <div style="font-size: 16px">
}}</span><span></span></div> <span class="facility-count">{{ facility.count }}</span
><span></span>
</div>
</div> </div>
</div> </div>
</div> </div>
</a-spin> </a-spin>
</SidePanelItem> </SidePanelItem>
<!-- 弹框 --> <!-- 弹框 -->
<a-modal v-model:open="modalVisible" :title="'栖息地保护工作开展情况'" :footer="null" width="1536px" @cancel="handleCloseModal"> <a-modal
<QixidiheduanjianceqingkuangEJ v-if="currentFacility" :activeKey="currentFacility.sttpCode" :tabs="facilities" v-model:open="modalVisible"
:baseId="baseid" /> :title="'栖息地保护工作开展情况'"
:footer="null"
width="1536px"
@cancel="handleCloseModal"
>
<QixidiheduanjianceqingkuangEJ
v-if="currentFacility"
:activeKey="currentFacility.sttpCode"
:tabs="facilities"
:baseId="baseid"
/>
</a-modal> </a-modal>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue'; import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue'; import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent"; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { fhGetKendoListCust } from '@/api/qxd' import { fhGetKendoListCust } from '@/api/qxd';
import QixidiheduanjianceqingkuangEJ from "./qixidiheduanjianceqingkuangEJ/index.vue" import QixidiheduanjianceqingkuangEJ from './qixidiheduanjianceqingkuangEJ/index.vue';
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
name: 'qixidibaohugongzuokaizhanQK' name: 'qixidibaohugongzuokaizhanQK'
@ -65,43 +95,47 @@ const facilities = ref([
count: 0, count: 0,
icon: 'icon iconfont icon-shipinjiankongshebei', icon: 'icon iconfont icon-shipinjiankongshebei',
sttpCode: 'VD' sttpCode: 'VD'
}, }
]); ]);
const baseid = ref('') const baseid = ref('');
// //
const modalVisible = ref(false); const modalVisible = ref(false);
const currentFacility = ref<any>(null); const currentFacility = ref<any>(null);
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// //
const getData = async () => { const getData = async () => {
loading.value = true; loading.value = true;
try { try {
let params = { let params = {
"filter": { filter: {
"logic": "and", logic: 'and',
"filters": [ filters: [
baseid.value != 'all' ? { baseid.value != 'all'
"field": "baseId", ? {
"operator": "eq", field: 'baseId',
"dataType": "string", operator: 'eq',
"value": baseid.value dataType: 'string',
} : null value: baseid.value
}
: null
].filter(Boolean) ].filter(Boolean)
}, },
"group": [ group: [
{ {
"dir": "asc", dir: 'asc',
"field": "sttpCode" field: 'sttpCode'
} }
], ],
"groupResultFlat": true groupResultFlat: true
} };
const res = await fhGetKendoListCust(params); //-VD const res = await fhGetKendoListCust(params); //-VD
let data = res?.data?.data || res?.data || []; let data = res?.data?.data || res?.data || [];
// facilities count // facilities count
facilities.value.forEach(facility => { facilities.value.forEach(facility => {
const matchedItem = data.find(item => item.sttpCode === facility.sttpCode); const matchedItem = data.find(
item => item.sttpCode === facility.sttpCode
);
if (matchedItem) { if (matchedItem) {
facility.count = matchedItem.count_sttpCode || 0; facility.count = matchedItem.count_sttpCode || 0;
} else { } else {
@ -113,13 +147,11 @@ const getData = async () => {
} finally { } finally {
loading.value = false; loading.value = false;
} }
} };
// //
const handleFacilityClick = (facility: any) => { const handleFacilityClick = (facility: any) => {
currentFacility.value = facility; currentFacility.value = facility;
modalVisible.value = true; modalVisible.value = true;
}; };
// //
const handleCloseModal = () => { const handleCloseModal = () => {
@ -129,22 +161,19 @@ const handleCloseModal = () => {
watch( watch(
() => JidiSelectEventStore.selectedItem, () => JidiSelectEventStore.selectedItem,
(newVal) => { newVal => {
baseid.value = newVal.wbsCode; baseid.value = newVal.wbsCode;
getData() getData();
}, },
{ deep: true, immediate: true } { deep: true, immediate: true }
); );
// //
onMounted(() => { onMounted(() => {
// //
}); });
// //
onUnmounted(() => { onUnmounted(() => {});
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -153,7 +182,9 @@ onUnmounted(() => {
flex-flow: wrap; flex-flow: wrap;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji,
Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
} }
.facility-card { .facility-card {

View File

@ -57,6 +57,8 @@ import type { ECharts } from 'echarts';
import { msstbprptGetKendoList } from '@/api/stll'; import { msstbprptGetKendoList } from '@/api/stll';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import STLLXFFS from './TwoLayer/STLLXFFS.vue'; import STLLXFFS from './TwoLayer/STLLXFFS.vue';
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
name: 'xieFangFangShi' name: 'xieFangFangShi'
@ -78,7 +80,7 @@ const apiRawData = ref<any[]>([]); // 保存原始 API 数据
const modalVisible = ref(false); const modalVisible = ref(false);
const modalTitle = ref(''); const modalTitle = ref('');
const selectedData = ref<any>(null); const selectedData = ref<any>(null);
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// //
const colors = [ const colors = [
'#9556a4', // - '#9556a4', // -

View File

@ -38,6 +38,8 @@ import type { ECharts } from 'echarts';
import { vmsstbprptGetKendoList } from '@/api/stll'; import { vmsstbprptGetKendoList } from '@/api/stll';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import FBQKTwolayer from './TwoLayer/FenBuQingKuangTwoLayer.vue'; import FBQKTwolayer from './TwoLayer/FenBuQingKuangTwoLayer.vue';
import { useDraggable } from '@/utils/drag';
// //
defineOptions({ defineOptions({
name: 'XieFangFenBu' name: 'XieFangFenBu'
@ -59,7 +61,7 @@ const wbsCode = ref('');
const modalVisible = ref(false); const modalVisible = ref(false);
const selectData = ref(''); // const selectData = ref(''); //
const jidiName = ref(''); // const jidiName = ref(''); //
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// //
const typeName = [ const typeName = [
{ label: '生态放流孔', eqtp: 'EQ_1' }, { label: '生态放流孔', eqtp: 'EQ_1' },

View File

@ -105,6 +105,8 @@ import { useMapViewStore } from '@/modules/map/stores/map-view.store';
import STLLXFFS from './TwoLayer/ShengTaiLiuLiangDaBQKTwoLayer.vue'; import STLLXFFS from './TwoLayer/ShengTaiLiuLiangDaBQKTwoLayer.vue';
import ModalYkzhbzdjcgz from './TwoLayer/ModalYkzhbzdjcgz.vue'; import ModalYkzhbzdjcgz from './TwoLayer/ModalYkzhbzdjcgz.vue';
import HuanbaoZDJCGZKZ from '@/modules/huanbaozdjcgzkzQK/index.vue'; import HuanbaoZDJCGZKZ from '@/modules/huanbaozdjcgzkzQK/index.vue';
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
name: 'shengtaidabiaoMod' name: 'shengtaidabiaoMod'
@ -149,7 +151,8 @@ const modalVisible = ref(false);
const modalTitle = ref(''); const modalTitle = ref('');
const selectedItem = ref<any>(null); const selectedItem = ref<any>(null);
const huanbaoModalVisible = ref(false); const huanbaoModalVisible = ref(false);
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
useDraggable(huanbaoModalVisible, { boundary: true, resetOnOpen: true });
// //
const handleStationClick = () => { const handleStationClick = () => {
huanbaoModalVisible.value = true; huanbaoModalVisible.value = true;

View File

@ -67,6 +67,8 @@ import { eqqecRateCount, evnmAutoMonitorGetKendoListCust } from '@/api/stll';
import ModalYkzhbzdjcgz from '../shengtaidabiaoMod/TwoLayer/ModalYkzhbzdjcgz.vue'; import ModalYkzhbzdjcgz from '../shengtaidabiaoMod/TwoLayer/ModalYkzhbzdjcgz.vue';
import STLLXFFS from './TwoLayer/STLLXFFS.vue' import STLLXFFS from './TwoLayer/STLLXFFS.vue'
import { useMapViewStore } from '@/modules/map/stores/map-view.store'; import { useMapViewStore } from '@/modules/map/stores/map-view.store';
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
name: 'shengtaidabiaoMod' name: 'shengtaidabiaoMod'
@ -604,6 +606,8 @@ watch(
const detailModalVisible = ref(false); const detailModalVisible = ref(false);
const detailModalTitle = ref(''); const detailModalTitle = ref('');
const detailData = ref<any[]>([]); const detailData = ref<any[]>([]);
useDraggable(huanbaoModalVisible, { boundary: true, resetOnOpen: true });
useDraggable(detailModalVisible, { boundary: true, resetOnOpen: true });
const detailColumns = ref([ const detailColumns = ref([
{ {
title: mode.value === 'top' ? '基地名称' : '调节性能', title: mode.value === 'top' ? '基地名称' : '调节性能',

View File

@ -68,6 +68,8 @@ import { eqqecRateCount, evnmAutoMonitorGetKendoListCust } from '@/api/stll';
import ModalYkzhbzdjcgz from '../shengtaidabiaoMod/TwoLayer/ModalYkzhbzdjcgz.vue'; import ModalYkzhbzdjcgz from '../shengtaidabiaoMod/TwoLayer/ModalYkzhbzdjcgz.vue';
import STLLXFFS from './TwoLayer/STLLXFFS.vue' import STLLXFFS from './TwoLayer/STLLXFFS.vue'
import { useMapViewStore } from '@/modules/map/stores/map-view.store'; import { useMapViewStore } from '@/modules/map/stores/map-view.store';
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
name: 'shengtaidabiaoMod' name: 'shengtaidabiaoMod'
@ -97,6 +99,7 @@ const huanbaoModalVisible = ref(false);
const handleStationClick = () => { const handleStationClick = () => {
huanbaoModalVisible.value = true; huanbaoModalVisible.value = true;
}; };
// //
const loadData = async () => { const loadData = async () => {
spinning.value = true; spinning.value = true;
@ -633,6 +636,8 @@ const detailColumns = ref([
watch(mode, () => { watch(mode, () => {
loadData(); loadData();
}); });
useDraggable(huanbaoModalVisible, { boundary: true, resetOnOpen: true });
useDraggable(detailModalVisible, { boundary: true, resetOnOpen: true });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -62,6 +62,8 @@ import { ref, onMounted, onUnmounted, computed } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue'; import SidePanelItem from '@/components/SidePanelItem/index.vue';
import ArtsDetail from '@/components/carouselIntroduce/ArtsDetail.vue'; import ArtsDetail from '@/components/carouselIntroduce/ArtsDetail.vue';
import { sttpbGetKendoList } from '@/api/sw'; import { sttpbGetKendoList } from '@/api/sw';
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
name: 'diwenshuijianhuansheshileixingzuchengjijieruqingkuang' name: 'diwenshuijianhuansheshileixingzuchengjijieruqingkuang'
@ -96,6 +98,7 @@ const isTransitioning = ref(false);
// //
const modalVisible = ref(false); const modalVisible = ref(false);
const currentItem = ref<any>(null); const currentItem = ref<any>(null);
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// //
const initRenderData = () => { const initRenderData = () => {
const length = originalMediaData.value.length; const length = originalMediaData.value.length;

View File

@ -43,6 +43,7 @@ import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import YaerAverage from './TwoLayers/yaerAverage.vue'; import YaerAverage from './TwoLayers/yaerAverage.vue';
import { MapClass } from '@/components/gis/map.class'; import { MapClass } from '@/components/gis/map.class';
import { useDraggable } from '@/utils/drag';
const JidiSelectEventStore = useJidiSelectEventStore(); const JidiSelectEventStore = useJidiSelectEventStore();
// //
@ -52,7 +53,7 @@ const showemit = ref(true);
// //
const modalVisible = ref(false); const modalVisible = ref(false);
const currentData = ref<any>({}); const currentData = ref<any>({});
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
const chartRef = ref<HTMLElement | null>(null); const chartRef = ref<HTMLElement | null>(null);
let chartInstance: echarts.ECharts | null = null; let chartInstance: echarts.ECharts | null = null;
// //

View File

@ -27,6 +27,7 @@ import { ref, watch } from 'vue';
import { getVmsstbprptKendoList } from '@/api/home'; import { getVmsstbprptKendoList } from '@/api/home';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import ShuiDianKaiFQKTwoLayer from './TwoLayer/ShuiDianKaiFQKTwoLayer.vue'; import ShuiDianKaiFQKTwoLayer from './TwoLayer/ShuiDianKaiFQKTwoLayer.vue';
import { useDraggable } from '@/utils/drag';
defineOptions({ defineOptions({
name: 'DataTable' name: 'DataTable'
@ -43,7 +44,7 @@ const tableData = ref<any[]>([]);
const modalVisible = ref(false); const modalVisible = ref(false);
const modalProps = ref<any>({}); const modalProps = ref<any>({});
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
const openDialog = (record: any) => { const openDialog = (record: any) => {
const currentJidiInfo = JidiSelectEventStore.selectedItem; const currentJidiInfo = JidiSelectEventStore.selectedItem;
const isAll = currentJidiInfo?.wbsCode === 'all'; const isAll = currentJidiInfo?.wbsCode === 'all';

View File

@ -68,6 +68,7 @@ import SsstdcgkTk from './SsstdcgkTk.vue';
import { wbsbGetKendoList, getDftYear, getWeFisht } from '@/api/stdc'; import { wbsbGetKendoList, getDftYear, getWeFisht } from '@/api/stdc';
import moment from 'moment'; import moment from 'moment';
import { Label } from 'cesium'; import { Label } from 'cesium';
import { useDraggable } from '@/utils/drag';
// //
defineOptions({ defineOptions({
@ -80,7 +81,7 @@ const dataLoading = ref(false);
// ==================== ==================== // ==================== ====================
const modalVisible = ref(false); const modalVisible = ref(false);
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// ==================== ==================== // ==================== ====================
// //
const select = ref({ const select = ref({

View File

@ -40,6 +40,8 @@ import SidePanelItem from "@/components/SidePanelItem/index.vue";
import { getKendoListCust, baseEvnmAutoMonitorGetKendoListCust } from "@/api/sw"; import { getKendoListCust, baseEvnmAutoMonitorGetKendoListCust } from "@/api/sw";
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent"; import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
import ShuiwenjiancegongzuoEJ from "./shuiwenjiancegongzuoEJ.vue" import ShuiwenjiancegongzuoEJ from "./shuiwenjiancegongzuoEJ.vue"
import { useDraggable } from '@/utils/drag';
const JidiSelectEventStore = useJidiSelectEventStore(); const JidiSelectEventStore = useJidiSelectEventStore();
// 便 // 便
defineOptions({ defineOptions({
@ -68,7 +70,7 @@ const loading = ref(false);
// //
const modalVisible = ref(false); const modalVisible = ref(false);
const currentFacility = ref<any>(null); const currentFacility = ref<any>(null);
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// //
const handleFacilityClick = (facility: any) => { const handleFacilityClick = (facility: any) => {
// console.log(facility); // console.log(facility);

View File

@ -33,6 +33,8 @@ import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent"; import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
import { msstbprptGetKendoList } from '@/api/sz' import { msstbprptGetKendoList } from '@/api/sz'
import ShuiwenjiancegongzuoEJ from "./shuiwenjiancegongzuoEJ.vue" import ShuiwenjiancegongzuoEJ from "./shuiwenjiancegongzuoEJ.vue"
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
name: 'shuizhijiancegongzuoQK' name: 'shuizhijiancegongzuoQK'
@ -74,7 +76,7 @@ const modalVisible = ref(false);
const currentFacility = ref<any>(null); const currentFacility = ref<any>(null);
const baseid = ref("") const baseid = ref("")
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// //
const getDataList = async () => { const getDataList = async () => {
loading.value = true; loading.value = true;

View File

@ -460,9 +460,7 @@ const getSelectConfig = async () => {
return indexA - indexB; return indexA - indexB;
}); });
select.value.options = filterSelectOptions(dataMapNameArr); select.value.options = filterSelectOptions(dataMapNameArr);
if (baseid.value === 'all') { if (filterSelectOptions(dataMapNameArr)[0]?.children) {
select.value.value = 'SJLY1U';
} else if (filterSelectOptions(dataMapNameArr)[0]?.children) {
select.value.value = select.value.value =
filterSelectOptions(dataMapNameArr)[0]?.children[0]?.value; filterSelectOptions(dataMapNameArr)[0]?.children[0]?.value;
} else if (filterSelectOptions(dataMapNameArr)[0]?.value) { } else if (filterSelectOptions(dataMapNameArr)[0]?.value) {

View File

@ -396,6 +396,7 @@ import { postIdUrl } from '@/api/mapModal';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import videoCover from '@/assets/images/videFm.jpg'; import videoCover from '@/assets/images/videFm.jpg';
import { useDraggable } from '@/utils/drag';
const baseUrl = import.meta.env.VITE_APP_ATTACHMENT_URL; const baseUrl = import.meta.env.VITE_APP_ATTACHMENT_URL;
@ -489,7 +490,7 @@ const detailType = ref('');
const detailDataType = computed(() => detailActiveKey.value); const detailDataType = computed(() => detailActiveKey.value);
const qingpiaoModalVisible = ref(false); const qingpiaoModalVisible = ref(false);
const qingpiaoFids = ref<string[]>([]); const qingpiaoFids = ref<string[]>([]);
useDraggable(detailModalVisible, { boundary: true, resetOnOpen: true });
// React // React
const calendarStatusMap: Record< const calendarStatusMap: Record<
string, string,

View File

@ -50,6 +50,7 @@ import SidePanelItem from '@/components/SidePanelItem/index.vue';
import AISBTK from './AISBTK.vue'; import AISBTK from './AISBTK.vue';
import { getAisbdbyxList } from '@/api/zngj'; import { getAisbdbyxList } from '@/api/zngj';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
@ -104,7 +105,7 @@ const handleCardClick = (tabIdx: string) => {
const handleModalClose = () => { const handleModalClose = () => {
modalVisible.value = false; modalVisible.value = false;
}; };
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// ==================== ==================== // ==================== ====================
const getCardData = async () => { const getCardData = async () => {
if (!datetimePicker.value.value || !baseid.value) return; if (!datetimePicker.value.value || !baseid.value) return;

View File

@ -50,6 +50,8 @@ import {
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { MapClass } from '@/components/gis/map.class'; import { MapClass } from '@/components/gis/map.class';
import ZengZhiZhanQingKuangTwoLayers from './TwoLayers/ZengZhiZhanQingKuangTwoLayers.vue'; import ZengZhiZhanQingKuangTwoLayers from './TwoLayers/ZengZhiZhanQingKuangTwoLayers.vue';
import { useDraggable } from '@/utils/drag';
const JidiSelectEventStore = useJidiSelectEventStore(); const JidiSelectEventStore = useJidiSelectEventStore();
const baseid = ref(''); const baseid = ref('');
@ -65,7 +67,7 @@ let chartInstance: ECharts | null = null;
// //
const dialogVisible = ref(false); const dialogVisible = ref(false);
const dialogData = ref<any>(null); const dialogData = ref<any>(null);
useDraggable(dialogVisible, { boundary: true, resetOnOpen: true });
// //
const selectedOption = computed(() => { const selectedOption = computed(() => {
return select.value.options.find( return select.value.options.find(

View File

@ -63,6 +63,8 @@ import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { msstbprptGetKendoList } from '@/api/zzfl'; import { msstbprptGetKendoList } from '@/api/zzfl';
import ArtsDetail from '@/components/carouselIntroduce/ArtsDetail.vue'; import ArtsDetail from '@/components/carouselIntroduce/ArtsDetail.vue';
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
name: 'zengZhiZhanJieShaoMod' name: 'zengZhiZhanJieShaoMod'
@ -103,7 +105,7 @@ const isHovering = ref(false);
// transition // transition
const isTransitioning = ref(false); const isTransitioning = ref(false);
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// //
const initRenderData = () => { const initRenderData = () => {
const length = originalMediaData.value.length; const length = originalMediaData.value.length;

View File

@ -60,6 +60,8 @@ import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { overviewGetKendoListCust } from '@/api/zzfl'; import { overviewGetKendoListCust } from '@/api/zzfl';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import WholeValuedStationOverviewDetail from "./WholeValuedStationOverviewDetail/index.vue" import WholeValuedStationOverviewDetail from "./WholeValuedStationOverviewDetail/index.vue"
import { useDraggable } from '@/utils/drag';
// 便 // 便
defineOptions({ defineOptions({
name: 'zengzhizhanjiansheyunxing' name: 'zengzhizhanjiansheyunxing'
@ -68,6 +70,7 @@ const JidiSelectEventStore = useJidiSelectEventStore();
const baseid = ref(''); const baseid = ref('');
const loading = ref(false); const loading = ref(false);
const dialogVisible = ref(false); const dialogVisible = ref(false);
useDraggable(dialogVisible, { boundary: true, resetOnOpen: true });
const dialogTitle = ref('增殖站概况'); const dialogTitle = ref('增殖站概况');
const datetimePicker = ref({ const datetimePicker = ref({
show: true, show: true,

View File

@ -27,6 +27,7 @@ export const useShuJuTianBaoStore = defineStore('shuJuTianBao', () => {
try { try {
baseLoading.value = true; baseLoading.value = true;
const res = await getBaseDropdown({}); const res = await getBaseDropdown({});
// debugger
if (res.data && Array.isArray(res.data)) { if (res.data && Array.isArray(res.data)) {
const list = [...res.data]; const list = [...res.data];
// 直接赋值给 ref触发响应式更新 // 直接赋值给 ref触发响应式更新
@ -58,10 +59,15 @@ export const useShuJuTianBaoStore = defineStore('shuJuTianBao', () => {
} }
}; };
// 获取电站列表 // 获取电站列表
const getEngOption = async (rvcd: string) => { const getEngOption = async (rvcd: string, type: string) => {
try { try {
engLoading.value = true; engLoading.value = true;
const param = rvcd === 'all' ? {} : { reachcd: rvcd }; let param:any
if (type == 'baseId') {
param = rvcd === 'all' ? {} : { baseId: rvcd };
} else {
param = rvcd === 'all' ? {} : { reachcd: rvcd };
}
const res = await getEngInfoDropdown(param); const res = await getEngInfoDropdown(param);
if (res.data && Array.isArray(res.data)) { if (res.data && Array.isArray(res.data)) {
// 直接赋值给 ref // 直接赋值给 ref

View File

@ -26,21 +26,23 @@ export function useDraggable(
let cleanup: (() => void) | null = null; let cleanup: (() => void) | null = null;
const initDrag = (): (() => void) | null => { const initDrag = (): (() => void) | null => {
const modalContent = document.querySelector(
modalSelector
) as HTMLElement | null;
const dragHandle = document.querySelector(handle) as HTMLElement | null;
if (!modalContent || !dragHandle) return null;
// 重置位置到居中
if (resetOnOpen) { if (resetOnOpen) {
modalContent.style.position = ''; const modalContents = document.querySelectorAll(
modalContent.style.left = ''; modalSelector
modalContent.style.top = ''; ) as NodeListOf<HTMLElement>;
modalContent.style.margin = ''; modalContents.forEach(content => {
modalContent.style.transform = ''; if (content.offsetParent !== null) {
content.style.position = '';
content.style.left = '';
content.style.top = '';
content.style.margin = '';
content.style.transform = '';
content.style.width = '';
}
});
} }
let currentModalContent: HTMLElement | null = null;
let isDragging = false; let isDragging = false;
let startX = 0; let startX = 0;
let startY = 0; let startY = 0;
@ -56,19 +58,30 @@ export function useDraggable(
}; };
const onPointerDown = (e: MouseEvent | TouchEvent) => { const onPointerDown = (e: MouseEvent | TouchEvent) => {
const target = e.target instanceof HTMLElement ? e.target : null;
const dragHandle = target?.closest(handle) as HTMLElement | null;
if (!dragHandle) return;
const modalContent = dragHandle.closest(
modalSelector
) as HTMLElement | null;
if (!modalContent) return;
if ( if (
e.target instanceof HTMLElement && target.closest('.ant-modal-close') ||
(e.target.closest('.ant-modal-close') || target.closest('button') ||
e.target.closest('button') || target.closest('input') ||
e.target.closest('input') || target.closest('select') ||
e.target.closest('select') || target.closest('textarea') ||
e.target.closest('textarea') || target.closest('a')
e.target.closest('a'))
) )
return; return;
e.preventDefault(); e.preventDefault();
isDragging = true; isDragging = true;
currentModalContent = modalContent;
const rect = modalContent.getBoundingClientRect(); const rect = modalContent.getBoundingClientRect();
startLeft = rect.left; startLeft = rect.left;
startTop = rect.top; startTop = rect.top;
@ -76,7 +89,6 @@ export function useDraggable(
startX = pos.clientX - startLeft; startX = pos.clientX - startLeft;
startY = pos.clientY - startTop; startY = pos.clientY - startTop;
// --- 新增:固定宽度 ---
const currentWidth = modalContent.offsetWidth; const currentWidth = modalContent.offsetWidth;
modalContent.style.width = currentWidth + 'px'; modalContent.style.width = currentWidth + 'px';
@ -91,46 +103,63 @@ export function useDraggable(
document.addEventListener('touchmove', onPointerMove, { passive: false }); document.addEventListener('touchmove', onPointerMove, { passive: false });
document.addEventListener('touchend', onPointerUp); document.addEventListener('touchend', onPointerUp);
}; };
const onPointerMove = (e: MouseEvent | TouchEvent) => { const onPointerMove = (e: MouseEvent | TouchEvent) => {
if (!isDragging) return; if (!isDragging || !currentModalContent) return;
e.preventDefault(); e.preventDefault();
const pos = getPointerPos(e); const pos = getPointerPos(e);
let newLeft = pos.clientX - startX; let newLeft = pos.clientX - startX;
let newTop = pos.clientY - startY; let newTop = pos.clientY - startY;
if (boundary) { if (boundary) {
const maxX = window.innerWidth - modalContent.offsetWidth; const maxX = window.innerWidth - currentModalContent.offsetWidth;
const maxY = window.innerHeight - modalContent.offsetHeight; const maxY = window.innerHeight - currentModalContent.offsetHeight;
newLeft = Math.max(0, Math.min(newLeft, maxX)); newLeft = Math.max(0, Math.min(newLeft, maxX));
newTop = Math.max(0, Math.min(newTop, maxY)); newTop = Math.max(0, Math.min(newTop, maxY));
} }
modalContent.style.left = `${newLeft}px`; currentModalContent.style.left = `${newLeft}px`;
modalContent.style.top = `${newTop}px`; currentModalContent.style.top = `${newTop}px`;
}; };
const onPointerUp = () => { const onPointerUp = () => {
if (!currentModalContent) return;
isDragging = false; isDragging = false;
modalContent.style.userSelect = ''; currentModalContent.style.userSelect = '';
modalContent.style.webkitUserSelect = ''; currentModalContent.style.webkitUserSelect = '';
document.removeEventListener('mousemove', onPointerMove); document.removeEventListener('mousemove', onPointerMove);
document.removeEventListener('mouseup', onPointerUp); document.removeEventListener('mouseup', onPointerUp);
document.removeEventListener('touchmove', onPointerMove); document.removeEventListener('touchmove', onPointerMove);
document.removeEventListener('touchend', onPointerUp); document.removeEventListener('touchend', onPointerUp);
currentModalContent = null;
}; };
dragHandle.addEventListener('mousedown', onPointerDown); document.addEventListener('mousedown', onPointerDown);
dragHandle.addEventListener('touchstart', onPointerDown, { document.addEventListener('touchstart', onPointerDown, {
passive: false passive: false
}); });
return () => { return () => {
dragHandle.removeEventListener('mousedown', onPointerDown); document.removeEventListener('mousedown', onPointerDown);
dragHandle.removeEventListener('touchstart', onPointerDown); document.removeEventListener('touchstart', onPointerDown);
document.removeEventListener('mousemove', onPointerMove); document.removeEventListener('mousemove', onPointerMove);
document.removeEventListener('mouseup', onPointerUp); document.removeEventListener('mouseup', onPointerUp);
document.removeEventListener('touchmove', onPointerMove); document.removeEventListener('touchmove', onPointerMove);
document.removeEventListener('touchend', onPointerUp); document.removeEventListener('touchend', onPointerUp);
const modalContents = document.querySelectorAll(
modalSelector
) as NodeListOf<HTMLElement>;
modalContents.forEach(content => {
content.style.position = '';
content.style.left = '';
content.style.top = '';
content.style.margin = '';
content.style.transform = '';
content.style.width = '';
content.style.userSelect = '';
content.style.webkitUserSelect = '';
});
}; };
}; };

View File

@ -40,6 +40,7 @@
import { ref } from 'vue'; import { ref } from 'vue';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import { deletePowerInfo } from '@/api/DataQueryMenuModule'; import { deletePowerInfo } from '@/api/DataQueryMenuModule';
import { useDraggable } from '@/utils/drag';
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
@ -72,7 +73,8 @@ const open = (record: any, callback: Function) => {
dataSourceVisible.value = true; dataSourceVisible.value = true;
onSuccess.value = callback; onSuccess.value = callback;
}; };
useDraggable(dataSourceVisible, { boundary: true, resetOnOpen: true });
useDraggable(confirmVisible, { boundary: true, resetOnOpen: true });
// //
const handleDataSourceConfirm = () => { const handleDataSourceConfirm = () => {
dataSourceVisible.value = false; dataSourceVisible.value = false;

View File

@ -58,6 +58,7 @@ import FishDataSearch from './FishDataSearch.vue';
import BasicTable from '@/components/BasicTable/index.vue'; import BasicTable from '@/components/BasicTable/index.vue';
import { getFishReleaseMonitorList } from '@/api/DataQueryMenuModule'; import { getFishReleaseMonitorList } from '@/api/DataQueryMenuModule';
import { calcTableScrollY } from '@/utils/index'; import { calcTableScrollY } from '@/utils/index';
import { useDraggable } from '@/utils/drag';
const sort = ref<any>([ const sort = ref<any>([
{ {
@ -93,7 +94,8 @@ const previewImageUrl = ref('');
// //
const videoPreviewVisible = ref(false); const videoPreviewVisible = ref(false);
const previewVideoUrl = ref(''); const previewVideoUrl = ref('');
useDraggable(imagePreviewVisible, { boundary: true, resetOnOpen: true });
useDraggable(videoPreviewVisible, { boundary: true, resetOnOpen: true });
const openImagePreview = (url: string) => { const openImagePreview = (url: string) => {
previewImageUrl.value = import.meta.env.VITE_APP_ATTACHMENT_URL + '/?' + url; previewImageUrl.value = import.meta.env.VITE_APP_ATTACHMENT_URL + '/?' + url;
imagePreviewVisible.value = true; imagePreviewVisible.value = true;

View File

@ -279,6 +279,7 @@ import {
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import router from '@/router'; import router from '@/router';
import { encrypt } from '@/utils/rsaEncrypt'; import { encrypt } from '@/utils/rsaEncrypt';
import { useDraggable } from '@/utils/drag';
// //
const registerData = reactive({ const registerData = reactive({
@ -510,7 +511,7 @@ const registerRules = {
const loading = ref(false); const loading = ref(false);
const activeTab = ref('register'); const activeTab = ref('register');
const modalVisible = ref(false); const modalVisible = ref(false);
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// //
const loadGroupList = async () => { const loadGroupList = async () => {
try { try {

View File

@ -7,12 +7,13 @@ import SSSTDCQK from '@/modules/shuiShengShengTaiDiaoCha/index.vue'; // 水生
import AlongFishMod from '@/modules/alongFishMod/index.vue'; //沿 import AlongFishMod from '@/modules/alongFishMod/index.vue'; //沿
import SSSTDCDB from './shuiShengShengTaiDiaoCha/SSSTDCDB.vue'; import SSSTDCDB from './shuiShengShengTaiDiaoCha/SSSTDCDB.vue';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { useDraggable } from '@/utils/drag';
const JidiSelectEventStore = useJidiSelectEventStore(); const JidiSelectEventStore = useJidiSelectEventStore();
const modalVisible = ref(false); const modalVisible = ref(false);
const currentItem = computed(() => JidiSelectEventStore.selectedItem); const currentItem = computed(() => JidiSelectEventStore.selectedItem);
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
const handleOpenModal = () => { const handleOpenModal = () => {
modalVisible.value = true; modalVisible.value = true;
}; };

View File

@ -226,6 +226,7 @@ import {
import { Tag } from 'ant-design-vue'; // Tag import { Tag } from 'ant-design-vue'; // Tag
import { getDictItemsByCode } from '@/api/dict'; import { getDictItemsByCode } from '@/api/dict';
import { calcTableScrollY } from '@/utils/index'; import { calcTableScrollY } from '@/utils/index';
import { useDraggable } from '@/utils/drag';
const baseUrl = import.meta.env.VITE_APP_ATTACHMENT_URL; const baseUrl = import.meta.env.VITE_APP_ATTACHMENT_URL;
const baseUrlApi = import.meta.env.VITE_APP_BASE_API_URL; const baseUrlApi = import.meta.env.VITE_APP_BASE_API_URL;
@ -324,7 +325,7 @@ const baseColumnsConfig: ColumnConfig[] = [
// --- --- // --- ---
const visible = ref(false); // Modal const visible = ref(false); // Modal
const editModalRef = ref<any>(null); const editModalRef = ref<any>(null);
useDraggable(visible, { boundary: true, resetOnOpen: true });
// //
const editModalVisible = ref(false); const editModalVisible = ref(false);
const isView = ref(false); const isView = ref(false);