Browse Source

新增招投标并修改合同和文档相关内容

ai_dev
zhouhaibin 2 weeks ago
parent
commit
6ccb26f1bb
  1. 52
      src/api/tenderReview/TenderTask/index.ts
  2. 117
      src/api/tenderReview/TenderTask/model.ts
  3. 192
      src/api/tenderReview/TenderTaskResults/index.ts
  4. 99
      src/api/tenderReview/TenderTaskResults/model.ts
  5. 12
      src/components/UniversalResultDrawer.vue
  6. 125
      src/configs/contractTaskConfigs.ts
  7. 58
      src/configs/documentTaskConfigs.ts
  8. 8
      src/configs/taskConfigs.ts
  9. 156
      src/configs/tenderTaskConfigs.ts
  10. 22
      src/enums/taskEnum.ts
  11. 42
      src/views/contractReview/ContractualTasks/ContractualResultDetailDrawer.vue
  12. 61
      src/views/contractReview/ContractualTasks/ContractualTasks.data.ts
  13. 78
      src/views/contractReview/ContractualTasks/list.vue
  14. 55
      src/views/tenderReview/TenderTask/TenderDocsDrawer.vue
  15. 56
      src/views/tenderReview/TenderTask/TenderResultDetailDrawer.vue
  16. 161
      src/views/tenderReview/TenderTask/TenderTask.data.ts
  17. 11
      src/views/tenderReview/TenderTask/TenderTaskModal.vue
  18. 169
      src/views/tenderReview/TenderTask/index.vue
  19. 55
      src/views/tenderReview/TenderTask/tender-caozuomiaoshu.md

52
src/api/tenderReview/TenderTask/index.ts

@ -1,6 +1,8 @@
import { defHttp } from '@/utils/http/axios';
import { ID, IDS, commonExport } from '@/api/base';
import { TenderTaskVO, TenderTaskForm, TenderTaskQuery } from './model';
import { UploadFileParams } from '#/axios';
import { AxiosProgressEvent } from 'axios';
/**
*
@ -8,7 +10,7 @@ import { TenderTaskVO, TenderTaskForm, TenderTaskQuery } from './model';
* @returns
*/
export function TenderTaskList(params?: TenderTaskQuery) {
return defHttp.get<TenderTaskVO[]>({ url: '/productManagement/TenderTask/list', params });
return defHttp.get<TenderTaskVO[]>({ url: '/tenderTask/tenderTasks/list', params });
}
/**
@ -17,7 +19,7 @@ export function TenderTaskList(params?: TenderTaskQuery) {
* @returns
*/
export function TenderTaskExport(params?: TenderTaskQuery) {
return commonExport('/productManagement/TenderTask/export', params ?? {});
return commonExport('/tenderTask/tenderTasks/export', params ?? {});
}
/**
@ -26,7 +28,7 @@ export function TenderTaskExport(params?: TenderTaskQuery) {
* @returns
*/
export function TenderTaskInfo(id: ID) {
return defHttp.get<TenderTaskVO>({ url: '/productManagement/TenderTask/' + id });
return defHttp.get<TenderTaskVO>({ url: '/tenderTask/tenderTasks/' + id });
}
/**
@ -35,7 +37,7 @@ export function TenderTaskInfo(id: ID) {
* @returns
*/
export function TenderTaskAdd(data: TenderTaskForm) {
return defHttp.postWithMsg<void>({ url: '/productManagement/TenderTask', data });
return defHttp.postWithMsg<void>({ url: '/tenderTask/tenderTasks', data, timeout: 1000 * 60 * 10 });
}
/**
@ -44,7 +46,7 @@ export function TenderTaskAdd(data: TenderTaskForm) {
* @returns
*/
export function TenderTaskUpdate(data: TenderTaskForm) {
return defHttp.putWithMsg<void>({ url: '/productManagement/TenderTask', data });
return defHttp.putWithMsg<void>({ url: '/tenderTask/tenderTasks', data });
}
/**
@ -53,5 +55,43 @@ export function TenderTaskUpdate(data: TenderTaskForm) {
* @returns
*/
export function TenderTaskRemove(id: ID | IDS) {
return defHttp.deleteWithMsg<void>({ url: '/productManagement/TenderTask/' + id },);
return defHttp.deleteWithMsg<void>({ url: '/tenderTask/tenderTasks/' + id });
}
/**
*
* @param id id
* @returns
*/
export function TenderTaskStop(id: ID | IDS) {
return defHttp.putWithMsg<void>({ url: '/tenderTask/tenderTasks/stopTask/' + id });
}
/**
*
* @param ossId ossId
* @returns
*/
export function TenderTaskDeleteFile(ossId: string) {
return defHttp.deleteWithMsg<void>({ url: '/tenderTask/tenderTasks/ossRemoveById/' + ossId });
}
/**
*
* @param params
* @param onUploadProgress
* @returns
*/
export function uploadTenderDocument(
params: UploadFileParams,
onUploadProgress?: (progressEvent: AxiosProgressEvent) => void,
) {
return defHttp.uploadFile<any>(
{
url: '/tenderTask/tenderTasks/back/upload',
onUploadProgress,
timeout: 1000 * 60 * 10,
},
params,
);
}

117
src/api/tenderReview/TenderTask/model.ts

@ -1,6 +1,11 @@
import { BaseEntity, PageQuery } from '@/api/base';
export interface TenderTaskVO {
/**
* ID
*/
id: string | number;
/**
*
*/
@ -16,6 +21,16 @@ export interface TenderTaskVO {
*/
taskName: string;
/**
*
*/
tenderDocumentName: string;
/**
*
*/
bidDocumentName: string;
/**
*
*/
@ -28,10 +43,75 @@ export interface TenderTaskVO {
/**
*
*/
progressStatus: string;
/**
*
*/
createTime: string;
/**
*
*/
createUser: string;
/**
*
*/
progress: string;
/**
*
*/
delFile: string;
/**
*
*/
childrenTasks: TenderChildTaskVO[];
/**
*
*/
taskDuration?: string;
/**
*
*/
taskType?: string;
}
export interface TenderChildTaskVO {
/**
* ID
*/
id: string | number;
/**
*
*/
taskName: string;
/**
*
*/
taskType: string;
/**
*
*/
taskDuration: string;
/**
*
*/
progressStatus: string;
/**
* ossId
*/
ossId: string | number;
}
export interface TenderTaskForm extends BaseEntity {
@ -50,6 +130,16 @@ export interface TenderTaskForm extends BaseEntity {
*/
taskName?: string;
/**
*
*/
tenderDocumentName?: string;
/**
*
*/
bidDocumentName?: string;
/**
*
*/
@ -62,14 +152,21 @@ export interface TenderTaskForm extends BaseEntity {
/**
*
*/
progressStatus?: string;
/**
* OSS ID
*/
tenderDocOssId?: string | number;
/**
* OSS ID
*/
bidDocZipOssId?: string | number;
}
export interface TenderTaskQuery extends PageQuery {
/**
*
*/
@ -85,6 +182,16 @@ export interface TenderTaskQuery extends PageQuery {
*/
taskName?: string;
/**
*
*/
tenderDocumentName?: string;
/**
*
*/
bidDocumentName?: string;
/**
*
*/
@ -97,10 +204,14 @@ export interface TenderTaskQuery extends PageQuery {
/**
*
*/
progressStatus?: string;
/**
*
*/
deleteFlag?: string;
/**
*
*/

192
src/api/tenderReview/TenderTaskResults/index.ts

@ -0,0 +1,192 @@
import { defHttp } from '@/utils/http/axios';
import { ID, IDS, commonExport } from '@/api/base';
import { TenderTaskResultsVO, TenderTaskResultsForm, TenderTaskResultsQuery, TenderTaskResultDetailVO } from './model';
import { message } from 'ant-design-vue';
interface DownloadOptions {
filename?: string;
mimeType?: string;
}
/**
*
* @param url
* @param onError
* @returns Promise<boolean>
*/
export async function useDownload(
url: string,
onError?: (error: any) => void
): Promise<boolean> {
try {
const response = await defHttp.get(
{
url,
responseType: 'blob',
timeout: 60000, // 设置较长的超时时间
},
{
isReturnNativeResponse: true,
// 自定义错误处理
errorMessageMode: 'none',
}
);
// 检查响应类型
const contentType = response.headers['content-type'];
if (contentType && contentType.includes('application/json')) {
// 如果返回的是JSON(通常是错误信息),转换并抛出
const reader = new FileReader();
reader.onload = () => {
const error = JSON.parse(reader.result as string);
message.error(error.message || '下载失败');
onError?.(error);
};
reader.readAsText(response.data);
return false;
}
// 获取文件名
const contentDisposition = response.headers['content-disposition'];
let fileName = '';
if (contentDisposition) {
const matches = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
if (matches && matches[1]) {
fileName = decodeURIComponent(matches[1].replace(/['"]/g, ''));
}
}
// 创建Blob对象
const blob = new Blob([response.data], {
type: contentType || 'application/octet-stream'
});
if (window.navigator && (window.navigator as any).msSaveOrOpenBlob) {
// 针对IE的处理
(window.navigator as any).msSaveOrOpenBlob(blob, fileName);
} else {
// 现代浏览器的处理
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = fileName;
link.style.display = 'none';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
}
return true;
} catch (error: any) {
console.error('下载失败:', error);
message.error(error.message || '下载失败,请稍后重试');
onError?.(error);
return false;
}
}
/**
*
* @param params
* @returns
*/
export function TenderTaskResultsList(params?: TenderTaskResultsQuery) {
return defHttp.get<TenderTaskResultsVO[]>({ url: '/tenderTask/tenderTaskResults/list', params });
}
/**
*
* @param params
* @returns
*/
export function TenderTaskResultsExport(params?: TenderTaskResultsQuery) {
return commonExport('/tenderTask/tenderTaskResults/export', params ?? {});
}
/**
*
* @param id id
* @returns
*/
export function TenderTaskResultsInfo(id: ID) {
return defHttp.get<TenderTaskResultsVO>({ url: '/tenderTask/tenderTaskResults/' + id });
}
/**
* id查询详细分类的招投标任务结果
* @param taskId ID
* @returns
*/
export function getDetailResultsByTaskId(taskId: ID) {
return defHttp.get<TenderTaskResultDetailVO[]>({ url: '/tenderTask/tenderTaskResults/taskDetail/' + taskId });
}
/**
*
* @param data
* @returns
*/
export function TenderTaskResultsAdd(data: TenderTaskResultsForm) {
return defHttp.postWithMsg<void>({ url: '/tenderTask/tenderTaskResults', data });
}
/**
*
* @param data
* @returns
*/
export function TenderTaskResultsUpdate(data: TenderTaskResultsForm) {
return defHttp.putWithMsg<void>({ url: '/tenderTask/tenderTaskResults', data });
}
/**
*
* @param id id
* @returns
*/
export function TenderTaskResultsRemove(id: ID | IDS) {
return defHttp.deleteWithMsg<void>({ url: '/tenderTask/tenderTaskResults/' + id });
}
/**
* /
* @param id ID
* @param field isRead/isAdopted
* @param value 0/1
* @returns
*/
export function updateResultItemStatus(id: ID, field: 'isRead' | 'isAdopted', value: '0' | '1') {
return defHttp.putWithMsg<void>({
url: `/tenderTask/tenderTaskResults/updateResultItemStatus/${id}/${field}/${value}`
});
}
/**
*
* @param id id
* @returns
*/
export function TenderTaskResultDownload(id: ID | IDS) {
return useDownload(`/tenderTask/tenderTaskResults/downloadResult/${id}`);
}
/**
* PDF文件流
* @param taskId ID
* @returns Promise<Blob>
*/
export function getPdfStream(taskId: ID): Promise<Blob> {
return defHttp.get(
{
url: `/tenderTask/tenderTaskResults/getPdfStream/${taskId}`,
responseType: 'blob',
timeout:600000
},
{
isReturnNativeResponse: true,
errorMessageMode: 'none',
}
).then(response => response.data);
}

99
src/api/tenderReview/TenderTaskResults/model.ts

@ -0,0 +1,99 @@
import { BaseEntity, PageQuery } from '@/api/base';
export interface TenderTaskResultsVO {
/**
*
*/
result?: string;
}
export interface TenderTaskResultDetailVO {
/**
*
*/
name: string;
/**
*
*/
results: {
/**
* ID
*/
id?: string;
/**
*
*/
serialNumber?: number;
/**
*
*/
issueName?: string;
/**
*
*/
originalText?: string;
/**
*
*/
comparedText?: string;
/**
*
*/
modifiedContent?: string;
/**
*
*/
modificationDisplay?: string;
/**
*
*/
existingIssues?: string;
/**
*
*/
reviewBasis?: {
/**
*
*/
reviewContent?: string;
/**
*
*/
reviewPoints?: string[];
};
/**
*
*/
isRead?: string;
/**
*
*/
isAdopted?: string;
}[];
}
export interface TenderTaskResultsForm extends BaseEntity {
}
export interface TenderTaskResultsQuery extends PageQuery {
/**
* id
*/
id?: string | number;
/**
* id
*/
tenderTaskId?: string | number;
/**
*
*/
result?: string;
/**
*
*/
params?: any;
}

12
src/components/UniversalResultDrawer.vue

@ -465,10 +465,10 @@
return [];
}
// tabs""
const dataToProcess = props.taskResultDetail.slice(1); //
// 使
const dataToProcess = props.taskResultDetail;
//
//
return dataToProcess.map((category, index) => {
let label = `${category.name} (${category.results?.length || 0})`;
@ -480,7 +480,7 @@
return {
key: category.name, // 使namekey
label: label,
dataIndex: index + 1, // +1
dataIndex: index, //
name: category.name
};
});
@ -492,8 +492,8 @@
return [];
}
// tabs""
const dataToSearch = props.taskResultDetail.slice(1); //
//
const dataToSearch = props.taskResultDetail;
// tab name
const targetCategory = dataToSearch.find(category => category.name === currentTab.value);

125
src/configs/contractTaskConfigs.ts

@ -4,16 +4,15 @@ import type { TaskConfig } from './taskConfigTypes';
// 合同审核任务配置
export const CONTRACT_TASK_CONFIGS: Record<string, TaskConfig> = {
// 合同审核(多标签模式)
"contractReview": {
taskType: "contractReview",
name: "合同审核",
// 实质性审查
"contractSubstantiveReview": {
taskType: "contractSubstantiveReview",
name: "实质性审查",
mode: "tabs",
pdfConfig: {
layout: "split",
layout: "single",
sources: [
{ id: "contract", title: "合同文件", apiField: "id" },
{ id: "bid", title: "招标文件", apiField: "id" }
{ id: "contract", title: "合同文件", apiField: "id" }
]
},
tabs: [
@ -58,7 +57,22 @@ export const CONTRACT_TASK_CONFIGS: Record<string, TaskConfig> = {
}
}
]
}
]
},
// 合规性审查
"contractComplianceReview": {
taskType: "contractComplianceReview",
name: "合规性审查",
mode: "tabs",
pdfConfig: {
layout: "single",
sources: [
{ id: "contract", title: "合同文件", apiField: "id" }
]
},
tabs: [
{
key: "compliance",
label: "合规性审查",
@ -77,24 +91,6 @@ export const CONTRACT_TASK_CONFIGS: Record<string, TaskConfig> = {
pdfSource: 'contract',
required: true
},
// {
// field: 'existingIssues',
// title: '合规性问题',
// dataType: 'string',
// displayType: 'markdown'
// },
// {
// field: 'modifiedContent',
// title: '修改建议',
// dataType: 'string',
// displayType: 'markdown',
// showComparison: true,
// comparisonConfig: {
// comparisonField: 'modificationDisplay',
// comparisonTitle: '修改情况展示',
// showButton: true
// }
// },
{
field: 'reviewBasis',
title: '法规依据',
@ -109,7 +105,23 @@ export const CONTRACT_TASK_CONFIGS: Record<string, TaskConfig> = {
}
}
]
}
]
},
// 一致性审查
"contractConsistencyReview": {
taskType: "contractConsistencyReview",
name: "一致性审查",
mode: "tabs",
pdfConfig: {
layout: "split",
sources: [
{ id: "contract", title: "合同文件", apiField: "id" },
{ id: "bid", title: "招标文件", apiField: "id" }
]
},
tabs: [
{
key: "consistency",
label: "一致性审查",
@ -136,20 +148,59 @@ export const CONTRACT_TASK_CONFIGS: Record<string, TaskConfig> = {
displayType: 'markdown',
pdfSource: 'bid',
required: true
}
]
}
]
},
// {
// field: 'modifiedContent',
// title: '修改建议',
// dataType: 'string',
// displayType: 'markdown',
// showComparison: true,
// comparisonConfig: {
// comparisonField: 'modificationDisplay',
// comparisonTitle: '修改情况展示',
// showButton: true
// }
// }
// 通用合同审查配置(兜底配置)
"contractReview": {
taskType: "contractReview",
name: "合同审查",
mode: "single",
pdfConfig: {
layout: "single",
sources: [
{ id: "contract", title: "合同文件", apiField: "id" }
]
},
fields: [
{
field: 'originalText',
title: '原文',
dataType: 'string',
displayType: 'markdown',
pdfSource: 'contract',
required: true
},
{
field: 'existingIssues',
title: '存在问题',
dataType: 'string',
displayType: 'markdown'
},
{
field: 'modifiedContent',
title: '修改建议',
dataType: 'string',
displayType: 'markdown',
showComparison: true,
comparisonConfig: {
comparisonField: 'modificationDisplay',
comparisonTitle: '修改情况展示',
showButton: true
}
},
{
field: 'reviewBasis',
title: '审查依据',
dataType: 'json',
displayType: 'markdown',
jsonConfig: {
extractFields: ['review_points','review_content'],
separator: ':'
}
}
]
}

58
src/configs/documentTaskConfigs.ts

@ -215,7 +215,65 @@ export const DOCUMENT_TASK_CONFIGS: Record<string, TaskConfig> = {
}
}
]
},
// 全文重复检查
"tenderReview": {
taskType: "tenderReview",
name: "投标文件审核",
mode: "single",
pdfConfig: {
layout: "single",
sources: [
{ id: "document", title: "文档", apiField: "id" }
]
},
fields: [
{
field: 'issueName',
title: '合规性分类-具体问题(示例:资质审查-业绩要求)',
dataType: 'string',
displayType: 'markdown',
pdfSource: 'document'
},
{
field: 'originalText',
title: '原文',
dataType: 'string',
displayType: 'markdown',
pdfSource: 'document'
},
{
field: 'reviewBasis',
title: '相关法律法规政策',
dataType: 'json',
displayType: 'markdown',
jsonConfig: {
extractFields: ['review_points'],
separator: ':',
fieldProcessors: {
'review_points': (value) => Array.isArray(value) ? value.join('\n') : value
}
}
},
{
field: 'modifiedContent',
title: '修改建议',
dataType: 'string',
displayType: 'markdown',
pdfSource: 'document'
},
{
field: 'reviewBasis',
title: '风险等级(红色预警:直接废标项,橙色风险:可能引发投诉项)',
dataType: 'json',
displayType: 'markdown',
jsonConfig: {
extractFields: ['risk_level'],
separator: ':'
}
}
]
},
};
// 获取文档任务配置

8
src/configs/taskConfigs.ts

@ -3,11 +3,13 @@
import type { TaskConfig, FieldConfig } from './taskConfigTypes';
import { DOCUMENT_TASK_CONFIGS, getDocumentTaskConfig } from './documentTaskConfigs';
import { CONTRACT_TASK_CONFIGS, getContractTaskConfig } from './contractTaskConfigs';
import { TENDER_TASK_CONFIGS, getTenderTaskConfig } from './tenderTaskConfigs';
// 合并所有任务配置
const ALL_TASK_CONFIGS: Record<string, TaskConfig> = {
...DOCUMENT_TASK_CONFIGS,
...CONTRACT_TASK_CONFIGS
...CONTRACT_TASK_CONFIGS,
...TENDER_TASK_CONFIGS
};
// 统一的获取任务配置函数
@ -20,6 +22,10 @@ export function getTaskConfig(taskType: string): TaskConfig | null {
config = getContractTaskConfig(taskType);
if (config) return config;
// 最后尝试从招投标任务配置中获取
config = getTenderTaskConfig(taskType);
if (config) return config;
return null;
}

156
src/configs/tenderTaskConfigs.ts

@ -0,0 +1,156 @@
// 招投标审核任务配置文件
import type { TaskConfig } from './taskConfigTypes';
// 招投标审核任务配置
export const TENDER_TASK_CONFIGS: Record<string, TaskConfig> = {
// 招投标文件审核(多标签模式)
"sjjbidAnalysis": {
taskType: "sjjbidAnalysis",
name: "招投标文件审核",
mode: "tabs",
pdfConfig: {
layout: "split",
sources: [
{ id: "bid", title: "投标文件", apiField: "id" },
{ id: "tender", title: "招标文件", apiField: "id" }
]
},
tabs: [
{
key: "两两相似",
label: "两两相似",
pdfConfig: {
layout: "split",
sources: [
{ id: "bid", title: "投标文件", apiField: "id" },
{ id: "tender", title: "招标文件", apiField: "id" }
]
},
fields: [
{
field: 'originalText',
title: '文档1内容',
dataType: 'string',
displayType: 'markdown',
pdfSource: 'bid',
required: true
},
{
field: 'comparedText',
title: '文档2内容',
dataType: 'string',
displayType: 'markdown',
pdfSource: 'bid',
required: true
},
{
field: 'modificationDisplay',
title: '相似情况分析',
dataType: 'string',
displayType: 'markdown'
},
{
field: 'reviewBasis',
title: '分析详情',
dataType: 'json',
displayType: 'markdown',
jsonConfig: {
extractFields: ['review_content', 'review_points'],
separator: ':'
}
}
]
},
{
key: "错别字",
label: "错别字",
pdfConfig: {
layout: "split",
sources: [
{ id: "bid", title: "投标文件", apiField: "id" },
{ id: "tender", title: "招标文件", apiField: "id" }
]
},
fields: [
{
field: 'originalText',
title: '文档1原文',
dataType: 'string',
displayType: 'markdown',
pdfSource: 'bid',
required: true
},
{
field: 'comparedText',
title: '文档2原文',
dataType: 'string',
displayType: 'markdown',
pdfSource: 'bid',
required: true
},
{
field: 'modificationDisplay',
title: '错误分析与修改建议',
dataType: 'string',
displayType: 'markdown'
},
{
field: 'reviewBasis',
title: '错误详情',
dataType: 'json',
displayType: 'markdown',
jsonConfig: {
extractFields: ['review_content', 'review_points'],
separator: ':',
fieldProcessors: {
'review_points': (value) => Array.isArray(value) ? value.join('\n') : value
}
}
}
]
},
{
key: "多家相同内容",
label: "多家相同内容",
pdfConfig: {
layout: "single",
sources: [
{ id: "bid", title: "投标文件", apiField: "id" }
]
},
fields: [
{
field: 'modificationDisplay',
title: '涉及文档',
dataType: 'string',
displayType: 'markdown'
},
{
field: 'reviewBasis',
title: '各文档具体内容',
dataType: 'json',
displayType: 'markdown',
jsonConfig: {
extractFields: ['review_content', 'review_points'],
separator: ':',
fieldProcessors: {
'review_points': (value) => Array.isArray(value) ? value.join('\n\n') : value
}
}
}
]
}
]
}
};
// 获取招投标任务配置
export function getTenderTaskConfig(taskType: string): TaskConfig | null {
return TENDER_TASK_CONFIGS[taskType] || null;
}
// 获取所有招投标任务配置
export function getAllTenderTaskConfigs(): TaskConfig[] {
return Object.values(TENDER_TASK_CONFIGS);
}

22
src/enums/taskEnum.ts

@ -74,11 +74,23 @@ export const SchemeTask = {
// 合同审核子任务
export const ContractTask = {
CONTRACT_REVIEW: {
value: 'contractReview',
label: '合同审核',
icon: 'fluent-mdl2:document-approval',
color: '#722ED1'
CONTRACT_SUBSTANTIVE_REVIEW: {
value: 'contractSubstantiveReview',
label: '实质性审查',
icon: 'mdi:file-document-check-outline',
color: '#E6A23C'
},
CONTRACT_COMPLIANCE_REVIEW: {
value: 'contractComplianceReview',
label: '合规性审查',
icon: 'mdi:file-document-check',
color: '#67C23A'
},
CONTRACT_CONSISTENCY_REVIEW: {
value: 'contractConsistencyReview',
label: '一致性审查',
icon: 'mdi:file-compare',
color: '#409EFF'
}
} as const;

42
src/views/contractReview/ContractualTasks/ContractualResultDetailDrawer.vue

@ -3,7 +3,7 @@
:visible="visible"
:title="title"
:width="width"
:taskType="'contractReview'"
:taskType="computedTaskType"
:taskResultDetail="taskResultDetail as any"
:taskInfo="taskInfo"
:getPdfStream="getPdfStream"
@ -14,7 +14,7 @@
</template>
<script lang="ts" setup>
import { type PropType } from 'vue';
import { type PropType, computed } from 'vue';
import UniversalResultDrawer from '@/components/UniversalResultDrawer.vue';
import { ContractualTaskResultDetailVO } from '@/api/contractReview/ContractualTaskResults/model';
import { updateResultItemStatus, getPdfStream } from '@/api/contractReview/ContractualTaskResults';
@ -44,6 +44,44 @@
const emit = defineEmits(['update:visible', 'close']);
//
const computedTaskType = computed(() => {
// taskResultDetail
if (props.taskResultDetail && props.taskResultDetail.length > 0) {
const firstCategory = props.taskResultDetail[0];
if (firstCategory && firstCategory.name) {
// taskType
switch (firstCategory.name) {
case '实质性审查':
return 'contractSubstantiveReview';
case '合规性审查':
return 'contractComplianceReview';
case '一致性审查':
return 'contractConsistencyReview';
default:
break;
}
}
}
// taskInfotaskName
if (props.taskInfo && props.taskInfo.taskName) {
switch (props.taskInfo.taskName) {
case 'contractSubstantiveReview':
return 'contractSubstantiveReview';
case 'contractComplianceReview':
return 'contractComplianceReview';
case 'contractConsistencyReview':
return 'contractConsistencyReview';
default:
break;
}
}
//
return 'contractReview';
});
//
const handleStatusChange = async (id: string, field: string, value: string) => {
return await updateResultItemStatus(id, field as 'isRead' | 'isAdopted', value as '0' | '1');

61
src/views/contractReview/ContractualTasks/ContractualTasks.data.ts

@ -38,11 +38,6 @@ export const formSchemas: FormSchema[] = [
field: 'documentName',
component: 'Input',
},
{
label: '审查类型',
field: 'reviewTypes',
component: 'Input',
},
{
label: '状态',
field: 'progressStatus',
@ -54,41 +49,12 @@ export const formSchemas: FormSchema[] = [
];
const { renderDict } = useRender();
export const columns: BasicColumn[] = [
{
title: '任务名称',
dataIndex: 'taskName',
customRender: ({ value }) => renderDict(value, 'contract_review'),
},
{
title: '文档名称',
dataIndex: 'documentName',
},
{
title: '审查类型',
dataIndex: 'reviewTypes',
customRender: ({ value }) => {
if (!value) return '-';
// 将逗号分隔的字符串转换为更友好的显示格式
const types = value.split(',').map((type: string) => {
switch (type.trim()) {
case 'substantive':
return '实质性审查';
case 'compliance':
return '合规性审查';
case 'consistency':
return '一致性审查';
default:
return type.trim();
}
});
return types.join('、');
},
},
// 父表列配置
export const columns: BasicColumn[] = [
{
title: '审查立场',
dataIndex: 'contractPartyRole',
title: '合同文件名称',
dataIndex: 'contractDocumentName',
},
{
title: '上传时间',
@ -97,7 +63,20 @@ export const columns: BasicColumn[] = [
{
title: '提交人',
dataIndex: 'createUser',
auth: 'documentReview:DocumentTasks:tableShow',
// auth: 'documentReview:DocumentTasks:tableShow',
},
{
title: '进度',
dataIndex: 'progress',
},
];
// 子表列配置
export const childColumns: BasicColumn[] = [
{
title: '任务名称',
dataIndex: 'taskName',
customRender: ({ value }) => renderDict(value, 'contract_review'),
},
{
title: '任务耗时',
@ -127,12 +106,12 @@ export const modalSchemas: FormSchema[] = [
required: true,
component: 'Select',
componentProps: {
options:getDictOptions('contract_review'),
options: getDictOptions('contract_review'),
mode: 'multiple',
},
},
{
label: '文档名称',
label: '合同文档',
field: 'ossId',
required: true,
component: 'Upload',

78
src/views/contractReview/ContractualTasks/list.vue

@ -1,6 +1,6 @@
<template>
<PageWrapper dense>
<BasicTable @register="registerTable">
<BasicTable @register="registerTable" @expand="tableExpand">
<template #toolbar>
<!-- <a-button
@click="downloadExcel(ContractualTasksExport, '合同任务数据', getForm().getFieldsValue())"
@ -22,6 +22,32 @@
>新增</a-button
>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction
stopButtonPropagation
:actions="[
{
label: record.childrenTasks.length > 1 ? '下载全部' : '下载',
icon: IconEnum.DOWNLOAD,
type: 'primary',
color: 'success',
ghost: true,
ifShow: () => {
if (record.progress.includes('100%')) {
return true;
} else {
return false;
}
},
onClick: handleDownload.bind(null, record),
},
]"
/>
</template>
</template>
<template #expandedRowRender>
<BasicTable @register="registerChildTable">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction
@ -88,6 +114,8 @@
</template>
</template>
</BasicTable>
</template>
</BasicTable>
<ContractualTasksModal @register="registerModal" @reload="reload" />
<DocsDrawer @register="registerDrawer" />
<ContractualResultDetailDrawer
@ -107,7 +135,7 @@
import { downloadExcel } from '@/utils/file/download';
import { useModal } from '@/components/Modal';
import ContractualTasksModal from './ContractualTasksModal.vue';
import { formSchemas, columns } from './ContractualTasks.data';
import { formSchemas, columns, childColumns } from './ContractualTasks.data';
import { IconEnum } from '@/enums/appEnum';
import DocsDrawer from '@/views/documentReview/DocumentTasks/DocsDrawer.vue';
import { useDrawer } from '@/components/Drawer';
@ -127,6 +155,7 @@
const resultDetailDrawerVisible = ref(false);
const taskResultDetail = ref<ContractualTaskResultDetailVO[]>([]);
const currentTaskInfo = ref<Recordable>({});
const childTableData = ref([]);
defineOptions({ name: 'ContractualTasks' });
@ -137,7 +166,9 @@
title: '合同任务列表',
api: ContractualTasksList,
showIndexColumn: false,
clickToRowSelect: false,
rowKey: 'id',
expandRowByClick: false,
useSearchForm: true,
formConfig: {
schemas: formSchemas,
@ -157,6 +188,24 @@
},
});
const [registerChildTable, { setProps: setChildProps }] = useTable({
size: 'small', //
api: getchildTableData,
columns: childColumns,
rowKey: 'id',
useSearchForm: false,
showIndexColumn: false,
showTableSetting: false,
pagination: false,
maxHeight: 50,
actionColumn: {
width: 200,
title: '操作',
key: 'action',
fixed: 'right',
},
});
const [registerModal, { openModal }] = useModal();
// refresh
@ -192,6 +241,23 @@
resultDetailDrawerVisible.value = false;
}
function tableExpand(expanded, record) {
if (expanded) {
childTableData.value = record.childrenTasks;
console.log('expanded, record', expanded, record);
}
}
// getchildTableData
function getchildTableData() {
console.log('childTableData', childTableData.value);
const height = 50 * childTableData.value.length;
setChildProps({ maxHeight: height });
// Promise
return Promise.resolve(childTableData.value);
}
async function handleStop(record: Recordable) {
await DocumentTasksStop(record.id);
await reload();
@ -203,9 +269,17 @@
async function handleDownload(record: Recordable) {
if (record.childrenTasks?.length > 1) {
await ContractualTaskResultDownload(record.childrenTasks.map((item) => item.id));
await reload();
} else if (record.childrenTasks?.length == 1) {
await ContractualTaskResultDownload([record.childrenTasks[0].id]);
await reload();
} else {
await ContractualTaskResultDownload([record.id]);
await reload();
}
}
</script>
<style scoped></style>

55
src/views/tenderReview/TenderTask/TenderDocsDrawer.vue

@ -0,0 +1,55 @@
<template>
<BasicDrawer v-bind="$attrs" title="结果详情" :width="drawerWidth" @register="registerDrawer">
<!-- 纯预览 -->
<MdPreview
:modelValue="value"
:theme="theme"
previewTheme="github"
codeTheme="github"
:showCodeRowNumber="true"
:previewOnly="true"
/>
<template #footer> </template>
</BasicDrawer>
</template>
<script setup lang="ts">
import text from './tender-caozuomiaoshu.md?raw';
import { MdPreview } from 'md-editor-v3';
import 'md-editor-v3/lib/style.css';
import { ref, onMounted } from 'vue';
import { BasicDrawer, useDrawer, useDrawerInner } from '@/components/Drawer';
import { useMaxWidthOrDefault } from '@/hooks/web/useSize';
const value = ref<string>('');
const type = ref<string>('markdown');
const MarkdownViewerkeynum = ref<number>(0);
const iframeKey = ref<number>(10);
const drawerWidth = useMaxWidthOrDefault(1000);
const textvalue = ref<string>(text);
const [registerDrawer] = useDrawerInner(init);
// 'light' | 'dark'
const theme = ref<'light' | 'dark'>('light');
onMounted(() => {});
function init(data) {
console.log('TenderDocsDrawer', data, document.documentElement.clientHeight);
if (data) {
value.value = data.value;
type.value = data.type;
MarkdownViewerkeynum.value += 1;
iframeKey.value += 1;
if (type.value == 'def') {
console.log(textvalue.value);
value.value = textvalue.value;
}
}
}
</script>
<style scoped>
iframe {
width: 100%;
}
</style>

56
src/views/tenderReview/TenderTask/TenderResultDetailDrawer.vue

@ -0,0 +1,56 @@
<template>
<UniversalResultDrawer
:visible="visible"
:title="title"
:width="width"
:taskType="taskInfo.taskName || 'checkTenderError'"
:taskResultDetail="taskResultDetail as any"
:taskInfo="taskInfo"
:getPdfStream="handleGetPdfStream"
:updateResultItemStatus="handleStatusChange"
@update:visible="$emit('update:visible', $event)"
@close="$emit('close')"
/>
</template>
<script lang="ts" setup>
import { type PropType } from 'vue';
import UniversalResultDrawer from '@/components/UniversalResultDrawer.vue';
import { TenderTaskResultDetailVO } from '@/api/tenderReview/TenderTaskResults/model';
import { updateResultItemStatus, getPdfStream } from '@/api/tenderReview/TenderTaskResults';
const props = defineProps({
visible: {
type: Boolean,
default: false
},
title: {
type: String,
default: '招投标审核结果'
},
width: {
type: [String, Number],
default: '95%'
},
taskResultDetail: {
type: Array as PropType<TenderTaskResultDetailVO[]>,
default: () => []
},
taskInfo: {
type: Object,
default: () => ({})
}
});
const emit = defineEmits(['update:visible', 'close']);
// PDF
const handleGetPdfStream = async (taskId: string) => {
return await getPdfStream(taskId);
};
//
const handleStatusChange = async (id: string, field: string, value: string) => {
return await updateResultItemStatus(id, field as 'isRead' | 'isAdopted', value as '0' | '1');
};
</script>

161
src/views/tenderReview/TenderTask/TenderTask.data.ts

@ -2,74 +2,64 @@ import { BasicColumn } from '@/components/Table';
import { FormSchema } from '@/components/Form';
import { getDictOptions } from '@/utils/dict';
import { useRender } from '@/hooks/component/useRender';
import { uploadDocument } from '@/api/documentReview/DocumentTasks';
import { useUserStore } from '@/store/modules/user';
import { RoleEnum } from '@/enums/roleEnum';
import { uploadTenderDocument } from '@/api/tenderReview/TenderTask';
const { roleList } = useUserStore();
export const formSchemas: FormSchema[] = [
// {
// label: '模型所属行业',
// field: 'taskIndustry',
// component: 'Select',
// componentProps: {
// options: getDictOptions('model_industry')
// },
// },
// {
// label: '模型所属区域',
// field: 'taskRegion',
// component: 'Select',
// componentProps: {
// options: getDictOptions('model_region')
// },
// },
{
label: '任务名称',
field: 'taskNameList',
component: 'Select',
componentProps: {
options: getDictOptions('tender_review'),
options: [{
label: '招标文件文本审核',
value: 'sjjbidAnalysis',
},
{
label: '招标文件图片审核',
value: 'sjjbidImageAnalysis',
}],
mode: 'multiple',
defaultValue:"tenderSummary"
},
},
{
label: '文档名称',
field: 'documentName',
label: '招标文件名称',
field: 'tenderDocumentName',
component: 'Input',
},
{
label: '投标文件名称',
field: 'bidDocumentName',
component: 'Input',
},
{
label: '状态',
label: '进度状态',
field: 'progressStatus',
component: 'Select',
componentProps: {
options: getDictOptions('document_task_status'),
options: getDictOptions('document_task_status')
},
},
{
label: '文件是否已删除',
field: 'deleteFlag',
component: 'Select',
componentProps: {
options: getDictOptions('sys_yes_no')
},
},
];
const { renderDict } = useRender();
export const columns: BasicColumn[] = [
{
title: '任务名称',
dataIndex: 'taskName',
customRender: ({ value }) => renderDict(value, 'tender_review'),
},
{
title: '文档名称',
dataIndex: 'documentName',
},
// 父表列配置
export const columns: BasicColumn[] = [
{
title: '模型所属区域',
dataIndex: 'taskRegion',
customRender: ({ value }) => renderDict(value, 'model_region'),
title: '招标文件名称',
dataIndex: 'tenderDocumentName',
},
{
title: '模型所属行业',
dataIndex: 'taskIndustry',
customRender: ({ value }) => renderDict(value, 'model_industry'),
title: '投标文件名称',
dataIndex: 'bidDocumentName',
},
{
title: '上传时间',
@ -78,7 +68,32 @@ export const columns: BasicColumn[] = [
{
title: '提交人',
dataIndex: 'createUser',
auth: 'documentReview:DocumentTasks:tableShow',
},
{
title: '进度',
dataIndex: 'progress',
},
];
// 子表列配置 - 与文档审核任务保持一致
export const childColumns: BasicColumn[] = [
{
title: '任务名称',
dataIndex: 'taskName',
customRender: ({ value, record }) => {
if (value === 'sjjbidAnalysis') {
return '招标文件文本审核';
} else if (value === 'sjjbidImageAnalysis') {
return '招标文件图片审核';
}
return value;
},
},
{
title: '任务类型',
dataIndex: 'taskType',
ifShow: false,
customRender: ({ value }) => renderDict(value, 'task_type'),
},
{
title: '任务耗时',
@ -93,58 +108,46 @@ export const columns: BasicColumn[] = [
export const modalSchemas: FormSchema[] = [
{
label: '模型所属区域',
field: 'taskRegion',
label: '任务名称',
field: 'taskNameList',
required: true,
component: 'Select',
// componentProps: {
// options: taskRegionPermission(),
// defaultValue:"normal",
// },
componentProps: () => {
const isSuperAdmin = roleList.includes(RoleEnum.SUPER_ADMIN);
let options = getDictOptions('model_region');
if (!isSuperAdmin) {
// 如果不是超级管理员,移除 label 带有 '#' 的项
options = options.filter((option) => !option.label.includes('#'));
}
return {
options: options,
defaultValue: 'normal',
};
},
componentProps: {
options: [{
label: '招标文件文本审核',
value: 'sjjbidAnalysis',
},
{
label: '模型所属行业',
field: 'taskIndustry',
required: true,
component: 'Select',
componentProps: {
options: getDictOptions('model_industry'),
defaultValue: 'normal',
label: '招标文件图片审核',
value: 'sjjbidImageAnalysis',
}],
mode: 'multiple',
},
},
{
label: '任务名称',
field: 'taskNameList',
required: true,
component: 'Select',
label: '招标文件',
field: 'tenderDocOssId',
component: 'Upload',
componentProps: {
options: getDictOptions('tender_review') ,
mode: 'multiple',
accept: ['.docx', '.pdf'],
maxSize: 1000,
multiple: false,
resultField: 'ossId',
// api: uploadTenderDocument,
beforeUploadPrompt:"严禁在本互联网非涉密平台处理、传输国家秘密。请再次确认您上传的文件资料不涉及国家秘密。"
},
},
{
label: '文档名称',
field: 'ossId',
label: '投标文件集',
field: 'bidDocZipOssId',
required: true,
component: 'Upload',
componentProps: {
accept: ['.docx', '.doc', '.wps'],
maxSize: 500,
accept: ['.zip'],
maxSize: 1000,
multiple: false,
resultField: 'ossId',
api: uploadDocument,
// api: uploadTenderDocument,
beforeUploadPrompt:"严禁在本互联网非涉密平台处理、传输国家秘密。请再次确认您上传的文件资料不涉及国家秘密。"
},
},

11
src/views/tenderReview/TenderTask/TenderTaskModal.vue

@ -17,7 +17,6 @@
import { computed, ref, unref } from 'vue';
import { TenderTaskInfo, TenderTaskAdd, TenderTaskUpdate } from '@/api/tenderReview/TenderTask';
import { modalSchemas } from './TenderTask.data';
import { ModelUserPromptssettingInfoByUserId } from '@/api/modelConfiguration/ModelUserPromptssetting/index';
defineOptions({ name: 'TenderTaskModal' });
@ -31,8 +30,6 @@
const [registerInnerModal, { modalLoading, closeModal }] = useModalInner(
async (data: { record?: Recordable; update: boolean }) => {
modalLoading(true);
const settings = await ModelUserPromptssettingInfoByUserId();
await setFieldsValue(settings);
const { record, update } = data;
isUpdate.value = update;
if (update && record) {
@ -53,10 +50,16 @@
try {
modalLoading(true);
const data = await validate();
data['ossId'] = data['ossId'][0];
if (unref(isUpdate)) {
await TenderTaskUpdate(data);
} else {
if(data['tenderDocOssId']){
data['tenderDocOssId'] = data['tenderDocOssId'][0];
}
if(data['bidDocZipOssId']){
data['bidDocZipOssId'] = data['bidDocZipOssId'][0];
}
await TenderTaskAdd(data);
}
emit('reload');

169
src/views/tenderReview/TenderTask/index.vue

@ -1,7 +1,15 @@
<template>
<PageWrapper dense>
<BasicTable @register="registerTable">
<BasicTable @register="registerTable" @expand="tableExpand">
<template #toolbar>
<div>
<a-button
id="how-to-edit"
class="font-bold"
type="link"
@click="openDrawer(true, { value: '', type: 'def' })"
>👉如何新增任务?
</a-button>
<a-button
@click="
downloadExcel(TenderTaskExport, '招标摘要任务数据', getForm().getFieldsValue())
@ -23,7 +31,52 @@
v-auth="'productManagement:TenderTask:add'"
>新增</a-button
>
</div>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction
stopButtonPropagation
:actions="[
{
label: record.childrenTasks.length > 1 ? '下载全部' : '下载',
icon: IconEnum.DOWNLOAD,
type: 'primary',
color: 'success',
ghost: true,
ifShow: () => {
if (record.progress.includes('100%')) {
return true;
} else {
return false;
}
},
onClick: handleDownload.bind(null, record),
},
{
label: '删文件',
icon: IconEnum.DOWNLOAD,
type: 'primary',
color: 'error',
ghost: true,
ifShow: () => {
if (record.progress.includes('100%')) {
if(record.delFile=='Y'){
return false;
}
return true;
} else {
return false;
}
},
onClick: handleDeleteFile.bind(null, record),
},
]"
/>
</template>
</template>
<template #expandedRowRender>
<BasicTable @register="registerChildTable">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction
@ -90,8 +143,17 @@
</template>
</template>
</BasicTable>
</template>
</BasicTable>
<TenderTaskModal @register="registerModal" @reload="reload" />
<DocsDrawer @register="registerDrawer" />
<TenderDocsDrawer @register="registerDrawer" />
<TenderResultDetailDrawer
:visible="resultDetailDrawerVisible"
:taskResultDetail="taskResultDetail"
:taskInfo="currentTaskInfo"
@update:visible="resultDetailDrawerVisible = $event"
@close="handleResultDetailDrawerClose"
/>
</PageWrapper>
</template>
@ -102,19 +164,29 @@
TenderTaskList,
TenderTaskExport,
TenderTaskRemove,
TenderTaskStop,
TenderTaskDeleteFile,
} from '@/api/tenderReview/TenderTask';
import { downloadExcel } from '@/utils/file/download';
import { useModal } from '@/components/Modal';
import TenderTaskModal from './TenderTaskModal.vue';
import { formSchemas, columns } from './TenderTask.data';
import { formSchemas, columns, childColumns } from './TenderTask.data';
import { IconEnum } from '@/enums/appEnum';
import DocsDrawer from '@/views/documentReview/DocumentTasks/DocsDrawer.vue';
import TenderDocsDrawer from './TenderDocsDrawer.vue';
import { useDrawer } from '@/components/Drawer';
import { DocumentTasksStop } from '@/api/documentReview/DocumentTasks';
import {
DocumentTaskResultDownload,
} from '@/api/documentReview/DocumentTaskResults';
TenderTaskResultDownload,
getDetailResultsByTaskId,
} from '@/api/tenderReview/TenderTaskResults';
import TenderResultDetailDrawer from './TenderResultDetailDrawer.vue';
import { onMounted, ref } from 'vue';
import { TenderTaskResultDetailVO } from '@/api/tenderReview/TenderTaskResults/model';
const [registerDrawer, { openDrawer }] = useDrawer();
const resultDetailDrawerVisible = ref(false);
const childTableData = ref([]);
const taskResultDetail = ref<TenderTaskResultDetailVO[]>([]);
const currentTaskInfo = ref<Recordable>({});
defineOptions({ name: 'TenderTask' });
@ -125,7 +197,9 @@
title: '招标审核任务列表',
api: TenderTaskList,
showIndexColumn: false,
clickToRowSelect: false,
rowKey: 'id',
expandRowByClick: false,
useSearchForm: true,
formConfig: {
schemas: formSchemas,
@ -145,32 +219,91 @@
},
});
const [registerChildTable, { setProps: setChildProps }] = useTable({
size: 'small', //
api: getchildTableData,
columns: childColumns,
rowKey: 'id',
useSearchForm: false,
showIndexColumn: false,
showTableSetting: false,
pagination: false,
maxHeight: 50,
actionColumn: {
width: 200,
title: '操作',
key: 'action',
fixed: 'right',
},
});
const [registerModal, { openModal }] = useModal();
async function handleDetail(record: Recordable) {
// try {
// let res = await DocumentTaskResultsInfoByTaskId(record.id);
onMounted(async () => {
});
// openDrawer(true, { value: res.result, type: 'markdown' });
// console.log('res', res);
// } catch (ex) {
// openDrawer(true, { value: '', type: 'markdown' });
// }
//record.id
const handleResultDetailDrawerClose = () => {
resultDetailDrawerVisible.value = false;
};
async function handleDetail(record: Recordable) {
try {
const detailRes = await getDetailResultsByTaskId(record.id);
if (detailRes && detailRes.length > 0) {
taskResultDetail.value = detailRes;
currentTaskInfo.value = record;
resultDetailDrawerVisible.value = true;
return;
}
} catch (detailEx) {
console.error('获取详细结果失败', detailEx);
}
}
async function handleStop(record: Recordable) {
await DocumentTasksStop(record.id);
await TenderTaskStop(record.id);
await reload();
}
function handleAdd() {
openModal(true, { update: false });
}
function tableExpand(expanded, record) {
if (expanded) {
childTableData.value = record.childrenTasks;
console.log('expanded, record', expanded, record);
}
}
async function handleDeleteFile(record: Recordable) {
await TenderTaskDeleteFile(record.childrenTasks[0].ossId);
await reload();
}
// getchildTableData
function getchildTableData() {
console.log('childTableData', childTableData.value);
const height = 50 * childTableData.value.length;
setChildProps({ maxHeight: height });
// Promise
return Promise.resolve(childTableData.value);
}
async function handleDownload(record: Recordable) {
await DocumentTaskResultDownload([record.id]);
if (record.childrenTasks?.length > 1) {
await TenderTaskResultDownload(record.childrenTasks.map((item) => item.id));
await reload();
} else if (record.childrenTasks?.length == 1) {
await TenderTaskResultDownload([record.childrenTasks[0].id]);
await reload();
} else {
await TenderTaskResultDownload([record.id]);
await reload();
}
}
async function handleDelete(record: Recordable) {
await TenderTaskRemove([record.id]);
await reload();

55
src/views/tenderReview/TenderTask/tender-caozuomiaoshu.md

@ -0,0 +1,55 @@
# 招投标文件审核操作说明
## 🎯 功能概述
招投标文件审核系统帮助您快速对招标文件和投标文件进行智能分析和审核,提高工作效率。
## 📋 操作步骤
### 1. 新增审核任务
1. **点击"新增"按钮**
2. **选择任务类型**
- 招标文件文本审核
- 招标文件图片审核
3. **上传文件**
- 招标文件:支持.docx、.pdf格式
- 投标文件集:支持.zip格式
4. **提交任务**
### 2. 查看任务进度
- 在任务列表中可以实时查看任务进度
- 任务状态:
- 🟡 **待处理**:任务已提交,等待处理
- 🔵 **处理中**:任务正在执行
- 🟢 **已完成**:任务处理完成
- 🔴 **已终止**:任务被手动终止
### 3. 下载结果
- 任务完成后,点击"下载"按钮获取审核结果
- 支持批量下载多个任务结果
### 4. 查看详细结果
- 点击"详情"按钮查看详细的审核报告
- 包含问题点分析、修改建议等
## ⚠️ 注意事项
1. **文件大小限制**:单个文件不超过1GB
2. **文件格式**:请确保上传正确的文件格式
3. **安全提醒**:严禁上传涉及国家秘密的文件
4. **任务管理**:可随时终止正在处理的任务
## 🔧 常见问题
**Q: 任务一直处于"处理中"状态怎么办?**
A: 请检查网络连接,如果问题持续存在,可以终止任务后重新提交。
**Q: 支持哪些文件格式?**
A: 招标文件支持.docx、.pdf格式;投标文件需要压缩为.zip格式上传。
**Q: 可以同时处理多个任务吗?**
A: 是的,系统支持并发处理多个任务。
Loading…
Cancel
Save