2026-06-16 16:52:50 +08:00
|
|
|
|
<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;
|
2026-07-03 15:59:05 +08:00
|
|
|
|
} // 浅层转换(只处理第一层属性)
|
|
|
|
|
|
const transformDashToNull = obj => {
|
|
|
|
|
|
const result = { ...obj };
|
|
|
|
|
|
for (const key in result) {
|
|
|
|
|
|
if (result[key] === '-') {
|
|
|
|
|
|
result[key] = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
currentRecord.value = transformDashToNull(record);
|
2026-06-16 16:52:50 +08:00
|
|
|
|
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>
|