| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <!-- 报表选择器 --> |
| | | <el-card class="report-selector" shadow="never"> |
| | | <el-tabs v-model="activeReport" @tab-change="handleReportChange"> |
| | | <el-tab-pane label="采购订单执行汇总表" name="orderSummary"> |
| | | <template #label> |
| | | <span class="tab-label"> |
| | | <el-icon><Document /></el-icon> |
| | | 采购订单执行汇总表 |
| | | </span> |
| | | </template> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="采购订单执行明细表" name="orderDetail"> |
| | | <template #label> |
| | | <span class="tab-label"> |
| | | <el-icon><List /></el-icon> |
| | | 采购订单执行明细表 |
| | | </span> |
| | | </template> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="采购业务汇总表" name="businessSummary"> |
| | | <template #label> |
| | | <span class="tab-label"> |
| | | <el-icon><TrendCharts /></el-icon> |
| | | 采购业务汇总表 |
| | | </span> |
| | | </template> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="供应商供货汇总表" name="supplierSummary"> |
| | | <template #label> |
| | | <span class="tab-label"> |
| | | <el-icon><Shop /></el-icon> |
| | | 供应商供货汇总表 |
| | | </span> |
| | | </template> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | </el-card> |
| | | |
| | | <!-- 查询条件 --> |
| | | <el-card class="search-card" shadow="never"> |
| | | <el-form :model="searchForm" :inline="true" class="search-form"> |
| | | <el-form :model="searchForm" :inline="true" class="search-form"> |
| | | <el-form-item label="时间范围:"> |
| | | <el-date-picker |
| | | v-model="searchForm.dateRange" |
| | |
| | | style="width: 240px" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="供应商:" v-if="activeReport === 'supplierSummary'"> |
| | | <el-select v-model="searchForm.supplierId" placeholder="请选择供应商" clearable style="width: 200px"> |
| | | <el-option |
| | | v-for="supplier in supplierList" |
| | | :key="supplier.id" |
| | | :label="supplier.name" |
| | | :value="supplier.id" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="商品类别:" v-if="activeReport === 'businessSummary'"> |
| | | <el-select v-model="searchForm.categoryId" placeholder="请选择商品类别" clearable style="width: 200px"> |
| | | <el-option |
| | | v-for="category in categoryList" |
| | | :key="category.id" |
| | | :label="category.name" |
| | | :value="category.id" |
| | | /> |
| | | </el-select> |
| | | <el-form-item label="产品大类:"> |
| | | <el-tree-select |
| | | v-model="searchForm.productCategory" |
| | | placeholder="请选择商品类别" |
| | | clearable |
| | | check-strictly |
| | | :data="productOptions" |
| | | :render-after-expand="false" |
| | | style="width: 200px" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleSearch" :loading="loading"> |
| | | <el-icon><Search /></el-icon> |
| | | 查询 |
| | | </el-button> |
| | | <el-button @click="resetSearch"> |
| | | <el-icon><Refresh /></el-icon> |
| | | 重置 |
| | | </el-button> |
| | | <el-button type="success" @click="exportReport"> |
| | | <el-button type="info" @click="exportReport"> |
| | | <el-icon><Download /></el-icon> |
| | | 导出 |
| | | </el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </el-card> |
| | | |
| | | <!-- 报表内容 --> |
| | | <el-card class="report-content" shadow="never"> |
| | | <!-- 采购订单执行汇总表 --> |
| | | <div v-if="activeReport === 'orderSummary'" class="report-section"> |
| | | <div class="section-header"> |
| | | <h3>采购订单执行汇总表</h3> |
| | | <div class="summary-stats"> |
| | | <div class="stat-item"> |
| | | <span class="stat-label">总订单数:</span> |
| | | <span class="stat-value">{{ orderSummaryStats.totalOrders }}</span> |
| | | </div> |
| | | <div class="stat-item"> |
| | | <span class="stat-label">总金额:</span> |
| | | <span class="stat-value">¥{{ orderSummaryStats.totalAmount.toLocaleString() }}</span> |
| | | </div> |
| | | <div class="stat-item"> |
| | | <span class="stat-label">完成率:</span> |
| | | <span class="stat-value">{{ orderSummaryStats.completionRate }}%</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <el-table :data="orderSummaryData" border v-loading="loading" stripe> |
| | | <el-table-column label="订单编号" prop="orderNo" width="180" fixed="left" /> |
| | | <el-table-column label="供应商名称" prop="supplierName" width="150" /> |
| | | <el-table-column label="订单日期" prop="orderDate" width="120" /> |
| | | <el-table-column label="计划交期" prop="plannedDelivery" width="120" /> |
| | | <el-table-column label="实际交期" prop="actualDelivery" width="120" /> |
| | | <el-table-column label="订单金额" prop="orderAmount" width="120"> |
| | | <template #default="{ row }">¥{{ row.orderAmount.toLocaleString() }}</template> |
| | | </el-table-column> |
| | | <el-table-column label="已付金额" prop="paidAmount" width="120"> |
| | | <template #default="{ row }">¥{{ row.paidAmount.toLocaleString() }}</template> |
| | | </el-table-column> |
| | | <el-table-column label="完成状态" prop="status" width="100"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="getStatusType(row.status)">{{ getStatusText(row.status) }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="完成率" prop="completionRate" width="100"> |
| | | <template #default="{ row }">{{ row.completionRate }}%</template> |
| | | </el-table-column> |
| | | <el-table-column label="延迟天数" prop="delayDays" width="100"> |
| | | <template #default="{ row }"> |
| | | <span :class="{ 'delay-text': row.delayDays > 0 }">{{ row.delayDays }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <!-- 采购订单执行明细表 --> |
| | | <div v-if="activeReport === 'orderDetail'" class="report-section"> |
| | | <div class="section-header"> |
| | | <h3>采购订单执行明细表</h3> |
| | | <div class="summary-stats"> |
| | | <div class="stat-item"> |
| | | <span class="stat-label">明细条数:</span> |
| | | <span class="stat-value">{{ orderDetailStats.totalItems }}</span> |
| | | </div> |
| | | <div class="stat-item"> |
| | | <span class="stat-label">已收货:</span> |
| | | <span class="stat-value">{{ orderDetailStats.receivedItems }}</span> |
| | | </div> |
| | | <div class="stat-item"> |
| | | <span class="stat-label">待收货:</span> |
| | | <span class="stat-value">{{ orderDetailStats.pendingItems }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <el-table :data="orderDetailData" border v-loading="loading" stripe> |
| | | <el-table-column label="订单编号" prop="orderNo" width="150" fixed="left" /> |
| | | <el-table-column label="商品编码" prop="productCode" width="120" /> |
| | | <el-table-column label="商品名称" prop="productName" width="200" /> |
| | | <el-table-column label="规格型号" prop="specification" width="150" /> |
| | | <el-table-column label="单位" prop="unit" width="80" /> |
| | | <el-table-column label="计划数量" prop="plannedQuantity" width="100" /> |
| | | <el-table-column label="已收货数量" prop="receivedQuantity" width="120" /> |
| | | <el-table-column label="待收货数量" prop="pendingQuantity" width="120" /> |
| | | <el-table-column label="单价" prop="unitPrice" width="100"> |
| | | <template #default="{ row }">¥{{ row.unitPrice.toFixed(2) }}</template> |
| | | </el-table-column> |
| | | <el-table-column label="小计" prop="subtotal" width="120"> |
| | | <template #default="{ row }">¥{{ row.subtotal.toLocaleString() }}</template> |
| | | </el-table-column> |
| | | <el-table-column label="收货状态" prop="status" width="100"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="getReceiptStatusType(row.status)">{{ getReceiptStatusText(row.status) }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="最后收货日期" prop="lastReceiptDate" width="120" /> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <!-- 采购业务汇总表 --> |
| | | <div v-if="activeReport === 'businessSummary'" class="report-section"> |
| | | <div class="report-section"> |
| | | <div class="section-header"> |
| | | <h3>采购业务汇总表</h3> |
| | | <div class="summary-stats"> |
| | |
| | | <span class="stat-label">商品种类:</span> |
| | | <span class="stat-value">{{ businessSummaryStats.productTypes }}</span> |
| | | </div> |
| | | <div class="stat-item"> |
| | | <span class="stat-label">供应商数:</span> |
| | | <span class="stat-value">{{ businessSummaryStats.supplierCount }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <el-table :data="businessSummaryData" border v-loading="loading" stripe> |
| | | <el-table-column label="商品类别" prop="category" width="150" fixed="left" /> |
| | | <el-table-column label="商品编码" prop="productCode" width="120" /> |
| | | <el-table-column label="商品名称" prop="productName" width="200" /> |
| | | <el-table-column label="规格型号" prop="specification" width="150" /> |
| | | <el-table-column label="采购数量" prop="purchaseQuantity" width="120" /> |
| | | <el-table-column label="采购金额" prop="purchaseAmount" width="120"> |
| | | <template #default="{ row }">¥{{ row.purchaseAmount.toLocaleString() }}</template> |
| | | </el-table-column> |
| | | <el-table-column label="平均单价" prop="avgPrice" width="100"> |
| | | <template #default="{ row }">¥{{ row.avgPrice.toFixed(2) }}</template> |
| | | </el-table-column> |
| | | <el-table-column label="采购次数" prop="purchaseCount" width="100" /> |
| | | <el-table-column label="主要供应商" prop="mainSupplier" width="150" /> |
| | | <el-table-column label="最后采购日期" prop="lastPurchaseDate" width="120" /> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <!-- 供应商供货汇总表 --> |
| | | <div v-if="activeReport === 'supplierSummary'" class="report-section"> |
| | | <div class="section-header"> |
| | | <h3>供应商供货汇总表</h3> |
| | | <div class="summary-stats"> |
| | | <div class="stat-item"> |
| | | <span class="stat-label">供应商总数:</span> |
| | | <span class="stat-value">{{ supplierSummaryStats.totalSuppliers }}</span> |
| | | </div> |
| | | <div class="stat-item"> |
| | | <span class="stat-label">供货总额:</span> |
| | | <span class="stat-value">¥{{ supplierSummaryStats.totalAmount.toLocaleString() }}</span> |
| | | </div> |
| | | <div class="stat-item"> |
| | | <span class="stat-label">平均评分:</span> |
| | | <span class="stat-value">{{ supplierSummaryStats.avgRating.toFixed(1) }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <el-table :data="supplierSummaryData" border v-loading="loading" stripe> |
| | | <el-table-column label="供应商编码" prop="supplierCode" width="120" fixed="left" /> |
| | | <el-table-column label="供应商名称" prop="supplierName" width="200" /> |
| | | <el-table-column label="联系人" prop="contactPerson" width="120" /> |
| | | <el-table-column label="联系电话" prop="phone" width="130" /> |
| | | <el-table-column label="供货订单数" prop="orderCount" width="120" /> |
| | | <el-table-column label="供货金额" prop="supplyAmount" width="120"> |
| | | <template #default="{ row }">¥{{ row.supplyAmount.toLocaleString() }}</template> |
| | | </el-table-column> |
| | | <el-table-column label="已付金额" prop="paidAmount" width="120"> |
| | | <template #default="{ row }">¥{{ row.paidAmount.toLocaleString() }}</template> |
| | | </el-table-column> |
| | | <el-table-column label="未付金额" prop="unpaidAmount" width="120"> |
| | | <template #default="{ row }">¥{{ row.unpaidAmount.toLocaleString() }}</template> |
| | | </el-table-column> |
| | | <el-table-column label="按时交货率" prop="onTimeRate" width="120"> |
| | | <template #default="{ row }">{{ row.onTimeRate }}%</template> |
| | | </el-table-column> |
| | | <el-table-column label="质量评分" prop="qualityRating" width="100"> |
| | | <template #default="{ row }"> |
| | | <el-rate v-model="row.qualityRating" disabled show-score text-color="#ff9900" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="合作状态" prop="status" width="100"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="getSupplierStatusType(row.status)">{{ getSupplierStatusText(row.status) }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <PIMTable |
| | | :table-data="businessSummaryData" |
| | | :column="tableColumns" |
| | | :table-loading="loading" |
| | | :is-selection="false" |
| | | :border="true" |
| | | :is-show-pagination="true" |
| | | :page="page" |
| | | @pagination="handlePagination" |
| | | /> |
| | | </div> |
| | | </el-card> |
| | | </div> |
| | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from 'vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import { Document, List, TrendCharts, Shop, Search, Refresh, Download } from '@element-plus/icons-vue' |
| | | import { Download } from '@element-plus/icons-vue' |
| | | import PIMTable from '@/components/PIMTable/PIMTable.vue' |
| | | import { procurementBusinessSummaryListPage } from '@/api/procurementManagement/procurementReport' |
| | | import { productTreeList } from '@/api/basicData/product' |
| | | |
| | | // 响应式数据 |
| | | const loading = ref(false) |
| | | const activeReport = ref('orderSummary') |
| | | |
| | | // 搜索表单 |
| | | const searchForm = reactive({ |
| | | dateRange: [], |
| | | supplierId: '', |
| | | categoryId: '' |
| | | productCategory: '' |
| | | }) |
| | | |
| | | // 供应商列表 |
| | | const supplierList = ref([ |
| | | { id: 1, name: '江苏华联电子科技有限公司' }, |
| | | { id: 2, name: '上海精密机械制造有限公司' }, |
| | | { id: 3, name: '深圳智能设备有限公司' }, |
| | | { id: 4, name: '北京新材料科技有限公司' }, |
| | | { id: 5, name: '广州电子元器件有限公司' } |
| | | ]) |
| | | |
| | | // 商品类别列表 |
| | | const categoryList = ref([ |
| | | { id: 1, name: '电子元器件' }, |
| | | { id: 2, name: '机械设备' }, |
| | | { id: 3, name: '原材料' }, |
| | | { id: 4, name: '办公用品' }, |
| | | { id: 5, name: '包装材料' } |
| | | ]) |
| | | // 产品类别树选项 |
| | | const productOptions = ref([]) |
| | | |
| | | // 统计数据 |
| | | const orderSummaryStats = ref({ |
| | | totalOrders: 156, |
| | | totalAmount: 2580000, |
| | | completionRate: 87.5 |
| | | }) |
| | | |
| | | const orderDetailStats = ref({ |
| | | totalItems: 1248, |
| | | receivedItems: 1089, |
| | | pendingItems: 159 |
| | | }) |
| | | |
| | | const businessSummaryStats = ref({ |
| | | totalAmount: 2580000, |
| | | productTypes: 89, |
| | | supplierCount: 25 |
| | | totalAmount: 0, |
| | | productTypes: 0 |
| | | }) |
| | | |
| | | const supplierSummaryStats = ref({ |
| | | totalSuppliers: 25, |
| | | totalAmount: 2580000, |
| | | avgRating: 4.2 |
| | | }) |
| | | |
| | | // 采购订单执行汇总表数据 |
| | | const orderSummaryData = ref([ |
| | | // 表格列配置(根据后端字段定义) |
| | | const tableColumns = ref([ |
| | | { |
| | | orderNo: 'PO20241201001', |
| | | supplierName: '江苏华联电子科技有限公司', |
| | | orderDate: '2024-12-01', |
| | | plannedDelivery: '2024-12-15', |
| | | actualDelivery: '2024-12-14', |
| | | orderAmount: 125000, |
| | | paidAmount: 100000, |
| | | status: 'completed', |
| | | completionRate: 100, |
| | | delayDays: -1 |
| | | label: '产品大类', |
| | | prop: 'productCategory', |
| | | width: 150, |
| | | }, |
| | | { |
| | | orderNo: 'PO20241201002', |
| | | supplierName: '上海精密机械制造有限公司', |
| | | orderDate: '2024-12-02', |
| | | plannedDelivery: '2024-12-20', |
| | | actualDelivery: '2024-12-22', |
| | | orderAmount: 280000, |
| | | paidAmount: 140000, |
| | | status: 'partial', |
| | | completionRate: 75, |
| | | delayDays: 2 |
| | | label: '规格型号', |
| | | prop: 'specificationModel', |
| | | width: 180 |
| | | }, |
| | | { |
| | | orderNo: 'PO20241201003', |
| | | supplierName: '深圳智能设备有限公司', |
| | | orderDate: '2024-12-03', |
| | | plannedDelivery: '2024-12-25', |
| | | actualDelivery: '', |
| | | orderAmount: 180000, |
| | | paidAmount: 0, |
| | | status: 'pending', |
| | | completionRate: 0, |
| | | delayDays: 0 |
| | | label: '采购数量', |
| | | prop: 'purchaseNum', |
| | | width: 120, |
| | | formatData: (val) => { |
| | | return val ? parseFloat(val).toLocaleString() : '0' |
| | | } |
| | | }, |
| | | { |
| | | orderNo: 'PO20241201004', |
| | | supplierName: '北京新材料科技有限公司', |
| | | orderDate: '2024-12-04', |
| | | plannedDelivery: '2024-12-18', |
| | | actualDelivery: '2024-12-18', |
| | | orderAmount: 95000, |
| | | paidAmount: 95000, |
| | | status: 'completed', |
| | | completionRate: 100, |
| | | delayDays: 0 |
| | | label: '采购金额', |
| | | prop: 'purchaseAmount', |
| | | width: 140, |
| | | formatData: (val) => { |
| | | return val ? `¥${parseFloat(val).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : '¥0.00' |
| | | } |
| | | }, |
| | | { |
| | | orderNo: 'PO20241201005', |
| | | supplierName: '广州电子元器件有限公司', |
| | | orderDate: '2024-12-05', |
| | | plannedDelivery: '2024-12-28', |
| | | actualDelivery: '', |
| | | orderAmount: 220000, |
| | | paidAmount: 0, |
| | | status: 'pending', |
| | | completionRate: 0, |
| | | delayDays: 0 |
| | | } |
| | | ]) |
| | | |
| | | // 采购订单执行明细表数据 |
| | | const orderDetailData = ref([ |
| | | { |
| | | orderNo: 'PO20241201001', |
| | | productCode: 'EL001', |
| | | productName: '电阻器 1KΩ ±5%', |
| | | specification: '1/4W 碳膜电阻', |
| | | unit: '个', |
| | | plannedQuantity: 1000, |
| | | receivedQuantity: 1000, |
| | | pendingQuantity: 0, |
| | | unitPrice: 0.15, |
| | | subtotal: 150, |
| | | status: 'completed', |
| | | lastReceiptDate: '2024-12-14' |
| | | label: '采购次数', |
| | | prop: 'purchaseTimes', |
| | | width: 100 |
| | | }, |
| | | { |
| | | orderNo: 'PO20241201001', |
| | | productCode: 'EL002', |
| | | productName: '电容器 100μF', |
| | | specification: '25V 铝电解电容', |
| | | unit: '个', |
| | | plannedQuantity: 500, |
| | | receivedQuantity: 500, |
| | | pendingQuantity: 0, |
| | | unitPrice: 0.85, |
| | | subtotal: 425, |
| | | status: 'completed', |
| | | lastReceiptDate: '2024-12-14' |
| | | label: '平均单价', |
| | | prop: 'averagePrice', |
| | | width: 120, |
| | | formatData: (val) => { |
| | | return val ? `¥${parseFloat(val).toFixed(2)}` : '¥0.00' |
| | | } |
| | | }, |
| | | { |
| | | orderNo: 'PO20241201002', |
| | | productCode: 'ME001', |
| | | productName: '精密轴承', |
| | | specification: '6205-2RS 深沟球轴承', |
| | | unit: '个', |
| | | plannedQuantity: 200, |
| | | receivedQuantity: 150, |
| | | pendingQuantity: 50, |
| | | unitPrice: 25.5, |
| | | subtotal: 5100, |
| | | status: 'partial', |
| | | lastReceiptDate: '2024-12-20' |
| | | label: '供应商名称', |
| | | prop: 'supplierName', |
| | | width: 200 |
| | | }, |
| | | { |
| | | orderNo: 'PO20241201002', |
| | | productCode: 'ME002', |
| | | productName: '不锈钢螺丝', |
| | | specification: 'M8×20 304不锈钢', |
| | | unit: '个', |
| | | plannedQuantity: 1000, |
| | | receivedQuantity: 1000, |
| | | pendingQuantity: 0, |
| | | unitPrice: 0.8, |
| | | subtotal: 800, |
| | | status: 'completed', |
| | | lastReceiptDate: '2024-12-20' |
| | | }, |
| | | { |
| | | orderNo: 'PO20241201003', |
| | | productCode: 'SM001', |
| | | productName: '智能传感器', |
| | | specification: '温度传感器 DS18B20', |
| | | unit: '个', |
| | | plannedQuantity: 300, |
| | | receivedQuantity: 0, |
| | | pendingQuantity: 300, |
| | | unitPrice: 12.5, |
| | | subtotal: 3750, |
| | | status: 'pending', |
| | | lastReceiptDate: '' |
| | | label: '录入日期', |
| | | prop: 'entryDate', |
| | | width: 120 |
| | | } |
| | | ]) |
| | | |
| | | // 采购业务汇总表数据 |
| | | const businessSummaryData = ref([ |
| | | { |
| | | category: '电子元器件', |
| | | productCode: 'EL001', |
| | | productName: '电阻器 1KΩ ±5%', |
| | | specification: '1/4W 碳膜电阻', |
| | | purchaseQuantity: 5000, |
| | | purchaseAmount: 750, |
| | | avgPrice: 0.15, |
| | | purchaseCount: 8, |
| | | mainSupplier: '江苏华联电子科技有限公司', |
| | | lastPurchaseDate: '2024-12-01' |
| | | }, |
| | | { |
| | | category: '电子元器件', |
| | | productCode: 'EL002', |
| | | productName: '电容器 100μF', |
| | | specification: '25V 铝电解电容', |
| | | purchaseQuantity: 2500, |
| | | purchaseAmount: 2125, |
| | | avgPrice: 0.85, |
| | | purchaseCount: 6, |
| | | mainSupplier: '江苏华联电子科技有限公司', |
| | | lastPurchaseDate: '2024-12-01' |
| | | }, |
| | | { |
| | | category: '机械设备', |
| | | productCode: 'ME001', |
| | | productName: '精密轴承', |
| | | specification: '6205-2RS 深沟球轴承', |
| | | purchaseQuantity: 800, |
| | | purchaseAmount: 20400, |
| | | avgPrice: 25.5, |
| | | purchaseCount: 4, |
| | | mainSupplier: '上海精密机械制造有限公司', |
| | | lastPurchaseDate: '2024-12-02' |
| | | }, |
| | | { |
| | | category: '机械设备', |
| | | productCode: 'ME002', |
| | | productName: '不锈钢螺丝', |
| | | specification: 'M8×20 304不锈钢', |
| | | purchaseQuantity: 5000, |
| | | purchaseAmount: 4000, |
| | | avgPrice: 0.8, |
| | | purchaseCount: 12, |
| | | mainSupplier: '上海精密机械制造有限公司', |
| | | lastPurchaseDate: '2024-12-02' |
| | | }, |
| | | { |
| | | category: '智能设备', |
| | | productCode: 'SM001', |
| | | productName: '智能传感器', |
| | | specification: '温度传感器 DS18B20', |
| | | purchaseQuantity: 1200, |
| | | purchaseAmount: 15000, |
| | | avgPrice: 12.5, |
| | | purchaseCount: 5, |
| | | mainSupplier: '深圳智能设备有限公司', |
| | | lastPurchaseDate: '2024-12-03' |
| | | } |
| | | ]) |
| | | const businessSummaryData = ref([]) |
| | | |
| | | // 供应商供货汇总表数据 |
| | | const supplierSummaryData = ref([ |
| | | { |
| | | supplierCode: 'SUP001', |
| | | supplierName: '江苏华联电子科技有限公司', |
| | | contactPerson: '张经理', |
| | | phone: '0512-88888888', |
| | | orderCount: 45, |
| | | supplyAmount: 850000, |
| | | paidAmount: 680000, |
| | | unpaidAmount: 170000, |
| | | onTimeRate: 95, |
| | | qualityRating: 4.5, |
| | | status: 'active' |
| | | }, |
| | | { |
| | | supplierCode: 'SUP002', |
| | | supplierName: '上海精密机械制造有限公司', |
| | | contactPerson: '李总', |
| | | phone: '021-66666666', |
| | | orderCount: 32, |
| | | supplyAmount: 1200000, |
| | | paidAmount: 900000, |
| | | unpaidAmount: 300000, |
| | | onTimeRate: 88, |
| | | qualityRating: 4.2, |
| | | status: 'active' |
| | | }, |
| | | { |
| | | supplierCode: 'SUP003', |
| | | supplierName: '深圳智能设备有限公司', |
| | | contactPerson: '王工程师', |
| | | phone: '0755-77777777', |
| | | orderCount: 28, |
| | | supplyAmount: 680000, |
| | | paidAmount: 400000, |
| | | unpaidAmount: 280000, |
| | | onTimeRate: 92, |
| | | qualityRating: 4.3, |
| | | status: 'active' |
| | | }, |
| | | { |
| | | supplierCode: 'SUP004', |
| | | supplierName: '北京新材料科技有限公司', |
| | | contactPerson: '陈博士', |
| | | phone: '010-55555555', |
| | | orderCount: 18, |
| | | supplyAmount: 320000, |
| | | paidAmount: 250000, |
| | | unpaidAmount: 70000, |
| | | onTimeRate: 85, |
| | | qualityRating: 4.0, |
| | | status: 'active' |
| | | }, |
| | | { |
| | | supplierCode: 'SUP005', |
| | | supplierName: '广州电子元器件有限公司', |
| | | contactPerson: '刘经理', |
| | | phone: '020-44444444', |
| | | orderCount: 22, |
| | | supplyAmount: 480000, |
| | | paidAmount: 200000, |
| | | unpaidAmount: 280000, |
| | | onTimeRate: 78, |
| | | qualityRating: 3.8, |
| | | status: 'warning' |
| | | } |
| | | ]) |
| | | // 分页参数(后端返回:total/size/current/pages) |
| | | const page = reactive({ |
| | | total: 0, |
| | | current: 1, |
| | | size: 50, |
| | | }) |
| | | |
| | | // 方法 |
| | | const handleReportChange = (tabName) => { |
| | | activeReport.value = tabName |
| | | handleSearch() |
| | | // 转换产品树数据,将 id 改为 value |
| | | function convertIdToValue(data) { |
| | | return data.map((item) => { |
| | | const { id, children, ...rest } = item |
| | | const newItem = { |
| | | ...rest, |
| | | value: id, |
| | | } |
| | | if (children && children.length > 0) { |
| | | newItem.children = convertIdToValue(children) |
| | | } |
| | | return newItem |
| | | }) |
| | | } |
| | | |
| | | const handleSearch = () => { |
| | | loading.value = true |
| | | // 模拟API调用 |
| | | setTimeout(() => { |
| | | // 获取产品类别树数据 |
| | | const getProductOptions = () => { |
| | | return productTreeList().then((res) => { |
| | | productOptions.value = convertIdToValue(res) |
| | | }).catch((error) => { |
| | | console.error('获取产品树失败:', error) |
| | | ElMessage.error('获取产品类别失败') |
| | | }) |
| | | } |
| | | |
| | | // 根据 id 查找产品类别名称 |
| | | const findNodeLabelById = (nodes, id) => { |
| | | if (!id) return null |
| | | for (let i = 0; i < nodes.length; i++) { |
| | | if (nodes[i].value === id) { |
| | | return nodes[i].label |
| | | } |
| | | if (nodes[i].children && nodes[i].children.length > 0) { |
| | | const found = findNodeLabelById(nodes[i].children, id) |
| | | if (found) return found |
| | | } |
| | | } |
| | | return null |
| | | } |
| | | |
| | | // 查询列表 |
| | | const handleSearch = async () => { |
| | | try { |
| | | loading.value = true |
| | | const params = {} |
| | | |
| | | // 时间范围 |
| | | if (searchForm.dateRange && searchForm.dateRange.length === 2) { |
| | | params.entryDateStart = searchForm.dateRange[0] |
| | | params.entryDateEnd = searchForm.dateRange[1] |
| | | } |
| | | |
| | | // 产品类别 |
| | | if (searchForm.productCategory) { |
| | | const categoryName = findNodeLabelById(productOptions.value, searchForm.productCategory) |
| | | if (categoryName) { |
| | | params.productCategory = categoryName |
| | | } |
| | | } |
| | | |
| | | // 分页参数 |
| | | params.current = page.current |
| | | params.size = page.size |
| | | |
| | | const res = await procurementBusinessSummaryListPage(params) |
| | | if (res && res.data) { |
| | | // 兼容后端可能直接返回数组/或返回分页对象 |
| | | businessSummaryData.value = Array.isArray(res.data) ? res.data : (res.data.records || []) |
| | | |
| | | if (!Array.isArray(res.data)) { |
| | | page.total = Number(res.data.total ?? 0) |
| | | page.current = Number(res.data.current ?? page.current) |
| | | page.size = Number(res.data.size ?? page.size) |
| | | } |
| | | |
| | | // 计算统计数据 |
| | | if (businessSummaryData.value.length > 0) { |
| | | businessSummaryStats.value.totalAmount = businessSummaryData.value.reduce((sum, item) => { |
| | | return sum + (parseFloat(item.purchaseAmount) || 0) |
| | | }, 0) |
| | | businessSummaryStats.value.productTypes = new Set(businessSummaryData.value.map(item => item.productCategory)).size |
| | | } else { |
| | | businessSummaryStats.value = { |
| | | totalAmount: 0, |
| | | productTypes: 0 |
| | | } |
| | | } |
| | | } |
| | | } catch (error) { |
| | | console.error('查询失败:', error) |
| | | } finally { |
| | | loading.value = false |
| | | ElMessage.success('查询完成') |
| | | }, 1000) |
| | | } |
| | | } |
| | | |
| | | // 翻页/切换每页条数 |
| | | const handlePagination = ({ page: current, limit }) => { |
| | | page.current = current |
| | | page.size = limit |
| | | handleSearch() |
| | | } |
| | | |
| | | const resetSearch = () => { |
| | | Object.assign(searchForm, { |
| | | dateRange: [], |
| | | supplierId: '', |
| | | categoryId: '' |
| | | productCategory: '' |
| | | }) |
| | | page.current = 1 |
| | | handleSearch() |
| | | } |
| | | |
| | |
| | | ElMessage.success('导出功能开发中...') |
| | | } |
| | | |
| | | // 状态相关方法 |
| | | const getStatusType = (status) => { |
| | | const statusMap = { |
| | | completed: 'success', |
| | | partial: 'warning', |
| | | pending: 'info' |
| | | } |
| | | return statusMap[status] || 'info' |
| | | } |
| | | |
| | | const getStatusText = (status) => { |
| | | const statusMap = { |
| | | completed: '已完成', |
| | | partial: '部分完成', |
| | | pending: '待执行' |
| | | } |
| | | return statusMap[status] || '未知' |
| | | } |
| | | |
| | | const getReceiptStatusType = (status) => { |
| | | const statusMap = { |
| | | completed: 'success', |
| | | partial: 'warning', |
| | | pending: 'info' |
| | | } |
| | | return statusMap[status] || 'info' |
| | | } |
| | | |
| | | const getReceiptStatusText = (status) => { |
| | | const statusMap = { |
| | | completed: '已收货', |
| | | partial: '部分收货', |
| | | pending: '待收货' |
| | | } |
| | | return statusMap[status] || '未知' |
| | | } |
| | | |
| | | const getSupplierStatusType = (status) => { |
| | | const statusMap = { |
| | | active: 'success', |
| | | warning: 'warning', |
| | | inactive: 'info' |
| | | } |
| | | return statusMap[status] || 'info' |
| | | } |
| | | |
| | | const getSupplierStatusText = (status) => { |
| | | const statusMap = { |
| | | active: '正常合作', |
| | | warning: '需关注', |
| | | inactive: '暂停合作' |
| | | } |
| | | return statusMap[status] || '未知' |
| | | } |
| | | |
| | | onMounted(() => { |
| | | // 初始化产品类别树 |
| | | getProductOptions() |
| | | |
| | | // 设置默认时间范围为最近30天 |
| | | const endDate = new Date() |
| | | const startDate = new Date() |
| | |
| | | startDate.toISOString().split('T')[0], |
| | | endDate.toISOString().split('T')[0] |
| | | ] |
| | | |
| | | // 初始加载数据 |
| | | handleSearch() |
| | | }) |
| | | </script> |
| | | |
| | |
| | | margin: 0; |
| | | font-size: 16px; |
| | | opacity: 0.9; |
| | | } |
| | | |
| | | .report-selector { |
| | | margin-bottom: 20px; |
| | | border-radius: 8px; |
| | | } |
| | | |
| | | .tab-label { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .search-card { |
| | | margin-bottom: 20px; |
| | | border-radius: 8px; |
| | | } |
| | | |
| | | .search-form { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .report-content { |
| | |
| | | font-weight: 600; |
| | | } |
| | | |
| | | :deep(.el-table) { |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | :deep(.el-table th) { |
| | | background-color: #f8f9fa; |
| | | color: #606266; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | :deep(.el-table--striped .el-table__body tr.el-table__row--striped td) { |
| | | background-color: #fafafa; |
| | | } |
| | | |
| | | :deep(.el-tabs__header) { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | :deep(.el-tabs__nav-wrap) { |
| | | padding: 0 20px; |
| | | } |
| | | |
| | | :deep(.el-tabs__item) { |
| | | font-size: 16px; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | :deep(.el-tabs__item.is-active) { |
| | | color: #409EFF; |
| | | } |
| | | |
| | | :deep(.el-rate) { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | :deep(.el-rate__text) { |
| | | margin-left: 8px; |
| | | font-size: 14px; |
| | | color: #606266; |
| | | } |
| | | </style> |