WholeProcessPlatform/frontend/src/modules/dianzhanzhuantiMod/ZenZhiZhanYunXingPG/ZenZhiZhanYunXingDetailModal.vue

293 lines
7.2 KiB
Vue

<template>
<!-- 详情弹窗 -->
<a-modal
v-model:open="modalVisible"
:title="mFilter?.ctitle || '详情'"
width="80%"
:footer="null"
:bodyStyle="{ height: '700px' }"
centered
destroyOnClose
@cancel="handleModalCancel"
>
<!-- Tab 切换 -->
<div class="modal-tabs" v-if="mFilter?.proTable?.length">
<div
v-for="item in mFilter.proTable"
:key="item.key"
class="modal-tabs__item"
:class="{ 'modal-tabs__item--active': activeTab?.key === item.key }"
@click="switchTab(item)"
>
{{ item.title }}
</div>
</div>
<!-- 筛选表单 -->
<BasicSearch
v-if="activeTab && searchList.length"
:key="activeTab.key"
:searchList="searchList"
@finish="handleTableSearch"
@reset="handleTableReset"
/>
<!-- 数据表格 -->
<BasicTable
v-if="activeTab"
:key="activeTab.key"
ref="tableRef"
:columns="tableColumns"
:listUrl="tableListUrl"
:searchParams="tableSearchParams"
:transformData="customTransform"
:defaultPageSize="20"
:scrollY="400"
>
<template #fid="{ record }">
<a v-if="record.fid" @click="handleAttachmentPreview(record.fid)">查看</a>
<span v-else class="no-data-link">查看</span>
</template>
</BasicTable>
</a-modal>
<!-- 附件预览弹窗 -->
<a-modal
v-model:open="attachmentModalVisible"
title="附件预览"
width="80vw"
:footer="null"
destroyOnClose
:bodyStyle="{ height: '70vh' }"
>
<AttachmentPreview :fid="currentAttachmentFid" />
</a-modal>
</template>
<script lang="ts" setup>
import { ref, computed, nextTick } from 'vue';
import request from '@/utils/request';
import BasicSearch from '@/components/BasicSearch/index.vue';
import BasicTable from '@/components/BasicTable/index.vue';
import AttachmentPreview from '@/components/MapModal/components/AIYXSB/AttachmentPreview.vue';
import { getFishDic } from '@/api/dianZhanZhuanTi';
defineOptions({ name: 'ZenZhiZhanYunXingDetailModal' });
const props = defineProps<{
selectedStcd: string;
}>();
// 不需要默认排序的 tab key
const igKeys = ['1-2-1'];
// ==================== 弹窗状态 ====================
const modalVisible = ref(false);
const activeTab = ref<any>(null);
const mFilter = ref<any>(null);
const searchForms = ref<any>({});
const tableRef = ref();
const fishDic = ref<Array<{ value: string; key: string }>>([]);
// ==================== 附件预览状态 ====================
const attachmentModalVisible = ref(false);
const currentAttachmentFid = ref('');
// ==================== 搜索列表(从 activeTab.filter 构建) ====================
const searchList = computed(() => {
if (!activeTab.value?.filter) return [];
return activeTab.value.filter.map((f: any) => {
const item: any = {
type: f.type === 'select' ? 'Select' : 'Input',
name: f.name,
label: f.label,
placeholder: f.placeholder || `请输入${f.label}`
};
if (f.type === 'select' && f.name === 'ftp') {
item.options = fishDic.value.map((d: any) => ({
label: d.key,
value: d.value
}));
}
return item;
});
});
// ==================== 表格列(从 proliferationColumns 转换) ====================
const buildColumns = (cols: any[]): any[] => {
return cols
.filter((col: any) => col.visible !== false)
.map((col: any) => {
const base: any = {
title: col.title,
dataIndex: col.dataIndex,
key: col.key || col.dataIndex,
width: col.width || 150,
ellipsis: col.ellipsis ?? true
};
if (col.dataIndex === 'fid' || col.key === 'fid') {
base.slots = { customRender: 'fid' };
}
if (col.children?.length) {
base.children = buildColumns(col.children);
}
return base;
});
};
const tableColumns = computed(() => {
if (!activeTab.value?.columns) return [];
return buildColumns(activeTab.value.columns);
});
// ==================== 表格请求参数 ====================
const tableSearchParams = computed(() => {
const filters: any[] = [];
if (props.selectedStcd) {
filters.push({
field: 'stcd',
operator: 'eq',
dataType: 'string',
value: props.selectedStcd
});
}
if (searchForms.value) {
Object.keys(searchForms.value).forEach(key => {
if (searchForms.value[key] !== undefined && searchForms.value[key] !== '') {
filters.push({
field: key,
operator: 'contains',
dataType: 'string',
value: searchForms.value[key]
});
}
});
}
const result: any = {
filter: { logic: 'and', filters }
};
if (!igKeys.includes(activeTab.value?.key)) {
result.sort = [{ field: 'tm', dir: 'desc' }];
}
return result;
});
// ==================== listUrl ====================
const tableListUrl = computed(() => {
return (params: any) =>
request({
url: activeTab.value?.url || '',
method: 'post',
data: params
});
});
const customTransform = (res: any) => ({
records: res?.data?.data || res?.data?.items || [],
total: res?.data?.total || 0
});
// ==================== 事件 ====================
const switchTab = (item: any) => {
searchForms.value = {};
activeTab.value = item;
nextTick(() => {
tableRef.value?.getList(tableSearchParams.value.filter);
});
};
const handleTableSearch = (values: any) => {
searchForms.value = { ...values };
tableRef.value?.getList(tableSearchParams.value.filter);
};
const handleTableReset = () => {
searchForms.value = {};
tableRef.value?.getList(tableSearchParams.value.filter);
};
const handleModalCancel = () => {
modalVisible.value = false;
activeTab.value = null;
mFilter.value = null;
searchForms.value = {};
};
const handleAttachmentPreview = (fid: string) => {
if (fid) {
currentAttachmentFid.value = fid;
attachmentModalVisible.value = true;
}
};
// ==================== API ====================
const fetchFishDic = async () => {
if (fishDic.value.length > 0) return; // 已加载则跳过
try {
const res = await getFishDic({
filter: { logic: 'and', filters: [] },
select: ['id', 'name']
});
// debugger
const data = res?.data?.data || [];
fishDic.value = data.map((item: any) => ({
value: item.id,
key: item.name
}));
} catch (e) {
console.error('获取鱼类字典失败', e);
}
};
// ==================== 暴露方法 ====================
const open = (val: any) => {
searchForms.value = {};
mFilter.value = val;
activeTab.value = val.proTable?.[0] || null;
modalVisible.value = true;
fetchFishDic();
nextTick(() => {
tableRef.value?.getList(tableSearchParams.value.filter);
});
};
defineExpose({ open });
</script>
<style scoped>
.modal-tabs {
display: flex;
gap: 0;
margin-bottom: 16px;
border-bottom: 1px solid #e8e8e8;
}
.modal-tabs__item {
padding: 8px 20px;
cursor: pointer;
color: #666;
font-size: 14px;
border-bottom: 2px solid transparent;
transition: all 0.2s;
}
.modal-tabs__item:hover {
color: #2f6b98;
}
.modal-tabs__item--active {
color: #2f6b98;
border-bottom-color: #2f6b98;
font-weight: 500;
}
.no-data-link {
color: #d9d9d9;
cursor: not-allowed;
}
</style>