节拍统计新增

This commit is contained in:
17630416519 2026-01-31 15:54:33 +08:00
parent 425cce7bb7
commit ab5bc86fae
2 changed files with 468 additions and 42 deletions

View File

@ -0,0 +1,429 @@
<template>
<div>
<!-- 查询表单 -->
<el-form :model="queryParams" label-position="right" inline ref="queryRef" v-show="showSearch" @submit.prevent>
<el-form-item label="产品编号" prop="fkWorkorder">
<el-input v-model="queryParams.fkWorkorder" placeholder="请输入产品编号" />
</el-form-item>
<el-form-item label="产品名称" prop="fkWorkorder">
<el-input v-model="queryParams.fkWorkorder" placeholder="请输入产品名称" />
</el-form-item>
<el-form-item label="筛选日期" prop="timeRange">
<el-date-picker v-model="queryParams.timeRange" type="datetimerange" range-separator="To"
start-placeholder="Start date" end-placeholder="End date" @change="onDateRangeChange" />
</el-form-item>
<el-form-item>
<el-button icon="search" type="primary" @click="handleQuery">搜索</el-button>
<el-button icon="refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 工具区域 -->
<el-row :gutter="15" class="mb10">
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
</el-row>
<!-- 数据表格 -->
<el-table :data="dataList" height="300px" v-loading="loading" ref="table" border
header-cell-class-name="el-table-header-cell" highlight-current-row @sort-change="sortChange">
<el-table-column prop="groupCode" label="产品编号" align="center" :show-overflow-tooltip="true" />
<el-table-column prop="lineCode" label="产品名称" align="center" :show-overflow-tooltip="true" />
<el-table-column prop="fkWorkorder" label="生产日期" align="center" :show-overflow-tooltip="true" />
<el-table-column prop="productionCode" label="节拍" align="center" :show-overflow-tooltip="true" />
</el-table>
<pagination :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
@pagination="getList" />
<!-- ECharts 图表容器 -->
<div id="chartContainer" style="width: 100%; height: 42vh; margin-top: 20px;"></div>
</div>
</template>
<script setup name="beatStatistics">
import { listProReportwork } from '@/api/productManagement/proreportwork.js'
import { getCurrentInstance } from 'vue'
import * as echarts from 'echarts'
const { proxy } = getCurrentInstance()
const ids = ref([])
const loading = ref(false)
const showSearch = ref(true)
let myChart = null
//
function getDateTimeRange() {
const now = new Date()
const halfHourLater = new Date(now.getTime() + 30 * 60000) // 30 = 30 * 60 * 1000
return [now, halfHourLater]
}
const queryParams = reactive({
timeRange: getDateTimeRange(),
fkWorkorder: '',
groupCode: '',
lineCode: '',
warehouseconfirmationNum: 0,
unfinishReportwork: 1,
pageNum: 1,
pageSize: 10,
sort: 'groupCode',
sortType: 'asc'
})
const total = ref(8)
const dataList = ref([
{
groupCode: "PRD001",
lineCode: "产品A",
fkWorkorder: "2024-01-15 09:30:00",
productionCode: "45"
},
{
groupCode: "PRD002",
lineCode: "产品B",
fkWorkorder: "2024-01-15 09:45:00",
productionCode: "52"
},
{
groupCode: "PRD003",
lineCode: "产品C",
fkWorkorder: "2024-01-15 10:00:00",
productionCode: "38"
},
{
groupCode: "PRD004",
lineCode: "产品D",
fkWorkorder: "2024-01-15 10:15:00",
productionCode: "61"
},
{
groupCode: "PRD005",
lineCode: "产品E",
fkWorkorder: "2024-01-15 10:30:00",
productionCode: "48"
},
{
groupCode: "PRD006",
lineCode: "产品F",
fkWorkorder: "2024-01-15 10:45:00",
productionCode: "55"
},
{
groupCode: "PRD007",
lineCode: "产品G",
fkWorkorder: "2024-01-15 11:00:00",
productionCode: "41"
},
{
groupCode: "PRD008",
lineCode: "产品H",
fkWorkorder: "2024-01-15 11:15:00",
productionCode: "59"
}
])
const queryRef = ref()
// 20
function generateTimePoints(start, end) {
const startTime = new Date(start)
const endTime = new Date(end)
//
const totalTimeDiff = endTime - startTime
const interval = totalTimeDiff / 19 // 2019
const timePoints = []
for (let i = 0; i < 20; i++) {
const timePoint = new Date(startTime.getTime() + i * interval)
// YYYY-MM-DD HH:mm:ss
timePoints.push(formatDateTime(timePoint))
}
return timePoints
}
//
function formatDateTime(date) {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
const seconds = String(date.getSeconds()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
}
//
function generateRandomData() {
return Array.from({ length: 20 }, () => Math.floor(Math.random() * 100) + 1)
}
//
function onDateRangeChange() {
if (queryParams.timeRange && queryParams.timeRange.length === 2) {
const [start, end] = queryParams.timeRange
const timePoints = generateTimePoints(start, end)
const randomData = generateRandomData()
updateChartData(timePoints, randomData)
}
}
//
function initChart() {
const chartDom = document.getElementById('chartContainer')
if (!chartDom) return
myChart = echarts.init(chartDom)
const [start, end] = queryParams.timeRange
const timePoints = generateTimePoints(start, end)
const randomData = generateRandomData()
const option = {
tooltip: {
trigger: 'axis',
formatter: function (params) {
const param = params[0]
return `${param.axisValue}<br/>${param.seriesName}: ${param.value}`
}
},
title: {
text: '节拍统计趋势图',
left: 'center',
textStyle: {
fontSize: 16,
fontWeight: 'bold'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [{
type: 'category',
data: timePoints,
axisLine: {
lineStyle: {
color: '#999'
}
},
axisLabel: {
interval: 0, //
rotate: 45, //
fontSize: 10
}
}],
yAxis: [{
type: 'value',
splitNumber: 4,
splitLine: {
lineStyle: {
type: 'dashed',
color: '#DDD'
}
},
axisLine: {
show: false,
lineStyle: {
color: '#333'
},
},
nameTextStyle: {
color: '#999'
},
splitArea: {
show: false
}
}],
series: [{
name: '节拍统计',
type: 'line',
data: randomData,
lineStyle: {
normal: {
width: 8,
color: {
type: 'linear',
colorStops: [{
offset: 0,
color: '#A9F387' // 0%
}, {
offset: 1,
color: '#48D8BF' // 100%
}],
globalCoord: false // false
},
shadowColor: 'rgba(72,216,191, 0.3)',
shadowBlur: 10,
shadowOffsetY: 20
}
},
itemStyle: {
normal: {
color: '#fff',
borderWidth: 10,
borderColor: '#A9F387'
}
},
smooth: true
}]
}
myChart.setOption(option)
// tooltip
setTimeout(() => {
if (myChart) {
myChart.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: 1
})
}
}, 0)
window.addEventListener('resize', function () {
if (myChart) {
myChart.resize()
}
})
myChart.getZr().on('globalout', function () {
setTimeout(() => {
if (myChart) {
myChart.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: 1,
})
}
}, 0)
})
}
//
function updateChartData(xData, yData) {
if (myChart) {
myChart.setOption({
xAxis: [{
data: xData
}],
series: [{
data: yData
}]
})
}
}
//
function getList() {
loading.value = true
listProReportwork(queryParams).then((res) => {
const { code, data } = res
if (code == 200) {
dataList.value = data.result
total.value = data.totalNum
loading.value = false
//
if (data.result && data.result.length > 0) {
//
const xData = data.result.map(item => item.groupCode || item.lineCode)
const yData = data.result.map(item => parseInt(item.productionCode) || 0)
// 20
if (xData.length > 20) {
xData.splice(20)
yData.splice(20)
}
//
if (xData.length < 20) {
const [start, end] = queryParams.timeRange
const timePoints = generateTimePoints(start, end)
const randomData = generateRandomData()
updateChartData(timePoints, randomData)
} else {
updateChartData(xData, yData)
}
}
}
}).catch(error => {
console.error('获取数据失败:', error)
loading.value = false
// 使
const [start, end] = queryParams.timeRange
const timePoints = generateTimePoints(start, end)
const randomData = generateRandomData()
updateChartData(timePoints, randomData)
})
}
//
function handleQuery() {
queryParams.pageNum = 1
getList()
}
//
function resetQuery() {
proxy.resetForm('queryRef')
handleQuery()
}
//
function sortChange(column) {
var sort = undefined
var sortType = undefined
if (column.prop != null && column.order != null) {
sort = column.prop
sortType = column.order
}
queryParams.sort = sort
queryParams.sortType = sortType
handleQuery()
}
// =========== 线 ==========
import { GetAllRoute } from '@/api/productManagement/proworkorder.js'
const allRouteOptions = ref([])
function getAllRouteOptions() {
GetAllRoute().then((res) => {
if (res.code === 200) {
allRouteOptions.value = res.data.map((item) => {
return {
id: item.id,
label: `${item.code}-${item.name}`,
value: `${item.code}`
}
})
}
})
}
//
onMounted(() => {
initChart()
// handleQuery()
getAllRouteOptions()
})
//
onUnmounted(() => {
if (myChart) {
myChart.dispose()
}
})
</script>
<style scoped>
.mb10 {
margin-bottom: 10px;
}
</style>

View File

@ -1,20 +1,20 @@
<template> <template>
<div> <div>
<el-form :model="queryParams" label-position="right" inline ref="queryRef" v-show="showSearch" @submit.prevent> <el-form :model="queryParams" label-position="right" inline ref="queryRef" v-show="showSearch" @submit.prevent>
<el-form-item label="工单号" prop="workorder"> <el-form-item label="产线" prop="workorder">
<el-input v-model.trim="queryParams.workorder" clearable placeholder="请输入工单号" /> <el-input v-model.trim="queryParams.workorder" clearable placeholder="请输入产线" />
</el-form-item> </el-form-item>
<el-form-item label="产品名称" prop="productionName"> <el-form-item label="产品型号" prop="productionName">
<el-input v-model.trim="queryParams.productionName" clearable placeholder="请输入产品名称" /> <el-input v-model.trim="queryParams.productionName" clearable placeholder="请输入产品型号" />
</el-form-item> </el-form-item>
<el-form-item label="产品编码" prop="productionCode"> <!-- <el-form-item label="产品编码" prop="productionCode">
<el-input v-model.trim="queryParams.productionCode" clearable placeholder="请输入产品编码" /> <el-input v-model.trim="queryParams.productionCode" clearable placeholder="请输入产品编码" />
</el-form-item> </el-form-item> -->
<el-form-item label="工单日期" prop="workorderDate"> <el-form-item label="生产日期" prop="workorderDate">
<el-date-picker v-model="queryParams.workorderDate" type="daterange" range-separator="" <el-date-picker v-model="queryParams.workorderDate" type="daterange" range-separator=""
start-placeholder="开始时间" end-placeholder="结束时间" placeholder="请选择工单日期区间" /> start-placeholder="开始时间" end-placeholder="结束时间" placeholder="请选择生产日期区间" />
</el-form-item> </el-form-item>
<el-form-item label="工单状态" prop="status"> <!-- <el-form-item label="工单状态" prop="status">
<el-radio-group v-model="queryParams.status" @change="handleQuery"> <el-radio-group v-model="queryParams.status" @change="handleQuery">
<el-radio-button :value="-1"> 全部 </el-radio-button> <el-radio-button :value="-1"> 全部 </el-radio-button>
<el-radio-button v-for="item in options.statusOptions" :key="item.dictValue" <el-radio-button v-for="item in options.statusOptions" :key="item.dictValue"
@ -22,7 +22,7 @@
{{ item.dictLabel }} {{ item.dictLabel }}
</el-radio-button> </el-radio-button>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item> -->
<el-form-item> <el-form-item>
<el-button icon="search" type="primary" @click="handleQuery">{{ $t('btn.search') }}</el-button> <el-button icon="search" type="primary" @click="handleQuery">{{ $t('btn.search') }}</el-button>
<el-button icon="refresh" @click="resetQuery">{{ $t('btn.reset') }}</el-button> <el-button icon="refresh" @click="resetQuery">{{ $t('btn.reset') }}</el-button>
@ -30,35 +30,31 @@
</el-form> </el-form>
<el-table :data="dataList" v-loading="loading" ref="table" border header-row-class-name="table-header" <el-table :data="dataList" v-loading="loading" ref="table" border header-row-class-name="table-header"
:cell-class-name="tableCellClassName" @sort-change="sortChange"> :cell-class-name="tableCellClassName" @sort-change="sortChange">
<el-table-column type="index" width="50" align="center" /> <el-table-column type="index" width="70" align="center" />
<el-table-column prop="workorder" label="工单号" width="120" align="center" :show-overflow-tooltip="false" <el-table-column prop="workorder" label="产品型号" width="120" align="center" :show-overflow-tooltip="false"
v-if="columns.showColumn('workorder')"> </el-table-column> v-if="columns.showColumn('workorder')"> </el-table-column>
<el-table-column prop="productionCode" label="产品编号" width="100" align="center" <el-table-column prop="productionCode" label="产线状态" align="center" :show-overflow-tooltip="false"
:show-overflow-tooltip="false" v-if="columns.showColumn('productionCode')" /> v-if="columns.showColumn('productionCode')" />
<el-table-column prop="productionName" label="产品描述" width="140" align="center" <el-table-column prop="productionName" label="目标数量" align="center" :show-overflow-tooltip="false"
:show-overflow-tooltip="false" v-if="columns.showColumn('productionName')" /> v-if="columns.showColumn('productionName')" />
<el-table-column prop="status" width="80" label="状态" align="center" v-if="columns.showColumn('status')"> <!-- <el-table-column prop="status" width="80" label="状态" align="center" v-if="columns.showColumn('status')">
<template #default="scope"> <template #default="scope">
<dict-tag :options="options.statusOptions" :value="scope.row.status + ''" /> <dict-tag :options="options.statusOptions" :value="scope.row.status + ''" />
</template> </template>
</el-table-column> </el-table-column> -->
<el-table-column prop="lineCode" width="80" label="线别" align="center" <el-table-column prop="lineCode" label="实际数量" align="center" v-if="columns.showColumn('lineCode')" />
v-if="columns.showColumn('lineCode')" /> <el-table-column prop="groupCode" label="合格数量" align="center" v-if="columns.showColumn('groupCode')" />
<el-table-column prop="groupCode" width="80" label="组别" align="center" <el-table-column prop="startTime" label="不合格数量" align="center" v-if="columns.showColumn('startTime')" />
v-if="columns.showColumn('groupCode')" /> <el-table-column prop="endTime" label="合格率" align="center" v-if="columns.showColumn('endTime')" />
<el-table-column prop="startTime" width="140" label="开始时间" align="center"
v-if="columns.showColumn('startTime')" /> <!-- <el-table-column prop="beat" label="计划节拍" width="100" align="center" v-if="columns.showColumn('beat')" />
<el-table-column prop="endTime" width="140" label="结束时间" align="center"
v-if="columns.showColumn('endTime')" />
<!-- 添加计划节拍列 -->
<el-table-column prop="beat" label="计划节拍" width="100" align="center" v-if="columns.showColumn('beat')" />
<!-- 实际节拍列保持不变 -->
<el-table-column prop="actualBeat" label="实际节拍" width="100" align="center" <el-table-column prop="actualBeat" label="实际节拍" width="100" align="center"
v-if="columns.showColumn('actualBeat')" /> v-if="columns.showColumn('actualBeat')" />
<!-- 添加计划完成列 -->
<el-table-column prop="planNum" label="计划完成" width="100" align="center" <el-table-column prop="planNum" label="计划完成" width="100" align="center"
v-if="columns.showColumn('planNum')" /> v-if="columns.showColumn('planNum')" />
<!-- 添加实际完成列 -->
<el-table-column prop="actualNum" label="实际完成" width="100" align="center" <el-table-column prop="actualNum" label="实际完成" width="100" align="center"
v-if="columns.showColumn('actualNum')" /> v-if="columns.showColumn('actualNum')" />
<el-table-column prop="deliveryNum" label="工单进度" align="center"> <el-table-column prop="deliveryNum" label="工单进度" align="center">
@ -66,19 +62,19 @@
<el-progress :text-inside="true" :stroke-width="24" :percentage="getPercentage(scope.row)" <el-progress :text-inside="true" :stroke-width="24" :percentage="getPercentage(scope.row)"
:status="getProgressColor(scope.row)" /> :status="getProgressColor(scope.row)" />
</template> </template>
</el-table-column> </el-table-column> -->
<el-table-column label="操作" width="195" align="center"> <!-- <el-table-column label="操作" width="195" align="center">
<template #default="scope"> <template #default="scope">
<el-button type="primary" size="small" @click="handleView(scope.row)">下发</el-button> <el-button type="primary" size="small" @click="handleView(scope.row)">下发</el-button>
<el-button type="info" size="small" @click="handleUpdate(scope.row)">暂停</el-button> <el-button type="info" size="small" @click="handleUpdate(scope.row)">暂停</el-button>
<el-button type="success" size="small" @click="handleDelete(scope.row)">完成</el-button> <el-button type="success" size="small" @click="handleDelete(scope.row)">完成</el-button>
</template> </template>
</el-table-column> </el-table-column> -->
</el-table> </el-table>
<pagination :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" <pagination :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
@pagination="getList" /> @pagination="getList" />
<el-dialog :lock-scroll="false" v-model="open" draggable :close-on-click-modal="false" @close="cancel"> <el-dialog :lock-scroll="false" v-model="open" draggable :close-on-click-modal="false" @close="cancel">
<el-form ref="form" :model="form" :rules="rules" label-width="100px"> <el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
@ -94,7 +90,8 @@
</template> </template>
</el-dialog> </el-dialog>
<el-dialog :title="title1" :lock-scroll="false" v-model="open1" draggable :close-on-click-modal="false" @close="cancel2"> <el-dialog :title="title1" :lock-scroll="false" v-model="open1" draggable :close-on-click-modal="false"
@close="cancel2">
<el-form ref="form" :model="form1" :rules="rules" label-width="100px"> <el-form ref="form" :model="form1" :rules="rules" label-width="100px">
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
@ -146,7 +143,7 @@ const { proxy } = getCurrentInstance()
const loading = ref(false) const loading = ref(false)
const showSearch = ref(true) const showSearch = ref(true)
const open = ref(false) const open = ref(false)
const open1=ref(false) const open1 = ref(false)
const title = ref('') const title = ref('')
const title1 = ref('') const title1 = ref('')
// 使 JavaScript dayjs // 使 JavaScript dayjs
@ -231,10 +228,10 @@ function submitForm() {
open.value = false open.value = false
getList() getList()
}) })
} }
} }
function submitForm2(){ function submitForm2() {
console.log(form1.value,'完工参数'); console.log(form1.value, '完工参数');
EndWorkorder(form1.value).then((res) => { EndWorkorder(form1.value).then((res) => {
proxy.$modal.msgSuccess('完成成功') proxy.$modal.msgSuccess('完成成功')
form.value.workorder = null form.value.workorder = null
@ -291,7 +288,7 @@ const state = reactive({
dictWorkTypeOptions: [], dictWorkTypeOptions: [],
// eg:{ dictLabel: '', dictValue: '0'} // eg:{ dictLabel: '', dictValue: '0'}
statusOptions: [], statusOptions: [],
defectReason:[] defectReason: []
}, },
processList: [], processList: [],
stationList: [], stationList: [],
@ -302,7 +299,7 @@ const state = reactive({
}, },
}) })
const { options, form,form1 } = toRefs(state) const { options, form, form1 } = toRefs(state)
async function initDict() { async function initDict() {
const dictSelectList = ['pro_workorder_type', 'base_work_type'] const dictSelectList = ['pro_workorder_type', 'base_work_type']