导入流程走通,预览导入图片和视频
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
parent
05c4cd68c9
commit
10c3c33ad0
@ -6,3 +6,4 @@ 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'
|
||||||
|
VITE_APP_PREVIEW_URL = 'https://211.99.26.225:12125'
|
||||||
|
|||||||
@ -4,3 +4,4 @@ NODE_ENV='production'
|
|||||||
VITE_APP_TITLE = 'qgc-buji-web'
|
VITE_APP_TITLE = 'qgc-buji-web'
|
||||||
VITE_APP_PORT = 3000
|
VITE_APP_PORT = 3000
|
||||||
VITE_APP_BASE_API = '/prod-api'
|
VITE_APP_BASE_API = '/prod-api'
|
||||||
|
VITE_APP_PREVIEW_URL = 'https://211.99.26.225:12125'
|
||||||
|
|||||||
@ -79,6 +79,7 @@
|
|||||||
placeholder="请选择"
|
placeholder="请选择"
|
||||||
@change="dataDimensionDataChange"
|
@change="dataDimensionDataChange"
|
||||||
show-search
|
show-search
|
||||||
|
allow-clear
|
||||||
:loading="shuJuTianBaoStore.baseLoading"
|
:loading="shuJuTianBaoStore.baseLoading"
|
||||||
:filter-option="filterOption"
|
:filter-option="filterOption"
|
||||||
style="width: 135px"
|
style="width: 135px"
|
||||||
@ -97,6 +98,7 @@
|
|||||||
placeholder="请选择电站"
|
placeholder="请选择电站"
|
||||||
@change="stcdIdChange"
|
@change="stcdIdChange"
|
||||||
show-search
|
show-search
|
||||||
|
allow-clear
|
||||||
:loading="shuJuTianBaoStore.engLoading"
|
:loading="shuJuTianBaoStore.engLoading"
|
||||||
:filter-option="filterOption"
|
:filter-option="filterOption"
|
||||||
style="width: 135px"
|
style="width: 135px"
|
||||||
|
|||||||
@ -34,6 +34,7 @@ interface Props {
|
|||||||
// 默认每页显示数量
|
// 默认每页显示数量
|
||||||
defaultPageSize?: number;
|
defaultPageSize?: number;
|
||||||
getCheckboxProps?: (record: any) => any;
|
getCheckboxProps?: (record: any) => any;
|
||||||
|
transformData?: (res: any) => { records: any[]; total: number };
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
@ -41,7 +42,8 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
rowKey: "id",
|
rowKey: "id",
|
||||||
searchParams: () => ({}),
|
searchParams: () => ({}),
|
||||||
defaultPageSize: 20,
|
defaultPageSize: 20,
|
||||||
getCheckboxProps: undefined
|
getCheckboxProps: undefined,
|
||||||
|
transformData: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
@ -101,20 +103,29 @@ const getList = async (filter?: Record<string, any>) => {
|
|||||||
// skip: (page.value - 1) * size.value,
|
// skip: (page.value - 1) * size.value,
|
||||||
// take: size.value,
|
// take: size.value,
|
||||||
};
|
};
|
||||||
console.log(params);
|
|
||||||
|
|
||||||
const res = await props.listUrl(params);
|
const res = await props.listUrl(params);
|
||||||
|
let records: any[] = [];
|
||||||
|
let totalCount: number = 0;
|
||||||
|
|
||||||
|
// [!code ++] 核心逻辑:如果父组件传入了 transformData,则使用父组件的逻辑
|
||||||
|
if (props.transformData) {
|
||||||
|
const result = props.transformData(res);
|
||||||
|
records = result.records || [];
|
||||||
|
totalCount = result.total || 0;
|
||||||
|
} else {
|
||||||
|
// [!code ++] 否则使用默认逻辑
|
||||||
|
records = res?.data?.records || res?.data || [];
|
||||||
|
totalCount = res?.data?.total || res?.total || 0;
|
||||||
|
}
|
||||||
|
|
||||||
// 假设后端返回结构为 { data: { records: [], total: 0 } }
|
|
||||||
// 请根据实际后端接口调整以下取值逻辑
|
|
||||||
const records = res?.data?.records || res?.data?.list || res?.data || [];
|
|
||||||
const totalCount = res?.data?.total || res?.total || 0;
|
|
||||||
|
|
||||||
tableData.value = records;
|
tableData.value = records;
|
||||||
total.value = totalCount;
|
total.value = totalCount;
|
||||||
|
|
||||||
// 向父组件暴露当前请求参数和结果
|
// 向父组件暴露当前请求参数和结果
|
||||||
emit("data-loaded", params, { records, total: totalCount });
|
emit("data-loaded", params, { records, total: totalCount });
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Fetch table data error:", error);
|
console.error("Fetch table data error:", error);
|
||||||
tableData.value = [];
|
tableData.value = [];
|
||||||
|
|||||||
@ -56122,41 +56122,42 @@ const fetchPointData = _.debounce(async () => {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// 基础图层
|
// 基础图层
|
||||||
// mapClass.addBaseDataLayer({
|
mapClass.addBaseDataLayer({
|
||||||
// id: "customBaseLayer",
|
id: "customBaseLayer",
|
||||||
// key: "customBaseLayer",
|
key: "customBaseLayer",
|
||||||
// type: "wmts",
|
type: "wmts",
|
||||||
// name: "qgc_sx_gjjdx_arcgistiles_l13",
|
name: "qgc_sx_gjjdx_arcgistiles_l13",
|
||||||
// urlType: "gisurl",
|
urlType: "gisurl",
|
||||||
// url:
|
url:
|
||||||
// "/geoserver/gwc/service/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&LAYER=qgc_qsj_arcgistiles_l13&STYLE=&TILEMATRIX=EPSG:3857_qgc_qsj_arcgistiles_l13:{z}&TILEMATRIXSET=EPSG:3857_qgc_qsj_arcgistiles_l13&FORMAT=image/png&TILECOL={x}&TILEROW={y}",
|
"/geoserver/gwc/service/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&LAYER=qgc_qsj_arcgistiles_l13&STYLE=&TILEMATRIX=EPSG:3857_qgc_qsj_arcgistiles_l13:{z}&TILEMATRIXSET=EPSG:3857_qgc_qsj_arcgistiles_l13&FORMAT=image/png&TILECOL={x}&TILEROW={y}",
|
||||||
// url_3d:
|
url_3d:
|
||||||
// "/geoserver/gwc/service/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&LAYER=qgc_sx_gjjdx_arcgistiles_l13&STYLE=&TILEMATRIX=EPSG:3857_qgc_sx_gjjdx_arcgistiles_l13:{z}&TILEMATRIXSET=EPSG:3857_qgc_sx_gjjdx_arcgistiles_l13&FORMAT=image/png&TILECOL={x}&TILEROW={y}",
|
"/geoserver/gwc/service/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&LAYER=qgc_sx_gjjdx_arcgistiles_l13&STYLE=&TILEMATRIX=EPSG:3857_qgc_sx_gjjdx_arcgistiles_l13:{z}&TILEMATRIXSET=EPSG:3857_qgc_sx_gjjdx_arcgistiles_l13&FORMAT=image/png&TILECOL={x}&TILEROW={y}",
|
||||||
// matrixIds_index: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],
|
matrixIds_index: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],
|
||||||
// tileMatrixSetID: "EPSG:3857_qgc_sx_gjjdx_arcgistiles_l13",
|
tileMatrixSetID: "EPSG:3857_qgc_sx_gjjdx_arcgistiles_l13",
|
||||||
// });
|
});
|
||||||
// setTimeout(() => {
|
// setTimeout(() => {
|
||||||
mapClass.addBaseDataLayer({
|
// 单个
|
||||||
"id": "hydropBase",
|
// mapClass.addBaseDataLayer({
|
||||||
"key": "hydropBase",
|
// "id": "hydropBase",
|
||||||
"urlType": "gisurl",
|
// "key": "hydropBase",
|
||||||
"url": "https://211.99.26.225:18085/geoserver/gwc/service/tms/1.0.0/qgc%3AstationEra1117@EPSG%3A900913@pbf/{z}/{x}/{y}.pbf",
|
// "urlType": "gisurl",
|
||||||
"geojson_url": "https://211.99.26.225:18085/geoserver/qgc/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=qgc:stationEra1117&maxFeatures=50&outputFormat=application/json&token=bearer a9a0f227-1df3-4e68-b380-2eca5bb49bd1",
|
// "url": "https://211.99.26.225:18085/geoserver/gwc/service/tms/1.0.0/qgc%3AstationEra1117@EPSG%3A900913@pbf/{z}/{x}/{y}.pbf",
|
||||||
"url_3d": "https://211.99.26.225:18085/geoserver/qgc/wms",
|
// "geojson_url": "https://211.99.26.225:18085/geoserver/qgc/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=qgc:stationEra1117&maxFeatures=50&outputFormat=application/json&token=bearer a9a0f227-1df3-4e68-b380-2eca5bb49bd1",
|
||||||
"_layer": "stationEra1117",
|
// "url_3d": "https://211.99.26.225:18085/geoserver/qgc/wms",
|
||||||
"layers": "qgc:stationEra1117",
|
// "_layer": "stationEra1117",
|
||||||
"rasteropacity": 0.5,
|
// "layers": "qgc:stationEra1117",
|
||||||
"visible": true,
|
// "rasteropacity": 0.5,
|
||||||
"minZoom": 0,
|
// "visible": true,
|
||||||
"maxZoom": 20,
|
// "minZoom": 0,
|
||||||
"type": "vector",
|
// "maxZoom": 20,
|
||||||
"layerType": "line",
|
// "type": "vector",
|
||||||
"paint": {
|
// "layerType": "line",
|
||||||
"line-color": "#C5C6F3",
|
// "paint": {
|
||||||
"line-width": 1,
|
// "line-color": "#C5C6F3",
|
||||||
"line-opacity": 1
|
// "line-width": 1,
|
||||||
}
|
// "line-opacity": 1
|
||||||
})
|
// }
|
||||||
|
// })
|
||||||
// }, 2000);
|
// }, 2000);
|
||||||
|
|
||||||
// 梯级流域图
|
// 梯级流域图
|
||||||
|
|||||||
@ -439,7 +439,6 @@ export class MapOl implements MapInterface {
|
|||||||
if (layer.key === 'hydropBase') {
|
if (layer.key === 'hydropBase') {
|
||||||
// this.hydropBaseConfig = layer;
|
// this.hydropBaseConfig = layer;
|
||||||
}
|
}
|
||||||
console.log(this.geoJsonData1)
|
|
||||||
// ✅ 1. 创建矢量源,关键是要配置投影转换
|
// ✅ 1. 创建矢量源,关键是要配置投影转换
|
||||||
const vectorSource = new VectorSource({
|
const vectorSource = new VectorSource({
|
||||||
features: new GeoJSON().readFeatures(this.geoJsonData1, {
|
features: new GeoJSON().readFeatures(this.geoJsonData1, {
|
||||||
|
|||||||
@ -25,6 +25,7 @@
|
|||||||
placeholder="请选择流域"
|
placeholder="请选择流域"
|
||||||
:disabled="isView"
|
:disabled="isView"
|
||||||
show-search
|
show-search
|
||||||
|
allowClear
|
||||||
:filter-option="filterOption"
|
:filter-option="filterOption"
|
||||||
@change="baseChange"
|
@change="baseChange"
|
||||||
>
|
>
|
||||||
@ -47,6 +48,7 @@
|
|||||||
placeholder="请选择电站名称"
|
placeholder="请选择电站名称"
|
||||||
:disabled="isView"
|
:disabled="isView"
|
||||||
show-search
|
show-search
|
||||||
|
allowClear
|
||||||
:filter-option="filterOption"
|
:filter-option="filterOption"
|
||||||
@change="engChange"
|
@change="engChange"
|
||||||
>
|
>
|
||||||
@ -72,6 +74,7 @@
|
|||||||
placeholder="请选择过鱼设施"
|
placeholder="请选择过鱼设施"
|
||||||
:disabled="isView"
|
:disabled="isView"
|
||||||
show-search
|
show-search
|
||||||
|
allowClear
|
||||||
:filter-option="filterOption"
|
:filter-option="filterOption"
|
||||||
>
|
>
|
||||||
<a-select-option
|
<a-select-option
|
||||||
|
|||||||
@ -50,6 +50,11 @@
|
|||||||
批量审批
|
批量审批
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
|
<a-tooltip title="下载模板">
|
||||||
|
<a-button v-hasPerm="['sjtb:import-add']">
|
||||||
|
下载模板
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
<a-tooltip placement="leftBottom">
|
<a-tooltip placement="leftBottom">
|
||||||
<template #title>
|
<template #title>
|
||||||
<div>1.</div>
|
<div>1.</div>
|
||||||
@ -184,7 +189,10 @@ const onSearchFinish = (values: any) => {
|
|||||||
const onValuesChange = (changedValues: any, allValues: any) => {
|
const onValuesChange = (changedValues: any, allValues: any) => {
|
||||||
searchData.value = { ...searchData.value, ...allValues };
|
searchData.value = { ...searchData.value, ...allValues };
|
||||||
// 同步更新本地 searchData,以便其他逻辑使用
|
// 同步更新本地 searchData,以便其他逻辑使用
|
||||||
if (changedValues.rstcd || changedValues.baseId) {
|
if (
|
||||||
|
Object.keys(changedValues)[0] == "rstcd" ||
|
||||||
|
Object.keys(changedValues)[0] == "baseId"
|
||||||
|
) {
|
||||||
shuJuTianBaoStore.getFpssOption(
|
shuJuTianBaoStore.getFpssOption(
|
||||||
allValues.baseId == "all" ? "" : allValues.baseId,
|
allValues.baseId == "all" ? "" : allValues.baseId,
|
||||||
allValues.rstcd
|
allValues.rstcd
|
||||||
|
|||||||
@ -4,8 +4,8 @@
|
|||||||
:loading="fileLoading"
|
:loading="fileLoading"
|
||||||
:data-source="fileTableData"
|
:data-source="fileTableData"
|
||||||
:columns="modalColumns"
|
:columns="modalColumns"
|
||||||
:scroll="{ y: '100%', x: '100%' }"
|
:scroll="{ y: 500, x: '100%' }"
|
||||||
pagination="false"
|
:pagination="false"
|
||||||
:row-key="(record, index) => index"
|
:row-key="(record, index) => index"
|
||||||
>
|
>
|
||||||
<template #bodyCell="{ column, record, index }">
|
<template #bodyCell="{ column, record, index }">
|
||||||
@ -35,13 +35,13 @@
|
|||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div style="color: red; display: flex; align-items: center">
|
<div style="color: red; display: flex; align-items: center">
|
||||||
<span>{{record[column.dataIndex] }}</span>
|
<span>{{ record[column.dataIndex] }}</span>
|
||||||
<exclamation-circle-outlined style="margin-left: 4px" />
|
<exclamation-circle-outlined style="margin-left: 4px" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 3. 编辑状态下的单元格 (绑定到 editingData) -->
|
<!-- 3. 编辑状态下的单元格 (绑定到 editingData) -->
|
||||||
<template v-else-if="isEditing(index)">
|
<template v-else-if="isEditing(index) && column.dataIndex != 'picpth' && column.dataIndex != 'vdpth'">
|
||||||
<template v-if="column.dataIndex === 'baseName'">
|
<template v-if="column.dataIndex === 'baseName'">
|
||||||
<a-select
|
<a-select
|
||||||
v-model:value="editingData.baseId"
|
v-model:value="editingData.baseId"
|
||||||
@ -196,17 +196,28 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 其他默认文本输入 -->
|
|
||||||
<template v-else>
|
|
||||||
<a-input v-model:value="editingData[column.dataIndex]" size="small" />
|
|
||||||
</template>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 4. 普通展示状态 (直接显示 record) -->
|
<template
|
||||||
<!-- <template v-else>
|
v-else-if="column.dataIndex === 'picpth'"
|
||||||
{{ getDisplayValue(column.dataIndex, record) }}
|
>
|
||||||
</template> -->
|
<div class="preview" v-for="(item, index) in record.picpthList">
|
||||||
|
<div class="text" :class="{'text_warning': record.picpthsWarnings.includes(item.name)}" @click="emit('preview-click', record, 'image' ,index)">
|
||||||
|
{{ item.name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="record.picpthList.length==0">暂无图片</div>
|
||||||
|
</template>
|
||||||
|
<template
|
||||||
|
v-else-if="column.dataIndex === 'vdpth'"
|
||||||
|
>
|
||||||
|
<div class="preview" v-for="(item, index) in record.vdpthList">
|
||||||
|
<div class="text" :class="{'text_warning': record.vdpthsWarnings.includes(item.name)}" @click="emit('preview-click', record, 'vdpth' ,index)">
|
||||||
|
{{ item.name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="record.vdpthList.length==0">暂无视频</div>
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</a-table>
|
</a-table>
|
||||||
</template>
|
</template>
|
||||||
@ -217,7 +228,8 @@ import { message, Tag } from "ant-design-vue";
|
|||||||
import { ExclamationCircleOutlined } from "@ant-design/icons-vue";
|
import { ExclamationCircleOutlined } from "@ant-design/icons-vue";
|
||||||
import fishSearch from "@/components/fishSearch/index.vue";
|
import fishSearch from "@/components/fishSearch/index.vue";
|
||||||
import { getBaseDropdown, getEngInfoDropdown, getFpssDropdown } from "@/api/select";
|
import { getBaseDropdown, getEngInfoDropdown, getFpssDropdown } from "@/api/select";
|
||||||
import dayjs from "dayjs";
|
import { CloseCircleOutlined } from "@ant-design/icons-vue";
|
||||||
|
import { es } from "element-plus/es/locale/index.mjs";
|
||||||
|
|
||||||
const props: any = defineProps({
|
const props: any = defineProps({
|
||||||
fileTableData: { type: Array, default: () => [] },
|
fileTableData: { type: Array, default: () => [] },
|
||||||
@ -225,7 +237,7 @@ const props: any = defineProps({
|
|||||||
direction: { type: Array, default: () => [] },
|
direction: { type: Array, default: () => [] },
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(["update:fileTableData"]);
|
const emit = defineEmits(["update:fileTableData", "preview-click"]);
|
||||||
|
|
||||||
// --- 状态管理 ---
|
// --- 状态管理 ---
|
||||||
const editingRowIndex = ref<number | null>(null);
|
const editingRowIndex = ref<number | null>(null);
|
||||||
@ -236,9 +248,27 @@ const rowStates = reactive<Record<number, any>>({});
|
|||||||
const editingData = ref<any>(null);
|
const editingData = ref<any>(null);
|
||||||
|
|
||||||
const modalColumns = ref([
|
const modalColumns = ref([
|
||||||
{ dataIndex: "baseName", key: "baseName", dataIndexKey: "baseId", title: "流域", width: 140 },
|
{
|
||||||
{ dataIndex: "ennm", key: "ennm", dataIndexKey: "rstcd", title: "电站名称", width: 140 },
|
dataIndex: "baseName",
|
||||||
{ dataIndex: "stnm", key: "stnm", dataIndexKey: "stcd", title: "过鱼设施名称", width: 150 },
|
key: "baseName",
|
||||||
|
dataIndexKey: "baseId",
|
||||||
|
title: "流域",
|
||||||
|
width: 140,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: "ennm",
|
||||||
|
key: "ennm",
|
||||||
|
dataIndexKey: "rstcd",
|
||||||
|
title: "电站名称",
|
||||||
|
width: 140,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: "stnm",
|
||||||
|
key: "stnm",
|
||||||
|
dataIndexKey: "stcd",
|
||||||
|
title: "过鱼设施名称",
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
{ dataIndex: "strdt", key: "strdt", title: "过鱼时间", width: 190 },
|
{ dataIndex: "strdt", key: "strdt", title: "过鱼时间", width: 190 },
|
||||||
{ dataIndex: "ftpName", key: "ftpName", title: "鱼种类", width: 120 },
|
{ dataIndex: "ftpName", key: "ftpName", title: "鱼种类", width: 120 },
|
||||||
{
|
{
|
||||||
@ -258,17 +288,15 @@ const modalColumns = ref([
|
|||||||
key: "direction",
|
key: "direction",
|
||||||
title: "游向",
|
title: "游向",
|
||||||
width: 120,
|
width: 120,
|
||||||
customRender: ({ text }: any) => {
|
customRender: ({ text }: any) => props.direction.find((item: any) => item.itemCode === text)?.dictName || "-"
|
||||||
console.log(props.direction)
|
,
|
||||||
return props.direction.find((item: any) => item.itemCode === text)?.dictName || "-"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{ dataIndex: "fcnt", key: "fcnt", title: "过鱼数量(尾)", width: 120 },
|
{ dataIndex: "fcnt", key: "fcnt", title: "过鱼数量(尾)", width: 120 },
|
||||||
{ dataIndex: "fsz", key: "fsz", title: "体长(cm)", width: 160 },
|
{ dataIndex: "fsz", key: "fsz", title: "体长(cm)", width: 160 },
|
||||||
{ dataIndex: "fwet", key: "fwet", title: "平均体重(g)", width: 160 },
|
{ dataIndex: "fwet", key: "fwet", title: "平均体重(g)", width: 160 },
|
||||||
{ dataIndex: "wt", key: "wt", title: "水温(℃)", width: 80 },
|
{ dataIndex: "wt", key: "wt", title: "水温(℃)", width: 80 },
|
||||||
{ dataIndex: "picpth", key: "level5", title: "图片", width: 100 },
|
{ dataIndex: "picpth", key: "picpth", title: "图片", width: 160 },
|
||||||
{ dataIndex: "vdpth", key: "level6", title: "视频", width: 100 },
|
{ dataIndex: "vdpth", key: "vdpth", title: "视频", width: 160 },
|
||||||
{
|
{
|
||||||
title: "操作",
|
title: "操作",
|
||||||
key: "action",
|
key: "action",
|
||||||
@ -309,12 +337,14 @@ const ensureRowState = (index: number) => {
|
|||||||
// --- 级联逻辑 (操作 editingData) ---
|
// --- 级联逻辑 (操作 editingData) ---
|
||||||
|
|
||||||
const handleBaseChange = async (baseId: string, index: number) => {
|
const handleBaseChange = async (baseId: string, index: number) => {
|
||||||
console.log(baseId)
|
console.log(baseId);
|
||||||
editingData.value.baseName = baseOptions.value.find(
|
editingData.value.baseName = baseOptions.value.find(
|
||||||
(item: any) => item.baseid == baseId
|
(item: any) => item.baseid == baseId
|
||||||
)?.basename;
|
)?.basename;
|
||||||
if (baseId && editingData.value._warnings) {
|
if (baseId && editingData.value._warnings) {
|
||||||
editingData.value._warnings = editingData.value._warnings.filter((w: string) => w !== 'baseName');
|
editingData.value._warnings = editingData.value._warnings.filter(
|
||||||
|
(w: string) => w !== "baseName"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const state = ensureRowState(index);
|
const state = ensureRowState(index);
|
||||||
// 清空后续字段
|
// 清空后续字段
|
||||||
@ -338,7 +368,9 @@ const handleBaseChange = async (baseId: string, index: number) => {
|
|||||||
const handleEngChange = async (rstcd: string, index: number) => {
|
const handleEngChange = async (rstcd: string, index: number) => {
|
||||||
const state = ensureRowState(index);
|
const state = ensureRowState(index);
|
||||||
if (rstcd && editingData.value._warnings) {
|
if (rstcd && editingData.value._warnings) {
|
||||||
editingData.value._warnings = editingData.value._warnings.filter((w: string) => w !== 'ennm');
|
editingData.value._warnings = editingData.value._warnings.filter(
|
||||||
|
(w: string) => w !== "ennm"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
editingData.value.ennm = state.engOptions.find(
|
editingData.value.ennm = state.engOptions.find(
|
||||||
(item: any) => item.stcd === rstcd
|
(item: any) => item.stcd === rstcd
|
||||||
@ -360,7 +392,9 @@ const handleEngChange = async (rstcd: string, index: number) => {
|
|||||||
const handleFpssChange = (stcd: string, index: number) => {
|
const handleFpssChange = (stcd: string, index: number) => {
|
||||||
const state = ensureRowState(index);
|
const state = ensureRowState(index);
|
||||||
if (stcd && editingData.value._warnings) {
|
if (stcd && editingData.value._warnings) {
|
||||||
editingData.value._warnings = editingData.value._warnings.filter((w: string) => w !== 'stnm');
|
editingData.value._warnings = editingData.value._warnings.filter(
|
||||||
|
(w: string) => w !== "stnm"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
editingData.value.stnm = state.fpssOptions.find(
|
editingData.value.stnm = state.fpssOptions.find(
|
||||||
(item: any) => item.stcd === stcd
|
(item: any) => item.stcd === stcd
|
||||||
@ -483,22 +517,36 @@ const handleFtpChange = (val: any, opt: any) => {
|
|||||||
editingData.value.ftpName = opt.name;
|
editingData.value.ftpName = opt.name;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- 辅助函数 ---
|
|
||||||
|
|
||||||
|
// --- 辅助函数 ---
|
||||||
const filterOption = (input: string, option: any) => {
|
const filterOption = (input: string, option: any) => {
|
||||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 统一获取显示值
|
|
||||||
const getDisplayValue = (dataIndex: string, record: any) => {
|
|
||||||
const val = record[dataIndex];
|
|
||||||
if (val === undefined || val === null) return "-";
|
|
||||||
if (dataIndex === "isfs") return val === 1 ? "是" : "否";
|
|
||||||
if (dataIndex === "strdt") return val ? dayjs(val).format("YYYY-MM-DD HH:mm:ss") : "-";
|
|
||||||
return val;
|
|
||||||
};
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
editingRowIndex,
|
editingRowIndex,
|
||||||
editingData,
|
editingData,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.preview {
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #1890ff;
|
||||||
|
&:hover {
|
||||||
|
color: #40a9ff;
|
||||||
|
}
|
||||||
|
display: flex;
|
||||||
|
justify-content: justify-between;
|
||||||
|
align-items: center;
|
||||||
|
.text {
|
||||||
|
width: 120px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.text_warning {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -21,6 +21,7 @@
|
|||||||
:search-params="{}"
|
:search-params="{}"
|
||||||
:enable-row-selection="true"
|
:enable-row-selection="true"
|
||||||
:get-checkbox-props="getCheckboxProps"
|
:get-checkbox-props="getCheckboxProps"
|
||||||
|
:transform-data="customTransform"
|
||||||
@selection-change="handleSelectionChange"
|
@selection-change="handleSelectionChange"
|
||||||
>
|
>
|
||||||
<!-- 使用 bodyCell 插槽自定义单元格渲染 -->
|
<!-- 使用 bodyCell 插槽自定义单元格渲染 -->
|
||||||
@ -94,18 +95,17 @@
|
|||||||
cancel-text="取消导入"
|
cancel-text="取消导入"
|
||||||
:width="1500"
|
:width="1500"
|
||||||
v-model:open="visible"
|
v-model:open="visible"
|
||||||
maskClosable="false"
|
:maskClosable="false"
|
||||||
:confirm-loading="fileLoading"
|
:confirm-loading="fileLoading"
|
||||||
>
|
>
|
||||||
<div class="w-full h-[500px]">
|
|
||||||
<GuoYuSheShiShuJuTianBaoTable
|
<GuoYuSheShiShuJuTianBaoTable
|
||||||
ref="modalTableRef"
|
ref="modalTableRef"
|
||||||
:fileLoading="fileLoading"
|
:fileLoading="fileLoading"
|
||||||
:fileTableData="fileTableData"
|
:fileTableData="fileTableData"
|
||||||
:direction="direction"
|
:direction="direction"
|
||||||
@update:file-table-data="(val) => fileTableData = val"
|
@preview-click="handlePreviewClick"
|
||||||
|
@update:file-table-data="(val) => (fileTableData = val)"
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<a-button key="back" @click="handleCustomCancel">取消导入</a-button>
|
<a-button key="back" @click="handleCustomCancel">取消导入</a-button>
|
||||||
<a-button
|
<a-button
|
||||||
@ -120,7 +120,6 @@
|
|||||||
</a-modal>
|
</a-modal>
|
||||||
|
|
||||||
<!-- 新增/编辑 Modal (对应 React 的 EditModal) -->
|
<!-- 新增/编辑 Modal (对应 React 的 EditModal) -->
|
||||||
<!-- 假设已创建对应的 Vue 组件 GuoYuSheShiShuJuTianBaoForm -->
|
|
||||||
<EditModal
|
<EditModal
|
||||||
v-model:visible="editModalVisible"
|
v-model:visible="editModalVisible"
|
||||||
:is-view="isView"
|
:is-view="isView"
|
||||||
@ -131,23 +130,104 @@
|
|||||||
@ok="handleEditSubmit"
|
@ok="handleEditSubmit"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 视频预览 Modal -->
|
<!-- 媒体预览 Modal -->
|
||||||
<a-modal
|
<a-modal
|
||||||
title="视频预览"
|
v-model:open="mediaPreviewVisible"
|
||||||
v-model:open="videoPreviewVisible"
|
:title="videoPreviewTitle"
|
||||||
:footer="null"
|
:footer="null"
|
||||||
width="800px"
|
width="900px"
|
||||||
@cancel="closeVideoPreview"
|
@cancel="closeMediaPreview"
|
||||||
>
|
>
|
||||||
<video
|
<div class="flex h-[60vh] gap-4">
|
||||||
v-if="currentVideoUrl"
|
<!-- 左侧:混合列表 (图片+视频) -->
|
||||||
controls
|
<div class="w-1/4 overflow-y-auto border-r pr-2 media-list-container">
|
||||||
autoplay
|
<div
|
||||||
style="width: 100%"
|
v-for="(item, index) in previewList"
|
||||||
:src="currentVideoUrl"
|
:key="index"
|
||||||
>
|
class="mb-2 cursor-pointer list-item"
|
||||||
您的浏览器不支持视频播放
|
:class="{ select: index === currentMediaIndex }"
|
||||||
</video>
|
@click="currentMediaIndex = index"
|
||||||
|
>
|
||||||
|
<span class="file-name">{{ item.name }}</span>
|
||||||
|
|
||||||
|
<!-- 删除按钮 -->
|
||||||
|
<div class="list-item-delete" @click.stop="handleDeleteMedia(item, index)">
|
||||||
|
<CloseCircleOutlined />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧:动态预览区域 -->
|
||||||
|
<div
|
||||||
|
class="w-3/4 flex flex-col items-center justify-center bg-gray-100 relative p-4"
|
||||||
|
>
|
||||||
|
<!-- 图片预览 -->
|
||||||
|
<a-image
|
||||||
|
v-if="
|
||||||
|
currentMediaItem &&
|
||||||
|
currentMediaItem.url != '' &&
|
||||||
|
currentMediaItem.type === 'image'
|
||||||
|
"
|
||||||
|
:src="currentMediaItem.url"
|
||||||
|
class="max-w-full max-h-full object-contain"
|
||||||
|
:preview="{ visible: false }"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-else-if="
|
||||||
|
currentMediaItem &&
|
||||||
|
currentMediaItem.url == '' &&
|
||||||
|
currentMediaItem.type === 'image'
|
||||||
|
"
|
||||||
|
class="text-gray-400"
|
||||||
|
>
|
||||||
|
暂无图片预览
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 视频预览 -->
|
||||||
|
<video
|
||||||
|
v-else-if="
|
||||||
|
currentMediaItem &&
|
||||||
|
currentMediaItem.url != '' &&
|
||||||
|
currentMediaItem.type === 'video'
|
||||||
|
"
|
||||||
|
:src="currentMediaItem.url"
|
||||||
|
controls
|
||||||
|
autoplay
|
||||||
|
class="max-w-full max-h-[50vh]"
|
||||||
|
>
|
||||||
|
您的浏览器不支持视频播放
|
||||||
|
</video>
|
||||||
|
<div
|
||||||
|
v-else-if="
|
||||||
|
currentMediaItem &&
|
||||||
|
currentMediaItem.url == '' &&
|
||||||
|
currentMediaItem.type === 'video'
|
||||||
|
"
|
||||||
|
class="text-gray-400"
|
||||||
|
>
|
||||||
|
暂无视频预览
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部切换控制 -->
|
||||||
|
<div class="absolute bottom-4 flex gap-4 z-10">
|
||||||
|
<a-button
|
||||||
|
shape="circle"
|
||||||
|
:icon="h(LeftOutlined)"
|
||||||
|
@click="prevMedia"
|
||||||
|
:disabled="currentMediaIndex === 0"
|
||||||
|
/>
|
||||||
|
<span class="self-center text-gray-600 bg-white px-2 rounded shadow-sm">
|
||||||
|
{{ currentMediaIndex + 1 }} / {{ previewList.length }}
|
||||||
|
</span>
|
||||||
|
<a-button
|
||||||
|
shape="circle"
|
||||||
|
:icon="h(RightOutlined)"
|
||||||
|
@click="nextMedia"
|
||||||
|
:disabled="currentMediaIndex === previewList.length - 1"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -155,10 +235,12 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed, onMounted, h, nextTick } from "vue";
|
import { ref, computed, onMounted, h, nextTick } from "vue";
|
||||||
import { message, Modal } from "ant-design-vue"; // 假设使用 ant-design-vue
|
import { message, Modal } from "ant-design-vue"; // 假设使用 ant-design-vue
|
||||||
|
import { LeftOutlined, RightOutlined, CloseCircleOutlined } from "@ant-design/icons-vue"; // 引入图标组件
|
||||||
import BasicTable from "@/components/BasicTable/index.vue";
|
import BasicTable from "@/components/BasicTable/index.vue";
|
||||||
import GuoYuSheShiShuJuTianBaoSearch from "./guoYuSheShiShuJuTianBaoSearch.vue";
|
import GuoYuSheShiShuJuTianBaoSearch from "./guoYuSheShiShuJuTianBaoSearch.vue";
|
||||||
import GuoYuSheShiShuJuTianBaoTable from "./guoYuSheShiShuJuTianBaoTable.vue";
|
import GuoYuSheShiShuJuTianBaoTable from "./guoYuSheShiShuJuTianBaoTable.vue";
|
||||||
import EditModal from "./guoYuSheShiShuJuTianBaoForm.vue";
|
import EditModal from "./guoYuSheShiShuJuTianBaoForm.vue";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getFishDraftPage,
|
getFishDraftPage,
|
||||||
addFishDraft,
|
addFishDraft,
|
||||||
@ -172,12 +254,14 @@ import {
|
|||||||
checkImportStatus,
|
checkImportStatus,
|
||||||
batchSaveDraft,
|
batchSaveDraft,
|
||||||
getLastImportResult,
|
getLastImportResult,
|
||||||
markImportTaskSuccess
|
markImportTaskSuccess,
|
||||||
} from "@/api/guoYuSheShiShuJuTianBao";
|
} from "@/api/guoYuSheShiShuJuTianBao";
|
||||||
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 dayjs from "dayjs";
|
||||||
// import { FileImageOutlined, VideoCameraOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons-vue'
|
// import { FileImageOutlined, VideoCameraOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons-vue'
|
||||||
|
|
||||||
|
const baseUrl = import.meta.env.VITE_APP_PREVIEW_URL;
|
||||||
// --- 类型定义 ---
|
// --- 类型定义 ---
|
||||||
interface FormData {
|
interface FormData {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
@ -238,14 +322,12 @@ const baseColumnsConfig: ColumnConfig[] = [
|
|||||||
{ dataIndex: "fsz", key: "fsz", title: "体长(cm)", width: 110 },
|
{ dataIndex: "fsz", key: "fsz", title: "体长(cm)", width: 110 },
|
||||||
{ dataIndex: "fwet", key: "fwet", title: "平均体重(g)", width: 110 },
|
{ dataIndex: "fwet", key: "fwet", title: "平均体重(g)", width: 110 },
|
||||||
{ dataIndex: "wt", key: "wt", title: "水温(℃)", width: 80 },
|
{ dataIndex: "wt", key: "wt", title: "水温(℃)", width: 80 },
|
||||||
{ dataIndex: "picpth", key: "level5", title: "图片", width: 100 },
|
|
||||||
{ dataIndex: "vdpth", key: "level6", title: "视频", width: 100 },
|
|
||||||
{ dataIndex: "tm", key: "tm", title: "填报时间", width: 150 },
|
{ dataIndex: "tm", key: "tm", title: "填报时间", width: 150 },
|
||||||
{
|
{
|
||||||
dataIndex: "status",
|
dataIndex: "status",
|
||||||
key: "status",
|
key: "status",
|
||||||
title: "状态",
|
title: "状态",
|
||||||
width: 100,
|
width: 74,
|
||||||
customRender: ({ text }: any) => {
|
customRender: ({ text }: any) => {
|
||||||
let data = guoyuStatus.value.find((item: any) => item.itemCode === text);
|
let data = guoyuStatus.value.find((item: any) => item.itemCode === text);
|
||||||
return h(
|
return h(
|
||||||
@ -268,9 +350,19 @@ const isView = ref(false);
|
|||||||
const currentRecord = ref<FormData | null>(null);
|
const currentRecord = ref<FormData | null>(null);
|
||||||
const submitLoading = ref(false);
|
const submitLoading = ref(false);
|
||||||
|
|
||||||
// 视频预览相关状态
|
const mediaPreviewVisible = ref(false);
|
||||||
const videoPreviewVisible = ref(false);
|
const videoPreviewTitle = ref("视频预览");
|
||||||
const currentVideoUrl = ref<string>("");
|
interface MediaItem {
|
||||||
|
type: "image" | "video";
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
const previewList = ref<MediaItem[]>([]);
|
||||||
|
const currentMediaIndex = ref(0);
|
||||||
|
const tablePreviewRecord = ref<any>({});
|
||||||
|
|
||||||
|
// 计算当前选中的项
|
||||||
|
const currentMediaItem = computed(() => previewList.value[currentMediaIndex.value]);
|
||||||
|
|
||||||
// 表格数据
|
// 表格数据
|
||||||
const fileTableData = ref<any[]>([]);
|
const fileTableData = ref<any[]>([]);
|
||||||
@ -460,11 +552,14 @@ const handleReject = (id: any) => {
|
|||||||
};
|
};
|
||||||
// 多选禁用
|
// 多选禁用
|
||||||
const getCheckboxProps = (record: any) => {
|
const getCheckboxProps = (record: any) => {
|
||||||
console.log(record)
|
|
||||||
return {
|
return {
|
||||||
disabled: record.status === 'SUBMITTED' || record.status === 'APPROVED',
|
disabled: ['SUBMITTED', 'APPROVED'].includes(record.status),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
const handleDataLoaded = (params: any, data: any) => {
|
||||||
|
console.log(params, data);
|
||||||
|
return
|
||||||
|
};
|
||||||
// 多选
|
// 多选
|
||||||
const handleSelectionChange = (keys: any) => {
|
const handleSelectionChange = (keys: any) => {
|
||||||
batchData.value = keys;
|
batchData.value = keys;
|
||||||
@ -506,8 +601,10 @@ const isRowDataEqual = (oldRow: any, newRow: any, fields: string[]): boolean =>
|
|||||||
let newVal = newRow?.[field];
|
let newVal = newRow?.[field];
|
||||||
|
|
||||||
// 特殊处理:如果都是空值,视为相等
|
// 特殊处理:如果都是空值,视为相等
|
||||||
if ((oldVal === undefined || oldVal === null || oldVal === '') &&
|
if (
|
||||||
(newVal === undefined || newVal === null || newVal === '')) {
|
(oldVal === undefined || oldVal === null || oldVal === "") &&
|
||||||
|
(newVal === undefined || newVal === null || newVal === "")
|
||||||
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -537,7 +634,7 @@ const checkTableDataChanges = () => {
|
|||||||
const newRow = newData[i];
|
const newRow = newData[i];
|
||||||
|
|
||||||
// 如果某一行数据不一致,计数+1
|
// 如果某一行数据不一致,计数+1
|
||||||
if (!isRowDataEqual(oldRow, newRow, ['baseId'])) {
|
if (!isRowDataEqual(oldRow, newRow, ["baseId"])) {
|
||||||
changedCount++;
|
changedCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -547,30 +644,46 @@ const checkTableDataChanges = () => {
|
|||||||
|
|
||||||
// 提交导入
|
// 提交导入
|
||||||
const handleModalOk = () => {
|
const handleModalOk = () => {
|
||||||
console.log(orgFileTableData.value)
|
console.log(orgFileTableData.value);
|
||||||
console.log(fileTableData.value)
|
console.log(fileTableData.value);
|
||||||
console.log(modalTableRef.value.editingData)
|
console.log(modalTableRef.value.editingData);
|
||||||
if (modalTableRef.value.editingData != undefined) {
|
if (modalTableRef.value.editingData != undefined) {
|
||||||
message.warning("请点击保存后提交数据!");
|
message.warning("请点击保存后提交数据!");
|
||||||
return
|
|
||||||
}
|
|
||||||
const { hasChanged, changedCount } = checkTableDataChanges();
|
|
||||||
|
|
||||||
// 3. 如果没有变化,直接返回,不执行后续操作
|
|
||||||
if (!hasChanged) {
|
|
||||||
message.info("数据未发生任何变化,无需提交");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log(123)
|
for (let i = 0; i < fileTableData.value.length; i++) {
|
||||||
|
// if (fileTableData.value[i]._warnings?.length > 0) {
|
||||||
|
// message.warning("请检查数据,标红部分数据有误!");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
if (fileTableData.value[i].picpthsWarnings?.length > 0) {
|
||||||
|
message.warning("请检查图片,图片路径有误!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (fileTableData.value[i].vdpthsWarnings?.length > 0) {
|
||||||
|
message.warning("请检查视频,视频路径有误!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fileTableData.value.forEach((item) => {
|
||||||
|
item.tm = dayjs().format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
});
|
||||||
|
// const { hasChanged, changedCount } = checkTableDataChanges();
|
||||||
|
|
||||||
|
// // 3. 如果没有变化,直接返回,不执行后续操作
|
||||||
|
// if (!hasChanged) {
|
||||||
|
// message.info("数据未发生任何变化,无需提交");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: "是否提交导入数据?",
|
title: "是否提交导入数据?",
|
||||||
onOk: async () => {
|
onOk: async () => {
|
||||||
let res: any = await batchSaveDraft(fileTableData.value);
|
let res: any = await batchSaveDraft(fileTableData.value);
|
||||||
if (res && res?.code == 0) {
|
if (res && res?.code == 0) {
|
||||||
message.success("导入成功");
|
message.success("导入成功");
|
||||||
visible.value = false;
|
|
||||||
tableRef.value?.getList();
|
tableRef.value?.getList();
|
||||||
await markImportTaskSuccess({id: taskId.value});
|
visible.value = false;
|
||||||
|
await markImportTaskSuccess({ id: taskId.value });
|
||||||
} else {
|
} else {
|
||||||
message.error("导入失败,请检查数据是否正确");
|
message.error("导入失败,请检查数据是否正确");
|
||||||
}
|
}
|
||||||
@ -586,7 +699,7 @@ const handleCustomCancel = () => {
|
|||||||
okText: "确定",
|
okText: "确定",
|
||||||
onOk: async () => {
|
onOk: async () => {
|
||||||
// 可选:调用取消接口
|
// 可选:调用取消接口
|
||||||
let res: any = await cancelImportTask({taskId: taskId.value});
|
let res: any = await cancelImportTask({ taskId: taskId.value });
|
||||||
if (res && res?.code == 0) {
|
if (res && res?.code == 0) {
|
||||||
message.success("取消成功");
|
message.success("取消成功");
|
||||||
tableRef.value?.getList();
|
tableRef.value?.getList();
|
||||||
@ -600,7 +713,7 @@ const importBtn = async () => {
|
|||||||
let res: any = await checkImportStatus();
|
let res: any = await checkImportStatus();
|
||||||
taskId.value = "";
|
taskId.value = "";
|
||||||
if (res?.code == 0) {
|
if (res?.code == 0) {
|
||||||
const { hasImportingTask, currentTask} = res?.data || {};
|
const { hasImportingTask, currentTask } = res?.data || {};
|
||||||
if (currentTask) {
|
if (currentTask) {
|
||||||
taskId.value = currentTask.id;
|
taskId.value = currentTask.id;
|
||||||
}
|
}
|
||||||
@ -626,26 +739,28 @@ const importBtn = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
// 上传文件
|
// 上传文件
|
||||||
const fileChange = async (file: File) => {
|
const fileChange = (file: File) => {
|
||||||
try {
|
try {
|
||||||
visible.value = true;
|
nextTick(async () => {
|
||||||
fileLoading.value = true;
|
visible.value = true;
|
||||||
const formData = new FormData();
|
fileLoading.value = true;
|
||||||
formData.append("file", file);
|
fileTableData.value = [];
|
||||||
let res: any = await importFishZip(formData);
|
const formData = new FormData();
|
||||||
const { code } = res.data || {};
|
formData.append("file", file);
|
||||||
if (code == 1) {
|
let res: any = await importFishZip(formData);
|
||||||
message.error("导入失败");
|
const { code } = res.data || {};
|
||||||
} else {
|
if (code == 1) {
|
||||||
taskId.value = res.data.taskId;
|
message.error("导入失败");
|
||||||
message.success("导入成功");
|
} else {
|
||||||
fileTableaAnalysis(res, "file");
|
taskId.value = res.data.taskId;
|
||||||
}
|
message.success("导入成功");
|
||||||
|
fileTableaAnalysis(res, "file");
|
||||||
|
}
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
} finally {
|
} finally {
|
||||||
fileLoading.value = false;
|
fileLoading.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
// 获取文件列表
|
// 获取文件列表
|
||||||
const handleFileSelect = (e: Event) => {
|
const handleFileSelect = (e: Event) => {
|
||||||
@ -689,10 +804,13 @@ const fileTableaAnalysis = (res: any, type: string) => {
|
|||||||
} else {
|
} else {
|
||||||
list = res.data.result.failedRowDetails;
|
list = res.data.result.failedRowDetails;
|
||||||
}
|
}
|
||||||
console.log(list);
|
|
||||||
list.forEach((item) => {
|
list.forEach((item) => {
|
||||||
data.push({
|
data.push({
|
||||||
...item.data,
|
...item.data,
|
||||||
|
vdpthList: item.vdpthList,
|
||||||
|
vdpthsWarnings: item.vdpthsWarnings,
|
||||||
|
picpthList: item.picpthList,
|
||||||
|
picpthsWarnings: item.picpthsWarnings,
|
||||||
_warnings: item.warnings,
|
_warnings: item.warnings,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -703,6 +821,20 @@ const fileTableaAnalysis = (res: any, type: string) => {
|
|||||||
const handleReset = (values) => {
|
const handleReset = (values) => {
|
||||||
handleSearchFinish(values);
|
handleSearchFinish(values);
|
||||||
};
|
};
|
||||||
|
// 自定义数据转换函数
|
||||||
|
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 handleSearchFinish = (values: any) => {
|
const handleSearchFinish = (values: any) => {
|
||||||
const filters = [
|
const filters = [
|
||||||
@ -762,10 +894,100 @@ const handleSearchFinish = (values: any) => {
|
|||||||
};
|
};
|
||||||
tableRef.value?.getList(filter);
|
tableRef.value?.getList(filter);
|
||||||
};
|
};
|
||||||
|
// 处理预览点击 (由子组件触发)
|
||||||
|
const handlePreviewClick = (record: any, type: string, index: number) => {
|
||||||
|
const mixedList: MediaItem[] = [];
|
||||||
|
tablePreviewRecord.value = record;
|
||||||
|
if (type === "image") {
|
||||||
|
videoPreviewTitle.value = "图片预览";
|
||||||
|
const nameList = record.picpthList;
|
||||||
|
nameList.forEach((item: any) => {
|
||||||
|
mixedList.push({
|
||||||
|
type: "image",
|
||||||
|
name: item.name,
|
||||||
|
url: item.value ? `${baseUrl}/?${item.value}` : "",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
videoPreviewTitle.value = "视频预览";
|
||||||
|
const nameList = record.vdpthList;
|
||||||
|
nameList.forEach((item: any) => {
|
||||||
|
mixedList.push({
|
||||||
|
type: "video",
|
||||||
|
name: item.name, // 视频通常没有单独的名称字段,可根据需要调整
|
||||||
|
url: item.value ? `${baseUrl}/?${item.value}` : "",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const closeVideoPreview = () => {
|
mediaPreviewVisible.value = true;
|
||||||
videoPreviewVisible.value = false;
|
currentMediaIndex.value = index;
|
||||||
currentVideoUrl.value = "";
|
nextTick(() => {
|
||||||
|
previewList.value = mixedList;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 【新增】统一切换逻辑
|
||||||
|
const prevMedia = () => {
|
||||||
|
if (currentMediaIndex.value > 0) {
|
||||||
|
currentMediaIndex.value--;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const nextMedia = () => {
|
||||||
|
if (currentMediaIndex.value < previewList.value.length - 1) {
|
||||||
|
currentMediaIndex.value++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 【新增】统一删除逻辑
|
||||||
|
const handleDeleteMedia = (item: any, index: number) => {
|
||||||
|
Modal.confirm({
|
||||||
|
title: "确认删除",
|
||||||
|
content: "确定要从预览列表中移除该项吗?",
|
||||||
|
onOk: () => {
|
||||||
|
previewList.value.splice(index, 1);
|
||||||
|
console.log(previewList.value);
|
||||||
|
if (videoPreviewTitle.value == "图片预览") {
|
||||||
|
if (previewList.value.length == 0) {
|
||||||
|
tablePreviewRecord.value.picpthList = [];
|
||||||
|
tablePreviewRecord.value.picpthsWarnings = [];
|
||||||
|
} else {
|
||||||
|
tablePreviewRecord.value.picpthList.splice(index, 1);
|
||||||
|
tablePreviewRecord.value.picpthsWarnings = tablePreviewRecord.value.picpthsWarnings.filter(
|
||||||
|
(warningName: any) => warningName !== item.name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (previewList.value.length == 0) {
|
||||||
|
tablePreviewRecord.value.vdpthList = [];
|
||||||
|
tablePreviewRecord.value.vdpthsWarnings = [];
|
||||||
|
} else {
|
||||||
|
tablePreviewRecord.value.vdpthList.splice(index, 1);
|
||||||
|
tablePreviewRecord.value.vdpthsWarnings = tablePreviewRecord.value.vdpthsWarnings.filter(
|
||||||
|
(warningName: any) => warningName !== item.name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previewList.value.length === 0) {
|
||||||
|
mediaPreviewVisible.value = false;
|
||||||
|
} else {
|
||||||
|
// 调整索引
|
||||||
|
if (index <= currentMediaIndex.value) {
|
||||||
|
currentMediaIndex.value = Math.max(0, currentMediaIndex.value - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeMediaPreview = () => {
|
||||||
|
mediaPreviewVisible.value = false;
|
||||||
|
nextTick(() => {
|
||||||
|
previewList.value = [];
|
||||||
|
currentMediaIndex.value = 0;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- 生命周期 ---
|
// --- 生命周期 ---
|
||||||
@ -786,4 +1008,53 @@ onMounted(() => {
|
|||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
.media-list-container {
|
||||||
|
background-color: rgb(234, 241, 251);
|
||||||
|
padding: 10px;
|
||||||
|
|
||||||
|
.list-item {
|
||||||
|
width: 100%;
|
||||||
|
height: 36px;
|
||||||
|
line-height: 36px;
|
||||||
|
padding: 0 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
.file-name {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.select {
|
||||||
|
color: #ffffff;
|
||||||
|
background-color: rgb(37, 93, 138);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item-delete {
|
||||||
|
color: red;
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
margin-left: 8px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .list-item-delete {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user