293 lines
7.2 KiB
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>
|