bug修改,添加过鱼到数统计,添加公共弹框基础信息

This commit is contained in:
扈兆增 2026-05-08 19:11:10 +08:00
parent 2d9ff44ef9
commit 0d5c79bd2e
11 changed files with 7317 additions and 112 deletions

View File

@ -6,9 +6,15 @@ NODE_ENV='development'
VITE_APP_TITLE = '水电水利建设项目全过程环境管理信息平台' VITE_APP_TITLE = '水电水利建设项目全过程环境管理信息平台'
VITE_APP_PORT = 3000 VITE_APP_PORT = 3000
VITE_APP_BASE_API = '/dev-api' VITE_APP_BASE_API = '/dev-api'
## 开发环境API地址 # 本地环境
# VITE_APP_BASE_URL = 'http://localhost:8093' # VITE_APP_BASE_URL = 'http://localhost:8093'
# 测试环境
# VITE_APP_BASE_URL = 'http://172.16.21.142:8096'
# 汤伟
VITE_APP_BASE_URL = 'http://10.84.121.21:8093' VITE_APP_BASE_URL = 'http://10.84.121.21:8093'
VITE_APP_BASE_API_URL = 'http://10.84.121.21:8093'
# 开发环境导入预览地址
VITE_APP_BASE_API_URL = 'http://172.16.21.14:8096'
## 开发环境预览 图片视频地址 ## 开发环境预览 图片视频地址
VITE_APP_PREVIEW_URL = 'https://211.99.26.225:12125' VITE_APP_PREVIEW_URL = 'https://211.99.26.225:12125'

View File

@ -27,6 +27,7 @@ interface Props {
scrollY?: string | number; scrollY?: string | number;
// //
listUrl: (params: any) => Promise<any>; listUrl: (params: any) => Promise<any>;
data?: any[];
// //
enableRowSelection?: boolean; enableRowSelection?: boolean;
// Key Table // Key Table
@ -44,6 +45,7 @@ interface Props {
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
enableRowSelection: false, enableRowSelection: false,
rowKey: "id", rowKey: "id",
data: () => ([]),
isOneLoad: true, isOneLoad: true,
searchParams: () => ({}), searchParams: () => ({}),
defaultPageSize: 20, defaultPageSize: 20,
@ -105,6 +107,7 @@ const paginationConfig = computed(() => ({
* @param extraParams 额外的临时参数可选 * @param extraParams 额外的临时参数可选
*/ */
const getList = async (filter?: Record<string, any>) => { const getList = async (filter?: Record<string, any>) => {
if(props.data.length > 0) return
loading.value = true; loading.value = true;
tableData.value = []; tableData.value = [];
total.value = 0; total.value = 0;
@ -215,6 +218,7 @@ watch(
// --- Lifecycle --- // --- Lifecycle ---
onMounted(() => { onMounted(() => {
if(props.data && props.data.length > 0) tableData.value = props.data || [];
}); });
</script> </script>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,57 +1,44 @@
<template> <template>
<a-modal <a-modal
v-model:open="visible" :open="visible"
:title="title" :title="title"
width="800px" width="80vw"
:footer="null" :footer="null"
:closable="true" :closable="true"
@cancel="handleClose" @cancel="handleClose"
:destroyOnClose="true"
class="map-modal" class="map-modal"
> >
<div class="map-modal-content"> <a-tabs :active-key="currentActiveKey" @change="onTabChange">
<a-tabs v-model:activeKey="currentActiveKey"> <a-tab-pane v-for="tab in tabsConfig" :key="tab.key" :tab="tab.title">
<a-tab-pane <div class="content">
v-for="tab in tabsConfig" <!-- 基本信息组件 -->
:key="tab.key" <BasicInfo v-if="currentActiveKey === 'basicInfo'" :url="tab.url" />
:tab="tab.title" <!-- 地图组件 -->
> <!-- <MapView v-else-if="currentActiveKey === 'mapView'" :data="modalData" /> -->
<!-- 根据 key 动态渲染子组件 --> <!-- 周边配套组件 -->
<div v-if="currentActiveKey === 'basicInfo'" class="tab-pane-container"> <!-- <SurroundingInfo
<!-- 假设 BasicInfo 是预定义的组件 --> v-else-if="currentActiveKey === 'surrounding'"
<BasicInfo :data="modalData" /> :data="modalData"
</div> /> -->
</div>
<div v-else-if="currentActiveKey === 'mapView'" class="tab-pane-container"> </a-tab-pane>
<!-- 假设 MapView 是预定义的组件 --> </a-tabs>
<MapView :data="modalData" />
</div>
<div v-else-if="currentActiveKey === 'surrounding'" class="tab-pane-container">
<!-- 其他预定义组件 -->
<SurroundingInfo :data="modalData" />
</div>
<div v-else class="empty-placeholder">
未找到对应 Key ({{ currentActiveKey }}) 的组件配置
</div>
</a-tab-pane>
</a-tabs>
</div>
</a-modal> </a-modal>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, watch } from 'vue'; import { ref, watch } from "vue";
// Tab // Tab
// import BasicInfo from "./components/BasicInfo.vue";
import BasicInfo from './components/BasicInfo.vue'; // import MapView from './components/MapView.vue';
import MapView from './components/MapView.vue'; // import SurroundingInfo from './components/SurroundingInfo.vue';
import SurroundingInfo from './components/SurroundingInfo.vue';
// Tab // Tab
interface TabItem { interface TabItem {
key: string; key: string;
title: string; title: string;
url: string;
} }
// Props // Props
@ -64,56 +51,55 @@ const props = defineProps<{
}>(); }>();
// Emits // Emits
// 'update:activeKey' v-model:active-key
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:visible', value: boolean): void; (e: "update:visible", value: boolean): void;
(e: 'change', key: string): void; // tab (e: "update:activeKey", key: string): void;
(e: "change", key: string): void;
}>(); }>();
// activeKey // activeKey
const currentActiveKey = ref<string>(props.activeKey || ''); const currentActiveKey = ref<string>(props.activeKey || "");
// activeKey // activeKey
watch(() => props.activeKey, (newVal) => { watch(
if (newVal) { () => props.activeKey,
currentActiveKey.value = newVal; (newVal) => {
} if (newVal && newVal !== currentActiveKey.value) {
}, { immediate: true }); currentActiveKey.value = newVal;
}
},
{ immediate: true }
);
// tab // tab
watch(currentActiveKey, (newVal) => { const onTabChange = (key: string) => {
emit('change', newVal); currentActiveKey.value = key;
}); // activeKey ( v-model)
emit("update:activeKey", key);
// ()
emit("change", key);
};
// //
const handleClose = () => { const handleClose = () => {
emit('update:visible', false); emit("update:visible", false);
}; };
// 便使 props.data // 便使 props.data
const modalData = ref(props.data); const modalData = ref(props.data);
watch(() => props.data, (newVal) => { watch(
modalData.value = newVal; () => props.data,
}); (newVal) => {
modalData.value = newVal;
}
);
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.map-modal { .map-modal {
:deep(.ant-modal-body) { .content {
padding: 24px; min-height: 600px;
}
.map-modal-content {
min-height: 300px; //
.tab-pane-container {
padding: 10px 0;
}
.empty-placeholder {
color: #999;
text-align: center;
padding: 40px 0;
}
} }
} }
</style> </style>

View File

@ -0,0 +1,14 @@
import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useModelStore = defineStore('model', () => {
// state
const info = ref<{
type: string;
}>({
type: 'zh'
});
return {
info,
};
});

View File

@ -1,9 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted } from "vue"; import { onMounted, ref } from "vue";
import JidiSelectorMod from "@/modules/jidiSelectorMod.vue"; import JidiSelectorMod from "@/modules/jidiSelectorMod.vue";
import RightDrawer from "@/components/RightDrawer/index.vue"; import RightDrawer from "@/components/RightDrawer/index.vue";
import jidiInfoMod from "@/modules/jidiInfoMod/index.vue"; import jidiInfoMod from "@/modules/jidiInfoMod/index.vue";
import shuidianhuangjingjieruMod from "@/modules/shuidianhuangjingjieruMod/index.vue"; import shuidianhuangjingjieruMod from "@/modules/shuidianhuangjingjieruMod/index.vue";
import MapModal from "@/components/MapModal/index.vue";
import { useModelStore } from "@/store/modules/model";
const modelInfo = useModelStore();
// import { getQgcStaticData } from "@/api/ecoFlow"; // import { getQgcStaticData } from "@/api/ecoFlow";
onMounted(() => { onMounted(() => {
// const params = { // const params = {
@ -21,6 +25,31 @@ onMounted(() => {
// console.log(res); // console.log(res);
// }); // });
}); });
const modalVisible = ref(false);
const currentTabKey = ref("basicInfo");
const projectData = ref({ id: 1, name: "测试项目" });
const tabList = [
{ key: "basicInfo", title: "基础信息", url: "" },
{ key: "mapView", title: "地图视图", url: "" },
{ key: "surrounding", title: "周边配套", url: "" },
];
const showMapModal = () => {
modalVisible.value = true;
currentTabKey.value = "basicInfo";
modelInfo.info.type = "eng";
};
const showMapModal1 = () => {
modalVisible.value = true;
currentTabKey.value = "basicInfo";
modelInfo.info.type = "zh";
};
const onTabChange = (key: string) => {
console.log("Tab 切换为:", key);
};
</script> </script>
<template> <template>
@ -30,6 +59,17 @@ onMounted(() => {
</div> </div>
<div class="rightContent"> <div class="rightContent">
<RightDrawer> <RightDrawer>
<!-- <a-button @click="showMapModal">打开电站地图弹窗</a-button>
<a-button @click="showMapModal1">打开地图弹窗1</a-button>
<MapModal
v-model:visible="modalVisible"
v-model:active-key="currentTabKey"
title="三峡 详情信息"
:tabs-config="tabList"
:data="projectData"
@change="onTabChange"
/> -->
<jidiInfoMod /> <jidiInfoMod />
<shuidianhuangjingjieruMod /> <shuidianhuangjingjieruMod />
</RightDrawer> </RightDrawer>

View File

@ -856,6 +856,9 @@ onMounted(() => {
.ant-tabs-nav { .ant-tabs-nav {
height: 38px; height: 38px;
} }
:deep(.ant-checkbox+span){
padding-right: 0;
}
} }
/* 验证码布局 */ /* 验证码布局 */

View File

@ -0,0 +1,326 @@
<template>
<div class="guoYuDaoShuTongJi-page">
<!-- 搜索组件 -->
<ApprovalDetailSearch
:guoyu-status="guoyuStatus"
:direction="direction"
@search-finish="handleDetailSearchFinish"
@reset="handleDetailReset"
/>
<!-- 表格组件 -->
<BasicTable
ref="detailTableRef"
:columns="columns"
:isOneLoad="false"
:data="tableData"
:list-url="getFishDraftPage"
:scroll-y="'500px'"
:transform-data="customTransform"
>
</BasicTable>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, onMounted, h, computed, nextTick } from "vue";
import {
batchApproveByApprovalId,
batchReject,
} from "@/api/shengPiJiLu";
import { Tag, message } from "ant-design-vue";
import BasicTable from "@/components/BasicTable/index.vue";
import ApprovalDetailSearch from "../shengPiJiLu/approvalDetailSearch.vue";
import { getDictItemsByCode } from "@/api/dict";
import { getFishDraftPage } from "@/api/guoYuSheShiShuJuTianBao";
const baseUrl = import.meta.env.VITE_APP_PREVIEW_URL;
let columns = ref([
{ dataIndex: "hbrvnm", key: "hbrvnm", title: "流域",
customCell: (_, index) => {
if (index === 0) {
return { rowSpan: 2 };
}
// These two are merged into above cell
if (index === 1) {
return { rowSpan: 0 };
}
if (index === 2) {
return { colSpan: 1 };
}
},
},
{ dataIndex: "ennm", key: "ennm", title: "电站名称",
customCell: (_, index) => {
if (index === 0) {
return { rowSpan: 2 };
}
// These two are merged into above cell
if (index === 1) {
return { rowSpan: 0 };
}
if (index === 2) {
return { colSpan: 1 };
}
},},
{ dataIndex: "stnm", key: "stnm", title: "月份" },
{ dataIndex: "startTime", key: "startTime", title: "过鱼开始时间" },
{ dataIndex: "endTime", key: "endTime", title: "过鱼结束时间" },
{ dataIndex: "ftpName", key: "ftpName", title: "本月过鱼总数" },
{ dataIndex: "ftpName1", key: "ftpName1", title: "联系人/电话", width: 250 },
]);
const tableData = ref([
{
hbrvnm: "黄河干流上游",
ennm: "玛尔挡",
stnm: "2026-03",
ftpName: 61,
ftpName1: "张三13800000000",
startTime: "2026-03-01",
endTime: "2026-03-31",
},
{
hbrvnm: "黄河干流上游",
ennm: "玛尔挡",
stnm: "2026-04",
ftpName: 666,
ftpName1: "张三13800000000",
startTime: "2026-04-01",
endTime: "2026-04-31",
},
{
hbrvnm: "雅鲁藏布江流域",
ennm: "ZM",
stnm: "2026-04",
ftpName: 777,
ftpName1: "李四13800000000",
startTime: "2026-04-01",
endTime: "2026-04-31",
},
]);
const tableRef = ref();
const handleSearchFinish = (values: any) => {
console.log(values);
const filters = [
values.status && {
field: "status",
operator: "eq",
dataType: "string",
value: values.status,
},
values.hbrvcd !== "all" && {
field: "hbrvcd",
operator: "eq",
dataType: "string",
value: values.hbrvcd,
},
values.stcd && {
field: "stcd",
operator: "eq",
dataType: "string",
value: values.stcd,
},
].filter(Boolean);
const filter = {
logic: "and",
filters: filters,
};
tableRef.value?.getList(filter);
};
const handleReset = (values) => {
handleSearchFinish(values);
};
//
const approvalLogVisible = ref(false);
const approvalLogTableRef = ref();
//
const changeLogVisible = ref(false);
const changeLogTableRef = ref();
const currentApprovalId = ref("");
const actionTypeDict = ref([]);
const operationTypeDict = ref([]);
//
const detailVisible = ref(false);
const detailTableRef = ref();
const guoyuStatus = ref([]);
const direction = ref([]);
//
const viewModalVisible = ref(false);
const editModalRef = ref<any>(null);
const currentViewRecord = ref<any>(null);
//
const mediaPreviewVisible = ref(false);
const videoPreviewTitle = ref("预览");
interface MediaItem {
id: string;
type: "image" | "video" | "formVideo" | "formImage";
name: string;
url: string;
}
const previewList = ref<MediaItem[]>([]);
const currentMediaIndex = ref(0);
//
const customTransform = (res: any) => {
const rawRecords = res?.data?.records || [];
const modifiedRecords = rawRecords.map((item: any) => {
return {
...item,
picpthList: item.picpth
? item.picpth.split(",").map((item: string) => baseUrl + "/?" + item) || []
: [],
};
});
return {
records: modifiedRecords,
total: res?.data?.total || 0,
};
};
//
const handleDetailSearchFinish = (values: any) => {
console.log("详情搜索:", values);
const filters = [
values.ftp && {
field: "ftp",
operator: "eq",
dataType: "string",
value: values.ftp,
},
values.strdt && {
field: "strdt",
operator: "gte",
dataType: "date",
value: values.strdt[0] + " 00:00:00",
},
values.strdt && {
field: "strdt",
operator: "lte",
dataType: "date",
value: values.strdt[1] + " 23:59:59",
},
values.direction && {
field: "direction",
operator: "eq",
dataType: "string",
value: values.direction,
},
values.rstcd && {
field: "rstcd",
operator: "eq",
dataType: "string",
value: values.rstcd,
},
values.hbrvcd !== "all" && {
field: "hbrvcd",
operator: "eq",
dataType: "string",
value: values.hbrvcd,
},
approvalId.value && {
field: "approvalId", //
operator: "eq", //
dataType: "string", //
value: approvalId.value, // record
},
].filter(Boolean);
const filter = {
logic: "and",
filters: filters,
};
detailTableRef.value?.getList(filter);
};
//
const handleDetailReset = (values: any) => {
console.log("详情重置:", values);
handleDetailSearchFinish(values);
};
//
const approvalId = ref("");
//
onMounted(() => {
dictNmae();
//
getDictItemsByCode({ dictCode: "direction" }).then((res) => {
direction.value = res.data;
});
getDictItemsByCode({ dictCode: "approvalStatus" }).then((res) => {
guoyuStatus.value = res.data;
});
});
const shenStatus = ref([]);
const yeWuType = ref([]);
const dictNmae = () => {
getDictItemsByCode({ dictCode: "approvalStatus" }).then((res) => {
shenStatus.value = res.data;
});
getDictItemsByCode({ dictCode: "yeWuType" }).then((res) => {
yeWuType.value = res.data;
});
// TODO:
getDictItemsByCode({ dictCode: "caoType" }).then((res) => {
res.data.forEach((item: any) => {
if (item.itemCode == "UPDATE" || item.itemCode == "DELETE") {
operationTypeDict.value.push(item);
} else {
actionTypeDict.value.push(item);
}
});
});
};
const handName = (val: any, arr: any) => {
let dictName1 = "";
arr.forEach((item: any) => {
if (item.itemCode == val) {
dictName1 = item.dictName;
}
});
return dictName1;
};
//
const searchData = ref<any>({
hbrvcd: "all",
status: "",
});
//
const paramsTab = ref({
sort: [
{
field: "applyTime",
dir: "desc",
needSortFlag: true,
},
],
});
// 使 computed searchParams
const computedSearchParams = computed(() => ({
sort: paramsTab.value.sort,
}));
</script>
<style scoped lang="scss">
.guoYuDaoShuTongJi-page {
width: 100%;
height: 100%;
background-color: #ffffff;
padding: 20px;
}
</style>

View File

@ -57,46 +57,18 @@ const searchList: any = computed(() => [
}, },
options: [], options: [],
}, },
{
type: "Select",
name: "stcd",
label: "过鱼设施",
values: { name: "stnm", value: "stcd" },
fieldProps: {
allowClear: true,
},
options: shuJuTianBaoStore.fpssOption,
},
{
type: "Select",
name: "direction",
label: "游向",
width: 120,
options: props.direction,
fieldProps: {
allowClear: true,
},
},
{
type: "custom",
name: "ftp",
label: "鱼种类",
fieldProps: {
allowClear: true,
},
},
{ {
span: 12, span: 12,
type: "RangePicker", type: "RangePicker",
name: "strdt", name: "strdt",
label: "过鱼时间", label: "过鱼时间",
picker: "date", picker: "month",
fieldProps: { fieldProps: {
format: "YYYY-MM-DD", format: "YYYY-MM",
valueFormat: "YYYY-MM-DD", valueFormat: "YYYY-MM",
allowClear: false, allowClear: false,
}, },
presets: DateSetting.RangeButton.days, presets: DateSetting.RangeButton.month,
}, },
]); ]);

View File

@ -994,12 +994,12 @@ function handleClearSelection() {
<el-table-column prop="phone" label="手机号" width="160"></el-table-column> <el-table-column prop="phone" label="手机号" width="160"></el-table-column>
<el-table-column prop="username" label="登录账号" ></el-table-column> <el-table-column prop="username" label="登录账号" ></el-table-column>
<!-- <el-table-column prop="custom1" label="登录账号"></el-table-column> --> <!-- <el-table-column prop="custom1" label="登录账号"></el-table-column> -->
<el-table-column prop="rolename" label="所属角色" > <!-- <el-table-column prop="rolename" label="所属角色" >
<template #default="scope"> <template #default="scope">
<span v-for="(item, index) in scope.row.roles" :key="index">{{ item.rolename }} <span></span> <span v-for="(item, index) in scope.row.roles" :key="index">{{ item.rolename }} <span></span>
</span> </span>
</template> </template>
</el-table-column> </el-table-column> -->
<el-table-column prop="regStatus" label="审核状态" width="90" align="center"> <el-table-column prop="regStatus" label="审核状态" width="90" align="center">
<template #default="scope"> <template #default="scope">
<el-tag :type="getRegStatusColor(scope.row.regStatus)" size="small"> <el-tag :type="getRegStatusColor(scope.row.regStatus)" size="small">
@ -1007,7 +1007,7 @@ function handleClearSelection() {
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="lastmodifier" label="最近修改者" width="120"></el-table-column> <!-- <el-table-column prop="lastmodifier" label="最近修改者" width="120"></el-table-column> -->
<el-table-column prop="lastmodifydate" label="最近修改日期" width="160"> <el-table-column prop="lastmodifydate" label="最近修改日期" width="160">
<template #default="scope"> <template #default="scope">
{{ dateFormat(scope.row.lastmodifydate) }} {{ dateFormat(scope.row.lastmodifydate) }}