feat(credit): 企业详情页面增加子表数据导入功能

- 为18个信用相关API的导入方法添加companyId参数支持
- 在企业详情页面的各个子表tab中添加导入和刷新按钮
- 创建credit-company-related-import组件实现统一的导入弹窗
- 新增taxpayerCode字段到用户信息模型中
- 移除企业详情页面中冗余的描述项注释代码
- 实现基于企业ID或纳税人识别号的数据加载缓存机制
- 添加导入模板下载功能和文件类型验证
This commit is contained in:
2026-01-05 12:44:16 +08:00
parent 74b06dbc17
commit b494a7d951
3 changed files with 156 additions and 29 deletions

View File

@@ -1,5 +1,5 @@
VITE_APP_NAME=后台管理(开发环境) VITE_APP_NAME=后台管理(开发环境)
#VITE_API_URL=http://127.0.0.1:9200/api VITE_API_URL=http://127.0.0.1:9200/api
#VITE_SERVER_API_URL=http://127.0.0.1:8000/api #VITE_SERVER_API_URL=http://127.0.0.1:8000/api

View File

@@ -107,9 +107,12 @@ export async function getCreditUser(id: number) {
/** /**
* 导入招投标 * 导入招投标
*/ */
export async function importCreditUsers(file: File) { export async function importCreditUsers(file: File, companyId?: number) {
const formData = new FormData(); const formData = new FormData();
formData.append('file', file); formData.append('file', file);
if (companyId != null) {
formData.append('companyId', String(companyId));
}
const res = await request.post<ApiResult<unknown>>( const res = await request.post<ApiResult<unknown>>(
'/credit/credit-user/import', '/credit/credit-user/import',
formData, formData,

View File

@@ -93,24 +93,69 @@
import { useThemeStore } from '@/store/modules/theme'; import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import CreditCompanyRelatedImport from './credit-company-related-import.vue'; import CreditCompanyRelatedImport from './credit-company-related-import.vue';
import { pageCreditProject, importCreditProject } from '@/api/credit/creditProject'; import { pageCreditUser, importCreditUsers } from '@/api/credit/creditUser';
import { pageCreditExternal, importCreditExternal } from '@/api/credit/creditExternal'; import {
import { pageCreditRiskRelation, importCreditRiskRelation } from '@/api/credit/creditRiskRelation'; pageCreditExternal,
import { pageCreditCompetitor, importCreditCompetitor } from '@/api/credit/creditCompetitor'; importCreditExternal
import { pageCreditSupplier, importCreditSupplier } from '@/api/credit/creditSupplier'; } from '@/api/credit/creditExternal';
import { pageCreditCustomer, importCreditCustomer } from '@/api/credit/creditCustomer'; import {
import { pageCreditCaseFiling, importCreditCaseFiling } from '@/api/credit/creditCaseFiling'; pageCreditRiskRelation,
import { pageCreditMediation, importCreditMediation } from '@/api/credit/creditMediation'; importCreditRiskRelation
import { pageCreditCourtSession, importCreditCourtSession } from '@/api/credit/creditCourtSession'; } from '@/api/credit/creditRiskRelation';
import { pageCreditCourtAnnouncement, importCreditCourtAnnouncement } from '@/api/credit/creditCourtAnnouncement'; import {
import { pageCreditDeliveryNotice, importCreditDeliveryNotice } from '@/api/credit/creditDeliveryNotice'; pageCreditCompetitor,
import { pageCreditJudicialDocument, importCreditJudicialDocument } from '@/api/credit/creditJudicialDocument'; importCreditCompetitor
import { pageCreditJudgmentDebtor, importCreditJudgmentDebtor } from '@/api/credit/creditJudgmentDebtor'; } from '@/api/credit/creditCompetitor';
import { pageCreditBreachOfTrust, importCreditBreachOfTrust } from '@/api/credit/creditBreachOfTrust'; import {
import { pageCreditFinalVersion, importCreditFinalVersion } from '@/api/credit/creditFinalVersion'; pageCreditSupplier,
importCreditSupplier
} from '@/api/credit/creditSupplier';
import {
pageCreditCustomer,
importCreditCustomer
} from '@/api/credit/creditCustomer';
import {
pageCreditCaseFiling,
importCreditCaseFiling
} from '@/api/credit/creditCaseFiling';
import {
pageCreditMediation,
importCreditMediation
} from '@/api/credit/creditMediation';
import {
pageCreditCourtSession,
importCreditCourtSession
} from '@/api/credit/creditCourtSession';
import {
pageCreditCourtAnnouncement,
importCreditCourtAnnouncement
} from '@/api/credit/creditCourtAnnouncement';
import {
pageCreditDeliveryNotice,
importCreditDeliveryNotice
} from '@/api/credit/creditDeliveryNotice';
import {
pageCreditJudicialDocument,
importCreditJudicialDocument
} from '@/api/credit/creditJudicialDocument';
import {
pageCreditJudgmentDebtor,
importCreditJudgmentDebtor
} from '@/api/credit/creditJudgmentDebtor';
import {
pageCreditBreachOfTrust,
importCreditBreachOfTrust
} from '@/api/credit/creditBreachOfTrust';
import {
pageCreditFinalVersion,
importCreditFinalVersion
} from '@/api/credit/creditFinalVersion';
import { pageCreditXgxf, importCreditXgxf } from '@/api/credit/creditXgxf'; import { pageCreditXgxf, importCreditXgxf } from '@/api/credit/creditXgxf';
import { pageCreditGqdj, importCreditGqdj } from '@/api/credit/creditGqdj'; import { pageCreditGqdj, importCreditGqdj } from '@/api/credit/creditGqdj';
import { pageCreditJudiciary, importCreditJudiciaries } from '@/api/credit/creditJudiciary'; import {
pageCreditJudiciary,
importCreditJudiciaries
} from '@/api/credit/creditJudiciary';
const props = defineProps<{ const props = defineProps<{
// 弹窗是否打开 // 弹窗是否打开
@@ -161,9 +206,9 @@
const tabApiMap: Record<string, TabApiConfig> = { const tabApiMap: Record<string, TabApiConfig> = {
招投标: { 招投标: {
page: pageCreditProject as any, page: pageCreditUser as any,
importFn: importCreditProject as any, importFn: importCreditUsers as any,
templatePath: '/credit/credit-project/import/template' templatePath: '/credit/credit-user/import/template'
}, },
对外投资: { 对外投资: {
page: pageCreditExternal as any, page: pageCreditExternal as any,
@@ -235,7 +280,7 @@
importFn: importCreditFinalVersion as any, importFn: importCreditFinalVersion as any,
templatePath: '/credit/credit-final-version/import/template' templatePath: '/credit/credit-final-version/import/template'
}, },
'限制高消费': { 限制高消费: {
page: pageCreditXgxf as any, page: pageCreditXgxf as any,
importFn: importCreditXgxf as any, importFn: importCreditXgxf as any,
templatePath: '/credit/credit-xgxf/import/template' templatePath: '/credit/credit-xgxf/import/template'
@@ -259,6 +304,69 @@
ellipsis?: boolean; ellipsis?: boolean;
}; };
type TabColumnConfig = {
order?: string[];
hidden?: string[];
titleMap?: Record<string, string>;
};
const commonHiddenColumnKeys = new Set<string>([
'deleted',
'tenantId',
'userId',
'companyId'
]);
const commonTitleMap: Record<string, string> = {
id: 'ID',
name: '被执行人名称',
name1: '被执行人',
code: '税号',
url: '链接地址',
status: '状态',
comments: '备注',
createTime: '创建时间',
updateTime: '修改时间'
};
// 每个tab的“字段顺序/隐藏字段/中文表头”在这里配置
const tabColumnConfigMap: Record<string, TabColumnConfig> = {
招投标: {
order: [
'name',
'role',
'caseNumber',
'procurementName',
'winningName',
'winningPrice',
'releaseDate',
'url',
'createTime',
'updateTime'
],
hidden: [
'type',
'parentId',
'sortNumber',
'recommend',
'expirationTime',
'updateTime'
],
titleMap: {
name: '项目名称',
role: '企业角色',
caseNumber: '案号',
procurementName: '招采单位名称',
winningName: '中标单位名称',
winningPrice: '中标金额',
releaseDate: '发布日期',
url: '链接地址',
createTime: '创建时间',
updateTime: '修改时间'
}
}
};
type TabState = { type TabState = {
loading: boolean; loading: boolean;
data: Record<string, any>[]; data: Record<string, any>[];
@@ -280,7 +388,9 @@
// 子表导入弹窗 // 子表导入弹窗
const showRelatedImport = ref(false); const showRelatedImport = ref(false);
const relatedImportTabKey = ref(tabList[0].key); const relatedImportTabKey = ref(tabList[0].key);
const relatedImportConfig = computed(() => tabApiMap[relatedImportTabKey.value]); const relatedImportConfig = computed(
() => tabApiMap[relatedImportTabKey.value]
);
const relatedImportTitle = computed(() => { const relatedImportTitle = computed(() => {
const tab = tabList.find((t) => t.key === relatedImportTabKey.value); const tab = tabList.find((t) => t.key === relatedImportTabKey.value);
return `${tab?.label ?? relatedImportTabKey.value}批量导入`; return `${tab?.label ?? relatedImportTabKey.value}批量导入`;
@@ -405,12 +515,26 @@
return record.id ?? record.code ?? record.key ?? index; return record.id ?? record.code ?? record.key ?? index;
}; };
const buildColumns = (rows: Record<string, any>[]): TableColumn[] => { const buildColumns = (
tabKey: string,
rows: Record<string, any>[]
): TableColumn[] => {
if (!rows.length) { if (!rows.length) {
return []; return [];
} }
return Object.keys(rows[0]).map((key) => ({ const config = tabColumnConfigMap[tabKey];
title: key, const hidden = new Set<string>([
...commonHiddenColumnKeys,
...(config?.hidden ?? [])
]);
const titleMap = { ...commonTitleMap, ...(config?.titleMap ?? {}) };
const keysFromData = Object.keys(rows[0]);
const keys = config?.order?.length ? config.order : keysFromData;
const finalKeys = keys.filter((k) => !hidden.has(k));
return finalKeys.map((key) => ({
title: titleMap[key] ?? key,
dataIndex: key, dataIndex: key,
key, key,
ellipsis: true ellipsis: true
@@ -464,7 +588,7 @@
limit: 500 limit: 500
}); });
state.data = res?.list || []; state.data = res?.list || [];
state.columns = buildColumns(state.data); state.columns = buildColumns(key, state.data);
state.loadedIdentity = identity; state.loadedIdentity = identity;
} catch (e: any) { } catch (e: any) {
state.data = []; state.data = [];