Browse Source

修改前端文件

master
zhouhaibin 3 weeks ago
parent
commit
fb4c4422ef
  1. 4
      src/views/contractreview/ContractualTasks/ContractualTasksTable.vue
  2. 2
      src/views/contractualInfo/ContractualInfo/ContractualInfoEdit.vue
  3. 39
      src/views/contractualInfo/ContractualProductInfo/ContractualProductInfoEdit.vue
  4. 373
      src/views/contractualInfo/ContractualProductInfo/index.vue

4
src/views/contractreview/ContractualTasks/ContractualTasksTable.vue

@ -5,6 +5,9 @@
<el-form-item label="文档名称"> <el-form-item label="文档名称">
<el-input v-model="searchForm.documentName" placeholder="请输入文档名称" /> <el-input v-model="searchForm.documentName" placeholder="请输入文档名称" />
</el-form-item> </el-form-item>
<el-form-item label="单位名称">
<el-input v-model="searchForm.unitName" placeholder="请输入单位名称" />
</el-form-item>
<el-form-item label="状态"> <el-form-item label="状态">
<el-select <el-select
v-model="searchForm.progressStatus" v-model="searchForm.progressStatus"
@ -216,6 +219,7 @@ const dictOptions = {
// //
const searchForm = reactive({ const searchForm = reactive({
documentName: '', documentName: '',
unitName: '',
progressStatus: '', progressStatus: '',
resultType: '', resultType: '',
problemPoint: '', problemPoint: '',

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

@ -109,7 +109,7 @@ onMounted(async () => {
// PDF // PDF
try { try {
if (props.record.id) { if (props.record.taskId) {
const response = await getPdfFile(props.record.taskId); const response = await getPdfFile(props.record.taskId);
if (response instanceof Blob) { if (response instanceof Blob) {
pdfUrl.value = URL.createObjectURL(response); pdfUrl.value = URL.createObjectURL(response);

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

@ -82,8 +82,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, onMounted, nextTick, watch, computed } from 'vue'; import { ref, reactive, onMounted, nextTick, watch, computed } from 'vue';
import { ElMessage } from 'element-plus'; import { ElMessage, ElMessageBox } from 'element-plus';
import { updateContractualProductInfo,addContractualProductInfo } from '@/api/contractReview/ContractualProductInfo'; import { updateContractualProductInfo, addContractualProductInfo, delContractualProductInfo } from '@/api/contractReview/ContractualProductInfo';
import { getPdfFile } from '@/api/contractReview/JyjcontractualTaskBatch'; import { getPdfFile } from '@/api/contractReview/JyjcontractualTaskBatch';
defineOptions({ name: 'ContractualProductInfoEdit' }); defineOptions({ name: 'ContractualProductInfoEdit' });
@ -202,8 +202,41 @@
}; };
// //
const handleRemoveProduct = (index: number) => { const handleRemoveProduct = async (index: number) => {
const currentProduct = productList.value[index];
// IDAPI
if (currentProduct.id) {
try {
//
await ElMessageBox.confirm('确定要删除该产品记录吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
});
loading.value = true;
const res = await delContractualProductInfo(currentProduct.id);
if (res.code === 200) {
ElMessage.success('删除成功');
productList.value.splice(index, 1); productList.value.splice(index, 1);
emit('success', null); //
} else {
ElMessage.error(res.msg || '删除失败');
}
} catch (error: any) {
if (error !== 'cancel') {
console.error('删除失败', error);
ElMessage.error('删除失败');
}
} finally {
loading.value = false;
}
} else {
// ID
productList.value.splice(index, 1);
}
}; };
// //

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

@ -1,20 +1,38 @@
<template> <template>
<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" label-width="80px">
<el-form-item label="合同名称" prop="fileName"> <el-form-item label="合同名称" prop="fileName">
<el-input v-model="queryParams.fileName" placeholder="请输入合同名称" clearable /> <el-input v-model="queryParams.fileName" placeholder="请输入合同名称" clearable />
</el-form-item> </el-form-item>
<el-form-item label="采购人(甲方)" prop="purchaserName"> <el-form-item label="采购人" prop="purchaserName">
<el-input v-model="queryParams.purchaserName" placeholder="请输入采购人名称" clearable /> <el-input v-model="queryParams.purchaserName" placeholder="请输入采购人名称" clearable />
</el-form-item> </el-form-item>
<el-form-item label="品牌" prop="brand">
<el-input v-model="queryParams.brand" placeholder="请输入品牌" clearable />
</el-form-item>
<el-form-item label="型号/版本" prop="versionStr" class="no-wrap-label">
<el-input v-model="queryParams.versionStr" placeholder="请输入型号或版本号" clearable />
</el-form-item>
<el-form-item label="CPU型号" prop="cpuModel" class="no-wrap-label">
<el-input v-model="queryParams.cpuModel" placeholder="请输入CPU型号" clearable />
</el-form-item>
<!-- <el-form-item label="供应商(乙方)" prop="supplierName"> <!-- <el-form-item label="供应商(乙方)" prop="supplierName">
<el-input v-model="queryParams.supplierName" placeholder="请输入供应商名称" clearable /> <el-input v-model="queryParams.supplierName" 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 @click="resetQuery">重置</el-button> <el-icon><Search /></el-icon>
<el-button type="info" @click="showStatisticsDialog">查看统计</el-button> </el-button>
<el-button @click="resetQuery">
<el-icon><Refresh /></el-icon>
</el-button>
<el-button type="info" @click="showStatisticsDialog">
<el-icon><DataAnalysis /></el-icon>
</el-button>
<el-button type="success" @click="handleExport">
<el-icon><Download /></el-icon>
</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -57,29 +75,48 @@
<span v-else></span> <span v-else></span>
</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 label="操作" fixed="right" width="200"> <!-- 文件名称列 - 可点击 -->
<el-table-column prop="fileName" label="文件名称">
<template #default="scope">
<a href="javascript:;" class="clickable-filename" @click="handleOpenPdfDrawer(scope.row)">{{ scope.row.fileName }}</a>
</template>
</el-table-column>
<!-- 其他列 -->
<el-table-column v-for="col in tableColumns.filter(col => col.prop !== 'unitName' && col.prop !== 'fileName')"
:key="col.prop"
:label="col.label"
:prop="col.prop"
/>
<!-- 操作列 -->
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }"> <template #default="{ row }">
<el-button
link
type="primary"
@click="handleEdit(row)"
>编辑</el-button>
<el-popconfirm <el-popconfirm
:title="`是否删除合同产品信息[${row.id}]?`" :title="`确定删除该合同产品信息吗?`"
@confirm="handleDelete(row)" @confirm="handleDeleteItem(row)"
> >
<template #reference> <template #reference>
<el-button <el-button
link link
type="danger" type="danger"
size="small"
>删除</el-button> >删除</el-button>
</template> </template>
</el-popconfirm> </el-popconfirm>
</template> </template>
</el-table-column> --> </el-table-column>
</el-table> </el-table>
<!-- 子表操作工具栏 -->
<div class="child-table-toolbar" v-if="selectedRows[props.row.countyName]?.length > 0">
<el-button type="danger" size="small" @click="handleBatchDeleteItems(props.row.countyName)">
批量删除
</el-button>
<span class="selected-count">已选择 {{ selectedRows[props.row.countyName]?.length }} </span>
</div>
<!-- 子表分页 --> <!-- 子表分页 -->
<el-pagination <el-pagination
v-if="childTableData[props.row.countyName]?.total > 0" v-if="childTableData[props.row.countyName]?.total > 0"
@ -164,11 +201,38 @@
> >
<ShowTotal :tableData="allChildData" :total="allChildData.length" /> <ShowTotal :tableData="allChildData" :total="allChildData.length" />
</el-drawer> </el-drawer>
<!-- PDF预览抽屉 -->
<el-drawer
v-model="pdfDrawerVisible"
title="合同文件预览"
size="80%"
direction="rtl"
destroy-on-close
:close-on-click-modal="true"
:close-on-press-escape="true"
>
<div class="pdf-drawer-container">
<div v-if="currentFileRow" class="pdf-header">
<div class="pdf-file-info">
<h3>{{ currentFileRow.fileName }}</h3>
<p v-if="currentFileRow.unitName">单位{{ currentFileRow.unitName }}</p>
</div>
</div>
<div v-loading="pdfLoading" class="pdf-container">
<embed v-if="pdfUrl" :src="pdfUrl" type="application/pdf" width="100%" height="100%" class="pdf-embed" />
<div v-else-if="!pdfLoading" class="pdf-empty">无法加载PDF文件</div>
</div>
</div>
</el-drawer>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, reactive, onMounted } from 'vue'; import { ref, computed, reactive, onMounted, getCurrentInstance } from 'vue';
import type { ComponentInternalInstance } from 'vue';
import { Search, Refresh, DataAnalysis, Download } from '@element-plus/icons-vue';
import ContractualProductInfoModal from './ContractualProductInfoModal.vue'; import ContractualProductInfoModal from './ContractualProductInfoModal.vue';
import ContractualProductInfoEdit from './ContractualProductInfoEdit.vue'; import ContractualProductInfoEdit from './ContractualProductInfoEdit.vue';
import ShowTotal from './showtotal.vue'; import ShowTotal from './showtotal.vue';
@ -177,8 +241,12 @@ import {
listContractualProductInfo, listContractualProductInfo,
addContractualProductInfo, addContractualProductInfo,
updateContractualProductInfo, updateContractualProductInfo,
delContractualProductInfo delContractualProductInfo,
exportContractualProductInfo
} from '@/api/contractReview/ContractualProductInfo'; } from '@/api/contractReview/ContractualProductInfo';
import { getPdfFile } from '@/api/contractReview/JyjcontractualTaskBatch';
import { ContractualProductInfoQuery } from '@/api/contractReview/ContractualProductInfo/model';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
// API // API
// API // API
@ -234,7 +302,10 @@ const queryParams = reactive({
fileName: '', fileName: '',
purchaserName: '', purchaserName: '',
supplierName: '', supplierName: '',
type: '' brand: '',
type: '',
versionStr: '',
cpuModel: ''
}); });
// //
@ -279,6 +350,12 @@ const expandedRows = ref<Record<string, boolean>>({});
// //
const childPagination = ref<Record<string, { page: number, pageSize: number }>>({}); const childPagination = ref<Record<string, { page: number, pageSize: number }>>({});
// PDF
const pdfDrawerVisible = ref(false);
const pdfUrl = ref('');
const pdfLoading = ref(false);
const currentFileRow = ref<any>(null);
// //
const loadParentData = async () => { const loadParentData = async () => {
parentLoading.value = true; parentLoading.value = true;
@ -379,6 +456,9 @@ const resetQuery = () => {
queryParams.fileName = ''; queryParams.fileName = '';
queryParams.purchaserName = ''; queryParams.purchaserName = '';
queryParams.supplierName = ''; queryParams.supplierName = '';
queryParams.brand = '';
queryParams.versionStr = '';
queryParams.cpuModel = '';
queryParams.type = activeTab.value; queryParams.type = activeTab.value;
// //
@ -535,12 +615,173 @@ const handleShowDetails = (row: any, event: Event) => {
parentTableRef.value.toggleRowExpansion(row, true); parentTableRef.value.toggleRowExpansion(row, true);
expandedRows.value[row.countyName] = true; expandedRows.value[row.countyName] = true;
// //
if (!childTableData.value[row.countyName]) { childLoading.value[row.countyName] = true;
loadChildData(row.countyName); loadChildData(row.countyName);
};
// PDF
const handleOpenPdfDrawer = async (row: any) => {
console.log('点击打开PDF预览,行数据:', row);
if (!row) {
ElMessage.warning('行数据为空,无法预览文件');
return;
}
if (!row.taskId) {
ElMessage.warning('该记录缺少任务ID,无法预览文件');
console.error('缺少taskId字段:', row);
return;
}
currentFileRow.value = row;
pdfDrawerVisible.value = true;
pdfLoading.value = true;
pdfUrl.value = '';
try {
console.log('开始获取PDF文件, taskId:', row.taskId);
const response = await getPdfFile(row.taskId);
console.log('获取PDF文件响应:', response);
if (response instanceof Blob) {
// Blob
if (response.size === 0) {
ElMessage.error('获取的PDF文件为空');
return;
}
// URL
pdfUrl.value = URL.createObjectURL(response);
console.log('创建的PDF URL:', pdfUrl.value);
} else {
ElMessage.error('获取PDF文件失败:返回的不是Blob对象');
console.error('API返回的不是Blob对象:', response);
}
} catch (error: any) {
console.error('获取PDF文件失败:', error);
ElMessage.error('获取文件失败:' + (error.message || '未知错误'));
} finally {
pdfLoading.value = false;
} }
}; };
//
const handleDeleteItem = async (row: any) => {
if (!row || !row.id) {
ElMessage.warning('缺少ID,无法删除');
return;
}
try {
//
childLoading.value[row.unitName] = true;
// API
console.log('删除项目,ID:', row.id);
// API
const res = await delContractualProductInfo(row.id);
if (res.code === 200) {
//
ElMessage.success('删除成功');
//
if (row.unitName) {
loadChildData(row.unitName,
childPagination.value[row.unitName]?.page || 1,
childPagination.value[row.unitName]?.pageSize || 10);
}
//
loadParentData();
} else {
ElMessage.error(res.msg || '删除失败');
}
} catch (error: any) {
console.error('删除失败:', error);
ElMessage.error('删除失败: ' + (error.message || '未知错误'));
} finally {
childLoading.value[row.unitName] = false;
}
};
//
const handleBatchDeleteItems = async (countyName: string) => {
const selectedItems = selectedRows.value[countyName] || [];
if (selectedItems.length === 0) {
ElMessage.warning('请选择要删除的项目');
return;
}
try {
await ElMessageBox.confirm(
`确定要删除选中的 ${selectedItems.length} 项数据吗?此操作不可恢复!`,
'批量删除确认',
{
confirmButtonText: '确定删除',
cancelButtonText: '取消',
type: 'warning'
}
);
//
childLoading.value[countyName] = true;
// ID
const ids = selectedItems.map(item => item.id).join(',');
console.log('批量删除,IDs:', ids);
// API
const res = await delContractualProductInfo(ids);
if (res.code === 200) {
ElMessage.success(`成功删除 ${selectedItems.length} 项数据`);
//
selectedRows.value[countyName] = [];
//
loadChildData(countyName,
childPagination.value[countyName]?.page || 1,
childPagination.value[countyName]?.pageSize || 10);
//
loadParentData();
} else {
ElMessage.error(res.msg || '批量删除失败');
}
} catch (error: any) {
if (error !== 'cancel') { //
console.error('批量删除失败:', error);
ElMessage.error('批量删除失败: ' + (error.message || '未知错误'));
}
} finally {
childLoading.value[countyName] = false;
}
};
//
const handleExport = () => {
const params = {
...queryParams,
type: activeTab.value,
pageNum: page.value,
pageSize: pageSize.value
};
proxy?.download(
'/productManagement/ContractualProductInfo/export',
params,
`合同产品信息.xlsx`
);
//
};
// //
onMounted(() => { onMounted(() => {
loadParentData(); loadParentData();
@ -556,6 +797,12 @@ onMounted(() => {
background-color: #f5f7fa; background-color: #f5f7fa;
padding: 20px; padding: 20px;
border-radius: 4px; border-radius: 4px;
display: flex;
flex-wrap: wrap;
}
.searchbar :deep(.el-form-item) {
margin-right: 10px;
margin-bottom: 10px;
} }
.table-toolbar { .table-toolbar {
margin-bottom: 15px; margin-bottom: 15px;
@ -597,4 +844,90 @@ onMounted(() => {
.filter-tabs { .filter-tabs {
margin-bottom: 20px; margin-bottom: 20px;
} }
.pdf-drawer-container {
display: flex;
flex-direction: column;
height: 100%;
}
.pdf-header {
padding: 16px;
background-color: #f8f9fa;
border-bottom: 1px solid #ebeef5;
}
.pdf-file-info h3 {
margin: 0 0 8px 0;
font-size: 18px;
color: #303133;
}
.pdf-file-info p {
margin: 0;
color: #606266;
}
.pdf-container {
flex: 1;
height: calc(100% - 70px);
display: flex;
justify-content: center;
align-items: center;
background-color: #f0f2f5;
padding: 16px;
overflow: auto;
}
.pdf-embed {
width: 100%;
height: 100%;
border: none;
background: white;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.pdf-empty {
text-align: center;
color: #909399;
padding: 24px;
background: white;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.clickable-filename {
color: #409eff;
text-decoration: none;
font-weight: 500;
}
.clickable-filename:hover {
text-decoration: underline;
opacity: 0.8;
}
.child-table-toolbar {
margin: 10px 0;
padding: 8px;
background-color: #f8f9fa;
border-radius: 4px;
display: flex;
align-items: center;
}
.selected-count {
margin-left: 10px;
color: #606266;
font-size: 14px;
}
/* 防止标签文字换行 */
.searchbar :deep(.el-form-item__label) {
white-space: nowrap;
}
.no-wrap-label {
min-width: 200px;
}
</style> </style>

Loading…
Cancel
Save