Browse Source

Merge branch 'ai_dev' into sjj_dev

sjj_dev
zhouhaibin 22 hours ago
parent
commit
bec892f6cf
  1. 3
      package.json
  2. 37
      src/api/documentReview/DocumentTaskResults/index.ts
  3. 65
      src/api/documentReview/DocumentTaskResults/model.ts
  4. 65
      src/views/documentReview/DocumentTasks/DocumentTasksTable.vue
  5. 515
      src/views/documentReview/DocumentTasks/ResultDetailDrawer copy.vue
  6. 674
      src/views/documentReview/DocumentTasks/ResultDetailDrawer.vue
  7. 1
      src/views/tenderReview/TenderTask/TenderTask.data.ts
  8. 151
      src/views/tenderReview/inconsistency/TenderTask.data.ts
  9. 72
      src/views/tenderReview/inconsistency/TenderTaskModal.vue
  10. 181
      src/views/tenderReview/inconsistency/index.vue

3
package.json

@ -186,7 +186,8 @@
"md-editor-v3": "^4.9.0", "md-editor-v3": "^4.9.0",
"markdown-it": "^13.0.2", "markdown-it": "^13.0.2",
"markdown-it-anchor": "^8.6.7", "markdown-it-anchor": "^8.6.7",
"markdown-it-toc-done-right": "^4.2.0" "markdown-it-toc-done-right": "^4.2.0",
"vue-pdf-embed":"2.1.2"
}, },
"engines": { "engines": {

37
src/api/documentReview/DocumentTaskResults/index.ts

@ -1,6 +1,6 @@
import { defHttp } from '@/utils/http/axios'; import { defHttp } from '@/utils/http/axios';
import { ID, IDS, commonExport } from '@/api/base'; import { ID, IDS, commonExport } from '@/api/base';
import { DocumentTaskResultsVO, DocumentTaskResultsForm, DocumentTaskResultsQuery } from './model'; import { DocumentTaskResultsVO, DocumentTaskResultsForm, DocumentTaskResultsQuery, DocumentTaskResultDetailVO } from './model';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
interface DownloadOptions { interface DownloadOptions {
@ -113,6 +113,7 @@ export function DocumentTaskResultsExport(params?: DocumentTaskResultsQuery) {
export function DocumentTaskResultsInfo(id: ID) { export function DocumentTaskResultsInfo(id: ID) {
return defHttp.get<DocumentTaskResultsVO>({ url: '/productManagement/DocumentTaskResults/' + id }); return defHttp.get<DocumentTaskResultsVO>({ url: '/productManagement/DocumentTaskResults/' + id });
} }
/** /**
* id查询文档任务结果详细 * id查询文档任务结果详细
* @param id id * @param id id
@ -121,6 +122,16 @@ export function DocumentTaskResultsInfo(id: ID) {
export function DocumentTaskResultsInfoByTaskId(id: ID) { export function DocumentTaskResultsInfoByTaskId(id: ID) {
return defHttp.get<DocumentTaskResultsVO>({ url: '/productManagement/DocumentTaskResults/task/' + id }); return defHttp.get<DocumentTaskResultsVO>({ url: '/productManagement/DocumentTaskResults/task/' + id });
} }
/**
* id查询详细分类的文档任务结果
* @param taskId ID
* @returns
*/
export function getDetailResultsByTaskId(taskId: ID) {
return defHttp.get<DocumentTaskResultDetailVO[]>({ url: '/productManagement/DocumentTaskResults/taskDetail/' + taskId });
}
/** /**
* *
* @param data * @param data
@ -147,13 +158,27 @@ export function DocumentTaskResultsUpdate(data: DocumentTaskResultsForm) {
export function DocumentTaskResultsRemove(id: ID | IDS) { export function DocumentTaskResultsRemove(id: ID | IDS) {
return defHttp.deleteWithMsg<void>({ url: '/productManagement/DocumentTaskResults/' + id },); return defHttp.deleteWithMsg<void>({ url: '/productManagement/DocumentTaskResults/' + 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: `/productManagement/DocumentTaskResults/updateResultItemStatus/${id}/${field}/${value}`
});
}
/**
* *
* @param id id * @param id id
* @returns * @returns
*/ */
export function DocumentTaskResultDownload(id: ID | IDS) { export function DocumentTaskResultDownload(id: ID | IDS) {
return useDownload(`/productManagement/DocumentTaskResults/downloadResult/${id}`); return useDownload(`/productManagement/DocumentTaskResults/downloadResult/${id}`);
// return defHttp.get<void>({ url: '/productManagement/DocumentTaskResults/downloadResult/' + id ,responseType: 'blob',headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED }},); // return defHttp.get<void>({ url: '/productManagement/DocumentTaskResults/downloadResult/' + id ,responseType: 'blob',headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED }},);
} }

65
src/api/documentReview/DocumentTaskResults/model.ts

@ -7,6 +7,71 @@ export interface DocumentTaskResultsVO {
result?: string; result?: string;
} }
export interface DocumentTaskResultDetailVO {
/**
*
*/
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 DocumentTaskResultsForm extends BaseEntity { export interface DocumentTaskResultsForm extends BaseEntity {
} }

65
src/views/documentReview/DocumentTasks/DocumentTasksTable.vue

@ -108,6 +108,7 @@
</BasicTable> </BasicTable>
<DocumentTasksModal @register="registerModal" @reload="reload" /> <DocumentTasksModal @register="registerModal" @reload="reload" />
<DocsDrawer @register="registerDrawer" /> <DocsDrawer @register="registerDrawer" />
<ResultDetailDrawer @register="registerResultDetailDrawer" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -117,6 +118,7 @@
import { import {
DocumentTaskResultsInfoByTaskId, DocumentTaskResultsInfoByTaskId,
DocumentTaskResultDownload, DocumentTaskResultDownload,
getDetailResultsByTaskId,
} from '@/api/documentReview/DocumentTaskResults'; } from '@/api/documentReview/DocumentTaskResults';
import { useModal } from '@/components/Modal'; import { useModal } from '@/components/Modal';
import DocumentTasksModal from './DocumentTasksModal.vue'; import DocumentTasksModal from './DocumentTasksModal.vue';
@ -124,13 +126,17 @@
import { IconEnum } from '@/enums/appEnum'; import { IconEnum } from '@/enums/appEnum';
import { useDrawer } from '@/components/Drawer'; import { useDrawer } from '@/components/Drawer';
import DocsDrawer from '@/views/documentReview/DocumentTasks/DocsDrawer.vue'; import DocsDrawer from '@/views/documentReview/DocumentTasks/DocsDrawer.vue';
import ResultDetailDrawer from '@/views/documentReview/DocumentTasks/ResultDetailDrawer.vue';
import { onMounted, ref } from 'vue'; import { onMounted, ref } from 'vue';
import { DocumentTasksPermissionsVO } from '@/api/taskPermissions/DocumentTasksPermissions/model'; import { DocumentTasksPermissionsVO } from '@/api/taskPermissions/DocumentTasksPermissions/model';
import { DocumentTaskResultDetailVO } from '@/api/documentReview/DocumentTaskResults/model';
let props = defineProps(['useSearchForm', 'showTableSetting', 'showToolbar', 'pagination']); let props = defineProps(['useSearchForm', 'showTableSetting', 'showToolbar', 'pagination']);
defineOptions({ name: 'DocumentTasks' }); defineOptions({ name: 'DocumentTasks' });
const documentData = ref<DocumentTasksPermissionsVO>(); const documentData = ref<DocumentTasksPermissionsVO>();
const [registerDrawer, { openDrawer }] = useDrawer(); const [registerDrawer, { openDrawer }] = useDrawer();
const [registerResultDetailDrawer, { openDrawer: openResultDetailDrawer }] = useDrawer();
const childTableData = ref([]); const childTableData = ref([]);
const taskResultDetail = ref<DocumentTaskResultDetailVO[]>([]);
const [registerTable, { reload }] = useTable({ const [registerTable, { reload }] = useTable({
api: DocumentTasksList, api: DocumentTasksList,
showIndexColumn: false, showIndexColumn: false,
@ -180,31 +186,9 @@
fixed: 'right', fixed: 'right',
}, },
}); });
// // 便
// const timer = ref<any>(null);
// //loading 便
// const loading = ref(false);
// //使countdown autoRefreshTime
// const countdown = ref(0);
// // 6 6
// const autoRefreshTime = ref(30);
const [registerModal, { openModal }] = useModal(); const [registerModal, { openModal }] = useModal();
onMounted(async () => { onMounted(async () => {
documentData.value = await getTasksPermissionsByUserId(); documentData.value = await getTasksPermissionsByUserId();
// timer.value = window.setInterval(() => {
// //loading
// if (!loading.value) {
// //countdown +1
// if (countdown.value < autoRefreshTime.value) {
// countdown.value = countdown.value + 1;
// // refresh()
// if (countdown.value === autoRefreshTime.value) {
// countdown.value = 0;
// reload();
// }
// }
// }
// }, 1000);
}); });
const cleanHtml = (content) => { const cleanHtml = (content) => {
// DOCTYPEhtml // DOCTYPEhtml
@ -224,8 +208,26 @@
async function handleDetail(record: Recordable) { async function handleDetail(record: Recordable) {
try { try {
let res = await DocumentTaskResultsInfoByTaskId(record.id); let res = await DocumentTaskResultsInfoByTaskId(record.id);
// API使API
if (!res || !res.result) {
try {
const detailRes = await getDetailResultsByTaskId(record.id);
if (detailRes && detailRes.length > 0) {
taskResultDetail.value = detailRes;
openResultDetailDrawer(true, {
taskResultDetail: detailRes,
taskInfo: record
});
return;
}
} catch (detailEx) {
console.error('获取详细结果失败', detailEx);
}
}
//
if (record.taskName == 'schemEvaluation') { if (record.taskName == 'schemEvaluation') {
// res.result=generateTable(JSON.parse(res.result as string))
const updatedHtmlText = res.result?.replace( const updatedHtmlText = res.result?.replace(
/文件名称:\S+/g, /文件名称:\S+/g,
`文件名称:${record.documentName}`, `文件名称:${record.documentName}`,
@ -239,9 +241,22 @@
} }
console.log('res', res); console.log('res', res);
} catch (ex) { } catch (ex) {
openDrawer(true, { value: '加载失败,请刷新页面', type: 'markdown' }); // API使API
try {
const detailRes = await getDetailResultsByTaskId(record.id);
if (detailRes && detailRes.length > 0) {
taskResultDetail.value = detailRes;
openResultDetailDrawer(true, {
taskResultDetail: detailRes,
taskInfo: record,
});
return;
}
} catch (detailEx) {
console.error('获取详细结果也失败', detailEx);
openDrawer(true, { value: '加载失败,请刷新页面', type: 'markdown' });
}
} }
//record.id
} }
async function handleStop(record: Recordable) { async function handleStop(record: Recordable) {

515
src/views/documentReview/DocumentTasks/ResultDetailDrawer copy.vue

@ -0,0 +1,515 @@
<template>
<BasicDrawer
v-bind="$attrs"
@register="registerDrawer"
showFooter
title="文档审核结果"
width="80%"
:canFullscreen="true"
>
<template #default>
<div class="document-review-container">
<div class="tasks-container">
<Collapse v-model:activeKey="activeCollapseKeys" class="tasks-collapse">
<CollapsePanel
v-for="(category, index) in filteredTaskResultDetail"
:key="index.toString()"
:header="category.name + ' (' + category.results.length + ')'"
>
<div class="category-items">
<Collapse v-model:activeKey="activeItemKeys" class="items-collapse">
<CollapsePanel
v-for="(item, idx) in category.results"
:key="getItemKey(index, idx, item)"
>
<template #header>
<div class="item-header-content">
<div class="item-info">
<span class="item-serial">{{ item.serialNumber }}</span>
<span class="item-title">{{ item.issueName }}</span>
</div>
<div class="item-actions">
<Switch
:checked="item.isRead === '1'"
checked-children="已读"
un-checked-children="未读"
:loading="loading && currentOpId === item.id && currentOpField === 'isRead'"
@change="(checked: any) => handleStatusChange(item.id!, 'isRead', checked ? '1' : '0')"
/>
<Switch
class="ml-3"
:checked="item.isAdopted === '1'"
checked-children="已采纳"
un-checked-children="未采纳"
:loading="loading && currentOpId === item.id && currentOpField === 'isAdopted'"
@change="(checked: any) => handleStatusChange(item.id!, 'isAdopted', checked ? '1' : '0')"
/>
</div>
</div>
</template>
<div class="item-content">
<!-- 基于配置动态渲染内容区域 -->
<template v-for="(section, sectionIndex) in getContentSections(category.type, item)" :key="sectionIndex">
<div v-if="getItemValue(item, section.field)" class="content-section">
<div class="section-title">{{ section.title }}</div>
<div class="section-content markdown-content" v-html="renderContent(section, getItemValue(item, section.field))"></div>
<!-- 特殊处理审查要点列表 -->
<div v-if="section.type === 'reviewPointsList' && section.field === 'reviewBasis' && item.reviewBasis && item.reviewBasis.reviewPoints && item.reviewBasis.reviewPoints.length">
<Divider style="margin: 8px 0" />
<ul class="review-points">
<li v-for="(point, pointIdx) in item.reviewBasis.reviewPoints" :key="pointIdx">
{{ point }}
</li>
</ul>
</div>
</div>
</template>
</div>
</CollapsePanel>
</Collapse>
</div>
</CollapsePanel>
</Collapse>
</div>
</div>
</template>
<template #footer>
<div class="drawer-footer">
<div class="status-switches">
<Switch
:checked="expandReadItems"
checked-children="展开已读"
un-checked-children="折叠已读"
@change="(checked: any) => toggleExpandReadItems(checked)"
/>
<Switch
class="ml-3"
:checked="expandAdoptedItems"
checked-children="展开已采纳"
un-checked-children="折叠已采纳"
@change="(checked: any) => toggleExpandAdoptedItems(checked)"
/>
</div>
<Button type="primary" @click="handleClose">关闭</Button>
</div>
</template>
</BasicDrawer>
</template>
<script lang="ts" setup>
import { ref, watch, onMounted, computed } from 'vue';
import { BasicDrawer, useDrawerInner } from '@/components/Drawer';
import { DocumentTaskResultDetailVO } from '@/api/documentReview/DocumentTaskResults/model';
import { updateResultItemStatus } from '@/api/documentReview/DocumentTaskResults';
import { message } from 'ant-design-vue';
import { Switch, Tabs, TabPane, Divider, Button, Collapse, CollapsePanel } from 'ant-design-vue';
import MarkdownIt from 'markdown-it';
const md = new MarkdownIt({
html: true,
linkify: true,
typographer: true,
});
const activeCollapseKeys = ref<string[]>([]);
const activeItemKeys = ref<string[]>([]);
const taskResultDetail = ref<DocumentTaskResultDetailVO[]>([]);
const taskInfo = ref<Recordable>({});
const loading = ref<boolean>(false);
const currentOpId = ref<string>('');
const currentOpField = ref<string>('');
const expandReadItems = ref<boolean>(false);
const expandAdoptedItems = ref<boolean>(false);
//
interface ContentSectionConfig {
field: string;
title: string;
type?: 'markdown' | 'text' | 'reviewPointsList';
nestedFields?: string[];
}
//
const defaultContentSections: ContentSectionConfig[] = [
{ field: 'originalText', title: '原文', type: 'markdown' },
{ field: 'comparedText', title: '比对原文', type: 'markdown' },
{ field: 'modifiedContent', title: '修改后内容', type: 'markdown' },
{ field: 'modificationDisplay', title: '修改情况', type: 'markdown' },
{ field: 'existingIssues', title: '存在问题', type: 'markdown' },
{
field: 'reviewBasis',
title: '审查依据',
type: 'reviewPointsList',
nestedFields: ['reviewContent', 'reviewPoints']
}
];
//
const taskTypeContentConfig: Record<string, ContentSectionConfig[]> = {
//
'contract': [
{ field: 'originalText', title: '合同原文', type: 'markdown' },
{ field: 'legalIssues', title: '法律问题', type: 'markdown' },
{ field: 'suggestions', title: '修改建议', type: 'markdown' },
{
field: 'reviewBasis',
title: '法律依据',
type: 'reviewPointsList',
nestedFields: ['reviewContent', 'reviewPoints']
}
],
//
};
//
const getContentSections = (taskType: string, item: any): ContentSectionConfig[] => {
// 使使
return taskTypeContentConfig[taskType] || defaultContentSections;
};
//
const getItemValue = (item: any, field: string): any => {
if (!item || !field) return null;
// "reviewBasis.reviewContent"
if (field.includes('.')) {
const parts = field.split('.');
let value = item;
for (const part of parts) {
if (value && typeof value === 'object') {
value = value[part];
} else {
return null;
}
}
return value;
}
return item[field];
};
//
const renderContent = (section: ContentSectionConfig, value: any): string => {
if (!value) return '';
if (section.type === 'markdown') {
return renderMarkdown(value);
}
if (section.type === 'reviewPointsList' && section.nestedFields) {
let content = '';
// reviewContent
if (section.nestedFields.includes('reviewContent') && value.reviewContent) {
content += renderMarkdown(value.reviewContent);
}
return content;
}
return value.toString();
};
//
const filteredTaskResultDetail = computed(() => {
if (taskResultDetail.value.length <= 0) {
return [];
}
// results<=5
if (taskResultDetail.value.length <= 2 ||
(taskResultDetail.value[0] && taskResultDetail.value[0].results &&
taskResultDetail.value[0].results.length <= 5)) {
return [taskResultDetail.value[0]];
}
return taskResultDetail.value;
});
// key
const getItemKey = (categoryIndex: number, itemIndex: number, item: any) => {
return item.id ? item.id : `${categoryIndex}-${itemIndex}`;
};
//
const updateActiveItemKeys = () => {
const newActiveKeys: string[] = [];
filteredTaskResultDetail.value.forEach((category, categoryIndex) => {
category.results.forEach((item, itemIndex) => {
const itemKey = getItemKey(categoryIndex, itemIndex, item);
const isRead = item.isRead === '1';
const isAdopted = item.isAdopted === '1';
//
if ((!isRead && !isAdopted) ||
(isRead && expandReadItems.value) ||
(isAdopted && expandAdoptedItems.value)) {
newActiveKeys.push(itemKey);
}
});
});
activeItemKeys.value = newActiveKeys;
};
//
const toggleExpandReadItems = (checked: any) => {
expandReadItems.value = !!checked;
updateActiveItemKeys();
};
//
const toggleExpandAdoptedItems = (checked: any) => {
expandAdoptedItems.value = !!checked;
updateActiveItemKeys();
};
const renderMarkdown = (text) => {
if (!text) return '';
return md.render(text);
};
const [registerDrawer, { closeDrawer, setDrawerProps }] = useDrawerInner(async (data) => {
setDrawerProps({ loading: true });
try {
if (data?.taskResultDetail) {
taskResultDetail.value = data.taskResultDetail;
taskInfo.value = data.taskInfo || {};
//
if (taskResultDetail.value.length > 0) {
activeCollapseKeys.value = ['0'];
}
//
updateActiveItemKeys();
}
} catch (error) {
console.error('初始化详情抽屉时出错', error);
} finally {
setDrawerProps({ loading: false });
}
});
async function handleStatusChange(id: string, field: 'isRead' | 'isAdopted', value: '0' | '1') {
if (!id) {
message.error('缺少记录ID,无法更新状态');
return;
}
loading.value = true;
currentOpId.value = id;
currentOpField.value = field;
try {
await updateResultItemStatus(id, field, value);
message.success(`状态更新成功`);
//
taskResultDetail.value.forEach(category => {
category.results.forEach(item => {
if (item.id === id) {
item[field] = value;
}
});
});
//
updateActiveItemKeys();
} catch (error) {
console.error('更新状态失败', error);
message.error('更新状态失败');
} finally {
loading.value = false;
currentOpId.value = '';
currentOpField.value = '';
}
}
function handleClose() {
closeDrawer();
}
//
watch([expandReadItems, expandAdoptedItems], () => {
updateActiveItemKeys();
});
onMounted(() => {
//
});
</script>
<style lang="less" scoped>
:deep(.ant-drawer-body) {
padding: 16px;
height: calc(100% - 100px);
overflow: auto;
}
.document-review-container {
height: 100%;
}
.tasks-container {
height: 100%;
overflow: auto;
}
.tasks-collapse {
margin-bottom: 16px;
:deep(.ant-collapse-header) {
font-weight: 500;
padding: 12px 16px;
background-color: #f8f8f8;
}
:deep(.ant-collapse-content-box) {
padding: 0;
}
}
.items-collapse {
:deep(.ant-collapse-item) {
margin-bottom: 12px;
border: 1px solid #e8e8e8;
border-radius: 4px !important;
overflow: hidden;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
background-color: #fff;
}
:deep(.ant-collapse-header) {
padding: 8px 16px !important;
background-color: #f8f8f8;
}
}
.item-header-content {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}
.item-info {
display: flex;
align-items: center;
}
.item-serial {
margin-right: 12px;
font-weight: bold;
color: #1890ff;
}
.item-title {
font-weight: 500;
font-size: 16px;
}
.item-actions {
display: flex;
align-items: center;
margin-left: 16px;
}
.item-content {
padding: 16px;
}
.content-section {
margin-bottom: 16px;
}
.section-title {
font-weight: 500;
margin-bottom: 8px;
color: #333;
}
.section-content {
padding: 0 0 0 24px;
background-color: #f9fbfd;
border-radius: 4px;
padding: 12px;
}
.markdown-content {
:deep(p) {
margin-bottom: 8px;
}
:deep(ul), :deep(ol) {
padding-left: 24px;
}
:deep(h1), :deep(h2), :deep(h3), :deep(h4), :deep(h5), :deep(h6) {
margin-top: 16px;
margin-bottom: 8px;
}
:deep(code) {
background-color: #f5f5f5;
padding: 2px 4px;
border-radius: 4px;
}
:deep(pre) {
background-color: #f5f5f5;
padding: 12px;
border-radius: 4px;
overflow: auto;
}
:deep(blockquote) {
border-left: 4px solid #ddd;
padding-left: 16px;
color: #666;
margin: 16px 0;
}
:deep(table) {
border-collapse: collapse;
width: 100%;
margin: 16px 0;
th, td {
border: 1px solid #e8e8e8;
padding: 8px 12px;
}
th {
background-color: #f8f8f8;
font-weight: 500;
}
}
}
.review-points {
list-style-type: disc;
padding-left: 24px;
li {
margin-bottom: 4px;
}
}
.ml-3 {
margin-left: 12px;
}
.drawer-footer {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}
.status-switches {
display: flex;
align-items: center;
}
</style>

674
src/views/documentReview/DocumentTasks/ResultDetailDrawer.vue

@ -0,0 +1,674 @@
<template>
<BasicDrawer
v-bind="$attrs"
@register="registerDrawer"
showFooter
title="文档审核结果"
width="50%"
:canFullscreen="true"
>
<template #default>
<div class="document-review-container">
<div class="tasks-container">
<Tabs v-model:activeKey="activeCollapseKeys[0]">
<TabPane
v-for="(category, index) in filteredTaskResultDetail"
:key="index.toString()"
:tab="category.name + ' (' + category.results.length + ')'"
>
<div class="category-items">
<div class="items-card-list">
<Card
v-for="(item, idx) in category.results"
:key="getItemKey(index, idx, item)"
class="item-card"
:bordered="true"
:bodyStyle="{ padding: activeItemKeys.includes(getItemKey(index, idx, item)) ? '16px' : '0', height: activeItemKeys.includes(getItemKey(index, idx, item)) ? 'auto' : '0', overflow: 'hidden', transition: 'all 0.3s' }"
>
<template #title>
<div class="item-header-content" @click="toggleItemExpand(index, idx, item)">
<div class="item-info">
<span class="item-serial">{{ item.serialNumber }}</span>
<span class="item-title">{{ item.existingIssues }}</span>
</div>
<div class="item-actions">
<Switch
:checked="item.isRead === '1'"
checked-children="已读"
un-checked-children="未读"
:loading="loading && currentOpId === item.id && currentOpField === 'isRead'"
@change="(checked: any) => handleStatusChange(item.id!, 'isRead', checked ? '1' : '0')"
@click.stop
/>
<Switch
class="ml-3"
:checked="item.isAdopted === '1'"
checked-children="已采纳"
un-checked-children="未采纳"
:loading="loading && currentOpId === item.id && currentOpField === 'isAdopted'"
@change="(checked: any) => handleStatusChange(item.id!, 'isAdopted', checked ? '1' : '0')"
@click.stop
/>
<DownOutlined v-if="!activeItemKeys.includes(getItemKey(index, idx, item))" class="expand-icon ml-3" />
<UpOutlined v-else class="expand-icon ml-3" />
</div>
</div>
</template>
<div class="item-content" v-if="activeItemKeys.includes(getItemKey(index, idx, item))">
<!-- 基于配置动态渲染内容区域 -->
<template v-for="(section, sectionIndex) in getContentSections(receivedTaskType, item)" :key="sectionIndex">
<div v-if="getItemValue(item, section.field)" class="content-section">
<div class="section-title">
{{ section.title }}
<Button
type="link"
size="small"
class="copy-btn"
@click.stop="copyContent(getItemValue(item, section.field))"
v-if="getItemValue(item, section.field)"
>
<CopyOutlined /> 复制
</Button>
</div>
<div class="section-content markdown-content" v-html="renderContent(section, getItemValue(item, section.field))"></div>
<!-- 特殊处理审查要点列表 -->
<div v-if="section.type === 'reviewPointsList' && section.field === 'reviewBasis' && item.reviewBasis && item.reviewBasis.reviewPoints && item.reviewBasis.reviewPoints.length">
<Divider style="margin: 8px 0" />
<ul class="review-points">
<li v-for="(point, pointIdx) in item.reviewBasis.reviewPoints" :key="pointIdx">
{{ point }}
</li>
</ul>
</div>
</div>
</template>
</div>
</Card>
</div>
</div>
</TabPane>
</Tabs>
</div>
</div>
</template>
<template #footer>
<div class="drawer-footer">
<div class="status-switches">
<Switch
:checked="expandReadItems"
checked-children="展开已读"
un-checked-children="折叠已读"
@change="(checked: any) => toggleExpandReadItems(checked)"
/>
<Switch
class="ml-3"
:checked="expandAdoptedItems"
checked-children="展开已采纳"
un-checked-children="折叠已采纳"
@change="(checked: any) => toggleExpandAdoptedItems(checked)"
/>
</div>
<Button type="primary" @click="handleClose">关闭</Button>
</div>
</template>
</BasicDrawer>
</template>
<script lang="ts" setup>
import { ref, watch, onMounted, computed, nextTick } from 'vue';
import { BasicDrawer, useDrawerInner } from '@/components/Drawer';
import { DocumentTaskResultDetailVO } from '@/api/documentReview/DocumentTaskResults/model';
import { updateResultItemStatus, DocumentTaskResultDownload } from '@/api/documentReview/DocumentTaskResults';
import { message, Alert, Button, Card } from 'ant-design-vue';
import { Switch, Divider, Tabs, TabPane } from 'ant-design-vue';
import { DownOutlined, UpOutlined, CopyOutlined } from '@ant-design/icons-vue';
import MarkdownIt from 'markdown-it';
const md = new MarkdownIt({
html: true,
linkify: true,
typographer: true,
breaks: true,
});
const activeCollapseKeys = ref<string[]>(['0']);
const activeItemKeys = ref<string[]>([]);
const taskResultDetail = ref<DocumentTaskResultDetailVO[]>([]);
const taskInfo = ref<Recordable>({});
const loading = ref<boolean>(false);
const currentOpId = ref<string>('');
const currentOpField = ref<string>('');
const expandReadItems = ref<boolean>(false);
const expandAdoptedItems = ref<boolean>(false);
const receivedTaskType = ref<string>('');
//
interface ContentSectionConfig {
field: string;
title: string;
type?: 'markdown' | 'text' | 'reviewPointsList';
nestedFields?: string[];
}
//
const defaultContentSections: ContentSectionConfig[] = [
{ field: 'originalText', title: '原文', type: 'markdown' },
{ field: 'comparedText', title: '比对原文', type: 'markdown' },
{ field: 'modifiedContent', title: '修改后内容', type: 'markdown' },
{ field: 'modificationDisplay', title: '修改情况', type: 'markdown' },
{ field: 'existingIssues', title: '存在问题', type: 'markdown' },
{
field: 'reviewBasis',
title: '审查依据',
type: 'reviewPointsList',
nestedFields: ['reviewContent', 'reviewPoints']
}
];
//
const taskTypeContentConfig: Record<string, ContentSectionConfig[]> = {
//
'contract': [
{ field: 'originalText', title: '合同原文', type: 'markdown' },
{ field: 'legalIssues', title: '法律问题', type: 'markdown' },
{ field: 'suggestions', title: '修改建议', type: 'markdown' },
{
field: 'reviewBasis',
title: '法律依据',
type: 'reviewPointsList',
nestedFields: ['reviewContent', 'reviewPoints']
}
],
"checkCompanyName": [
{ field: 'modificationDisplay', title: '相关原文', type: 'markdown' },
],
"checkTitleName": [
{ field: 'modificationDisplay', title: '相关原文', type: 'markdown' },
],
"checkPlaceName": [
{ field: 'modificationDisplay', title: '相关原文', type: 'markdown' },
],
"checkRepeatText": [
{ field: 'originalText', title: '第一段原文', type: 'markdown' },
{ field: 'comparedText', title: '第二段原文', type: 'markdown' },
{ field: 'modificationDisplay', title: '相似情况', type: 'markdown' },
],
"checkDocumentError": [
{ field: 'originalText', title: '原文', type: 'markdown' },
{ field: 'modifiedContent', title: '修改建议', type: 'markdown' },
{ field: 'modificationDisplay', title: '修改情况', type: 'markdown' },
],
// checkDocumentErrorschemEvaluation
};
//
const getContentSections = (taskType: string | undefined, item: any): ContentSectionConfig[] => {
// 使
if (!taskType) return defaultContentSections;
// 使使
return taskTypeContentConfig[taskType] || defaultContentSections;
};
//
const getItemValue = (item: any, field: string): any => {
if (!item || !field) return null;
// "reviewBasis.reviewContent"
if (field.includes('.')) {
const parts = field.split('.');
let value = item;
for (const part of parts) {
if (value && typeof value === 'object') {
value = value[part];
} else {
return null;
}
}
return value;
}
return item[field];
};
//
const renderContent = (section: ContentSectionConfig, value: any): string => {
if (!value) return '';
if (section.type === 'markdown') {
return renderMarkdown(value);
}
if (section.type === 'reviewPointsList' && section.nestedFields) {
let content = '';
// reviewContent
if (section.nestedFields.includes('reviewContent') && value.reviewContent) {
content += renderMarkdown(value.reviewContent);
}
return content;
}
return value.toString().replace(/\n/g, '<br>');
};
//
const filteredTaskResultDetail = computed(() => {
if (taskResultDetail.value.length <= 0) {
return [];
}
// results<=5
if (taskResultDetail.value.length <= 2 ||
(taskResultDetail.value[0] && taskResultDetail.value[0].results &&
taskResultDetail.value[0].results.length <= 5)) {
return [taskResultDetail.value[0]];
}
return taskResultDetail.value;
});
// key
const getItemKey = (categoryIndex: number, itemIndex: number, item: any) => {
return item.id ? item.id : `${categoryIndex}-${itemIndex}`;
};
//
const updateActiveItemKeys = () => {
const newActiveKeys: string[] = [];
filteredTaskResultDetail.value.forEach((category, categoryIndex) => {
category.results.forEach((item, itemIndex) => {
const itemKey = getItemKey(categoryIndex, itemIndex, item);
const isRead = item.isRead === '1';
const isAdopted = item.isAdopted === '1';
//
if ((!isRead && !isAdopted) ||
(isRead && expandReadItems.value) ||
(isAdopted && expandAdoptedItems.value)) {
newActiveKeys.push(itemKey);
}
});
});
activeItemKeys.value = newActiveKeys;
};
//
const toggleExpandReadItems = (checked: any) => {
expandReadItems.value = !!checked;
updateActiveItemKeys();
};
//
const toggleExpandAdoptedItems = (checked: any) => {
expandAdoptedItems.value = !!checked;
updateActiveItemKeys();
};
// /
const toggleItemExpand = (categoryIndex: number, itemIndex: number, item: any) => {
const itemKey = getItemKey(categoryIndex, itemIndex, item);
const index = activeItemKeys.value.indexOf(itemKey);
if (index > -1) {
activeItemKeys.value.splice(index, 1);
} else {
activeItemKeys.value.push(itemKey);
}
};
const renderMarkdown = (text) => {
if (!text) return '';
// MarkdownMarkdown
// 使
const processedText = text.replace(/\n/g, ' \n');
return md.render(processedText);
};
const [registerDrawer, { closeDrawer, setDrawerProps }] = useDrawerInner(async (data) => {
setDrawerProps({ loading: true });
try {
if (data?.taskResultDetail) {
//
receivedTaskType.value = data.taskInfo.taskName || '';
console.log('receivedTaskType', receivedTaskType.value);
// categorytype
taskResultDetail.value = data.taskResultDetail;
taskInfo.value = data.taskInfo || {};
//
if (taskResultDetail.value.length > 0) {
activeCollapseKeys.value = ['0'];
}
//
updateActiveItemKeys();
}
} catch (error) {
console.error('初始化详情抽屉时出错', error);
} finally {
setDrawerProps({ loading: false });
}
});
async function handleStatusChange(id: string, field: 'isRead' | 'isAdopted', value: '0' | '1') {
if (!id) {
message.error('缺少记录ID,无法更新状态');
return;
}
loading.value = true;
currentOpId.value = id;
currentOpField.value = field;
try {
await updateResultItemStatus(id, field, value);
// message.success(``);
//
taskResultDetail.value.forEach(category => {
category.results.forEach(item => {
if (item.id === id) {
item[field] = value;
}
});
});
//
updateActiveItemKeys();
} catch (error) {
console.error('更新状态失败', error);
message.error('更新状态失败');
} finally {
loading.value = false;
currentOpId.value = '';
currentOpField.value = '';
}
}
function handleClose() {
closeDrawer();
}
//
watch([expandReadItems, expandAdoptedItems], () => {
updateActiveItemKeys();
});
//
const copyContent = (content: any) => {
if (!content) return;
//
let textToCopy = '';
if (typeof content === 'object') {
// reviewBasis
if (content.reviewContent) {
textToCopy = content.reviewContent;
//
if (content.reviewPoints && content.reviewPoints.length) {
textToCopy += '\n\n审查要点:\n';
content.reviewPoints.forEach((point, index) => {
textToCopy += `${index + 1}. ${point}\n`;
});
}
} else {
// JSON
try {
textToCopy = JSON.stringify(content, null, 2);
} catch (e) {
textToCopy = String(content);
}
}
} else {
//
textToCopy = String(content);
}
//
navigator.clipboard.writeText(textToCopy)
.then(() => {
message.success('内容已复制到剪贴板');
})
.catch((err) => {
console.error('复制失败:', err);
message.error('复制失败,请手动选择并复制');
//
const textarea = document.createElement('textarea');
textarea.value = textToCopy;
document.body.appendChild(textarea);
textarea.select();
try {
document.execCommand('copy');
message.success('内容已复制到剪贴板');
} catch (e) {
console.error('备用复制方法失败:', e);
message.error('复制失败,请手动选择并复制');
}
document.body.removeChild(textarea);
});
};
onMounted(() => {
//
});
</script>
<style lang="less" scoped>
:deep(.ant-drawer-body) {
padding: 16px;
height: calc(100% - 100px);
overflow: auto;
}
.document-review-container {
height: 100%;
}
.tasks-container {
height: 100%;
overflow: auto;
}
:deep(.ant-tabs-nav) {
margin-bottom: 16px;
}
:deep(.ant-tabs-tab) {
padding: 8px 16px;
font-weight: 500;
}
.items-card-list {
:deep(.ant-card) {
margin-bottom: 12px;
border: 1px solid #e8e8e8;
border-radius: 4px !important;
overflow: hidden;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
background-color: #fff;
}
:deep(.ant-card-head) {
padding: 0 !important;
background-color: #f8f8f8;
min-height: 40px;
.ant-card-head-title {
padding: 8px 16px !important;
}
}
:deep(.ant-card-body) {
transition: all 0.3s ease;
}
}
.item-card {
width: 100%;
margin-bottom: 10px;
cursor: pointer;
}
.expand-icon {
font-size: 12px;
color: rgba(0, 0, 0, 0.45);
}
.item-header-content {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}
.item-info {
display: flex;
align-items: center;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.item-serial {
margin-right: 12px;
font-weight: bold;
color: #1890ff;
}
.item-title {
font-weight: 500;
font-size: 14px;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.item-actions {
display: flex;
align-items: center;
margin-left: 16px;
flex-shrink: 0;
}
.item-content {
padding: 16px;
}
.content-section {
margin-bottom: 16px;
}
.section-title {
font-weight: 500;
margin-bottom: 8px;
color: #333;
display: flex;
align-items: center;
justify-content: space-between;
}
.copy-btn {
padding: 0 4px;
font-size: 12px;
height: 24px;
:deep(.anticon) {
font-size: 12px;
}
}
.section-content {
padding: 0 0 0 24px;
background-color: #f9fbfd;
border-radius: 4px;
padding: 12px;
white-space: pre-wrap;
max-height: 300px;
overflow: auto;
}
.markdown-content {
:deep(p) {
margin-bottom: 8px;
}
:deep(ul), :deep(ol) {
padding-left: 24px;
}
:deep(h1), :deep(h2), :deep(h3), :deep(h4), :deep(h5), :deep(h6) {
margin-top: 16px;
margin-bottom: 8px;
}
:deep(code) {
background-color: #f5f5f5;
padding: 2px 4px;
border-radius: 4px;
}
:deep(pre) {
background-color: #f5f5f5;
padding: 12px;
border-radius: 4px;
overflow: auto;
}
:deep(blockquote) {
border-left: 4px solid #ddd;
padding-left: 16px;
color: #666;
margin: 16px 0;
}
:deep(table) {
border-collapse: collapse;
width: 100%;
margin: 16px 0;
th, td {
border: 1px solid #e8e8e8;
padding: 8px 12px;
}
th {
background-color: #f8f8f8;
font-weight: 500;
}
}
}
.review-points {
list-style-type: disc;
padding-left: 24px;
li {
margin-bottom: 4px;
}
}
.ml-3 {
margin-left: 12px;
}
.drawer-footer {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}
.status-switches {
display: flex;
align-items: center;
}
</style>

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

@ -31,6 +31,7 @@ export const formSchemas: FormSchema[] = [
componentProps: { componentProps: {
options: getDictOptions('tender_review'), options: getDictOptions('tender_review'),
mode: 'multiple', mode: 'multiple',
defaultValue:"tenderSummary"
}, },
}, },
{ {

151
src/views/tenderReview/inconsistency/TenderTask.data.ts

@ -0,0 +1,151 @@
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';
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'),
mode: 'multiple',
defaultValue:"inconsistency"
},
},
{
label: '文档名称',
field: 'documentName',
component: 'Input',
},
{
label: '状态',
field: 'progressStatus',
component: 'Select',
componentProps: {
options: getDictOptions('document_task_status'),
},
},
];
const { renderDict } = useRender();
export const columns: BasicColumn[] = [
{
title: '任务名称',
dataIndex: 'taskName',
customRender: ({ value }) => renderDict(value, 'tender_review'),
},
{
title: '文档名称',
dataIndex: 'documentName',
},
{
title: '模型所属区域',
dataIndex: 'taskRegion',
customRender: ({ value }) => renderDict(value, 'model_region'),
},
{
title: '模型所属行业',
dataIndex: 'taskIndustry',
customRender: ({ value }) => renderDict(value, 'model_industry'),
},
{
title: '上传时间',
dataIndex: 'createTime',
},
{
title: '提交人',
dataIndex: 'createUser',
auth: 'documentReview:DocumentTasks:tableShow',
},
{
title: '任务耗时',
dataIndex: 'taskDuration',
},
{
title: '状态',
dataIndex: 'progressStatus',
customRender: ({ value }) => renderDict(value, 'document_task_status'),
},
];
export const modalSchemas: FormSchema[] = [
{
label: '模型所属区域',
field: 'taskRegion',
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',
};
},
},
{
label: '模型所属行业',
field: 'taskIndustry',
required: true,
component: 'Select',
componentProps: {
options: getDictOptions('model_industry'),
defaultValue: 'normal',
},
},
{
label: '任务名称',
field: 'taskNameList',
required: true,
component: 'Select',
componentProps: {
options: getDictOptions('tender_review') ,
mode: 'multiple',
},
},
{
label: '文档名称',
field: 'ossId',
required: true,
component: 'Upload',
componentProps: {
accept: ['.docx', '.doc', '.wps'],
maxSize: 500,
multiple: false,
resultField: 'ossId',
api: uploadDocument,
beforeUploadPrompt:"严禁在本互联网非涉密平台处理、传输国家秘密。请再次确认您上传的文件资料不涉及国家秘密。"
},
},
];

72
src/views/tenderReview/inconsistency/TenderTaskModal.vue

@ -0,0 +1,72 @@
<template>
<BasicModal
v-bind="$attrs"
:title="title"
@register="registerInnerModal"
@ok="handleSubmit"
@cancel="resetForm"
>
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script setup lang="ts">
import { BasicModal, useModalInner } from '@/components/Modal';
import { BasicForm, useForm } from '@/components/Form';
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' });
const emit = defineEmits(['register', 'reload']);
const isUpdate = ref<boolean>(false);
const title = computed<string>(() => {
return isUpdate.value ? '编辑招标审核任务' : '新增招标审核任务';
});
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) {
await setFieldsValue(record);
}
modalLoading(false);
},
);
const [registerForm, { setFieldsValue, resetForm, validate }] = useForm({
labelWidth: 100,
showActionButtonGroup: false,
baseColProps: { span: 24 },
schemas: modalSchemas,
});
async function handleSubmit() {
try {
modalLoading(true);
const data = await validate();
data['ossId'] = data['ossId'][0];
if (unref(isUpdate)) {
await TenderTaskUpdate(data);
} else {
await TenderTaskAdd(data);
}
emit('reload');
closeModal();
await resetForm();
} catch (e) {
} finally {
modalLoading(false);
}
}
</script>
<style scoped></style>

181
src/views/tenderReview/inconsistency/index.vue

@ -0,0 +1,181 @@
<template>
<PageWrapper dense>
<BasicTable @register="registerTable">
<template #toolbar>
<a-button
@click="
downloadExcel(TenderTaskExport, '招标摘要任务数据', getForm().getFieldsValue())
"
v-auth="'productManagement:TenderTask:export'"
>导出</a-button
>
<a-button
type="primary"
danger
@click="multipleRemove(TenderTaskRemove)"
:disabled="!selected"
v-auth="'productManagement:TenderTask:remove'"
>删除</a-button
>
<a-button
type="primary"
@click="handleAdd"
v-auth="'productManagement:TenderTask:add'"
>新增</a-button
>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction
stopButtonPropagation
:actions="[
{
label: '详情',
icon: IconEnum.EDIT,
type: 'primary',
ghost: true,
ifShow: () => {
if (
record.progressStatus != 'PENDING' &&
record.progressStatus != 'STARTED' &&
record.progressStatus != 'REVOKED'
) {
return true;
} else {
return false;
}
},
onClick: handleDetail.bind(null, record),
},
{
label: '下载',
icon: IconEnum.DOWNLOAD,
type: 'primary',
color: 'success',
ghost: true,
ifShow: () => {
if (
record.progressStatus != 'PENDING' &&
record.progressStatus != 'STARTED' &&
record.progressStatus != 'REVOKED'
) {
return true;
} else {
return false;
}
},
onClick: handleDownload.bind(null, record),
},
{
label: '终止任务',
icon: IconEnum.DELETE,
type: 'primary',
danger: true,
ghost: true,
ifShow: () => {
if (record.progressStatus == 'PENDING') {
return true;
} else {
return false;
}
},
popConfirm: {
placement: 'left',
title: '是否终止当前任务?',
confirm: handleStop.bind(null, record),
},
},
]"
/>
</template>
</template>
</BasicTable>
<TenderTaskModal @register="registerModal" @reload="reload" />
<DocsDrawer @register="registerDrawer" />
</PageWrapper>
</template>
<script setup lang="ts">
import { PageWrapper } from '@/components/Page';
import { BasicTable, useTable, TableAction } from '@/components/Table';
import {
TenderTaskList,
TenderTaskExport,
TenderTaskRemove,
} 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 { IconEnum } from '@/enums/appEnum';
import DocsDrawer from '@/views/documentReview/DocumentTasks/DocsDrawer.vue';
import { useDrawer } from '@/components/Drawer';
import { DocumentTasksStop } from '@/api/documentReview/DocumentTasks';
import {
DocumentTaskResultsInfoByTaskId,
DocumentTaskResultDownload,
} from '@/api/documentReview/DocumentTaskResults';
const [registerDrawer, { openDrawer }] = useDrawer();
defineOptions({ name: 'TenderTask' });
const [registerTable, { reload, multipleRemove, selected, getForm }] = useTable({
rowSelection: {
type: 'checkbox',
},
title: '招标审核任务列表',
api: TenderTaskList,
showIndexColumn: false,
rowKey: 'id',
useSearchForm: true,
formConfig: {
schemas: formSchemas,
baseColProps: {
xs: 24,
sm: 24,
md: 24,
lg: 6,
},
},
columns: columns,
actionColumn: {
width: 200,
title: '操作',
key: 'action',
fixed: 'right',
},
});
const [registerModal, { openModal }] = useModal();
async function handleDetail(record: Recordable) {
try {
let res = await DocumentTaskResultsInfoByTaskId(record.id);
openDrawer(true, { value: res.result, type: 'markdown' });
console.log('res', res);
} catch (ex) {
openDrawer(true, { value: '加载失败,请刷新页面', type: 'markdown' });
}
//record.id
}
async function handleStop(record: Recordable) {
await DocumentTasksStop(record.id);
await reload();
}
function handleAdd() {
openModal(true, { update: false });
}
async function handleDownload(record: Recordable) {
await DocumentTaskResultDownload([record.id]);
await reload();
}
async function handleDelete(record: Recordable) {
await TenderTaskRemove([record.id]);
await reload();
}
</script>
<style scoped></style>
Loading…
Cancel
Save