Browse Source

提交文件

master
zhouhaibin 1 week ago
parent
commit
664f42918d
  1. 10
      src/api/contractReview/ContractualInfo/index.ts
  2. 10
      src/api/contractReview/ContractualProductInfo/index.ts
  3. 167
      src/views/contractreview/ContractualTasks/ContractualShowModal.vue
  4. 11
      src/views/contractreview/jyjcontractualtaskbatch/index.vue
  5. 95
      src/views/contractualInfo/ContractualInfo/ContractualInfoEdit.vue
  6. 4
      src/views/contractualInfo/ContractualInfo/index.vue
  7. 353
      src/views/contractualInfo/ContractualProductInfo/ContractualProductInfoEdit.vue
  8. 52
      src/views/contractualInfo/ContractualProductInfo/index.vue

10
src/api/contractReview/ContractualInfo/index.ts

@ -35,7 +35,15 @@ export const getContractualInfo = (id: ID): AxiosPromise<ContractualInfoVO> => {
method: 'get' method: 'get'
}); });
}; };
/**
*
*/
export const getContractualInfoByTaskid = (id: ID): AxiosPromise<ContractualInfoVO> => {
return request({
url: '/productManagement/ContractualInfo/getInfoByTaskid/' + id,
method: 'get'
});
};
/** /**
* *
*/ */

10
src/api/contractReview/ContractualProductInfo/index.ts

@ -35,7 +35,15 @@ export const getContractualProductInfo = (id: ID): AxiosPromise<ContractualProdu
method: 'get' method: 'get'
}); });
}; };
/**
*
*/
export const getContractualProductInfoByTaskid = (id: ID): AxiosPromise<ContractualProductInfoVO> => {
return request({
url: '/productManagement/ContractualProductInfo/getInfoByTaskid/' + id,
method: 'get'
});
};
/** /**
* *
*/ */

167
src/views/contractreview/ContractualTasks/ContractualShowModal.vue

@ -4,6 +4,8 @@
<h2 class="modal-title">合同审查详情</h2> <h2 class="modal-title">合同审查详情</h2>
<div class="modal-actions"> <div class="modal-actions">
<el-button type="primary" @click="showTextDialog">查看识别内容</el-button> <el-button type="primary" @click="showTextDialog">查看识别内容</el-button>
<el-button type="primary" @click="showContractInfoEdit">编辑合同信息</el-button>
<el-button type="primary" @click="showProductInfoEdit">编辑产品信息</el-button>
<el-button type="primary" @click="submit">提交</el-button> <el-button type="primary" @click="submit">提交</el-button>
<el-button @click="handleClose">关闭</el-button> <el-button @click="handleClose">关闭</el-button>
</div> </div>
@ -20,6 +22,8 @@
</div> </div>
</div> </div>
</div> </div>
<!-- 文本对话框 -->
<el-dialog <el-dialog
v-model="textDialogVisible" v-model="textDialogVisible"
title="合同文本内容" title="合同文本内容"
@ -36,6 +40,48 @@
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
<!-- 合同信息编辑对话框 -->
<el-drawer
v-model="contractInfoDialogVisible"
title="编辑合同信息"
size="100%"
:destroy-on-close="true"
:show-close="true"
:close-on-click-modal="false"
:close-on-press-escape="true"
:with-header="false"
direction="rtl"
class="edit-dialog"
>
<ContractualInfoEdit
v-if="contractInfoDialogVisible"
:record="contractInfoData"
@close="contractInfoDialogVisible = false"
@success="handleContractInfoSuccess"
/>
</el-drawer>
<!-- 产品信息编辑对话框 -->
<el-drawer
v-model="productInfoDialogVisible"
title="编辑产品信息"
size="100%"
:destroy-on-close="true"
:show-close="true"
:close-on-click-modal="false"
:close-on-press-escape="true"
:with-header="false"
direction="rtl"
class="edit-dialog"
>
<ContractualProductInfoEdit
v-if="productInfoDialogVisible"
:record="productInfoData"
@close="productInfoDialogVisible = false"
@success="handleProductInfoSuccess"
/>
</el-drawer>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted, nextTick, computed } from 'vue'; import { ref, onMounted, nextTick, computed } from 'vue';
@ -45,6 +91,11 @@
import { getPdfFile } from '@/api/contractReview/JyjcontractualTaskBatch'; import { getPdfFile } from '@/api/contractReview/JyjcontractualTaskBatch';
import showResultCard from './showResultCard.vue'; import showResultCard from './showResultCard.vue';
import { cloneDeep } from 'lodash-es'; import { cloneDeep } from 'lodash-es';
//
import ContractualInfoEdit from '@/views/contractualInfo/ContractualInfo/ContractualInfoEdit.vue';
import ContractualProductInfoEdit from '@/views/contractualInfo/ContractualProductInfo/ContractualProductInfoEdit.vue';
import { getContractualProductInfoByTaskid } from '@/api/contractReview/ContractualProductInfo';
import { getContractualInfoByTaskid } from '@/api/contractReview/ContractualInfo';
// Props // Props
const props = defineProps({ const props = defineProps({
@ -69,6 +120,13 @@
const contractText = ref<string>(''); const contractText = ref<string>('');
const textDialogVisible = ref(false); const textDialogVisible = ref(false);
const historycardList = ref<any[]>([]); const historycardList = ref<any[]>([]);
//
const contractInfoDialogVisible = ref(false);
const productInfoDialogVisible = ref(false);
const contractInfoData = ref<any>({});
const productInfoData = ref<any>({});
// //
const fileType = computed(() => { const fileType = computed(() => {
const fileName = props.record.documentName?.toLowerCase() || ''; const fileName = props.record.documentName?.toLowerCase() || '';
@ -85,13 +143,15 @@
// //
try { try {
const response = await getPdfFile(props.record.id); const response = await getPdfFile(props.record.id);
if (response) { if (response instanceof Blob) {
pdfUrl.value = URL.createObjectURL(response); pdfUrl.value = URL.createObjectURL(response);
// //
nextTick(() => { nextTick(() => {
setTimeout(fitToWidth, 500); setTimeout(fitToWidth, 500);
}); });
} else {
console.error('获取PDF文件失败:返回的不是Blob对象');
} }
} catch (error) { } catch (error) {
console.error('获取PDF文件失败:', error); console.error('获取PDF文件失败:', error);
@ -155,7 +215,7 @@
if (!contractText.value) { if (!contractText.value) {
try { try {
const contentRes = await getContractulContent(props.record.id); const contentRes = await getContractulContent(props.record.id);
contractText.value = contentRes || '无法获取合同文本内容'; contractText.value = contentRes.data || '无法获取合同文本内容';
} catch (error) { } catch (error) {
console.error('获取合同文本内容失败:', error); console.error('获取合同文本内容失败:', error);
contractText.value = '获取合同文本内容失败'; contractText.value = '获取合同文本内容失败';
@ -169,6 +229,97 @@
textDialogVisible.value = false; textDialogVisible.value = false;
}; };
//
const showContractInfoEdit = async () => {
try {
//
loading.value = true;
// API
const res = await getContractualInfoByTaskid(props.record.id);
if (res.code === 200 && res.data) {
// 使
contractInfoData.value = {
...res.data,
taskId: props.record.id
};
} else {
// 使
contractInfoData.value = {
id: '',
taskId: props.record.id,
fileName: props.record.documentName,
purchaserName: '',
supplierName: '',
signDate: '',
contractAmount: ''
};
}
//
contractInfoDialogVisible.value = true;
} catch (error) {
console.error('获取合同信息失败:', error);
ElMessage.error('获取合同信息失败,请重试');
} finally {
loading.value = false;
}
};
//
const showProductInfoEdit = async () => {
try {
//
loading.value = true;
// API
const res = await getContractualProductInfoByTaskid(props.record.id);
if (res.code === 200 && res.data) {
// 使
productInfoData.value =res.data;
} else {
// 使
productInfoData.value = {
id: '',
taskId: props.record.id,
fileName: props.record.documentName,
unitName: '',
brand: '',
versionStr: '',
cpuModel: '',
type: '',
unitPrice: 0,
quantity: 0,
totalPrice: 0
};
}
//
productInfoDialogVisible.value = true;
} catch (error) {
console.error('获取产品信息失败:', error);
ElMessage.error('获取产品信息失败,请重试');
} finally {
loading.value = false;
}
};
//
const handleContractInfoSuccess = (data) => {
ElMessage.success('合同信息更新成功');
//
emit('reload');
};
//
const handleProductInfoSuccess = (data) => {
ElMessage.success('产品信息更新成功');
//
emit('reload');
};
// //
const fitToWidth = () => { const fitToWidth = () => {
const pdfContainer = document.querySelector('.pdf-wrapper'); const pdfContainer = document.querySelector('.pdf-wrapper');
@ -438,4 +589,16 @@
height: 100%; height: 100%;
overflow-y: auto; overflow-y: auto;
} }
/* 编辑对话框样式 */
:deep(.edit-dialog .el-dialog) {
height: 80vh !important;
max-width: 1600px;
}
:deep(.edit-dialog .el-dialog__body) {
height: calc(100% - 120px);
padding: 0;
overflow: hidden;
}
</style> </style>

11
src/views/contractreview/jyjcontractualtaskbatch/index.vue

@ -92,7 +92,7 @@
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<!-- <el-table-column prop="irrelevantCount" label="非审查范围数量" width="130"> <el-table-column prop="irrelevantCount" label="非审查范围数量" width="130">
<template #default="scope"> <template #default="scope">
<div class="count-cell"> <div class="count-cell">
<div>{{ scope.row.irrelevantCount }}</div> <div>{{ scope.row.irrelevantCount }}</div>
@ -108,7 +108,7 @@
</div> </div>
</div> </div>
</template> </template>
</el-table-column> --> </el-table-column>
<el-table-column prop="progress" label="进度" > <el-table-column prop="progress" label="进度" >
<template #default="scope"> <template #default="scope">
<div class="progress-column"> <div class="progress-column">
@ -196,7 +196,7 @@
</el-table-column> </el-table-column>
<!-- 非审查范围数量 --> <!-- 非审查范围数量 -->
<!-- <el-table-column prop="irrelevantCount" label="非审查范围数量" width="130"> <el-table-column prop="irrelevantCount" label="非审查范围数量" width="130">
<template #default="scope"> <template #default="scope">
<div class="count-cell"> <div class="count-cell">
<div>{{ scope.row.irrelevantCount }}</div> <div>{{ scope.row.irrelevantCount }}</div>
@ -212,7 +212,7 @@
</div> </div>
</div> </div>
</template> </template>
</el-table-column> --> </el-table-column>
<!-- 审核失败数量 --> <!-- 审核失败数量 -->
<!-- <el-table-column prop="failCount" label="审核失败数量" width="100"> <!-- <el-table-column prop="failCount" label="审核失败数量" width="100">
@ -453,6 +453,7 @@ function calculateParentTotals(parentItem: any) {
let approvedCount = 0; let approvedCount = 0;
let passCount = 0; let passCount = 0;
let rejectCount = 0; let rejectCount = 0;
let irrelevantCount=0;
// //
parentItem.children.forEach(child => { parentItem.children.forEach(child => {
@ -460,6 +461,7 @@ function calculateParentTotals(parentItem: any) {
approvedCount += Number(child.approvedCount || 0); approvedCount += Number(child.approvedCount || 0);
passCount += Number(child.passCount || 0); passCount += Number(child.passCount || 0);
rejectCount += Number(child.rejectCount || 0); rejectCount += Number(child.rejectCount || 0);
irrelevantCount+=Number(child.irrelevantCount || 0);
}); });
// //
@ -467,6 +469,7 @@ function calculateParentTotals(parentItem: any) {
parentItem.approvedCount = approvedCount; parentItem.approvedCount = approvedCount;
parentItem.passCount = passCount; parentItem.passCount = passCount;
parentItem.rejectCount = rejectCount; parentItem.rejectCount = rejectCount;
parentItem.irrelevantCount=irrelevantCount;
// //
if (totalContracts > 0) { if (totalContracts > 0) {

95
src/views/contractualInfo/ContractualInfo/ContractualInfoEdit.vue

@ -1,21 +1,21 @@
<template> <template>
<div class="h-full"> <div class="container">
<div class="modal-header"> <div class="header">
<h2 class="modal-title">编辑合同信息</h2> <h2 class="title">编辑合同信息</h2>
<div class="modal-actions"> <div class="actions">
<el-button type="primary" @click="handleSubmit">保存</el-button> <el-button type="primary" @click="handleSubmit">保存</el-button>
<el-button @click="handleClose">关闭</el-button> <el-button @click="handleClose">关闭</el-button>
</div> </div>
</div> </div>
<div class="grid grid-cols-2 gap-2 h-full"> <div class="content">
<!-- 左侧PDF显示区域 --> <!-- 左侧PDF显示区域 -->
<div class="col-span-1 h-full overflow-auto"> <div class="pdf-area">
<embed :src="pdfUrl" type="application/pdf" width="100%" height="100%" class="pdf-embed" /> <embed :src="pdfUrl" type="application/pdf" width="100%" height="100%" />
</div> </div>
<!-- 右侧编辑表单区域 --> <!-- 右侧编辑表单区域 -->
<div class="h-full overflow-auto"> <div class="form-area">
<el-form <el-form
ref="formRef" ref="formRef"
:model="formData" :model="formData"
@ -55,7 +55,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, onMounted, nextTick } from 'vue'; import { ref, reactive, onMounted, nextTick } from 'vue';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import { updateContractualInfo } from '@/api/contractReview/ContractualInfo'; import { updateContractualInfo,addContractualInfo } from '@/api/contractReview/ContractualInfo';
import { getPdfFile } from '@/api/contractReview/JyjcontractualTaskBatch'; import { getPdfFile } from '@/api/contractReview/JyjcontractualTaskBatch';
defineOptions({ name: 'ContractualInfoEdit' }); defineOptions({ name: 'ContractualInfoEdit' });
@ -76,6 +76,7 @@ const emit = defineEmits(['close', 'success']);
const formRef = ref(); const formRef = ref();
const formData = reactive({ const formData = reactive({
id: '', id: '',
taskId: props.record.length > 0 ? props.record[0].taskId : '',
fileName: '', fileName: '',
purchaserName: '', purchaserName: '',
supplierName: '', supplierName: '',
@ -136,11 +137,22 @@ const handleSubmit = async () => {
loading.value = true; loading.value = true;
// API // id
const res = await updateContractualInfo(formData); let res;
if (formData.id) {
//
res = await updateContractualInfo(formData);
} else {
//
res = await addContractualInfo(formData);
}
if (res.code === 200) { if (res.code === 200) {
ElMessage.success('保存成功'); ElMessage.success(formData.id ? '更新成功' : '新增成功');
// idid
if (!formData.id && res.data && res.data.id) {
formData.id = res.data.id;
}
emit('success', formData); emit('success', formData);
handleClose(); handleClose();
} else { } else {
@ -161,56 +173,59 @@ const handleClose = () => {
</script> </script>
<style scoped> <style scoped>
/* 头部样式 */ .container {
.modal-header { display: flex;
overflow: hidden; flex-direction: column;
height: 100%;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 24px; padding: 16px 24px;
background-color: #f5f7fa; background-color: #f5f7fa;
border-bottom: 1px solid #e4e7ed; border-bottom: 1px solid #e4e7ed;
} }
.modal-title { .title {
float: left;
margin: 0; margin: 0;
font-size: 18px; font-size: 18px;
color: #303133; color: #303133;
} }
.modal-actions { .actions {
float: right; display: flex;
gap: 12px;
} }
.modal-actions .el-button { .content {
margin-left: 12px; display: flex;
flex: 1;
overflow: hidden;
} }
/* 确保embed标签占满整个容器 */ .pdf-area {
.pdf-embed { width: 50%;
display: block; height: 100%;
height: calc(100vh - 70px) !important; /* 减去头部的高度 */ border-right: 1px solid #e4e7ed;
border: none; overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
} }
/* 使网格容器填充整个可用空间 */ .pdf-area embed {
.grid { width: 100%;
height: calc(100vh - 70px); /* 减去头部的高度 */ height: 100%;
overflow: hidden; border: none;
} }
/* 确保两列都有适当的滚动行为 */ .form-area {
.col-span-1 { width: 50%;
height: 100%; height: 100%;
overflow-y: auto; overflow-y: auto;
padding: 16px;
} }
/* 表单样式 */
.edit-form { .edit-form {
padding: 20px; padding: 16px;
}
/* 全局高度 */
.h-full {
height: 100%;
} }
</style> </style>

4
src/views/contractualInfo/ContractualInfo/index.vue

@ -47,7 +47,7 @@
> >
<el-table-column type="selection" width="55" /> <el-table-column type="selection" width="55" />
<el-table-column v-for="col in tableColumns" :key="col.prop" :label="col.label" :prop="col.prop" /> <el-table-column v-for="col in tableColumns" :key="col.prop" :label="col.label" :prop="col.prop" />
<el-table-column label="操作" fixed="right" width="200"> <!-- <el-table-column label="操作" fixed="right" width="200">
<template #default="{ row }"> <template #default="{ row }">
<el-button <el-button
link link
@ -66,7 +66,7 @@
</template> </template>
</el-popconfirm> </el-popconfirm>
</template> </template>
</el-table-column> </el-table-column> -->
</el-table> </el-table>
<!-- 分页区域 --> <!-- 分页区域 -->

353
src/views/contractualInfo/ContractualProductInfo/ContractualProductInfoEdit.vue

@ -1,140 +1,179 @@
<template> <template>
<div class="h-full"> <div class="container">
<div class="modal-header"> <div class="header">
<h2 class="modal-title">编辑合同产品信息</h2> <h2 class="title">编辑合同产品信息</h2>
<div class="modal-actions"> <div class="actions">
<el-button type="primary" @click="handleSubmit">保存</el-button> <el-button type="primary" @click="handleAddProduct">新增产品</el-button>
<el-button @click="handleClose">关闭</el-button> <el-button @click="handleClose">关闭</el-button>
</div> </div>
</div> </div>
<div class="grid grid-cols-2 gap-2 h-full"> <div class="content">
<!-- 左侧PDF显示区域 --> <!-- 左侧PDF显示区域 -->
<div class="col-span-1 h-full overflow-auto"> <div class="pdf-area">
<embed :src="pdfUrl" type="application/pdf" width="100%" height="100%" class="pdf-embed" /> <embed :src="pdfUrl" type="application/pdf" width="100%" height="100%" />
</div> </div>
<!-- 右侧编辑表单区域 --> <!-- 右侧编辑表单区域 -->
<div class="h-full overflow-auto"> <div class="form-area">
<el-form <!-- 产品列表 -->
ref="formRef" <div v-for="(product, index) in productList" :key="product.id || index" class="product-item">
:model="formData" <div class="product-header">
:rules="rules" <h3>产品 #{{ index + 1 }}</h3>
label-width="100px" <div class="product-actions">
class="edit-form" <el-button type="primary" size="small" @click="handleSubmitSingle(index)">保存</el-button>
> <el-button type="danger" size="small" @click="handleRemoveProduct(index)" v-if="productList.length > 1">
<el-form-item label="品牌" prop="brand"> 删除
<el-input v-model="formData.brand" placeholder="请输入品牌" /> </el-button>
</el-form-item> </div>
<el-form-item label="型号(版本号)" prop="versionStr"> </div>
<el-input v-model="formData.versionStr" placeholder="请输入型号" />
</el-form-item> <el-form
<el-form-item label="CPU型号" prop="cpuModel"> :ref="el => (formRefs[index] = el)"
<el-input v-model="formData.cpuModel" placeholder="请输入CPU型号" /> :model="product"
</el-form-item> label-width="100px"
<el-form-item label="类型" prop="type"> class="edit-form"
<el-input v-model="formData.type" placeholder="请输入类型" /> >
</el-form-item> <el-form-item label="品牌" prop="brand">
<el-form-item label="单价" prop="unitPrice"> <el-input v-model="product.brand" placeholder="请输入品牌" />
<el-input-number </el-form-item>
v-model="formData.unitPrice" <el-form-item label="型号(版本号)" prop="versionStr">
:precision="0" <el-input v-model="product.versionStr" placeholder="请输入型号" />
:step="1" </el-form-item>
:min="0" <el-form-item label="CPU型号" prop="cpuModel">
placeholder="请输入单价" <el-input v-model="product.cpuModel" placeholder="请输入CPU型号" />
/> </el-form-item>
</el-form-item> <el-form-item label="类型" prop="type">
<el-form-item label="数量" prop="quantity"> <el-input v-model="product.type" placeholder="请输入类型" />
<el-input-number </el-form-item>
v-model="formData.quantity" <el-form-item label="单价" prop="unitPrice">
:min="0" <el-input-number
placeholder="请输入数量" v-model="product.unitPrice"
/> :precision="0"
</el-form-item> :step="1"
<el-form-item label="总价" prop="totalPrice"> :min="0"
<el-input-number placeholder="请输入单价"
v-model="formData.totalPrice" />
:precision="0" </el-form-item>
:step="1" <el-form-item label="数量" prop="quantity">
:min="0" <el-input-number
placeholder="总价" v-model="product.quantity"
disabled :min="0"
/> placeholder="请输入数量"
</el-form-item> />
</el-form> </el-form-item>
<el-form-item label="总价" prop="totalPrice">
<el-input-number
v-model="product.totalPrice"
:precision="0"
:step="1"
:min="0"
placeholder="总价"
disabled
/>
</el-form-item>
</el-form>
<el-divider v-if="index < productList.length - 1" />
</div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, onMounted, nextTick, watch } from 'vue'; import { ref, reactive, onMounted, nextTick, watch, computed } from 'vue';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import { updateContractualProductInfo } from '@/api/contractReview/ContractualProductInfo'; import { updateContractualProductInfo,addContractualProductInfo } from '@/api/contractReview/ContractualProductInfo';
import { getPdfFile } from '@/api/contractReview/JyjcontractualTaskBatch'; import { getPdfFile } from '@/api/contractReview/JyjcontractualTaskBatch';
defineOptions({ name: 'ContractualProductInfoEdit' }); defineOptions({ name: 'ContractualProductInfoEdit' });
//
interface ProductInfo {
id: string | number;
taskId: string | number;
fileName: string;
unitName: string;
brand: string;
versionStr: string;
cpuModel: string;
type: string;
unitPrice: number;
quantity: number;
totalPrice: number;
}
// Props // Props
const props = defineProps({ const props = defineProps({
record: { record: {
type: Object, type: Array as () => ProductInfo[],
required: true, required: true,
default: () => ({}) default: () => []
} }
}); });
// Emits // Emits
const emit = defineEmits(['close', 'success']); const emit = defineEmits(['close', 'success']);
// //
const formRef = ref(); const createEmptyProduct = (): ProductInfo => {
const formData = reactive({ return {
id: '', id: '',
taskId: '', taskId: props.record.length > 0 ? props.record[0].taskId : '',
fileName: '', fileName: props.record.length > 0 ? props.record[0].fileName : '',
unitName: '', unitName: '',
brand: '', brand: '',
versionStr: '', versionStr: '',
cpuModel: '', cpuModel: '',
type: '', type: '',
unitPrice: 0, unitPrice: 0,
quantity: 0, quantity: 0,
totalPrice: 0 totalPrice: 0
}); };
//
const rules = {
brand: [{ required: true, message: '请输入品牌', trigger: 'blur' }],
}; };
//
const productList = ref<ProductInfo[]>([]);
//
const formRefs = ref<any[]>([]);
// PDFURL // PDFURL
const pdfUrl = ref<string>(''); const pdfUrl = ref<string>('');
const loading = ref(false); const loading = ref(false);
// //
watch( watch(productList, () => {
() => [formData.unitPrice, formData.quantity], productList.value.forEach(product => {
([newUnitPrice, newQuantity]) => { product.totalPrice = product.unitPrice * product.quantity;
formData.totalPrice = newUnitPrice * newQuantity; });
}, }, { deep: true });
{ immediate: true }
);
// //
onMounted(async () => { onMounted(async () => {
if (props.record) { if (props.record && props.record.length) {
// //
Object.keys(formData).forEach(key => { productList.value = props.record.map((item: ProductInfo) => {
if (props.record[key] !== undefined) { const product = createEmptyProduct();
formData[key] = props.record[key]; Object.keys(product).forEach(key => {
} if (item[key as keyof ProductInfo] !== undefined) {
// @ts-ignore
product[key as keyof ProductInfo] = item[key as keyof ProductInfo];
}
});
return product;
}); });
//
if (productList.value.length === 0) {
productList.value.push(createEmptyProduct());
}
// PDF // PDF
try { try {
if (props.record.id) { if (props.record.length > 0 && props.record[0].taskId) {
const response = await getPdfFile(props.record.taskId); // @ts-ignore
const response = await getPdfFile(props.record[0].taskId);
if (response instanceof Blob) { if (response instanceof Blob) {
pdfUrl.value = URL.createObjectURL(response); pdfUrl.value = URL.createObjectURL(response);
@ -151,23 +190,51 @@
} catch (error) { } catch (error) {
console.error('加载PDF文件失败:', error); console.error('加载PDF文件失败:', error);
} }
} else {
//
productList.value.push(createEmptyProduct());
} }
}); });
// //
const handleSubmit = async () => { const handleAddProduct = () => {
productList.value.push(createEmptyProduct());
};
//
const handleRemoveProduct = (index: number) => {
productList.value.splice(index, 1);
};
//
const handleSubmitSingle = async (index: number) => {
try { try {
await formRef.value.validate(); if (formRefs.value[index]) {
await formRefs.value[index].validate();
}
loading.value = true; loading.value = true;
// API //
const res = await updateContractualProductInfo(formData); const currentProduct = productList.value[index];
// idAPI
let res;
if (currentProduct.id) {
//
res = await updateContractualProductInfo(currentProduct);
} else {
//
res = await addContractualProductInfo(currentProduct);
// id
if (res.code === 200 && res.data) {
currentProduct.id = res.data.id;
}
}
if (res.code === 200) { if (res.code === 200) {
ElMessage.success('保存成功'); ElMessage.success(`产品 #${index + 1} ${currentProduct.id ? '更新' : '新增'}成功`);
emit('success', formData); emit('success', currentProduct);
handleClose();
} else { } else {
ElMessage.error(res.msg || '保存失败'); ElMessage.error(res.msg || '保存失败');
} }
@ -186,56 +253,84 @@
</script> </script>
<style scoped> <style scoped>
/* 头部样式 */ .container {
.modal-header { display: flex;
overflow: hidden; flex-direction: column;
height: 100%;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 24px; padding: 16px 24px;
background-color: #f5f7fa; background-color: #f5f7fa;
border-bottom: 1px solid #e4e7ed; border-bottom: 1px solid #e4e7ed;
} }
.modal-title { .title {
float: left;
margin: 0; margin: 0;
font-size: 18px; font-size: 18px;
color: #303133; color: #303133;
} }
.modal-actions { .actions {
float: right; display: flex;
gap: 12px;
} }
.modal-actions .el-button { .content {
margin-left: 12px; display: flex;
flex: 1;
overflow: hidden;
} }
/* 确保embed标签占满整个容器 */ .pdf-area {
.pdf-embed { width: 50%;
display: block; height: 100%;
height: calc(100vh - 70px) !important; /* 减去头部的高度 */ border-right: 1px solid #e4e7ed;
border: none; overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
} }
/* 使网格容器填充整个可用空间 */ .pdf-area embed {
.grid { width: 100%;
height: calc(100vh - 70px); /* 减去头部的高度 */ height: 100%;
overflow: hidden; border: none;
} }
/* 确保两列都有适当的滚动行为 */ .form-area {
.col-span-1 { width: 50%;
height: 100%; height: 100%;
overflow-y: auto; overflow-y: auto;
padding: 16px;
} }
/* 表单样式 */ .product-item {
.edit-form { margin-bottom: 20px;
padding: 20px; background-color: #f9fafc;
border-radius: 4px;
padding: 16px;
} }
/* 全局高度 */ .product-header {
.h-full { display: flex;
height: 100%; justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.product-header h3 {
margin: 0;
font-size: 16px;
font-weight: 500;
}
.product-actions {
display: flex;
gap: 8px;
}
.edit-form {
padding: 8px 0;
} }
</style> </style>

52
src/views/contractualInfo/ContractualProductInfo/index.vue

@ -2,30 +2,18 @@
<div class="page-container"> <div class="page-container">
<!-- 搜索区域 --> <!-- 搜索区域 -->
<el-form :model="queryParams" ref="queryFormRef" :inline="true" class="searchbar"> <el-form :model="queryParams" ref="queryFormRef" :inline="true" class="searchbar">
<!-- <el-form-item label="单位名称" prop="unitName"> <el-form-item label="合同名称" prop="fileName">
<el-input v-model="queryParams.unitName" placeholder="请输入单位名称" clearable /> <el-input v-model="queryParams.fileName" placeholder="请输入合同名称" clearable />
</el-form-item> </el-form-item>
<el-form-item label="文件名称" prop="fileName"> <el-form-item label="采购人(甲方)" prop="purchaserName">
<el-input v-model="queryParams.fileName" placeholder="请输入文件名称" clearable /> <el-input v-model="queryParams.purchaserName" placeholder="请输入采购人名称" clearable />
</el-form-item> </el-form-item>
<el-form-item label="品牌" prop="brand"> <!-- <el-form-item label="供应商(乙方)" prop="supplierName">
<el-input v-model="queryParams.brand" placeholder="请输入品牌" clearable /> <el-input v-model="queryParams.supplierName" placeholder="请输入供应商名称" clearable />
</el-form-item>
<el-form-item label="产品类型" prop="type">
<el-input v-model="queryParams.type" placeholder="请输入产品类型" clearable />
</el-form-item>
<el-form-item label="型号" prop="versionStr">
<el-input v-model="queryParams.versionStr" placeholder="请输入型号" clearable />
</el-form-item>
<el-form-item label="CPU型号" prop="cpuModel">
<el-input v-model="queryParams.cpuModel" placeholder="请输入CPU型号" clearable />
</el-form-item>
<el-form-item label="单价" prop="unitPrice">
<el-input v-model="queryParams.unitPrice" placeholder="请输入单价" clearable />
</el-form-item> --> </el-form-item> -->
<el-form-item> <el-form-item>
<!-- <el-button type="primary" @click="handleQuery">搜索</el-button> <el-button type="primary" @click="handleQuery">搜索</el-button>
<el-button @click="resetQuery">重置</el-button> --> <el-button @click="resetQuery">重置</el-button>
<el-button type="info" @click="showStatisticsDialog">查看统计</el-button> <el-button type="info" @click="showStatisticsDialog">查看统计</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -70,7 +58,7 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-for="col in tableColumns.filter(col => col.prop !== 'unitName')" :key="col.prop" :label="col.label" :prop="col.prop" /> <el-table-column v-for="col in tableColumns.filter(col => col.prop !== 'unitName')" :key="col.prop" :label="col.label" :prop="col.prop" />
<el-table-column label="操作" fixed="right" width="200"> <!-- <el-table-column label="操作" fixed="right" width="200">
<template #default="{ row }"> <template #default="{ row }">
<el-button <el-button
link link
@ -89,7 +77,7 @@
</template> </template>
</el-popconfirm> </el-popconfirm>
</template> </template>
</el-table-column> </el-table-column> -->
</el-table> </el-table>
<!-- 子表分页 --> <!-- 子表分页 -->
@ -244,13 +232,8 @@ const tableColumns = [
const queryFormRef = ref(); const queryFormRef = ref();
const queryParams = reactive({ const queryParams = reactive({
fileName: '', fileName: '',
unitName: '', purchaserName: '',
brand: '', supplierName: '',
versionStr: '',
cpuModel: '',
unitPrice: 0,
quantity: 0,
totalPrice: 0,
type: '' type: ''
}); });
@ -339,9 +322,9 @@ const loadChildData = async (countyName: string, page = 1, pageSize = 10) => {
pageNum: page, pageNum: page,
pageSize: pageSize, pageSize: pageSize,
unitName: countyName, // 使countyName unitName: countyName, // 使countyName
type:activeTab.value, ...queryParams
// ...queryParams
}; };
params.type = activeTab.value;
const res = await listContractualProductInfo(params); const res = await listContractualProductInfo(params);
if (res.code === 200) { if (res.code === 200) {
// unitName // unitName
@ -393,9 +376,10 @@ const handleQuery = () => {
// //
const resetQuery = () => { const resetQuery = () => {
// //
Object.keys(queryParams).forEach(key => { queryParams.fileName = '';
queryParams[key] = ''; queryParams.purchaserName = '';
}); queryParams.supplierName = '';
queryParams.type = activeTab.value;
// //
queryFormRef.value?.resetFields(); queryFormRef.value?.resetFields();

Loading…
Cancel
Save