WholeProcessPlatform/frontend-sjtb/src/views/shuJuTianBao/guoYuSheShiShuJuTianBao/index.vue
2026-07-03 15:59:05 +08:00

1068 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"
class="search-container"
:guoyuStatus="guoyuStatus"
:direction="direction"
:handle-add="handleAdd"
:batchData="batchData"
:importBtn="importBtn"
:batchDelBtn="batchDelBtn"
:submitBtn="submitBtn"
:allSubmitBtn="allSubmitBtn"
: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 #action="{ column, record }">
<div class="flex">
<a-button
v-hasPerm="['sjtb:import-add']"
type="link"
size="small"
@click="handleSubmit([record.id])"
v-if="record.status === 'DRAFT' || record.status === 'REJECTED'"
>提交</a-button
>
<a-button
v-hasPerm="['sjtb:import-add']"
type="link"
size="small"
@click="handleEdit(record, 'edit')"
v-if="record.status === 'DRAFT' || record.status === 'REJECTED'"
>编辑</a-button
>
<a-button
v-hasPerm="['sjtb:edit-review']"
type="link"
size="small"
@click="handleEdit(record, 'edit')"
v-if="record.status === 'PENDING'"
>编辑</a-button
>
<a-button
v-hasPerm="['sjtb:import-add']"
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="
(checkPerm(['sjtb:edit-review']) && record.status === 'DRAFT') ||
(checkPerm(['sjtb:import-add']) && record.status === 'PENDING') ||
(checkPerm(['sjtb:edit-review']) &&
record.status === 'REJECTED') ||
record.status === 'APPROVED'
"
>查看</a-button
>
<a-button
v-hasPerm="['sjtb:edit-review']"
type="link"
size="small"
@click="handleSuccess([record.id])"
v-if="record.status === 'PENDING'"
>审批</a-button
>
<a-button
v-hasPerm="['sjtb:edit-review']"
type="link"
danger
size="small"
@click="handleReject(record.id)"
v-if="record.status === 'PENDING'"
>驳回</a-button
>
</div>
</template>
</BasicTable>
<div class="buttonStyle">
<div class="button">
<a-tooltip title="提交数据">
<a-button
v-hasPerm="['sjtb:import-add']"
@click="submitBtn"
:disabled="batchData.length === 0"
size="large"
>
提交数据
</a-button>
</a-tooltip>
</div>
<div class="button">
<a-tooltip title="全部提交">
<a-button
v-hasPerm="['sjtb:import-add']"
@click="allSubmitBtn"
size="large"
>
全部提交
</a-button>
</a-tooltip>
</div>
<div class="button">
<a-tooltip title="批量删除">
<a-button
v-hasPerm="['sjtb:import-add']"
@click="batchDelBtn"
:disabled="batchData.length === 0"
size="large"
>
批量删除
</a-button>
</a-tooltip>
</div>
</div>
<!-- 隐藏的文件输入框 -->
<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"
@cancel="taskId = ''"
>
<GuoYuSheShiShuJuTianBaoTable
ref="modalTableRef"
:taskId="taskId"
:fileTableData="fileTableData"
:getFileList="getFileList"
:direction="direction"
@preview-click="handlePreviewClick"
v-model:file-loading="fileLoading"
@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
ref="editModalRef"
v-model:visible="editModalVisible"
:is-view="isView"
:direction="direction"
:initial-values="currentRecord"
@cancel="editModalCancel"
@ok="handleEditSubmit"
@preview-click="handlePreviewClick"
/>
<!-- 预览媒体组件 -->
<PreviewMedia
ref="previewMediaRef"
v-model:visible="mediaPreviewVisible"
:previewList="previewList"
:previewListIndex="previewListIndex"
:videoPreviewTitle="videoPreviewTitle"
:taskId="taskId"
:isDel="isPreviewMediaDelete"
@deleteMedia="handleDeleteMedia"
/>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, onMounted, h, nextTick, watch } from 'vue';
import { message, Modal } from 'ant-design-vue'; // 假设使用 ant-design-vue
import BasicTable from '@/components/BasicTable/index.vue';
import GuoYuSheShiShuJuTianBaoSearch from './guoYuSheShiShuJuTianBaoSearch.vue';
import GuoYuSheShiShuJuTianBaoTable from './guoYuSheShiShuJuTianBaoTable.vue';
import EditModal from './guoYuSheShiShuJuTianBaoForm.vue';
import PreviewMedia from '@/components/previewMedia/index.vue';
import { checkPerm } from '@/directive/permission';
import {
getFishDraftPage,
addFishDraft,
editFishDraft,
delFishDraft,
submitFishDraft,
successFishDraft,
rejectFishDraft,
importFishZip,
cancelImportTask,
checkImportStatus,
batchSaveDraft,
getLastImportResult,
batchApproveAll
} from '@/api/guoYuSheShiShuJuTianBao';
import { Tag } from 'ant-design-vue'; // 确保导入 Tag
import { getDictItemsByCode } from '@/api/dict';
import { calcTableScrollY } from '@/utils/index';
const baseUrl = import.meta.env.VITE_APP_ATTACHMENT_URL;
const baseUrlApi = import.meta.env.VITE_APP_BASE_API_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: 'rvnm',
key: 'rvnm',
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 editModalRef = ref<any>(null);
// 编辑相关状态
const editModalVisible = ref(false);
const isView = ref(false);
const currentRecord = ref<FormData | null>(null);
const mediaPreviewVisible = ref(false);
const isPreviewMediaDelete = ref(false);
const videoPreviewTitle = ref('视频预览');
interface MediaItem {
id: string;
type: 'image' | 'video';
name: string;
url: string;
}
const previewList = ref<MediaItem[]>([]);
const previewListIndex = ref(0);
const tablePreviewRecord = ref<any>({});
// 表格数据
const fileTableData = 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',
slots: { customRender: 'action' }
}
];
});
// --- 业务逻辑方法 ---
const handleAdd = () => {
isView.value = false;
currentRecord.value = null;
editModalVisible.value = true;
};
// 修改
const handleEdit = (record: any, type: string) => {
if (type == 'view') {
isView.value = true;
} else {
isView.value = false;
} // 浅层转换(只处理第一层属性)
const transformDashToNull = obj => {
const result = { ...obj };
for (const key in result) {
if (result[key] === '-') {
result[key] = null;
}
}
return result;
};
currentRecord.value = transformDashToNull(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?.refresh();
}
}
});
};
// 批量删除 - 按钮
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?.refresh();
}
}
});
};
// 批量提交-按钮
const submitBtn = async () => {
handleSubmit(batchData.value);
};
//全部提交按钮
const allSubmitBtn = async () => {
if (tableRef.value.tableData.length === 0) {
message.warning('请先添加数据!');
return;
}
Modal.confirm({
title: '是否 提交 全部数据吗?',
onOk: async () => {
let res: any = await batchApproveAll();
if (res && res?.code == 0) {
message.success('提交成功');
tableRef.value?.refresh();
}
}
});
};
// 单个/ 批量审批过鱼数据
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?.refresh();
}
}
});
};
// 批量审批-按钮
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?.refresh();
}
}
});
};
// 多选禁用
const getCheckboxProps = (record: any) => {
return {
disabled: [
!checkPerm(['sjtb:edit-review']) && 'PENDING',
'APPROVED'
].includes(record.status)
};
};
// 多选
const handleSelectionChange = (keys: any) => {
batchData.value = keys;
};
const editModalCancel = () => {
editModalVisible.value = false;
};
// 编辑/新增-按钮
const handleEditSubmit = async (values: FormData) => {
editModalRef.value.localLoading = true;
if (currentRecord.value) {
// 编辑逻辑
let res: any = await editFishDraft({
...values
});
if (res && res?.code == 0) {
message.success('编辑成功');
editModalVisible.value = false;
tableRef.value?.refresh();
}
editModalRef.value.localLoading = false;
} else {
// 新增逻辑
let res: any = await addFishDraft({
...values
});
if (res && res?.code == 0) {
message.success('新增成功');
editModalVisible.value = false;
tableRef.value?.refresh();
}
editModalRef.value.localLoading = false;
}
};
// 提交导入
const handleModalOk = () => {
if (modalTableRef.value.editingData != undefined) {
message.warning('请点击保存后提交数据!');
return;
}
for (let i = 0; i < fileTableData.value.length; i++) {
if (fileTableData.value[i].warnings?.length > 0) {
// if (fileTableData.value[i].warnings.includes("baseId")) {
// message.warning("请检查流域,流域填写有误!");
// return;
// }
if (fileTableData.value[i].warnings.includes('rvcd')) {
message.warning('请检查流域,流域填写有误!');
return;
}
if (fileTableData.value[i].warnings.includes('rstcd')) {
message.warning('请检查电站,电站填写有误!');
return;
}
if (fileTableData.value[i].warnings.includes('stcd')) {
message.warning('请检查过鱼设施,过鱼设施填写有误!');
return;
}
if (fileTableData.value[i].warnings.includes('strdt')) {
message.warning('请检查过鱼时间,过鱼时间填写有误!');
return;
}
if (fileTableData.value[i].warnings.includes('ftp')) {
message.warning('请检查鱼种类,鱼种类填写有误!');
return;
}
if (fileTableData.value[i].warnings.includes('direction')) {
message.warning('请检查游向,游向填写有误!');
return;
}
if (fileTableData.value[i].warnings.includes('isfs')) {
message.warning('请检查是否鱼苗,是否鱼苗填写有误!');
return;
}
if (fileTableData.value[i].warnings.includes('fcnt')) {
message.warning('请检查过鱼数量,过鱼数量填写有误!');
return;
}
}
if (fileTableData.value[i].picpthsWarnings?.length > 0) {
message.warning('请检查图片,图片路径有误!');
return;
}
if (fileTableData.value[i].vdpthsWarnings?.length > 0) {
message.warning('请检查视频,视频路径有误!');
return;
}
}
Modal.confirm({
title: '是否提交导入数据?',
onOk: async () => {
try {
let res: any = await batchSaveDraft({
taskId: taskId.value
});
if (res && res?.code == 0) {
fileTableData.value = [];
taskId.value = '';
tableRef.value?.refresh();
visible.value = false;
message.success('导入成功');
} else {
message.error('导入失败,请检查数据是否正确');
}
} catch (error) {
message.error('导入数据失败');
}
}
});
};
// 关闭导入弹窗
const handleCustomCancel = () => {
Modal.confirm({
title: '是否取消导入数据?',
content: '未提交的数据将丢失',
okText: '确定',
onOk: async () => {
// 可选:调用取消接口
let res: any = await cancelImportTask({ taskId: taskId.value });
if (res && res?.code == 0) {
fileTableData.value = [];
taskId.value = '';
message.success('取消成功');
tableRef.value?.refresh();
visible.value = false;
} else {
message.error('取消失败');
}
}
});
};
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;
fileLoading.value = true;
if (currentTask.status == 'UPLOADED') {
if (visible.value) {
// message.warning(currentTask.statusText)
setTimeout(() => {
if (visible.value) importBtn();
}, 5000);
}
} else if (currentTask.status == 'FAILED') {
message.error(currentTask.statusText);
fileLoading.value = false;
} else if (currentTask.status == 'VALIDATED') {
nextTick(async () => {
modalTableRef.value.editingRowIndex = null;
getFileList();
});
}
} else {
fileInputRef.value?.click();
}
} else {
message.error('导入查询失败');
}
};
const getFileList = async () => {
let res: any = await getLastImportResult();
fileTableaAnalysis(res);
};
// 上传文件
const fileChange = (file: File) => {
nextTick(async () => {
visible.value = true;
fileLoading.value = true;
fileTableData.value = [];
const formData = new FormData();
formData.append('file', file);
let res: any = await importFishZip(formData);
if (res && res?.code == 0) {
if (visible.value) importBtn();
setTimeout(() => {
if (visible.value) importBtn();
}, 5000);
}
});
};
// 获取文件列表
const handleFileSelect = (e: Event) => {
const target = e.target as HTMLInputElement;
const file = target.files?.[0];
if (!file) return;
// 校验文件大小 (300MB)
const maxSize = 300 * 1024 * 1024;
if (file.size > maxSize) {
message.error('文件大小不能超过300MB');
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) => {
let data = [];
let list = [];
list = res.data.result.rows;
list.sort((a: any, b: any) => {
const keyA =
a.rowIndex !== undefined && a.rowIndex !== null ? Number(a.rowIndex) : -1;
const keyB =
b.rowIndex !== undefined && b.rowIndex !== null ? Number(b.rowIndex) : -1;
return keyA - keyB;
});
list.forEach(item => {
data.push({
...item.data,
rowIndex: item.rowIndex,
vdpthList: item.vdpthList,
vdpthsWarnings: item.vdpthsWarnings,
picpthList: item.picpthList,
picpthsWarnings: item.picpthsWarnings,
warnings: item.warnings
});
});
fileTableData.value = data || [];
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: 'strdt',
operator: 'gte',
dataType: 'date',
value: values.strdt[0] + ' 00:00:00'
},
{
field: 'strdt',
operator: 'lte',
dataType: 'date',
value: values.strdt[1] + ' 23:59:59'
},
values.direction && {
field: 'direction',
operator: 'eq',
dataType: 'string',
value: values.direction
},
// status: 'DRAFT',
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.rvcd !== 'all' && {
field: 'rvcd',
operator: 'eq',
dataType: 'string',
value: values.rvcd
}
// 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,
action: string
) => {
const mixedList: MediaItem[] = [];
if (action === 'delete') {
isPreviewMediaDelete.value = true;
tablePreviewRecord.value = record;
} else if (action === 'preview') {
isPreviewMediaDelete.value = false;
}
if (type === 'image') {
videoPreviewTitle.value = '图片预览';
const nameList = record.picpthList;
nameList.forEach((item: any) => {
let url = '';
if (action === 'preview') {
url = item.url;
} else if (action === 'delete') {
url =
baseUrlApi +
'/data/fishDraft/previewFile?filename=' +
item.name +
'&taskId=' +
taskId.value +
'&type=1';
}
mixedList.push({
id: record.id,
type: 'image',
name: item.name,
url: url
});
});
} else if (type === 'video') {
videoPreviewTitle.value = '视频预览';
const nameList = record.vdpthList;
nameList.forEach((item: any) => {
let url = '';
if (action === 'preview') {
url = item.url;
} else if (action === 'delete') {
url =
baseUrlApi +
'/data/fishDraft/previewFile?filename=' +
item.name +
'&taskId=' +
taskId.value +
'&type=2';
}
mixedList.push({
id: record.id,
type: 'video',
name: item.name, // 视频通常没有单独的名称字段,可根据需要调整
url: url
});
});
}
mediaPreviewVisible.value = true;
previewListIndex.value = index;
nextTick(() => {
console.log(mixedList);
previewList.value = mixedList;
});
};
const handleDeleteMedia = (item: any, type: string, index: number) => {
previewList.value.splice(index, 1);
if (type == '图片预览') {
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
);
}
}
};
const tableContainerRef = ref<HTMLElement | null>(null);
const tableScrollY = ref<number | undefined>(undefined);
// 监听容器大小变化(窗口 resize 或内容变化)
const observer = new ResizeObserver(() => {
tableScrollY.value = calcTableScrollY(tableContainerRef.value);
});
// --- 生命周期 ---
onMounted(() => {
nextTick(() => {
tableScrollY.value = calcTableScrollY(tableContainerRef.value);
if (tableContainerRef.value) {
observer.observe(tableContainerRef.value);
}
});
getDictItemsByCode({ dictCode: 'direction' }).then(res => {
direction.value = res.data;
});
getDictItemsByCode({ dictCode: 'approvalStatus' }).then(res => {
guoyuStatus.value.length = 0;
res.data.forEach((item: any) => {
if (item.itemCode != 'APPROVED') {
guoyuStatus.value.push(item);
}
});
// guoyuStatus.value = res.data;
});
});
</script>
<style lang="scss" scoped>
.guoYuSheShiShuJuTianBao-page {
position: relative;
z-index: 900;
pointer-events: all;
width: 100%;
height: 100%;
background-color: #ffffff;
padding: 20px;
display: flex;
flex-direction: column;
gap: 10px;
box-sizing: border-box;
overflow: hidden;
}
.search-container {
flex-shrink: 0;
/* 搜索栏不压缩 */
}
.buttonStyle {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
.button {
margin: 0px 5px;
}
}
</style>