WholeProcessPlatform/frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBao/index.vue
扈兆增 10c3c33ad0 导入流程走通,预览导入图片和视频
Co-authored-by: Copilot <copilot@github.com>
2026-04-27 19:11:22 +08:00

1061 lines
29 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="guoYuSheShiShuJuTianBao-page">
<GuoYuSheShiShuJuTianBaoSearch
ref="searchRef"
:guoyuStatus="guoyuStatus"
:direction="direction"
:handle-add="handleAdd"
:batchData="batchData"
:importBtn="importBtn"
:batchDelBtn="batchDelBtn"
:submitBtn="submitBtn"
:successBtn="successBtn"
@reset="handleReset"
@search-finish="handleSearchFinish"
/>
<!-- 主表格 -->
<BasicTable
ref="tableRef"
:columns="columns"
:list-url="getFishDraftPage"
:search-params="{}"
:enable-row-selection="true"
:get-checkbox-props="getCheckboxProps"
:transform-data="customTransform"
@selection-change="handleSelectionChange"
>
<!-- 使用 bodyCell 插槽自定义单元格渲染 -->
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action' || column.dataIndex === 'action'">
<div class="flex">
<a-button
type="link"
size="small"
@click="handleSubmit([record.id])"
v-if="record.status === 'DRAFT' || record.status === 'REJECTED'"
>提交</a-button
>
<a-button
type="link"
size="small"
@click="handleEdit(record, 'edit')"
v-if="
record.status === 'DRAFT' ||
record.status === 'REJECTED' ||
record.status === 'SUBMITTED'
"
>编辑</a-button
>
<a-button
type="link"
danger
size="small"
@click="handleDelete([record.id])"
v-if="record.status === 'DRAFT' || record.status === 'REJECTED'"
>删除</a-button
>
<a-button
type="link"
size="small"
@click="handleEdit(record, 'view')"
v-if="record.status === 'SUBMITTED' || record.status === 'APPROVED'"
>查看</a-button
>
<a-button
type="link"
size="small"
@click="handleSuccess([record.id])"
v-if="record.status === 'SUBMITTED'"
>审批</a-button
>
<a-button
type="link"
danger
size="small"
@click="handleReject(record.id)"
v-if="record.status === 'SUBMITTED'"
>驳回</a-button
>
</div>
</template>
</template>
</BasicTable>
<!-- 隐藏的文件输入框 -->
<input
ref="fileInputRef"
type="file"
accept=".zip,application/zip,application/x-zip-compressed"
style="display: none"
@change="handleFileSelect"
/>
<!-- 导入预览 Modal -->
<a-modal
title="导入数据预览"
ok-text="提交导入"
cancel-text="取消导入"
:width="1500"
v-model:open="visible"
:maskClosable="false"
:confirm-loading="fileLoading"
>
<GuoYuSheShiShuJuTianBaoTable
ref="modalTableRef"
:fileLoading="fileLoading"
:fileTableData="fileTableData"
:direction="direction"
@preview-click="handlePreviewClick"
@update:file-table-data="(val) => (fileTableData = val)"
/>
<template #footer>
<a-button key="back" @click="handleCustomCancel">取消导入</a-button>
<a-button
key="submit"
type="primary"
:loading="fileLoading"
@click="handleModalOk"
>
提交导入
</a-button>
</template>
</a-modal>
<!-- 新增/编辑 Modal (对应 React 的 EditModal) -->
<EditModal
v-model:visible="editModalVisible"
:is-view="isView"
:direction="direction"
:initial-values="currentRecord"
:loading="submitLoading"
@cancel="editModalCancel"
@ok="handleEditSubmit"
/>
<!-- 媒体预览 Modal -->
<a-modal
v-model:open="mediaPreviewVisible"
:title="videoPreviewTitle"
:footer="null"
width="900px"
@cancel="closeMediaPreview"
>
<div class="flex h-[60vh] gap-4">
<!-- 左侧:混合列表 (图片+视频) -->
<div class="w-1/4 overflow-y-auto border-r pr-2 media-list-container">
<div
v-for="(item, index) in previewList"
:key="index"
class="mb-2 cursor-pointer list-item"
:class="{ select: index === currentMediaIndex }"
@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>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, onMounted, h, nextTick } from "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 GuoYuSheShiShuJuTianBaoSearch from "./guoYuSheShiShuJuTianBaoSearch.vue";
import GuoYuSheShiShuJuTianBaoTable from "./guoYuSheShiShuJuTianBaoTable.vue";
import EditModal from "./guoYuSheShiShuJuTianBaoForm.vue";
import {
getFishDraftPage,
addFishDraft,
editFishDraft,
delFishDraft,
submitFishDraft,
successFishDraft,
rejectFishDraft,
importFishZip,
cancelImportTask,
checkImportStatus,
batchSaveDraft,
getLastImportResult,
markImportTaskSuccess,
} from "@/api/guoYuSheShiShuJuTianBao";
import { Tag } from "ant-design-vue"; // 确保导入 Tag
import { getDictItemsByCode } from "@/api/dict";
import dayjs from "dayjs";
// import { FileImageOutlined, VideoCameraOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons-vue'
const baseUrl = import.meta.env.VITE_APP_PREVIEW_URL;
// --- 类型定义 ---
interface FormData {
[key: string]: any;
}
interface ColumnConfig {
dataIndex: string;
key: string;
title: string;
width?: number;
fixed?: string;
customRender?: (text: any, record: any) => any;
}
const fileInputRef = ref<any>(null);
const tableRef = ref<any>(null);
// 字典项
const direction = ref<any>([]);
const guoyuStatus = ref<any>([]);
// --- 基础配置 ---
const baseColumnsConfig: ColumnConfig[] = [
{
dataIndex: "baseName",
key: "baseName",
title: "流域",
width: 120,
fixed: "left",
},
{ dataIndex: "ennm", key: "ennm", title: "电站名称", width: 120, fixed: "left" },
{ dataIndex: "stnm", key: "stnm", title: "过鱼设施名称", width: 150, fixed: "left" },
{ dataIndex: "strdt", key: "strdt", title: "过鱼时间", width: 150 },
{ dataIndex: "ftpName", key: "ftpName", title: "鱼种类", width: 120 },
{
dataIndex: "isfs",
key: "isfs",
title: "是否鱼苗",
width: 74,
customRender: ({ text }: any) => {
const isYes = text === 1 || text === "1";
return h(
Tag,
{
color: isYes ? "success" : "error", // Antdv Tag 的颜色预设
style: { margin: 0 }, // 去除默认 margin使其在表格中对齐更好
},
() => (isYes ? "是" : "否")
);
},
},
{
dataIndex: "direction",
key: "direction",
title: "游向",
width: 80,
customRender: ({ text }: any) =>
direction.value.find((item: any) => item.itemCode === text)?.dictName || "-",
},
{ dataIndex: "fcnt", key: "fcnt", title: "过鱼数量(尾)", width: 120 },
{ dataIndex: "fsz", key: "fsz", title: "体长(cm)", width: 110 },
{ dataIndex: "fwet", key: "fwet", title: "平均体重(g)", width: 110 },
{ dataIndex: "wt", key: "wt", title: "水温(℃)", width: 80 },
{ dataIndex: "tm", key: "tm", title: "填报时间", width: 150 },
{
dataIndex: "status",
key: "status",
title: "状态",
width: 74,
customRender: ({ text }: any) => {
let data = guoyuStatus.value.find((item: any) => item.itemCode === text);
return h(
Tag,
{
color: data?.custom1 || "error", // Antdv Tag 的颜色预设
},
() => data?.dictName || "-"
);
},
},
];
// --- 状态定义 ---
const visible = ref(false); // 导入预览 Modal
// 编辑相关状态
const editModalVisible = ref(false);
const isView = ref(false);
const currentRecord = ref<FormData | null>(null);
const submitLoading = ref(false);
const mediaPreviewVisible = ref(false);
const videoPreviewTitle = ref("视频预览");
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 orgFileTableData = ref<any[]>([]);
const batchData = ref<any[]>([]);
const modalTableRef = ref<any>(null);
const fileLoading = ref(false);
const taskId = ref<string>("");
// 主表格 Columns
const columns = computed(() => {
return [
...baseColumnsConfig.map((col) => {
if (col.dataIndex === "level5") {
return {
...col,
customRender: ({ text }: any) => {
if (!text) return "-";
// 实际应渲染 Icon 和点击事件,此处简化
return `<span style="color:#52c41a; cursor:pointer">查看图片</span>`;
},
};
}
if (col.dataIndex === "level6") {
return {
...col,
customRender: ({ text }: any) => {
if (!text) return "-";
return `<span style="color:#1890ff; cursor:pointer">播放视频</span>`;
},
};
}
return { ...col, visible: true };
}),
{
title: "操作",
key: "action",
dataIndex: "action",
fixed: "right",
width: 200,
align: "center",
},
];
});
// --- 业务逻辑方法 ---
const handleAdd = () => {
currentRecord.value = null;
editModalVisible.value = true;
};
// 修改
const handleEdit = (record: any, type: string) => {
if (type == "view") {
isView.value = true;
} else {
isView.value = false;
}
currentRecord.value = { ...record };
editModalVisible.value = true;
};
// 单个/批量 删除过鱼数据
const handleDelete = (ids: any[]) => {
Modal.confirm({
title: "是否确认 删除 选中数据吗?",
onOk: async () => {
let res: any = await delFishDraft(ids);
if (res && res?.code == 0) {
message.success("删除成功");
tableRef.value?.getList();
}
},
});
};
// 批量删除 - 按钮
const batchDelBtn = () => {
handleDelete(batchData.value);
};
//单个/ 批量提交过鱼数据
const handleSubmit = (ids: any[]) => {
Modal.confirm({
title: "是否 提交 选中数据吗?",
onOk: async () => {
let res: any = await submitFishDraft(ids);
if (res && res?.code == 0) {
message.success("提交成功");
tableRef.value?.getList();
}
},
});
};
// 批量提交-按钮
const submitBtn = async () => {
handleSubmit(batchData.value);
};
// 单个/ 批量审批过鱼数据
const handleSuccess = (ids: any[]) => {
let rejectReason = "";
Modal.confirm({
title: "是否确认 审批通过 选中数据?",
// 使用 h 函数创建内容
content: h("div", { style: "margin-top: 10px;" }, [
h("div", { style: "margin-bottom: 8px;" }, [
h("span", { style: "color: red;" }, "* "),
h("span", "审批原因:"),
]),
h("textarea", {
class: "ant-input", // 使用 antdv 的样式类,使其看起来像 Antdv 输入框
placeholder: "请输入审批原因",
rows: 4,
style: {
width: "100%",
resize: "none",
border: "1px solid #d9d9d9",
padding: "8px",
borderRadius: "4px",
},
// 监听输入事件,更新局部变量
onInput: (e: Event) => {
rejectReason = (e.target as HTMLTextAreaElement).value;
},
}),
]),
okText: "确认审批",
cancelText: "取消",
onOk: async () => {
let res: any = await successFishDraft({ ids: ids, approveComment: rejectReason });
if (res && res?.code == 0) {
message.success("审批成功");
tableRef.value?.getList();
}
},
});
};
// 批量审批-按钮
const successBtn = async () => {
handleSuccess(batchData.value);
};
// 批量驳回过鱼数据
const handleReject = (id: any) => {
let rejectReason = "";
Modal.confirm({
title: "是否确认 驳回 选中数据?",
// 使用 h 函数创建内容
content: h("div", { style: "margin-top: 10px;" }, [
h("div", { style: "margin-bottom: 8px;" }, [
h("span", { style: "color: red;" }, "* "),
h("span", "驳回原因:"),
]),
h("textarea", {
class: "ant-input", // 使用 antdv 的样式类,使其看起来像 Antdv 输入框
placeholder: "请输入驳回原因",
rows: 4,
style: {
width: "100%",
resize: "none",
border: "1px solid #d9d9d9",
padding: "8px",
borderRadius: "4px",
},
// 监听输入事件,更新局部变量
onInput: (e: Event) => {
rejectReason = (e.target as HTMLTextAreaElement).value;
},
}),
]),
okText: "确认驳回",
cancelText: "取消",
onOk: async () => {
// 校验驳回原因不能为空
if (!rejectReason || rejectReason.trim() === "") {
message.warning("请输入驳回原因");
return Promise.reject(); // 阻止 Modal 关闭
}
let res: any = await rejectFishDraft({ id: id, rejectReason: rejectReason });
if (res && res?.code == 0) {
message.success("驳回成功");
tableRef.value?.getList();
}
},
});
};
// 多选禁用
const getCheckboxProps = (record: any) => {
return {
disabled: ['SUBMITTED', 'APPROVED'].includes(record.status),
};
};
const handleDataLoaded = (params: any, data: any) => {
console.log(params, data);
return
};
// 多选
const handleSelectionChange = (keys: any) => {
batchData.value = keys;
};
const editModalCancel = () => {
editModalVisible.value = false;
};
// 编辑/新增-按钮
const handleEditSubmit = async (values: FormData) => {
submitLoading.value = true;
if (currentRecord.value) {
// 编辑逻辑
let res: any = await editFishDraft({
...values,
});
if (res && res?.code == 0) {
message.success("编辑成功");
editModalVisible.value = false;
tableRef.value?.getList();
}
submitLoading.value = false;
} else {
// 新增逻辑
let res: any = await addFishDraft({
...values,
});
if (res && res?.code == 0) {
message.success("新增成功");
editModalVisible.value = false;
tableRef.value?.getList();
}
submitLoading.value = false;
}
};
const isRowDataEqual = (oldRow: any, newRow: any, fields: string[]): boolean => {
for (const field of fields) {
// 处理 undefined/null 的情况,确保比较的一致性
let oldVal = oldRow?.[field];
let newVal = newRow?.[field];
// 特殊处理:如果都是空值,视为相等
if (
(oldVal === undefined || oldVal === null || oldVal === "") &&
(newVal === undefined || newVal === null || newVal === "")
) {
continue;
}
// 严格不相等
if (oldVal !== newVal) {
return false;
}
}
return true;
};
const checkTableDataChanges = () => {
// 1. 定义需要比对的核心字段 (对应 Form 中的字段)
const oldData = orgFileTableData.value;
const newData = fileTableData.value;
// 2. 如果行数不同,肯定有变化
if (oldData.length !== newData.length) {
return { hasChanged: true, changedCount: newData.length };
}
let changedCount = 0;
// 3. 逐行比对
for (let i = 0; i < newData.length; i++) {
const oldRow = oldData[i];
const newRow = newData[i];
// 如果某一行数据不一致,计数+1
if (!isRowDataEqual(oldRow, newRow, ["baseId"])) {
changedCount++;
}
}
return { hasChanged: changedCount > 0, changedCount };
};
// 提交导入
const handleModalOk = () => {
console.log(orgFileTableData.value);
console.log(fileTableData.value);
console.log(modalTableRef.value.editingData);
if (modalTableRef.value.editingData != undefined) {
message.warning("请点击保存后提交数据!");
return;
}
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({
title: "是否提交导入数据?",
onOk: async () => {
let res: any = await batchSaveDraft(fileTableData.value);
if (res && res?.code == 0) {
message.success("导入成功");
tableRef.value?.getList();
visible.value = false;
await markImportTaskSuccess({ id: taskId.value });
} else {
message.error("导入失败,请检查数据是否正确");
}
},
});
};
// 关闭导入弹窗
const handleCustomCancel = () => {
Modal.confirm({
title: "是否取消导入数据?",
content: "未提交的数据将丢失",
okText: "确定",
onOk: async () => {
// 可选:调用取消接口
let res: any = await cancelImportTask({ taskId: taskId.value });
if (res && res?.code == 0) {
message.success("取消成功");
tableRef.value?.getList();
visible.value = false;
}
},
});
};
// 导入-按钮
const importBtn = async () => {
let res: any = await checkImportStatus();
taskId.value = "";
if (res?.code == 0) {
const { hasImportingTask, currentTask } = res?.data || {};
if (currentTask) {
taskId.value = currentTask.id;
}
if (hasImportingTask) {
visible.value = true;
nextTick(async () => {
try {
fileLoading.value = true;
modalTableRef.value.editingRowIndex = null;
let res1: any = await getLastImportResult();
fileTableaAnalysis(res1, "get");
} catch (error) {
message.error("导入失败");
} finally {
fileLoading.value = false;
}
});
} else {
fileInputRef.value?.click();
}
} else {
message.error("导入查询失败");
}
};
// 上传文件
const fileChange = (file: File) => {
try {
nextTick(async () => {
visible.value = true;
fileLoading.value = true;
fileTableData.value = [];
const formData = new FormData();
formData.append("file", file);
let res: any = await importFishZip(formData);
const { code } = res.data || {};
if (code == 1) {
message.error("导入失败");
} else {
taskId.value = res.data.taskId;
message.success("导入成功");
fileTableaAnalysis(res, "file");
}
});
} catch (error) {
} finally {
fileLoading.value = false;
}
};
// 获取文件列表
const handleFileSelect = (e: Event) => {
const target = e.target as HTMLInputElement;
const file = target.files?.[0];
if (!file) return;
// 校验文件大小 (50MB)
const maxSize = 50 * 1024 * 1024;
if (file.size > maxSize) {
message.error("文件大小不能超过50MB");
resetFileInput();
return;
}
// 校验文件类型
const isZip =
file.name.toLowerCase().endsWith(".zip") ||
file.type === "application/zip" ||
file.type === "application/x-zip-compressed";
if (!isZip) {
message.error("请选择.zip格式的压缩包");
resetFileInput();
return;
}
fileChange(file);
resetFileInput();
};
const resetFileInput = () => {
if (fileInputRef.value) {
fileInputRef.value.value = "";
}
};
const fileTableaAnalysis = (res: any, type: string) => {
let data = [];
let list = [];
if (type == "file") {
list = res.data.failedRows;
} else {
list = res.data.result.failedRowDetails;
}
list.forEach((item) => {
data.push({
...item.data,
vdpthList: item.vdpthList,
vdpthsWarnings: item.vdpthsWarnings,
picpthList: item.picpthList,
picpthsWarnings: item.picpthsWarnings,
_warnings: item.warnings,
});
});
fileTableData.value = data || [];
orgFileTableData.value = JSON.parse(JSON.stringify(fileTableData.value));
fileLoading.value = false;
};
const handleReset = (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 filters = [
values.ftp && {
field: "ftp",
operator: "eq",
dataType: "string",
value: values.ftp,
},
{
field: "TM",
operator: "gte",
dataType: "date",
value: values.strdt[0],
},
{
field: "TM",
operator: "lte",
dataType: "date",
value: values.strdt[1],
},
values.direction && {
field: "direction",
operator: "eq",
dataType: "string",
value: values.direction,
},
values.status && {
field: "status",
operator: "eq",
dataType: "string",
value: values.status,
},
values.stcd && {
field: "stcd",
operator: "eq",
dataType: "string",
value: values.stcd,
},
values.rstcd && {
field: "rstcd",
operator: "eq",
dataType: "string",
value: values.rstcd,
},
values.baseId !== "all" && {
field: "baseId",
operator: "eq",
dataType: "string",
value: values.baseId,
},
].filter(Boolean);
const filter = {
logic: "and",
filters: filters,
};
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}` : "",
});
});
}
mediaPreviewVisible.value = true;
currentMediaIndex.value = index;
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;
});
};
// --- 生命周期 ---
onMounted(() => {
getDictItemsByCode({ dictCode: "direction" }).then((res) => {
direction.value = res.data;
});
getDictItemsByCode({ dictCode: "guoyuStatus" }).then((res) => {
guoyuStatus.value = res.data;
});
});
</script>
<style lang="scss" scoped>
.guoYuSheShiShuJuTianBao-page {
width: 100%;
height: 100%;
background-color: #ffffff;
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>