Browse Source

优化jyj合同

jyj_dev
zhouhaibin 2 days ago
parent
commit
7a15a8efb5
  1. 8
      src/api/documentReview/DocumentTaskResults/index.ts
  2. 274
      src/views/contractReview/ContractualTasks/ContractualShowModal.vue
  3. 6
      src/views/contractReview/ContractualTasks/ContractualTasks.data.ts
  4. 2
      src/views/contractReview/ContractualTasks/ContractualTasksTable.vue
  5. 388
      src/views/contractReview/ContractualTasks/showResultCard.vue
  6. 6
      src/views/contractReview/JyjcontractualTaskBatch/ContractualTasksTableModal.vue

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

@ -157,3 +157,11 @@ export function DocumentTaskResultsRemove(id: ID | IDS) {
// return defHttp.get<void>({ url: '/productManagement/DocumentTaskResults/downloadResult/' + id ,responseType: 'blob',headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED }},);
}
/**
*
* @param data
* @returns
*/
export function modifyContractReview(documentTaskId: ID, contractualRes) {
return defHttp.putWithMsg<void>({ url: '/productManagement/DocumentTaskResults/modifyContractReview/'+documentTaskId, data: contractualRes });
}

274
src/views/contractReview/ContractualTasks/ContractualShowModal.vue

@ -4,56 +4,37 @@
title="title"
:canFullscreen="true"
:defaultFullscreen="true"
:showOkBtn="false"
@ok="submit"
@register="registerInnerModal"
>
<div class="grid grid-cols-5 gap-4">
<div class="col-span-3">
<!-- <CanvasEditor
ref="canvasEditor"
:parentContent="parentContent"
:view="view"
@save-content="handleSaveCanvasEditorContent"
/> -->
<div class="modal-content">
<div class="grid grid-cols-5 gap-4 h-full">
<div class="col-span-3 pdf-container">
<PdfViewer :id="currentId" :key="pdfViewerkey" v-if="currentId!=0"/>
</div>
<div class="col-span-2">
<!-- 添加 col-span-2 和高度样式 -->
<div class="tabs-container">
<Tabs v-model:activeKey="activeKey" type="card">
<TabPane key="1" tab="审查结果">
<div class="scroll-container">
<div class="card-container">
<Card
v-for="(item, index) in cardList"
:key="index"
:class="['custom-card', { 'card-selected': selectedCard === item.title }]"
@click="handleCardClick(item.title)"
>
<template #title>{{ item.title }}</template>
{{ item.text }}
{{ item.content }}
</Card>
</div>
<div class="col-span-2 review-container">
<div class="review-content">
<showResultCard v-model:cardList="cardList"/>
</div>
</TabPane>
<!-- <TabPane key="2" tab="Tab 2">Content of Tab Pane 2</TabPane>
<TabPane key="3" tab="Tab 3">Content of Tab Pane 3</TabPane> -->
</Tabs>
</div>
</div>
</div>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, onMounted, reactive } from 'vue';
import { ref, onMounted, reactive, h } from 'vue';
import { BasicModal, useModalInner } from '@/components/Modal';
import { Tabs, TabPane, Card } from 'ant-design-vue';
import { Tabs, TabPane, Card, Modal } from 'ant-design-vue';
import { useRouter } from 'vue-router';
import CanvasEditor from '@/views/CanvasEditor/index.vue';
import { getContractualResultById } from '@/api/contractReview/JyjcontractualTaskBatch';
import { modifyContractReview } from '@/api/documentReview/DocumentTaskResults';
import PdfViewer from "./PdfViewer.vue"
import showResultCard from './showResultCard.vue';
import { cloneDeep } from 'lodash-es';
const emit = defineEmits(['register', 'reload']);
const activeKey = ref('1');
const currentId = ref<any>(0);
const pdfViewerkey = ref(0);
@ -65,14 +46,17 @@
console.log('点击的卡片标题:', title);
};
// 便
const initialCardList = ref<any[]>([]);
const [registerInnerModal, { modalLoading, closeModal }] = useModalInner(
async (data: { record?: Recordable }) => {
modalLoading(true);
cardList.value=[]
cardList.value = [];
const { record } = data;
const res = await getContractualResultById(record.id);
pdfViewerkey.value+=1
currentId.value=record.id
pdfViewerkey.value += 1;
currentId.value = record.id;
for (const item of res.results) {
for (const content of item.contentList) {
cardList.value.push({
@ -84,6 +68,8 @@
});
}
}
//
initialCardList.value = cloneDeep(cardList.value);
modalLoading(false);
},
);
@ -101,7 +87,9 @@
getEditorContent();
view.value = 'parent';
});
function handleSaveContent1(){
console.log('保存内容',cardList.value);
}
//
const getEditorContent = () => {
parentContent = {
@ -159,106 +147,174 @@
setTimeout(() => {
loading.value = false;
}, 1500);
</script>
<style scoped>
/* Tabs 相关样式 */
/* 设置未选中标签的基本样式 */
:deep(.ant-tabs-card > .ant-tabs-nav .ant-tabs-tab) {
color: rgba(0, 0, 0, 0.85) !important; /* 文字颜色为黑色,带透明度 */
background: #fff; /* 背景色为白色 */
border: 1px solid #f0f0f0; /* 浅灰色边框 */
}
/* 设置选中标签的样式 */
:deep(.ant-tabs-card > .ant-tabs-nav .ant-tabs-tab-active) {
color: #ffffff !important; /* 文字颜色为白色 */
background: #1890ff !important; /* 背景色为蓝色 */
border-color: #1890ff !important; /* 边框颜色也改为蓝色 */
}
//
const submit = async () => {
//
const initialLength = initialCardList.value.length;
const currentLength = cardList.value.length;
//
const hasContentChanged = JSON.stringify(initialCardList.value) !== JSON.stringify(cardList.value);
/* 确保选中标签的文字颜色为白色 */
:deep(.ant-tabs-card > .ant-tabs-nav .ant-tabs-tab-active .ant-tabs-tab-btn) {
color: #ffffff !important; /* 文字颜色强制设为白色 */
if (!hasContentChanged) {
//
closeModal();
return;
}
/* 鼠标悬停时的文字颜色效果 */
:deep(.ant-tabs-card > .ant-tabs-nav .ant-tabs-tab:hover .ant-tabs-tab-btn) {
color: #1890ff !important; /* 悬停时文字变为蓝色 */
//
if (initialLength > 0 && currentLength === 0) {
Modal.confirm({
title: '确认提交',
content: h('div', [
'当前合同已无异常点, 状态将变为',
h('span', { style: { color: '#52c41a', fontWeight: 'bold' } }, '审核通过'),
',是否确认?'
]),
okText: '确认',
cancelText: '取消',
async onOk() {
await handleSubmit();
}
});
return;
}
/* Card 相关样式 */
/* 卡片容器布局设置 */
.card-container {
display: flex;
gap: 16px;
flex-wrap: wrap;
width: 100%;
//
if (initialLength === 0 && currentLength > 0) {
Modal.confirm({
title: '确认提交',
content: h('div', [
'当前合同新增异常点, 状态将变为',
h('span', { style: { color: '#ff4d4f', fontWeight: 'bold' } }, '审核不合格'),
',是否确认?'
]),
okText: '确认',
cancelText: '取消',
async onOk() {
await handleSubmit();
}
});
return;
}
/* 单个卡片的基本样式 */
.custom-card {
width: 100%;
margin-bottom: 16px;
cursor: pointer;
transition: all 0.3s;
background-color: #fff; /* 添加默认背景色 */
border: 1px solid #e8e8e8; /* 添加默认边框 */
//
Modal.confirm({
title: '确认提交',
content: '内容已修改,是否提交?',
okText: '确认',
cancelText: '取消',
async onOk() {
await handleSubmit();
}
});
};
/* 卡片选中状态 */
.custom-card.card-selected {
background-color: #e6f4ff !important; /* 选中时的淡蓝色背景 */
border: 1px solid #1890ff !important; /* 选中时的蓝色边框 */
//
const handleSubmit = async () => {
try {
console.log('原始数据', cardList.value);
//
const submitData = {
results: [
{
title: "人工干预", //
contentList: cardList.value.map(card => ({
problemTitle: card.title,
text: card.text,
problemDesc: card.content,
isPosition: card.isPosition,
accord: card.accord
}))
}
]
};
console.log('封装后的提交数据', submitData);
// TODO:
const res = await modifyContractReview(currentId.value,submitData);
emit('reload');
//
closeModal();
/* 卡片悬停效果 */
.custom-card:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transform: translateY(-2px);
//
Modal.success({
title: '提示',
content: '提交成功!'
});
} catch (error) {
//
console.log('提交失败',error);
Modal.error({
title: '错误',
content: '提交失败,请重试!'
});
}
};
</script>
<style scoped>
/* 添加新的样式 */
.modal-content {
height: 100%;
display: flex;
flex-direction: column;
}
/* 选中状态下的悬停效果 */
.custom-card.card-selected:hover {
background-color: #e6f4ff !important;
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.1);
.grid {
flex: 1;
min-height: 0; /* 重要:防止grid溢出 */
}
/* 卡片点击效果 */
.custom-card:active {
transform: translateY(0);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
.pdf-container {
height: 100%;
overflow: hidden;
}
/* 修改卡片内容区域的内边距 */
:deep(.ant-card-body) {
padding: 16px;
.review-container {
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* 滚动容器样式 */
.scroll-container {
height: calc(100vh - 25vh); /* 可以根据实际需要调整高度 */
overflow-y: auto; /* 添加垂直滚动条 */
padding: 16px;
.review-content {
flex: 1;
min-height: 0; /* 重要:防止内容溢出 */
overflow: hidden;
}
/* 美化滚动条样式(可选) */
.scroll-container::-webkit-scrollbar {
width: 6px; /* 滚动条宽度 */
/* 确保showResultCard组件占满剩余空间 */
.review-content :deep(.tabs-container) {
height: 100%;
display: flex;
flex-direction: column;
}
.scroll-container::-webkit-scrollbar-thumb {
background-color: #ccc; /* 滚动条颜色 */
border-radius: 3px; /* 滚动条圆角 */
/* 调整tabs内容区域的高度 */
.review-content :deep(.ant-tabs) {
height: 100%;
display: flex;
flex-direction: column;
}
.scroll-container::-webkit-scrollbar-track {
background-color: #f1f1f1; /* 滚动条轨道颜色 */
.review-content :deep(.ant-tabs-content) {
flex: 1;
height: 100%;
overflow: hidden;
}
/* 保持原有的卡片容器样式 */
.card-container {
.review-content :deep(.ant-tabs-tabpane) {
height: 100%;
display: flex;
gap: 16px;
flex-wrap: wrap;
flex-direction: column;
}
.review-content :deep(.scroll-container) {
flex: 1;
overflow-y: auto;
}
</style>

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

@ -21,7 +21,10 @@ export const formSchemas: FormSchema[] = [
{
label: '审核结果',
field: 'resultType',
component: 'Input',
component: 'Select',
componentProps: {
options: getDictOptions('jyj_contract_result_type'),
},
},
{
label: '批次名称',
@ -59,6 +62,7 @@ export const columns: BasicColumn[] = [
{
title: '审核结果',
dataIndex: 'resultType',
customRender: ({ value }) => renderDict(value, 'jyj_contract_result_type'),
},
{
title: '状态',

2
src/views/contractReview/ContractualTasks/ContractualTasksTable.vue

@ -95,7 +95,7 @@
</template>
</BasicTable>
<ContractualTasksModal @register="registerModal" @reload="reload" />
<ContractualShowModal @register="registerShowModal" />
<ContractualShowModal @register="registerShowModal" @reload="reload" />
<DocsDrawer @register="registerDrawer" />
</PageWrapper>

388
src/views/contractReview/ContractualTasks/showResultCard.vue

@ -1,49 +1,227 @@
<template>
<!-- 添加 col-span-2 和高度样式 -->
<div class="tabs-container">
<Tabs v-model:activeKey="activeKey" type="card">
<TabPane key="1" tab="审查结果">
<div class="action-buttons">
<Button type="primary" class="action-button add-button" @click="handleAdd">
<template #icon><PlusOutlined /></template>
新增审查点
</Button>
</div>
<div class="scroll-container">
<div class="card-container">
<!-- 编辑卡片 -->
<Card v-if="isAdding" class="custom-card edit-card">
<template #title>
<div class="input-group">
<div class="input-label">标题</div>
<Input v-model:value="newCard.title" placeholder="请输入标题" />
</div>
</template>
<div class="input-group">
<div class="input-label">属性</div>
<Input v-model:value="newCard.text" placeholder="请输入属性" style="margin-bottom: 8px;" />
</div>
<div class="input-group">
<div class="input-label">问题内容</div>
<Input.TextArea v-model:value="newCard.content" placeholder="请输入问题内容" style="margin-bottom: 8px;" />
</div>
<div class="card-actions">
<Button type="primary" size="small" class="action-button save-button" @click="handleSave">
<template #icon><SaveOutlined /></template>
保存
</Button>
<Button size="small" class="action-button cancel-button" @click="handleCancel">
<template #icon><CloseOutlined /></template>
取消
</Button>
</div>
</Card>
<!-- 展示卡片列表 -->
<Card
v-for="(item, index) in props.cardList"
:key="index"
:class="['custom-card', { 'card-selected': selectedCard === item.title }]"
@click="handleCardClick(item.title)"
:class="['custom-card', { 'card-selected': selectedIndex === index }]"
@click="handleCardClick(index)"
>
<template #title>{{ item.title }}</template>
{{ item.text }}
{{ item.content }}
<template #title>
<template v-if="editingIndex === index">
<div class="input-group">
<div class="input-label">标题</div>
<Input v-model:value="item.title" @click.stop />
</div>
</template>
<template v-else>
<div class="card-header">
<span class="card-title">{{ item.title }}</span>
<div class="card-header-actions">
<Button type="primary" size="small" class="action-button edit-button" @click.stop="startEdit(index)">
<template #icon><EditOutlined /></template>
编辑
</Button>
<Button type="primary" danger size="small" class="action-button delete-button" @click.stop="handleDelete(index)">
<template #icon><DeleteOutlined /></template>
删除
</Button>
</div>
</div>
</template>
</template>
<template v-if="editingIndex === index">
<div class="input-group">
<div class="input-label">属性</div>
<Input v-model:value="item.text" style="margin-bottom: 8px;" @click.stop />
</div>
<div class="input-group">
<div class="input-label">问题内容</div>
<Input.TextArea v-model:value="item.content" style="margin-bottom: 8px;" @click.stop />
</div>
<div class="card-actions">
<Button type="primary" size="small" class="action-button save-button" @click.stop="handleEditSave(index)">
<template #icon><SaveOutlined /></template>
保存
</Button>
<Button size="small" class="action-button cancel-button" @click.stop="cancelEdit">
<template #icon><CloseOutlined /></template>
取消
</Button>
</div>
</template>
<template v-else>
<div class="content-group">
<div class="content-label">属性</div>
<div>{{ item.text }}</div>
</div>
<div class="content-group">
<div class="content-label">问题内容</div>
<div>{{ item.content }}</div>
</div>
</template>
</Card>
</div>
</div>
</TabPane>
<!-- <TabPane key="2" tab="Tab 2">Content of Tab Pane 2</TabPane>
<TabPane key="3" tab="Tab 3">Content of Tab Pane 3</TabPane> -->
</Tabs>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, reactive } from 'vue';
import { ref, reactive } from 'vue';
import { Tabs, TabPane, Card, Input, Button, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined, SaveOutlined, EditOutlined, DeleteOutlined, CloseOutlined, PlusOutlined } from '@ant-design/icons-vue';
import { createVNode } from 'vue';
import { Tabs, TabPane, Card } from 'ant-design-vue';
// Props
interface Props {
cardList: any[];
}
const props = defineProps<Props>();
const emit = defineEmits(['update:cardList']);
const activeKey = ref('1');
//
const selectedCard = ref(''); //
const handleCardClick = (title) => {
selectedCard.value = title;
console.log('点击的卡片标题:', title);
const selectedIndex = ref(-1); // 使-1
const editingIndex = ref(-1); // 使-1
const isAdding = ref(false);
//
const newCard = reactive({
title: '',
text: '',
content: ''
});
//
const handleCardClick = (index: number) => {
selectedIndex.value = index;
};
//
const startEdit = (index: number) => {
editingIndex.value = index;
};
//
const cancelEdit = () => {
editingIndex.value = -1;
};
//
const handleEditSave = (index: number) => {
// 使
const newList = [...props.cardList];
//
emit('update:cardList', newList);
editingIndex.value = -1;
};
//
const handleAdd = () => {
isAdding.value = true;
newCard.title = '';
newCard.text = '';
newCard.content = '';
};
//
onMounted(() => {
//
const handleSave = () => {
if (!newCard.title.trim()) {
Modal.warning({
title: '提示',
content: '标题不能为空!'
});
return;
}
//
const isDuplicate = props.cardList.some(card => card.title === newCard.title);
if (isDuplicate) {
Modal.warning({
title: '提示',
content: '标题已存在,请修改!'
});
return;
}
//
const newList = [...props.cardList, {
title: newCard.title,
text: newCard.text,
content: newCard.content
}];
//
emit('update:cardList', newList);
//
newCard.title = '';
newCard.text = '';
newCard.content = '';
isAdding.value = false;
};
//
const handleCancel = () => {
isAdding.value = false;
};
//
const handleDelete = (index: number) => {
const title = props.cardList[index].title;
Modal.confirm({
title: '确认删除',
icon: createVNode(ExclamationCircleOutlined),
content: `确定要删除"${title}"吗?`,
okText: '确认',
cancelText: '取消',
onOk() {
const newList = props.cardList.filter((_, i) => i !== index);
emit('update:cardList', newList);
selectedIndex.value = -1; //
editingIndex.value = -1;
}
});
};
</script>
<style scoped>
/* Tabs 相关样式 */
@ -121,29 +299,177 @@
/* 滚动容器样式 */
.scroll-container {
height: calc(100vh - 25vh); /* 可以根据实际需要调整高度 */
overflow-y: auto; /* 添加垂直滚动条 */
flex: 1;
overflow-y: auto;
padding: 16px;
}
/* 美化滚动条样式(可选) */
.scroll-container::-webkit-scrollbar {
width: 6px; /* 滚动条宽度 */
/* 确保整个容器可以正确伸展 */
.tabs-container {
height: 100%;
display: flex;
flex-direction: column;
}
.scroll-container::-webkit-scrollbar-thumb {
background-color: #ccc; /* 滚动条颜色 */
border-radius: 3px; /* 滚动条圆角 */
:deep(.ant-tabs) {
height: 100%;
display: flex;
flex-direction: column;
}
.scroll-container::-webkit-scrollbar-track {
background-color: #f1f1f1; /* 滚动条轨道颜色 */
:deep(.ant-tabs-content) {
flex: 1;
overflow: hidden;
}
/* 保持原有的卡片容器样式 */
.card-container {
:deep(.ant-tabs-tabpane) {
height: 100%;
display: flex;
gap: 16px;
flex-wrap: wrap;
flex-direction: column;
}
/* 编辑卡片样式 */
.edit-card {
border: 1px dashed #1890ff;
}
/* 按钮组样式优化 */
.card-actions {
margin-top: 16px;
display: flex;
gap: 8px;
justify-content: flex-end;
}
/* 通用按钮样式 */
.action-button {
display: flex;
align-items: center;
gap: 4px;
padding: 4px 12px;
border-radius: 4px;
transition: all 0.3s;
}
/* 保存按钮样式 */
.save-button {
background-color: #1890ff;
border-color: #1890ff;
}
.save-button:hover {
background-color: #40a9ff;
border-color: #40a9ff;
}
/* 编辑按钮样式 */
.edit-button {
background-color: #1890ff;
border-color: #1890ff;
}
.edit-button:hover {
background-color: #40a9ff;
border-color: #40a9ff;
}
/* 取消按钮样式 */
.cancel-button {
color: #666;
background-color: #f4f4f4;
border-color: #d9d9d9;
}
.cancel-button:hover {
color: #40a9ff;
border-color: #40a9ff;
background-color: #fff;
}
/* 删除按钮样式 */
.delete-button {
background-color: #ff4d4f;
border-color: #ff4d4f;
}
.delete-button:hover {
background-color: #ff7875;
border-color: #ff7875;
}
/* 按钮图标样式 */
:deep(.anticon) {
font-size: 14px;
}
/* 输入框样式调整 */
:deep(.ant-input) {
margin-bottom: 8px;
}
.input-group {
margin-bottom: 12px;
}
.input-label {
font-weight: bold;
margin-bottom: 4px;
color: #333;
}
.content-group {
margin-bottom: 12px;
}
.content-label {
font-weight: bold;
margin-bottom: 4px;
color: #666;
}
/* 新增按钮样式 */
.action-buttons {
padding: 8px 16px;
}
.add-button {
background-color: #1890ff;
border-color: #1890ff;
}
.add-button:hover {
background-color: #40a9ff;
border-color: #40a9ff;
}
/* 添加卡片标题区域样式 */
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}
.card-title {
font-weight: bold;
font-size: 16px;
color: #333;
flex: 1;
}
.card-header-actions {
display: flex;
gap: 8px;
margin-left: 16px;
}
/* 调整卡片标题区域的按钮大小 */
.card-header-actions .action-button {
padding: 2px 8px;
font-size: 12px;
}
.card-header-actions :deep(.anticon) {
font-size: 12px;
}
</style>

6
src/views/contractReview/JyjcontractualTaskBatch/ContractualTasksTableModal.vue

@ -45,13 +45,13 @@
const { record, type } = data;
if (type == 'passCount') {
title.value = '查看审核通过记录';
resultType.value = '审查合格';
resultType.value = 'reviewSuccess';
} else if (type == 'rejectCount') {
title.value = '查看审核不通过记录';
resultType.value = '审查不合格';
resultType.value = 'reviewFail';
} else if(type=="irrelevantCount"){
title.value = '查看非审查范围记录';
resultType.value = '非审查范围文件';
resultType.value = 'notReviewable';
}else{
title.value = '查看审查失败的范围记录';
resultType.value = '审查失败文件';

Loading…
Cancel
Save