| | |
| | | @change="handleFilterChange" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="报表类型"> |
| | | <el-select v-model="filterForm.reportType" placeholder="请选择报表类型" @change="handleFilterChange" style="width: 300px"> |
| | | <el-option label="样品进度报表" value="sample" /> |
| | | <el-option label="设备使用报表" value="equipment" /> |
| | | <el-option label="检测项目报表" value="inspection" /> |
| | | <el-option label="领用记录报表" value="usage" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleFilterChange">查询</el-button> |
| | | <el-button @click="resetFilter">重置</el-button> |
| | | <el-button type="success" @click="exportReport">导出报表</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </el-card> |
| | | |
| | | |
| | | <!-- 统计卡片 --> |
| | | <div class="statistics-cards"> |
| | | <el-row :gutter="20"> |
| | |
| | | </div> |
| | | <div class="stat-info"> |
| | | <div class="stat-number">{{ statistics.totalSamples }}</div> |
| | | <div class="stat-label">总样品数</div> |
| | | <div class="stat-label">总订单数</div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | |
| | | </div> |
| | | <div class="stat-info"> |
| | | <div class="stat-number">{{ statistics.activeEquipment }}</div> |
| | | <div class="stat-label">在用设备</div> |
| | | <div class="stat-label">待生产数量</div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | |
| | | </div> |
| | | <div class="stat-info"> |
| | | <div class="stat-number">{{ statistics.completedInspections }}</div> |
| | | <div class="stat-label">已完成检测</div> |
| | | <div class="stat-label">已生产数量</div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | |
| | | </div> |
| | | <div class="stat-info"> |
| | | <div class="stat-number">{{ statistics.totalUsage }}</div> |
| | | <div class="stat-label">总领用次数</div> |
| | | <div class="stat-label">总核算工时</div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | |
| | | |
| | | <!-- 图表区域 --> |
| | | <div class="charts-container"> |
| | | <el-row :gutter="20"> |
| | |
| | | <el-card class="chart-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>样品进度统计</span> |
| | | <el-button link @click="refreshSampleChart">刷新</el-button> |
| | | <span>生产报工统计</span> |
| | | </div> |
| | | </template> |
| | | <div ref="sampleChartRef" class="chart-container"></div> |
| | | </el-card> |
| | | </el-col> |
| | | |
| | | |
| | | <!-- 设备使用图表 --> |
| | | <el-col :span="12"> |
| | | <el-card class="chart-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>设备使用率统计</span> |
| | | <el-button link @click="refreshEquipmentChart">刷新</el-button> |
| | | <span>生产核算统计</span> |
| | | </div> |
| | | </template> |
| | | <div ref="equipmentChartRef" class="chart-container"></div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="20" style="margin-top: 20px;"> |
| | | <!-- 检测项目统计 --> |
| | | <el-col :span="12"> |
| | | <el-card class="chart-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>检测项目分布</span> |
| | | <el-button link @click="refreshInspectionChart">刷新</el-button> |
| | | </div> |
| | | </template> |
| | | <div ref="inspectionChartRef" class="chart-container"></div> |
| | | </el-card> |
| | | </el-col> |
| | | |
| | | <!-- 领用记录趋势 --> |
| | | <el-col :span="12"> |
| | | <el-card class="chart-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>领用记录趋势</span> |
| | | <el-button link @click="refreshUsageChart">刷新</el-button> |
| | | </div> |
| | | </template> |
| | | <div ref="usageChartRef" class="chart-container"></div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | |
| | | |
| | | <!-- 详细数据表格 --> |
| | | <el-card class="table-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>详细数据</span> |
| | | <span>生产报工详情</span> |
| | | <div> |
| | | <el-button type="primary" size="small" @click="refreshTable">刷新</el-button> |
| | | <el-button type="success" size="small" @click="exportTable">导出</el-button> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | |
| | | <el-table |
| | | :data="tableData" |
| | | style="width: 100%" |
| | |
| | | border |
| | | > |
| | | <el-table-column prop="id" label="编号" width="80" /> |
| | | <el-table-column prop="name" label="名称" /> |
| | | <el-table-column prop="orderNo" label="生产订单号" /> |
| | | <el-table-column prop="productCategory" label="产品大类" /> |
| | | <el-table-column prop="specificationModel" label="规格型号" /> |
| | | <el-table-column prop="unit" label="单位" /> |
| | | <el-table-column prop="schedulingUserName" label="排产人" /> |
| | | <el-table-column prop="schedulingDate" label="排产日期" /> |
| | | <el-table-column prop="process" label="工序" /> |
| | | <el-table-column prop="schedulingNum" label="排产数量" /> |
| | | <el-table-column prop="finishedNum" label="生产数量" /> |
| | | <el-table-column prop="pendingFinishNum" label="待生产数量" > |
| | | <template #default="scope"> |
| | | <span>{{ scope.row.schedulingNum - scope.row.finishedNum }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="status" label="状态"> |
| | | <template #default="scope"> |
| | | <el-tag :type="getStatusType(scope.row.status)"> |
| | | {{ scope.row.status }} |
| | | <el-tag :type="getStatusType(scope.row.status).type"> |
| | | {{ getStatusType(scope.row.status).label }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="progress" label="进度"> |
| | | <template #default="scope"> |
| | | <el-progress :percentage="scope.row.progress" :status="getProgressStatus(scope.row.progress)" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="createTime" label="创建时间" width="180" /> |
| | | <el-table-column prop="updateTime" label="更新时间" width="180" /> |
| | | <el-table-column label="操作" width="150" fixed="right"> |
| | | <template #default="scope"> |
| | | <el-button link size="small" @click="viewDetail(scope.row)">查看</el-button> |
| | | <el-button link size="small" @click="editItem(scope.row)">编辑</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <div class="pagination-container"> |
| | | <el-pagination |
| | | v-model:current-page="pagination.currentPage" |
| | | v-model:page-size="pagination.pageSize" |
| | | :page-sizes="[10, 20, 50, 100]" |
| | | :total="pagination.total" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | /> |
| | | </div> |
| | | </el-card> |
| | | </div> |
| | | </template> |
| | |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import * as echarts from 'echarts' |
| | | import { Box, Tools, Document, ShoppingCart } from '@element-plus/icons-vue' |
| | | import {reportAnalysis} from '@/api/productionManagement/productionOrder' |
| | | |
| | | // 响应式数据 |
| | | const filterForm = reactive({ |
| | |
| | | }) |
| | | |
| | | const statistics = reactive({ |
| | | totalSamples: 1250, |
| | | activeEquipment: 45, |
| | | completedInspections: 890, |
| | | totalUsage: 2340 |
| | | totalSamples: 0, |
| | | activeEquipment: 0, |
| | | completedInspections: 0, |
| | | totalUsage: 0 |
| | | }) |
| | | |
| | | const tableData = ref([]) |
| | | const tableLoading = ref(false) |
| | | const pagination = reactive({ |
| | | currentPage: 1, |
| | | pageSize: 20, |
| | | total: 0 |
| | | }) |
| | | |
| | | // 图表引用 |
| | | const sampleChartRef = ref(null) |
| | | const equipmentChartRef = ref(null) |
| | | const inspectionChartRef = ref(null) |
| | | const usageChartRef = ref(null) |
| | | |
| | | // 图表实例 |
| | | let sampleChart = null |
| | |
| | | |
| | | // 初始化数据 |
| | | const initData = () => { |
| | | // 模拟表格数据 |
| | | tableData.value = [ |
| | | { |
| | | id: 'SP001', |
| | | name: '样品A-001', |
| | | type: '金属材料', |
| | | status: '检测中', |
| | | progress: 75, |
| | | createTime: '2025-01-15 09:30:00', |
| | | updateTime: '2025-01-20 14:20:00' |
| | | }, |
| | | { |
| | | id: 'SP002', |
| | | name: '样品B-002', |
| | | type: '塑料制品', |
| | | status: '已完成', |
| | | progress: 100, |
| | | createTime: '2025-01-10 10:15:00', |
| | | updateTime: '2025-01-18 16:45:00' |
| | | }, |
| | | { |
| | | id: 'SP003', |
| | | name: '样品C-003', |
| | | type: '电子元件', |
| | | status: '待检测', |
| | | progress: 0, |
| | | createTime: '2025-01-22 08:45:00', |
| | | updateTime: '2025-01-22 08:45:00' |
| | | }, |
| | | { |
| | | id: 'EQ001', |
| | | name: '检测设备A', |
| | | type: '光谱仪', |
| | | status: '使用中', |
| | | progress: 60, |
| | | createTime: '2025-01-05 14:20:00', |
| | | updateTime: '2025-01-20 11:30:00' |
| | | }, |
| | | { |
| | | id: 'EQ002', |
| | | name: '检测设备B', |
| | | type: '显微镜', |
| | | status: '空闲', |
| | | progress: 0, |
| | | createTime: '2025-01-08 16:10:00', |
| | | updateTime: '2025-01-19 09:15:00' |
| | | } |
| | | ] |
| | | |
| | | pagination.total = tableData.value.length |
| | | let startDate=null,endDate=null; |
| | | if(filterForm.dateRange && filterForm.dateRange.length===2){ |
| | | startDate = filterForm.dateRange[0]; |
| | | endDate = filterForm.dateRange[1]; |
| | | } |
| | | reportAnalysis({startDate:startDate,endDate:endDate}).then(res=>{ |
| | | statistics.totalSamples = res.data.totalData.totalOrderNum |
| | | statistics.activeEquipment = res.data.totalData.tobeProduced |
| | | statistics.completedInspections = res.data.totalData.finishProduced |
| | | statistics.totalUsage = res.data.totalData.totalWorkhours |
| | | // 初始化图表 |
| | | let chartData = res.data.productData?res.data.productData:{ |
| | | finishProduced:0, |
| | | inProduced:0, |
| | | tobeProduced:0 |
| | | }; |
| | | initSampleChart([ |
| | | { value: chartData.finishProduced, name: '已完成' }, |
| | | { value: chartData.inProduced, name: '生产中' }, |
| | | { value: chartData.tobeProduced, name: '待报工' }, |
| | | ]) |
| | | initEquipmentChart(res.data.workHours) |
| | | tableData.value = res.data.productDetails |
| | | }) |
| | | } |
| | | |
| | | // 初始化样品进度图表 |
| | | const initSampleChart = () => { |
| | | const initSampleChart = (charData) => { |
| | | if (sampleChartRef.value) { |
| | | sampleChart = echarts.init(sampleChartRef.value) |
| | | const option = { |
| | |
| | | labelLine: { |
| | | show: false |
| | | }, |
| | | data: [ |
| | | { value: 450, name: '已完成' }, |
| | | { value: 320, name: '检测中' }, |
| | | { value: 280, name: '待检测' }, |
| | | { value: 200, name: '已暂停' } |
| | | ] |
| | | data: charData |
| | | } |
| | | ] |
| | | } |
| | |
| | | } |
| | | |
| | | // 初始化设备使用图表 |
| | | const initEquipmentChart = () => { |
| | | const initEquipmentChart = (chartData) => { |
| | | if (equipmentChartRef.value) { |
| | | let processData = []; |
| | | let workHoursData = []; |
| | | if(chartData){ |
| | | chartData.forEach(item=>{ |
| | | processData.push(item.process); |
| | | workHoursData.push(item.workHours); |
| | | }) |
| | | } |
| | | equipmentChart = echarts.init(equipmentChartRef.value) |
| | | const option = { |
| | | title: { |
| | |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: ['光谱仪', '显微镜', '硬度计', '拉力机', '冲击机', '金相仪'] |
| | | data: processData, |
| | | name: '工序' |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | | name: '使用率(%)' |
| | | name: '核算工时' |
| | | }, |
| | | series: [ |
| | | { |
| | | name: '使用率', |
| | | name: '核算工时', |
| | | type: 'bar', |
| | | data: [85, 60, 75, 90, 45, 70], |
| | | data: workHoursData, |
| | | itemStyle: { |
| | | color: function(params) { |
| | | const colors = ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C', '#909399', '#9C27B0'] |
| | | return colors[params.dataIndex] |
| | | } |
| | | // color: function(params) { |
| | | // const colors = ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C', '#909399', '#9C27B0'] |
| | | // return colors[params.dataIndex] |
| | | // } |
| | | } |
| | | } |
| | | ] |
| | |
| | | } |
| | | } |
| | | |
| | | // 初始化检测项目图表 |
| | | const initInspectionChart = () => { |
| | | if (inspectionChartRef.value) { |
| | | inspectionChart = echarts.init(inspectionChartRef.value) |
| | | const option = { |
| | | title: { |
| | | show: false |
| | | }, |
| | | tooltip: { |
| | | trigger: 'item' |
| | | }, |
| | | legend: { |
| | | orient: 'vertical', |
| | | left: 'left' |
| | | }, |
| | | series: [ |
| | | { |
| | | name: '检测项目', |
| | | type: 'pie', |
| | | radius: '50%', |
| | | data: [ |
| | | { value: 335, name: '物理性能' }, |
| | | { value: 310, name: '化学分析' }, |
| | | { value: 234, name: '尺寸测量' }, |
| | | { value: 135, name: '外观检查' }, |
| | | { value: 148, name: '其他检测' } |
| | | ], |
| | | emphasis: { |
| | | itemStyle: { |
| | | shadowBlur: 10, |
| | | shadowOffsetX: 0, |
| | | shadowColor: 'rgba(0, 0, 0, 0.5)' |
| | | } |
| | | } |
| | | } |
| | | ] |
| | | } |
| | | inspectionChart.setOption(option) |
| | | } |
| | | } |
| | | |
| | | // 初始化领用记录图表 |
| | | const initUsageChart = () => { |
| | | if (usageChartRef.value) { |
| | | usageChart = echarts.init(usageChartRef.value) |
| | | const option = { |
| | | title: { |
| | | show: false |
| | | }, |
| | | tooltip: { |
| | | trigger: 'axis' |
| | | }, |
| | | legend: { |
| | | data: ['领用次数', '归还次数'] |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | boundaryGap: false, |
| | | data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'] |
| | | }, |
| | | yAxis: { |
| | | type: 'value' |
| | | }, |
| | | series: [ |
| | | { |
| | | name: '领用次数', |
| | | type: 'line', |
| | | stack: 'Total', |
| | | data: [120, 132, 101, 134, 90, 230, 210, 182, 191, 234, 290, 330] |
| | | }, |
| | | { |
| | | name: '归还次数', |
| | | type: 'line', |
| | | stack: 'Total', |
| | | data: [110, 125, 95, 128, 85, 220, 200, 175, 185, 225, 280, 320] |
| | | } |
| | | ] |
| | | } |
| | | usageChart.setOption(option) |
| | | } |
| | | } |
| | | |
| | | // 事件处理函数 |
| | | const handleFilterChange = () => { |
| | | ElMessage.success('筛选条件已更新') |
| | | // 这里可以根据筛选条件重新加载数据 |
| | | initData() |
| | | } |
| | | |
| | | const resetFilter = () => { |
| | |
| | | ElMessage.info('筛选条件已重置') |
| | | } |
| | | |
| | | const exportReport = () => { |
| | | ElMessage.success('报表导出功能开发中...') |
| | | } |
| | | |
| | | const refreshSampleChart = () => { |
| | | initSampleChart() |
| | | ElMessage.success('样品进度图表已刷新') |
| | | } |
| | | |
| | | const refreshEquipmentChart = () => { |
| | | initEquipmentChart() |
| | | ElMessage.success('设备使用图表已刷新') |
| | | } |
| | | |
| | | const refreshInspectionChart = () => { |
| | | initInspectionChart() |
| | | ElMessage.success('检测项目图表已刷新') |
| | | } |
| | | |
| | | const refreshUsageChart = () => { |
| | | initUsageChart() |
| | | ElMessage.success('领用记录图表已刷新') |
| | | } |
| | | |
| | | const refreshTable = () => { |
| | | tableLoading.value = true |
| | | setTimeout(() => { |
| | | tableLoading.value = false |
| | | ElMessage.success('表格数据已刷新') |
| | | }, 1000) |
| | | } |
| | | |
| | | const exportTable = () => { |
| | | ElMessage.success('表格导出功能开发中...') |
| | | } |
| | | |
| | | const handleSizeChange = (val) => { |
| | | pagination.pageSize = val |
| | | // 重新加载数据 |
| | | } |
| | | |
| | | const handleCurrentChange = (val) => { |
| | | pagination.currentPage = val |
| | | // 重新加载数据 |
| | | } |
| | | |
| | | const getStatusType = (status) => { |
| | | const statusMap = { |
| | | '已完成': 'success', |
| | | '检测中': 'warning', |
| | | '待检测': 'info', |
| | | '已暂停': 'danger', |
| | | '使用中': 'primary', |
| | | '空闲': 'info' |
| | | '3': {type:'success',label:'已完成'}, |
| | | '2': {type:'warning',label:'生产中'}, |
| | | '1': {type:'info',label:'待生产'} |
| | | } |
| | | return statusMap[status] || 'info' |
| | | return statusMap[status] || {type:'info',label:'未知状态'} |
| | | } |
| | | |
| | | const getProgressStatus = (progress) => { |
| | |
| | | return 'exception' |
| | | } |
| | | |
| | | const viewDetail = (row) => { |
| | | ElMessage.info(`查看详情: ${row.name}`) |
| | | } |
| | | |
| | | const editItem = (row) => { |
| | | ElMessage.info(`编辑项目: ${row.name}`) |
| | | } |
| | | |
| | | // 生命周期 |
| | | onMounted(() => { |
| | | initData() |
| | | nextTick(() => { |
| | | initSampleChart() |
| | | initEquipmentChart() |
| | | initInspectionChart() |
| | | initUsageChart() |
| | | }) |
| | | |
| | | // 监听窗口大小变化,重新调整图表大小 |
| | | window.addEventListener('resize', () => { |
| | | sampleChart?.resize() |
| | |
| | | padding: 20px; |
| | | background-color: #f5f5f5; |
| | | min-height: 100vh; |
| | | } |
| | | |
| | | .page-header { |
| | | margin-bottom: 20px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .page-header h2 { |
| | |
| | | |
| | | .table-card { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .pagination-container { |
| | | margin-top: 20px; |
| | | text-align: right; |
| | | } |
| | | |
| | | :deep(.el-card__header) { |