Merge remote-tracking branch 'origin/master'

master
suixy 6 days ago
commit a12efc2814

@ -0,0 +1,47 @@
import request from '@/utils/request'
export function listFirstLastInspection(query) {
return request({
url: '/base/firstLastInspection/list',
method: 'get',
params: query
})
}
export function getFirstLastInspection(objId) {
return request({
url: '/base/firstLastInspection/' + objId,
method: 'get'
})
}
export function addFirstLastInspection(data) {
return request({
url: '/base/firstLastInspection',
method: 'post',
data: data
})
}
export function updateFirstLastInspection(data) {
return request({
url: '/base/firstLastInspection',
method: 'put',
data: data
})
}
export function delFirstLastInspection(objId) {
return request({
url: '/base/firstLastInspection/' + objId,
method: 'delete'
})
}
export function getFirstLastInspectionList(query) {
return request({
url: '/base/firstLastInspection/getList',
method: 'get',
params: query
})
}

@ -0,0 +1,47 @@
import request from '@/utils/request'
export function listInspectionReport(query) {
return request({
url: '/base/inspectionReport/list',
method: 'get',
params: query
})
}
export function getInspectionReport(objId) {
return request({
url: '/base/inspectionReport/' + objId,
method: 'get'
})
}
export function addInspectionReport(data) {
return request({
url: '/base/inspectionReport',
method: 'post',
data: data
})
}
export function updateInspectionReport(data) {
return request({
url: '/base/inspectionReport',
method: 'put',
data: data
})
}
export function delInspectionReport(objId) {
return request({
url: '/base/inspectionReport/' + objId,
method: 'delete'
})
}
export function getInspectionReportList(query) {
return request({
url: '/base/inspectionReport/getList',
method: 'get',
params: query
})
}

@ -0,0 +1,47 @@
import request from '@/utils/request'
export function listInspectionStandard(query) {
return request({
url: '/base/inspectionStandard/list',
method: 'get',
params: query
})
}
export function getInspectionStandard(objId) {
return request({
url: '/base/inspectionStandard/' + objId,
method: 'get'
})
}
export function addInspectionStandard(data) {
return request({
url: '/base/inspectionStandard',
method: 'post',
data: data
})
}
export function updateInspectionStandard(data) {
return request({
url: '/base/inspectionStandard',
method: 'put',
data: data
})
}
export function delInspectionStandard(objId) {
return request({
url: '/base/inspectionStandard/' + objId,
method: 'delete'
})
}
export function getInspectionStandardList(query) {
return request({
url: '/base/inspectionStandard/getList',
method: 'get',
params: query
})
}

@ -0,0 +1,70 @@
import request from '@/utils/request'
// 查询工艺预警列表
export function listProcessAlert(query) {
return request({
url: '/base/processAlert/list',
method: 'get',
params: query
})
}
// 查询工艺预警详细
export function getProcessAlert(alertId) {
return request({
url: '/base/processAlert/' + alertId,
method: 'get'
})
}
// 新增工艺预警
export function addProcessAlert(data) {
return request({
url: '/base/processAlert',
method: 'post',
data: data
})
}
// 修改工艺预警
export function updateProcessAlert(data) {
return request({
url: '/base/processAlert',
method: 'put',
data: data
})
}
// 删除工艺预警
export function delProcessAlert(alertId) {
return request({
url: '/base/processAlert/' + alertId,
method: 'delete'
})
}
// 处理工艺预警
export function handleProcessAlert(data) {
return request({
url: '/base/processAlert/handle',
method: 'put',
data: data
})
}
// 检查阈值预警
export function checkThresholdAlert() {
return request({
url: '/base/processAlert/checkThreshold',
method: 'post'
})
}
// 批量标记预警为已处理
export function batchMarkAsProcessed(data) {
return request({
url: '/base/processAlert/batchMarkProcessed',
method: 'put',
data: data
})
}

@ -0,0 +1,53 @@
import request from '@/utils/request'
// 查询工艺文档列表
export function listProcessDocument(query) {
return request({
url: '/base/processDocument/list',
method: 'get',
params: query
})
}
// 查询工艺文档详细
export function getProcessDocument(docId) {
return request({
url: '/base/processDocument/' + docId,
method: 'get'
})
}
// 新增工艺文档
export function addProcessDocument(data) {
return request({
url: '/base/processDocument',
method: 'post',
data: data
})
}
// 修改工艺文档
export function updateProcessDocument(data) {
return request({
url: '/base/processDocument',
method: 'put',
data: data
})
}
// 删除工艺文档
export function delProcessDocument(docId) {
return request({
url: '/base/processDocument/' + docId,
method: 'delete'
})
}
// 获取工艺文档列表(不分页)
export function getProcessDocumentList(query) {
return request({
url: '/base/processDocument/getProcessDocumentList',
method: 'get',
params: query
})
}

@ -0,0 +1,47 @@
import request from '@/utils/request'
export function listQualityTrace(query) {
return request({
url: '/base/qualityTrace/list',
method: 'get',
params: query
})
}
export function getQualityTrace(objId) {
return request({
url: '/base/qualityTrace/' + objId,
method: 'get'
})
}
export function addQualityTrace(data) {
return request({
url: '/base/qualityTrace',
method: 'post',
data: data
})
}
export function updateQualityTrace(data) {
return request({
url: '/base/qualityTrace',
method: 'put',
data: data
})
}
export function delQualityTrace(objId) {
return request({
url: '/base/qualityTrace/' + objId,
method: 'delete'
})
}
export function getQualityTraceList(query) {
return request({
url: '/base/qualityTrace/getList',
method: 'get',
params: query
})
}

@ -0,0 +1,47 @@
import request from '@/utils/request'
export function listSamplingInspection(query) {
return request({
url: '/base/samplingInspection/list',
method: 'get',
params: query
})
}
export function getSamplingInspection(objId) {
return request({
url: '/base/samplingInspection/' + objId,
method: 'get'
})
}
export function addSamplingInspection(data) {
return request({
url: '/base/samplingInspection',
method: 'post',
data: data
})
}
export function updateSamplingInspection(data) {
return request({
url: '/base/samplingInspection',
method: 'put',
data: data
})
}
export function delSamplingInspection(objId) {
return request({
url: '/base/samplingInspection/' + objId,
method: 'delete'
})
}
export function getSamplingInspectionList(query) {
return request({
url: '/base/samplingInspection/getList',
method: 'get',
params: query
})
}

@ -0,0 +1,47 @@
import request from '@/utils/request'
export function listSamplingPlan(query) {
return request({
url: '/base/samplingPlan/list',
method: 'get',
params: query
})
}
export function getSamplingPlan(objId) {
return request({
url: '/base/samplingPlan/' + objId,
method: 'get'
})
}
export function addSamplingPlan(data) {
return request({
url: '/base/samplingPlan',
method: 'post',
data: data
})
}
export function updateSamplingPlan(data) {
return request({
url: '/base/samplingPlan',
method: 'put',
data: data
})
}
export function delSamplingPlan(objId) {
return request({
url: '/base/samplingPlan/' + objId,
method: 'delete'
})
}
export function getSamplingPlanList(query) {
return request({
url: '/base/samplingPlan/getList',
method: 'get',
params: query
})
}

@ -0,0 +1,47 @@
import request from '@/utils/request'
export function listStandardDocument(query) {
return request({
url: '/base/standardDocument/list',
method: 'get',
params: query
})
}
export function getStandardDocument(objId) {
return request({
url: '/base/standardDocument/' + objId,
method: 'get'
})
}
export function addStandardDocument(data) {
return request({
url: '/base/standardDocument',
method: 'post',
data: data
})
}
export function updateStandardDocument(data) {
return request({
url: '/base/standardDocument',
method: 'put',
data: data
})
}
export function delStandardDocument(objId) {
return request({
url: '/base/standardDocument/' + objId,
method: 'delete'
})
}
export function getStandardDocumentList(query) {
return request({
url: '/base/standardDocument/getList',
method: 'get',
params: query
})
}

@ -0,0 +1,64 @@
import request from '@/utils/request'
// 获取完整的看板数据
export function getDashboardData(productLineCode) {
return request({
url: '/production/andon/dashboard/all',
method: 'get',
params: { productLineCode }
})
}
// 获取设备状态统计
export function getDeviceStatusSummary(productLineCode) {
return request({
url: '/production/andon/dashboard/device-status',
method: 'get',
params: { productLineCode }
})
}
// 获取任务完成情况
export function getTaskCompletionSummary(productLineCode) {
return request({
url: '/production/andon/dashboard/task-completion',
method: 'get',
params: { productLineCode }
})
}
// 获取OEE数据
export function getOeeSummary(productLineCode) {
return request({
url: '/production/andon/dashboard/oee',
method: 'get',
params: { productLineCode }
})
}
// 获取利用率统计
export function getUtilizationSummary(productLineCode) {
return request({
url: '/production/andon/dashboard/utilization',
method: 'get',
params: { productLineCode }
})
}
// 获取品质数据
export function getQualitySummary(productLineCode) {
return request({
url: '/production/andon/dashboard/quality',
method: 'get',
params: { productLineCode }
})
}
// 获取安灯事件统计
export function getAndonEventSummary(productLineCode) {
return request({
url: '/production/andon/dashboard/andon-events',
method: 'get',
params: { productLineCode }
})
}

@ -0,0 +1,53 @@
import request from '@/utils/request'
// 查询周排产计划列表
export function listPlan(query) {
return request({
url: '/production/plan/list',
method: 'get',
params: query
})
}
// 查询周排产计划详细
export function getPlan(id) {
return request({
url: '/production/plan/' + id,
method: 'get'
})
}
// 新增周排产计划
export function addPlan(data) {
return request({
url: '/production/plan',
method: 'post',
data: data
})
}
// 修改周排产计划
export function updatePlan(data) {
return request({
url: '/production/plan',
method: 'put',
data: data
})
}
// 删除周排产计划
export function delPlan(id) {
return request({
url: '/production/plan/' + id,
method: 'delete'
})
}
// 批量更新周排产计划
export function batchUpdatePlan(data) {
return request({
url: '/production/plan/batchUpdate',
method: 'put',
data: data
})
}

@ -0,0 +1,53 @@
import request from '@/utils/request'
// 查询子件物料周需求列表
export function listReq(query) {
return request({
url: '/production/req/list',
method: 'get',
params: query
})
}
// 查询子件物料周需求详细
export function getReq(id) {
return request({
url: '/production/req/' + id,
method: 'get'
})
}
// 新增子件物料周需求
export function addReq(data) {
return request({
url: '/production/req',
method: 'post',
data: data
})
}
// 修改子件物料周需求
export function updateReq(data) {
return request({
url: '/production/req',
method: 'put',
data: data
})
}
// 删除子件物料周需求
export function delReq(id) {
return request({
url: '/production/req/' + id,
method: 'delete'
})
}
// 批量更新子件物料周需求
export function batchUpdateReq(data) {
return request({
url: '/production/req/batchUpdate',
method: 'put',
data: data
})
}

@ -507,6 +507,34 @@ export const dynamicRoutes = [
},
],
},
{
path: "/dms/maintDetail",
component: Layout,
hidden: true,
permissions: ["dms:maint:query"],
children: [
{
path: "index/:planMaintId/:planMaintCode",
component: () => import("@/views/dms/maintDetail/index"),
name: "MaintDetail",
meta: {title: "保养计划明细", activeMenu: "/dms/maint"},
},
],
},
{
path: "/base/processAlert",
component: Layout,
hidden: true,
permissions: ["base:processAlert:list"],
children: [
{
path: "index",
component: () => import("@/views/base/processAlert/index"),
name: "ProcessAlert",
meta: {title: "工艺预警", activeMenu: "/base/processAlert"},
},
],
},
]
// 防止连续点击多次路由报错

@ -114,6 +114,21 @@
</template>
</el-table-column>
<el-table-column label="读取频率" align="center" prop="readFrequency" v-if="columns[7].visible"/>
<el-table-column label="上限阈值" align="center" prop="upperLimit" v-if="columns[14].visible"/>
<el-table-column label="下限阈值" align="center" prop="lowerLimit" v-if="columns[15].visible"/>
<el-table-column label="预警级别" align="center" prop="alertLevel" v-if="columns[16].visible">
<template slot-scope="scope">
<el-tag v-if="scope.row.alertLevel === '1'" type="info"></el-tag>
<el-tag v-else-if="scope.row.alertLevel === '2'" type="warning">重要</el-tag>
<el-tag v-else-if="scope.row.alertLevel === '3'" type="danger">紧急</el-tag>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="启用预警" align="center" prop="alertEnabled" v-if="columns[17].visible">
<template slot-scope="scope">
<el-tag :type="scope.row.alertEnabled === '1' ? 'success' : 'info'">{{ scope.row.alertEnabled === '1' ? '是' : '否' }}</el-tag>
</template>
</el-table-column>
<el-table-column label="启用标识" align="center" prop="isFlag" v-if="columns[8].visible">
<template slot-scope="scope">
<dict-tag :options="dict.type.is_flag" :value="scope.row.isFlag"/>
@ -195,7 +210,23 @@
</el-select>
</el-form-item>
<el-form-item label="读取频率" prop="readFrequency">
<el-input v-model="form.readFrequency" placeholder="请输入读取频率" />
<el-input v-model="form.readFrequency" placeholder="请输入读取频率(毫秒)" />
</el-form-item>
<el-form-item label="上限阈值" prop="upperLimit">
<el-input-number v-model="form.upperLimit" placeholder="参数上限" :precision="4" :controls="false" style="width: 100%" />
</el-form-item>
<el-form-item label="下限阈值" prop="lowerLimit">
<el-input-number v-model="form.lowerLimit" placeholder="参数下限" :precision="4" :controls="false" style="width: 100%" />
</el-form-item>
<el-form-item label="预警级别" prop="alertLevel">
<el-select v-model="form.alertLevel" placeholder="请选择预警级别" clearable style="width: 100%">
<el-option label="一般" value="1" />
<el-option label="重要" value="2" />
<el-option label="紧急" value="3" />
</el-select>
</el-form-item>
<el-form-item label="启用预警" prop="alertEnabled">
<el-switch v-model="form.alertEnabled" active-value="1" inactive-value="0" active-text="" inactive-text="" />
</el-form-item>
<el-form-item label="启用标识" prop="isFlag">
<el-radio-group v-model="form.isFlag">
@ -322,6 +353,10 @@ export default {
{ key: 11, label: `更新人`, visible: false },
{ key: 12, label: `更新时间`, visible: false },
{ key: 13, label: `产线`, visible: true },
{ key: 14, label: `上限阈值`, visible: true },
{ key: 15, label: `下限阈值`, visible: true },
{ key: 16, label: `预警级别`, visible: true },
{ key: 17, label: `启用预警`, visible: true },
],
//
deviceLedgerList: [],

@ -0,0 +1,285 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80">
<el-form-item label="检验单号" prop="inspectionNo">
<el-input v-model="queryParams.inspectionNo" placeholder="请输入检验单号" clearable />
</el-form-item>
<el-form-item label="检验类型" prop="inspectionType">
<el-input v-model="queryParams.inspectionType" placeholder="请输入检验类型" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['base:firstLastInspection:add']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['base:firstLastInspection:edit']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['base:firstLastInspection:remove']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['base:firstLastInspection:export']"></el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="firstLastInspectionList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="检验单号" align="center" prop="inspectionNo" />
<el-table-column label="检验类型" align="center" prop="inspectionType" />
<el-table-column label="产品编号" align="center" prop="productCode" />
<el-table-column label="产品名称" align="center" prop="productName" />
<el-table-column label="工单编号" align="center" prop="workOrderNo" />
<el-table-column label="工位编号" align="center" prop="stationCode" />
<el-table-column label="检验员" align="center" prop="inspector" />
<el-table-column label="检验结果" align="center" prop="inspectionResult" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['base:firstLastInspection:edit']"></el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['base:firstLastInspection:remove']"></el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="检验单号" prop="inspectionNo">
<el-input v-model="form.inspectionNo" placeholder="请输入检验单号" />
</el-form-item>
<el-form-item label="检验类型" prop="inspectionType">
<el-input v-model="form.inspectionType" placeholder="请输入检验类型" />
</el-form-item>
<el-form-item label="产品编号" prop="productCode">
<el-input v-model="form.productCode" placeholder="请输入产品编号" />
</el-form-item>
<el-form-item label="产品名称" prop="productName">
<el-input v-model="form.productName" placeholder="请输入产品名称" />
</el-form-item>
<el-form-item label="工单编号" prop="workOrderNo">
<el-input v-model="form.workOrderNo" placeholder="请输入工单编号" />
</el-form-item>
<el-form-item label="工位" prop="stationCode">
<el-select v-model="form.stationCode" placeholder="请选择工位" clearable filterable @change="handleStationChange">
<el-option
v-for="item in processStationList"
:key="item.processCode"
:label="item.processCode + ' - ' + item.processName"
:value="item.processCode"
/>
</el-select>
</el-form-item>
<el-form-item label="检验标准" prop="standardCode">
<el-select v-model="form.standardCode" placeholder="请选择检验标准" clearable filterable>
<el-option
v-for="item in inspectionStandardList"
:key="item.standardCode"
:label="item.standardCode + ' - ' + item.standardName"
:value="item.standardCode"
/>
</el-select>
</el-form-item>
<el-form-item label="检验员" prop="inspector">
<el-input v-model="form.inspector" placeholder="请输入检验员" />
</el-form-item>
<el-form-item label="检验时间" prop="inspectionTime">
<el-date-picker clearable v-model="form.inspectionTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="请选择检验时间" />
</el-form-item>
<el-form-item label="检验结果" prop="inspectionResult">
<el-input v-model="form.inspectionResult" placeholder="请输入检验结果" />
</el-form-item>
<el-form-item label="合格数量" prop="qualifiedQty">
<el-input-number v-model="form.qualifiedQty" :min="0" />
</el-form-item>
<el-form-item label="不合格数量" prop="unqualifiedQty">
<el-input-number v-model="form.unqualifiedQty" :min="0" />
</el-form-item>
<el-form-item label="缺陷描述" prop="defectDescription">
<el-input v-model="form.defectDescription" type="textarea" placeholder="请输入缺陷描述" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-input v-model="form.status" placeholder="请输入状态" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listFirstLastInspection, getFirstLastInspection, delFirstLastInspection, addFirstLastInspection, updateFirstLastInspection } from "@/api/base/firstLastInspection";
import { getInspectionStandardList } from "@/api/base/inspectionStandard";
import { listProcessStation } from "@/api/base/processStation";
export default {
name: "FirstLastInspection",
data() {
return {
loading: true,
ids: [],
single: true,
multiple: true,
showSearch: true,
total: 0,
firstLastInspectionList: [],
inspectionStandardList: [],
processStationList: [],
title: "",
open: false,
queryParams: {
pageNum: 1,
pageSize: 10,
inspectionNo: null,
inspectionType: null,
productCode: null,
productName: null,
workOrderNo: null,
stationCode: null,
inspector: null,
inspectionResult: null,
status: null
},
form: {},
rules: {
inspectionNo: [{ required: true, message: "检验单号不能为空", trigger: "blur" }],
inspectionType: [{ required: true, message: "检验类型不能为空", trigger: "blur" }]
}
};
},
created() {
this.getList();
this.loadInspectionStandardList();
this.loadProcessStationList();
},
methods: {
getList() {
this.loading = true;
listFirstLastInspection(this.queryParams).then(response => {
this.firstLastInspectionList = response.rows;
this.total = response.total;
this.loading = false;
});
},
cancel() {
this.open = false;
this.reset();
},
reset() {
this.form = {
objId: null,
inspectionNo: null,
inspectionType: null,
productCode: null,
productName: null,
workOrderNo: null,
stationCode: null,
stationName: null,
standardCode: null,
inspector: null,
inspectionTime: null,
inspectionResult: null,
qualifiedQty: null,
unqualifiedQty: null,
defectDescription: null,
status: null,
remark: null
};
this.resetForm("form");
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
handleSelectionChange(selection) {
this.ids = selection.map(item => item.objId);
this.single = selection.length !== 1;
this.multiple = !selection.length;
},
handleAdd() {
this.reset();
this.open = true;
this.title = "添加首末检验";
},
handleUpdate(row) {
this.reset();
const objId = row.objId || this.ids;
getFirstLastInspection(objId).then(response => {
this.form = response.data;
this.syncStationNameFromCode(this.form.stationCode);
this.open = true;
this.title = "修改首末检验";
});
},
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.objId != null) {
updateFirstLastInspection(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addFirstLastInspection(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
handleDelete(row) {
const objIds = row.objId || this.ids;
this.$modal.confirm('是否确认删除首末检验编号为"' + objIds + '"的数据项?').then(function() {
return delFirstLastInspection(objIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
handleExport() {
this.download('base/firstLastInspection/export', { ...this.queryParams }, `firstLastInspection_${new Date().getTime()}.xlsx`);
},
loadInspectionStandardList() {
getInspectionStandardList().then(response => {
this.inspectionStandardList = response.rows || [];
});
},
loadProcessStationList() {
listProcessStation().then(response => {
this.processStationList = response.rows || [];
this.syncStationNameFromCode(this.form.stationCode);
});
},
handleStationChange(val) {
const station = this.processStationList.find(item => item.processCode === val);
this.form.stationName = station ? station.processName : '';
},
syncStationNameFromCode(code) {
if (!code) {
this.form.stationName = '';
return;
}
const station = this.processStationList.find(item => item.processCode === code);
this.form.stationName = station ? station.processName : '';
}
}
};
</script>

@ -0,0 +1,234 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80">
<el-form-item label="报表编号" prop="reportNo">
<el-input v-model="queryParams.reportNo" placeholder="请输入报表编号" clearable />
</el-form-item>
<el-form-item label="报表名称" prop="reportName">
<el-input v-model="queryParams.reportName" placeholder="请输入报表名称" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['base:inspectionReport:add']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['base:inspectionReport:edit']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['base:inspectionReport:remove']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['base:inspectionReport:export']"></el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="inspectionReportList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="报表编号" align="center" prop="reportNo" />
<el-table-column label="报表名称" align="center" prop="reportName" />
<el-table-column label="产品编号" align="center" prop="productCode" />
<el-table-column label="产品名称" align="center" prop="productName" />
<el-table-column label="工单编号" align="center" prop="workOrderNo" />
<el-table-column label="检验类型" align="center" prop="inspectionType" />
<el-table-column label="检验工单总数" align="center" prop="totalInspections" />
<el-table-column label="通过数量" align="center" prop="passedQty" />
<el-table-column label="不通过数量" align="center" prop="failedQty" />
<el-table-column label="未检验数量" align="center" prop="pendingQty" />
<el-table-column label="合格率" align="center" prop="passRate" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['base:inspectionReport:edit']"></el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['base:inspectionReport:remove']"></el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="报表编号" prop="reportNo">
<el-input v-model="form.reportNo" placeholder="请输入报表编号" />
</el-form-item>
<el-form-item label="报表名称" prop="reportName">
<el-input v-model="form.reportName" placeholder="请输入报表名称" />
</el-form-item>
<el-form-item label="产品编号" prop="productCode">
<el-input v-model="form.productCode" placeholder="请输入产品编号" />
</el-form-item>
<el-form-item label="产品名称" prop="productName">
<el-input v-model="form.productName" placeholder="请输入产品名称" />
</el-form-item>
<el-form-item label="工单编号" prop="workOrderNo">
<el-input v-model="form.workOrderNo" placeholder="请输入工单编号" />
</el-form-item>
<el-form-item label="检验类型" prop="inspectionType">
<el-input v-model="form.inspectionType" placeholder="请输入检验类型" />
</el-form-item>
<el-form-item label="检验工单总数" prop="totalInspections">
<el-input-number v-model="form.totalInspections" :min="0" />
</el-form-item>
<el-form-item label="通过数量" prop="passedQty">
<el-input-number v-model="form.passedQty" :min="0" />
</el-form-item>
<el-form-item label="不通过数量" prop="failedQty">
<el-input-number v-model="form.failedQty" :min="0" />
</el-form-item>
<el-form-item label="未检验数量" prop="pendingQty">
<el-input-number v-model="form.pendingQty" :min="0" />
</el-form-item>
<el-form-item label="合格率" prop="passRate">
<el-input v-model="form.passRate" placeholder="请输入合格率" />
</el-form-item>
<el-form-item label="开始时间" prop="startTime">
<el-date-picker clearable v-model="form.startTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="请选择开始时间" />
</el-form-item>
<el-form-item label="结束时间" prop="endTime">
<el-date-picker clearable v-model="form.endTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="请选择结束时间" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listInspectionReport, getInspectionReport, delInspectionReport, addInspectionReport, updateInspectionReport } from "@/api/base/inspectionReport";
export default {
name: "InspectionReport",
data() {
return {
loading: true,
ids: [],
single: true,
multiple: true,
showSearch: true,
total: 0,
inspectionReportList: [],
title: "",
open: false,
queryParams: {
pageNum: 1,
pageSize: 10,
reportNo: null,
reportName: null,
productCode: null,
productName: null,
workOrderNo: null,
inspectionType: null
},
form: {},
rules: {
reportNo: [{ required: true, message: "报表编号不能为空", trigger: "blur" }],
reportName: [{ required: true, message: "报表名称不能为空", trigger: "blur" }]
}
};
},
created() {
this.getList();
},
methods: {
getList() {
this.loading = true;
listInspectionReport(this.queryParams).then(response => {
this.inspectionReportList = response.rows;
this.total = response.total;
this.loading = false;
});
},
cancel() {
this.open = false;
this.reset();
},
reset() {
this.form = {
objId: null,
reportNo: null,
reportName: null,
productCode: null,
productName: null,
workOrderNo: null,
inspectionType: null,
totalInspections: null,
passedQty: null,
failedQty: null,
pendingQty: null,
passRate: null,
startTime: null,
endTime: null,
createdBy: null,
createdTime: null
};
this.resetForm("form");
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
handleSelectionChange(selection) {
this.ids = selection.map(item => item.objId);
this.single = selection.length !== 1;
this.multiple = !selection.length;
},
handleAdd() {
this.reset();
this.open = true;
this.title = "添加检验报表";
},
handleUpdate(row) {
this.reset();
const objId = row.objId || this.ids;
getInspectionReport(objId).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改检验报表";
});
},
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.objId != null) {
updateInspectionReport(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addInspectionReport(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
handleDelete(row) {
const objIds = row.objId || this.ids;
this.$modal.confirm('是否确认删除检验报表编号为"' + objIds + '"的数据项?').then(function() {
return delInspectionReport(objIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
handleExport() {
this.download('base/inspectionReport/export', { ...this.queryParams }, `inspectionReport_${new Date().getTime()}.xlsx`);
}
}
};
</script>

@ -0,0 +1,236 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80">
<el-form-item label="标准编号" prop="standardCode">
<el-input v-model="queryParams.standardCode" placeholder="请输入标准编号" clearable />
</el-form-item>
<el-form-item label="标准名称" prop="standardName">
<el-input v-model="queryParams.standardName" placeholder="请输入标准名称" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['base:inspectionStandard:add']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['base:inspectionStandard:edit']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['base:inspectionStandard:remove']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['base:inspectionStandard:export']"></el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="inspectionStandardList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="标准编号" align="center" prop="standardCode" />
<el-table-column label="标准名称" align="center" prop="standardName" />
<el-table-column label="产品编号" align="center" prop="productCode" />
<el-table-column label="产品名称" align="center" prop="productName" />
<el-table-column label="检验类型" align="center" prop="inspectionType" />
<el-table-column label="检验项目" align="center" prop="inspectionItems" />
<el-table-column label="检验方法" align="center" prop="inspectionMethod" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['base:inspectionStandard:edit']"></el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['base:inspectionStandard:remove']"></el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="标准编号" prop="standardCode">
<el-input v-model="form.standardCode" placeholder="请输入标准编号" />
</el-form-item>
<el-form-item label="标准名称" prop="standardName">
<el-input v-model="form.standardName" placeholder="请输入标准名称" />
</el-form-item>
<el-form-item label="产品编号" prop="productCode">
<el-input v-model="form.productCode" placeholder="请输入产品编号" />
</el-form-item>
<el-form-item label="产品名称" prop="productName">
<el-input v-model="form.productName" placeholder="请输入产品名称" />
</el-form-item>
<el-form-item label="检验类型" prop="inspectionType">
<el-input v-model="form.inspectionType" placeholder="请输入检验类型" />
</el-form-item>
<el-form-item label="检验项目" prop="inspectionItems">
<el-input v-model="form.inspectionItems" placeholder="请输入检验项目" />
</el-form-item>
<el-form-item label="检验方法" prop="inspectionMethod">
<el-input v-model="form.inspectionMethod" placeholder="请输入检验方法" />
</el-form-item>
<el-form-item label="标准值" prop="standardValue">
<el-input v-model="form.standardValue" placeholder="请输入标准值" />
</el-form-item>
<el-form-item label="公差范围" prop="toleranceRange">
<el-input v-model="form.toleranceRange" placeholder="请输入公差范围" />
</el-form-item>
<el-form-item label="抽样方案" prop="samplingPlanCode">
<el-select v-model="form.samplingPlanCode" placeholder="请选择抽样方案" clearable filterable>
<el-option
v-for="item in samplingPlanList"
:key="item.planCode"
:label="item.planCode + ' - ' + item.planName"
:value="item.planCode"
/>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listInspectionStandard, getInspectionStandard, delInspectionStandard, addInspectionStandard, updateInspectionStandard, getInspectionStandardList } from "@/api/base/inspectionStandard";
import { getSamplingPlanList } from "@/api/base/samplingPlan";
export default {
name: "InspectionStandard",
data() {
return {
loading: true,
ids: [],
single: true,
multiple: true,
showSearch: true,
total: 0,
inspectionStandardList: [],
samplingPlanList: [],
title: "",
open: false,
queryParams: {
pageNum: 1,
pageSize: 10,
standardCode: null,
standardName: null,
productCode: null,
productName: null,
inspectionType: null,
isFlag: null
},
form: {},
rules: {
standardCode: [{ required: true, message: "标准编号不能为空", trigger: "blur" }],
standardName: [{ required: true, message: "标准名称不能为空", trigger: "blur" }]
}
};
},
created() {
this.getList();
this.loadSamplingPlanList();
},
methods: {
getList() {
this.loading = true;
listInspectionStandard(this.queryParams).then(response => {
this.inspectionStandardList = response.rows;
this.total = response.total;
this.loading = false;
});
},
cancel() {
this.open = false;
this.reset();
},
reset() {
this.form = {
objId: null,
standardCode: null,
standardName: null,
productCode: null,
productName: null,
inspectionType: null,
inspectionItems: null,
inspectionMethod: null,
standardValue: null,
toleranceRange: null,
samplingPlanCode: null,
remark: null,
isFlag: null
};
this.resetForm("form");
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
handleSelectionChange(selection) {
this.ids = selection.map(item => item.objId);
this.single = selection.length !== 1;
this.multiple = !selection.length;
},
handleAdd() {
this.reset();
this.open = true;
this.title = "添加检验标准";
},
handleUpdate(row) {
this.reset();
const objId = row.objId || this.ids;
getInspectionStandard(objId).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改检验标准";
});
},
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.objId != null) {
updateInspectionStandard(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addInspectionStandard(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
handleDelete(row) {
const objIds = row.objId || this.ids;
this.$modal.confirm('是否确认删除检验标准编号为"' + objIds + '"的数据项?').then(function() {
return delInspectionStandard(objIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
handleExport() {
this.download('base/inspectionStandard/export', { ...this.queryParams }, `inspectionStandard_${new Date().getTime()}.xlsx`);
},
loadSamplingPlanList() {
getSamplingPlanList().then(response => {
this.samplingPlanList = response.rows || [];
});
}
}
};
</script>

@ -0,0 +1,258 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
<el-form-item label="预警编号" prop="alertCode">
<el-input v-model="queryParams.alertCode" placeholder="请输入预警编号" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="设备编码" prop="deviceCode">
<el-input v-model="queryParams.deviceCode" placeholder="请输入设备编码" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="预警类型" prop="alertType">
<el-select v-model="queryParams.alertType" placeholder="请选择类型" clearable>
<el-option label="参数超限" value="参数超限"/>
<el-option label="设备异常" value="设备异常"/>
<el-option label="质量异常" value="质量异常"/>
</el-select>
</el-form-item>
<el-form-item label="预警状态" prop="alertStatus">
<el-select v-model="queryParams.alertStatus" placeholder="请选择状态" clearable>
<el-option label="未处理" value="0"/>
<el-option label="处理中" value="1"/>
<el-option label="已处理" value="2"/>
</el-select>
</el-form-item>
<el-form-item label="预警时间">
<el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-refresh" size="mini" @click="handleCheckThreshold" v-hasPermi="['base:processAlert:add']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-check" size="mini" :disabled="multiple" @click="handleBatchMarkProcessed" v-hasPermi="['base:processAlert:edit']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['base:processAlert:export']"></el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="alertList" :row-class-name="tableRowClassName" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="预警编号" align="center" prop="alertCode" width="120"/>
<el-table-column label="预警类型" align="center" prop="alertType" width="100"/>
<el-table-column label="预警级别" align="center" prop="alertLevel" width="80">
<template slot-scope="scope">
<el-tag :type="scope.row.alertLevel === '3' ? 'danger' : scope.row.alertLevel === '2' ? 'warning' : 'info'">
{{ scope.row.alertLevel === '3' ? '紧急' : scope.row.alertLevel === '2' ? '重要' : '一般' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="设备编码" align="center" prop="deviceCode"/>
<el-table-column label="设备名称" align="center" prop="deviceName"/>
<el-table-column label="参数名称" align="center" prop="paramName"/>
<el-table-column label="预警内容" align="center" prop="alertContent" show-overflow-tooltip/>
<el-table-column label="预警值" align="center" prop="alertValue" width="80"/>
<el-table-column label="阈值" align="center" prop="thresholdValue" width="80"/>
<el-table-column label="预警时间" align="center" prop="alertTime" width="160"/>
<el-table-column label="状态" align="center" prop="alertStatus" width="80">
<template slot-scope="scope">
<el-tag :type="scope.row.alertStatus === '2' ? 'success' : scope.row.alertStatus === '1' ? 'warning' : 'danger'">
{{ scope.row.alertStatus === '2' ? '已处理' : scope.row.alertStatus === '1' ? '处理中' : '未处理' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="150">
<template slot-scope="scope">
<el-button v-if="scope.row.alertStatus !== '2'" size="mini" type="text" icon="el-icon-check" @click="handleProcess(scope.row)" v-hasPermi="['base:processAlert:edit']"></el-button>
<el-button size="mini" type="text" icon="el-icon-view" @click="handleView(scope.row)"></el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList"/>
<el-dialog title="处理预警" :visible.sync="processOpen" width="500px" append-to-body>
<el-form ref="processForm" :model="processForm" :rules="processRules" label-width="100px">
<el-form-item label="预警编号">
<el-input v-model="processForm.alertCode" disabled/>
</el-form-item>
<el-form-item label="预警内容">
<el-input v-model="processForm.alertContent" type="textarea" disabled/>
</el-form-item>
<el-form-item label="处理状态" prop="alertStatus">
<el-radio-group v-model="processForm.alertStatus">
<el-radio label="1">处理中</el-radio>
<el-radio label="2">已处理</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="处理结果" prop="handleResult">
<el-input v-model="processForm.handleResult" type="textarea" placeholder="请输入处理结果"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitProcess"> </el-button>
<el-button @click="processOpen = false"> </el-button>
</div>
</el-dialog>
<el-dialog title="预警详情" :visible.sync="viewOpen" width="600px" append-to-body>
<el-descriptions :column="2" border>
<el-descriptions-item label="预警编号">{{ currentRow.alertCode }}</el-descriptions-item>
<el-descriptions-item label="预警类型">{{ currentRow.alertType }}</el-descriptions-item>
<el-descriptions-item label="预警级别">{{ currentRow.alertLevel === '3' ? '紧急' : currentRow.alertLevel === '2' ? '重要' : '一般' }}</el-descriptions-item>
<el-descriptions-item label="预警状态">{{ currentRow.alertStatus === '2' ? '已处理' : currentRow.alertStatus === '1' ? '处理中' : '未处理' }}</el-descriptions-item>
<el-descriptions-item label="设备编码">{{ currentRow.deviceCode }}</el-descriptions-item>
<el-descriptions-item label="设备名称">{{ currentRow.deviceName }}</el-descriptions-item>
<el-descriptions-item label="参数编码">{{ currentRow.paramCode }}</el-descriptions-item>
<el-descriptions-item label="参数名称">{{ currentRow.paramName }}</el-descriptions-item>
<el-descriptions-item label="预警值">{{ currentRow.alertValue }}</el-descriptions-item>
<el-descriptions-item label="阈值">{{ currentRow.thresholdValue }}</el-descriptions-item>
<el-descriptions-item label="预警内容" :span="2">{{ currentRow.alertContent }}</el-descriptions-item>
<el-descriptions-item label="预警时间" :span="2">{{ currentRow.alertTime }}</el-descriptions-item>
<el-descriptions-item label="处理人">{{ currentRow.handleUser }}</el-descriptions-item>
<el-descriptions-item label="处理时间">{{ currentRow.handleTime }}</el-descriptions-item>
<el-descriptions-item label="处理结果" :span="2">{{ currentRow.handleResult }}</el-descriptions-item>
</el-descriptions>
<div slot="footer" class="dialog-footer">
<el-button @click="viewOpen = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listProcessAlert, getProcessAlert, handleProcessAlert, checkThresholdAlert, batchMarkAsProcessed } from "@/api/base/processAlert";
export default {
name: "ProcessAlert",
data() {
return {
loading: true,
showSearch: true,
total: 0,
alertList: [],
ids: [],
multiple: true,
dateRange: [],
processOpen: false,
viewOpen: false,
currentRow: {},
processForm: {},
queryParams: {
pageNum: 1,
pageSize: 10,
alertCode: null,
deviceCode: null,
alertType: null,
alertStatus: null,
},
processRules: {
alertStatus: [{ required: true, message: "请选择处理状态", trigger: "change" }],
handleResult: [{ required: true, message: "请输入处理结果", trigger: "blur" }],
}
};
},
created() {
this.getList();
},
methods: {
getList() {
this.loading = true;
let params = { ...this.queryParams };
if (this.dateRange && this.dateRange.length === 2) {
params.params = { beginTime: this.dateRange[0], endTime: this.dateRange[1] };
}
listProcessAlert(params).then(response => {
this.alertList = response.rows;
this.total = response.total;
this.loading = false;
});
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.dateRange = [];
this.resetForm("queryForm");
this.handleQuery();
},
handleSelectionChange(selection) {
this.ids = selection.map(item => item.alertId);
this.multiple = !selection.length;
},
tableRowClassName({ row }) {
if (row.alertStatus === '0' && row.alertLevel === '3') {
return 'danger-row';
} else if (row.alertStatus === '0') {
return 'warning-row';
}
return '';
},
handleProcess(row) {
this.processForm = {
alertId: row.alertId,
alertCode: row.alertCode,
alertContent: row.alertContent,
alertStatus: row.alertStatus === '0' ? '1' : row.alertStatus,
handleResult: row.handleResult,
};
this.processOpen = true;
},
handleView(row) {
this.currentRow = row;
this.viewOpen = true;
},
submitProcess() {
this.$refs["processForm"].validate(valid => {
if (valid) {
handleProcessAlert(this.processForm).then(response => {
this.$modal.msgSuccess("处理成功");
this.processOpen = false;
this.getList();
});
}
});
},
handleExport() {
this.download('base/processAlert/export', { ...this.queryParams }, `processAlert_${new Date().getTime()}.xlsx`);
},
handleCheckThreshold() {
this.$modal.confirm('是否检查参数阈值并生成预警?').then(() => {
checkThresholdAlert().then(response => {
this.$modal.msgSuccess(response.msg);
this.getList();
});
}).catch(() => {});
},
handleBatchMarkProcessed() {
if (this.ids.length === 0) {
this.$modal.msgWarning("请选择要处理的预警");
return;
}
this.$modal.confirm('确认将选中的 ' + this.ids.length + ' 条预警标记为已处理?').then(() => {
batchMarkAsProcessed(this.ids).then(response => {
this.$modal.msgSuccess(response.msg);
this.getList();
});
}).catch(() => {});
}
}
};
</script>
<style scoped>
::v-deep .warning-row {
background-color: #FDF6EC !important;
}
::v-deep .danger-row {
background-color: #FEF0F0 !important;
}
</style>

@ -0,0 +1,309 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
<el-form-item label="文档编号" prop="docCode">
<el-input v-model="queryParams.docCode" placeholder="请输入文档编号" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="文档名称" prop="docName">
<el-input v-model="queryParams.docName" placeholder="请输入文档名称" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="文档类型" prop="docType">
<el-select v-model="queryParams.docType" placeholder="请选择文档类型" clearable>
<el-option label="SOP" value="SOP"/>
<el-option label="参数要求" value="参数要求"/>
<el-option label="作业指导书" value="作业指导书"/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['base:processDocument:add']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['base:processDocument:edit']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['base:processDocument:remove']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['base:processDocument:export']"></el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="documentList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center"/>
<el-table-column label="文档编号" align="center" prop="docCode"/>
<el-table-column label="文档名称" align="center" prop="docName" show-overflow-tooltip/>
<el-table-column label="文档类型" align="center" prop="docType"/>
<el-table-column label="产品编码" align="center" prop="productCode"/>
<el-table-column label="设备编码" align="center" prop="deviceCode"/>
<el-table-column label="版本" align="center" prop="docVersion" width="80"/>
<el-table-column label="文件名称" align="center" prop="fileName" show-overflow-tooltip/>
<el-table-column label="状态" align="center" prop="docStatus" width="80">
<template slot-scope="scope">
<el-tag :type="scope.row.docStatus === '1' ? 'success' : scope.row.docStatus === '2' ? 'danger' : 'info'">
{{ scope.row.docStatus === '1' ? '发布' : scope.row.docStatus === '2' ? '作废' : '草稿' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="160"/>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-view" @click="handleView(scope.row)"></el-button>
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['base:processDocument:edit']"></el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['base:processDocument:remove']"></el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList"/>
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="文档编号" prop="docCode">
<el-input v-model="form.docCode" placeholder="请输入文档编号"/>
</el-form-item>
<el-form-item label="文档名称" prop="docName">
<el-input v-model="form.docName" placeholder="请输入文档名称"/>
</el-form-item>
<el-form-item label="文档类型" prop="docType">
<el-select v-model="form.docType" placeholder="请选择文档类型" style="width: 100%">
<el-option label="SOP" value="SOP"/>
<el-option label="参数要求" value="参数要求"/>
<el-option label="作业指导书" value="作业指导书"/>
</el-select>
</el-form-item>
<el-form-item label="产品编码" prop="productCode">
<el-input v-model="form.productCode" placeholder="请输入产品编码"/>
</el-form-item>
<el-form-item label="产品名称" prop="productName">
<el-input v-model="form.productName" placeholder="请输入产品名称"/>
</el-form-item>
<el-form-item label="设备编码" prop="deviceCode">
<el-input v-model="form.deviceCode" placeholder="请输入设备编码"/>
</el-form-item>
<el-form-item label="设备名称" prop="deviceName">
<el-input v-model="form.deviceName" placeholder="请输入设备名称"/>
</el-form-item>
<el-form-item label="文档版本" prop="docVersion">
<el-input v-model="form.docVersion" placeholder="请输入文档版本"/>
</el-form-item>
<el-form-item label="文件上传" prop="filePath">
<el-upload
:action="uploadUrl"
:headers="uploadHeaders"
:file-list="fileList"
:limit="1"
:on-success="handleUploadSuccess"
:on-error="handleUploadError"
:on-remove="handleFileRemove"
:on-exceed="handleExceed"
:before-upload="beforeUpload"
>
<el-button size="small" type="primary">选取文件</el-button>
<div slot="tip" class="el-upload__tip">只能上传一个文件大小不超过10MB</div>
</el-upload>
</el-form-item>
<el-form-item label="文档状态" prop="docStatus">
<el-radio-group v-model="form.docStatus">
<el-radio label="0">草稿</el-radio>
<el-radio label="1">发布</el-radio>
<el-radio label="2">作废</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listProcessDocument, getProcessDocument, delProcessDocument, addProcessDocument, updateProcessDocument } from "@/api/base/processDocument";
import { getToken } from "@/utils/auth";
export default {
name: "ProcessDocument",
data() {
return {
loading: true,
ids: [],
single: true,
multiple: true,
showSearch: true,
total: 0,
documentList: [],
title: "",
open: false,
fileList: [],
uploadUrl: process.env.VUE_APP_BASE_API + "/common/upload",
uploadHeaders: { Authorization: "Bearer " + getToken() },
queryParams: {
pageNum: 1,
pageSize: 10,
docCode: null,
docName: null,
docType: null,
},
form: {},
rules: {
docCode: [{ required: true, message: "文档编号不能为空", trigger: "blur" }],
docName: [{ required: true, message: "文档名称不能为空", trigger: "blur" }],
docType: [{ required: true, message: "文档类型不能为空", trigger: "change" }],
}
};
},
created() {
this.getList();
},
methods: {
getList() {
this.loading = true;
listProcessDocument(this.queryParams).then(response => {
this.documentList = response.rows;
this.total = response.total;
this.loading = false;
});
},
cancel() {
this.open = false;
this.reset();
},
reset() {
this.form = {
docId: null,
docCode: null,
docName: null,
docType: null,
productCode: null,
productName: null,
deviceCode: null,
deviceName: null,
moldCode: null,
moldName: null,
docVersion: null,
filePath: null,
fileName: null,
fileSize: null,
docStatus: "0",
isFlag: "1",
remark: null,
};
this.fileList = [];
this.resetForm("form");
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
handleSelectionChange(selection) {
this.ids = selection.map(item => item.docId);
this.single = selection.length !== 1;
this.multiple = !selection.length;
},
handleAdd() {
this.reset();
this.open = true;
this.title = "添加工艺文档";
},
handleUpdate(row) {
this.reset();
const docId = row.docId || this.ids;
getProcessDocument(docId).then(response => {
this.form = response.data;
if (this.form.filePath) {
this.fileList = [{ name: this.getFileName(this.form.filePath), url: this.form.filePath }];
}
this.open = true;
this.title = "修改工艺文档";
});
},
handleView(row) {
if (row.filePath) {
window.open(process.env.VUE_APP_BASE_API + row.filePath, '_blank');
} else {
this.$modal.msgWarning("暂无文件可查看");
}
},
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.docId != null) {
updateProcessDocument(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addProcessDocument(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
handleDelete(row) {
const docIds = row.docId || this.ids;
this.$modal.confirm('是否确认删除工艺文档编号为"' + docIds + '"的数据项?').then(function() {
return delProcessDocument(docIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
handleExport() {
this.download('base/processDocument/export', { ...this.queryParams }, `processDocument_${new Date().getTime()}.xlsx`);
},
handleUploadSuccess(res, file) {
if (res.code === 200) {
this.form.filePath = res.fileName;
this.form.fileName = this.getFileName(res.fileName);
this.$modal.msgSuccess("上传成功");
} else {
this.$modal.msgError(res.msg || "上传失败");
this.fileList = [];
}
},
handleUploadError() {
this.$modal.msgError("上传失败");
this.fileList = [];
},
handleFileRemove() {
this.form.filePath = null;
this.form.fileName = null;
this.fileList = [];
},
handleExceed() {
this.$modal.msgWarning("只能上传一个文件");
},
beforeUpload(file) {
const isLt10M = file.size / 1024 / 1024 < 10;
if (!isLt10M) {
this.$modal.msgError("上传文件大小不能超过 10MB!");
}
return isLt10M;
},
getFileName(path) {
if (!path) return "";
return path.lastIndexOf("/") > -1 ? path.slice(path.lastIndexOf("/") + 1) : path;
}
}
};
</script>

@ -0,0 +1,297 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80">
<el-form-item label="追溯编号" prop="traceNo">
<el-input v-model="queryParams.traceNo" placeholder="请输入追溯编号" clearable />
</el-form-item>
<el-form-item label="产品编号" prop="productCode">
<el-input v-model="queryParams.productCode" placeholder="请输入产品编号" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['base:qualityTrace:add']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['base:qualityTrace:edit']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['base:qualityTrace:remove']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['base:qualityTrace:export']"></el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="qualityTraceList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="追溯编号" align="center" prop="traceNo" />
<el-table-column label="产品编号" align="center" prop="productCode" />
<el-table-column label="产品名称" align="center" prop="productName" />
<el-table-column label="工单编号" align="center" prop="workOrderNo" />
<el-table-column label="批次号" align="center" prop="batchNo" />
<el-table-column label="生产线" align="center" prop="productionLine" />
<el-table-column label="工位编号" align="center" prop="stationCode" />
<el-table-column label="检验单号" align="center" prop="inspectionNo" />
<el-table-column label="检验类型" align="center" prop="inspectionType" />
<el-table-column label="检验结果" align="center" prop="inspectionResult" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['base:qualityTrace:edit']"></el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['base:qualityTrace:remove']"></el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="追溯编号" prop="traceNo">
<el-input v-model="form.traceNo" placeholder="请输入追溯编号" />
</el-form-item>
<el-form-item label="产品编号" prop="productCode">
<el-input v-model="form.productCode" placeholder="请输入产品编号" />
</el-form-item>
<el-form-item label="产品名称" prop="productName">
<el-input v-model="form.productName" placeholder="请输入产品名称" />
</el-form-item>
<el-form-item label="工单编号" prop="workOrderNo">
<el-input v-model="form.workOrderNo" placeholder="请输入工单编号" />
</el-form-item>
<el-form-item label="批次号" prop="batchNo">
<el-input v-model="form.batchNo" placeholder="请输入批次号" />
</el-form-item>
<el-form-item label="生产日期" prop="productionDate">
<el-date-picker clearable v-model="form.productionDate" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="请选择生产日期" />
</el-form-item>
<el-form-item label="生产线" prop="productionLine">
<el-select v-model="form.productionLine" placeholder="请选择生产线" clearable filterable>
<el-option
v-for="item in productLineList"
:key="item.productLineCode"
:label="item.productLineName"
:value="item.productLineCode"
/>
</el-select>
</el-form-item>
<el-form-item label="工位" prop="stationCode">
<el-select v-model="form.stationCode" placeholder="请选择工位" clearable filterable @change="handleStationChange">
<el-option
v-for="item in processStationList"
:key="item.processCode"
:label="item.processCode + ' - ' + item.processName"
:value="item.processCode"
/>
</el-select>
</el-form-item>
<el-form-item label="检验单号" prop="inspectionNo">
<el-input v-model="form.inspectionNo" placeholder="请输入检验单号" />
</el-form-item>
<el-form-item label="检验类型" prop="inspectionType">
<el-input v-model="form.inspectionType" placeholder="请输入检验类型" />
</el-form-item>
<el-form-item label="检验结果" prop="inspectionResult">
<el-input v-model="form.inspectionResult" placeholder="请输入检验结果" />
</el-form-item>
<el-form-item label="缺陷编号" prop="defectCode">
<el-input v-model="form.defectCode" placeholder="请输入缺陷编号" />
</el-form-item>
<el-form-item label="缺陷名称" prop="defectName">
<el-input v-model="form.defectName" placeholder="请输入缺陷名称" />
</el-form-item>
<el-form-item label="缺陷数量" prop="defectQty">
<el-input-number v-model="form.defectQty" :min="0" />
</el-form-item>
<el-form-item label="处理措施" prop="handlingMeasure">
<el-input v-model="form.handlingMeasure" type="textarea" placeholder="请输入处理措施" />
</el-form-item>
<el-form-item label="责任人" prop="responsiblePerson">
<el-input v-model="form.responsiblePerson" placeholder="请输入责任人" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listQualityTrace, getQualityTrace, delQualityTrace, addQualityTrace, updateQualityTrace } from "@/api/base/qualityTrace";
import { findProductLineList } from "@/api/base/productLine";
import { listProcessStation } from "@/api/base/processStation";
export default {
name: "QualityTrace",
data() {
return {
loading: true,
ids: [],
single: true,
multiple: true,
showSearch: true,
total: 0,
qualityTraceList: [],
productLineList: [],
processStationList: [],
title: "",
open: false,
queryParams: {
pageNum: 1,
pageSize: 10,
traceNo: null,
productCode: null,
productName: null,
workOrderNo: null,
batchNo: null,
productionLine: null,
stationCode: null,
inspectionNo: null,
inspectionType: null,
inspectionResult: null,
defectCode: null
},
form: {},
rules: {
traceNo: [{ required: true, message: "追溯编号不能为空", trigger: "blur" }],
productCode: [{ required: true, message: "产品编号不能为空", trigger: "blur" }]
}
};
},
created() {
this.getList();
this.loadProductLineList();
this.loadProcessStationList();
},
methods: {
getList() {
this.loading = true;
listQualityTrace(this.queryParams).then(response => {
this.qualityTraceList = response.rows;
this.total = response.total;
this.loading = false;
});
},
cancel() {
this.open = false;
this.reset();
},
reset() {
this.form = {
objId: null,
traceNo: null,
productCode: null,
productName: null,
workOrderNo: null,
batchNo: null,
productionDate: null,
productionLine: null,
stationCode: null,
stationName: null,
inspectionNo: null,
inspectionType: null,
inspectionResult: null,
defectCode: null,
defectName: null,
defectQty: null,
handlingMeasure: null,
responsiblePerson: null,
remark: null
};
this.resetForm("form");
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
handleSelectionChange(selection) {
this.ids = selection.map(item => item.objId);
this.single = selection.length !== 1;
this.multiple = !selection.length;
},
handleAdd() {
this.reset();
this.open = true;
this.title = "添加品质质量追溯";
},
handleUpdate(row) {
this.reset();
const objId = row.objId || this.ids;
getQualityTrace(objId).then(response => {
this.form = response.data;
this.syncStationNameFromCode(this.form.stationCode);
this.open = true;
this.title = "修改品质质量追溯";
});
},
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.objId != null) {
updateQualityTrace(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addQualityTrace(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
handleDelete(row) {
const objIds = row.objId || this.ids;
this.$modal.confirm('是否确认删除品质质量追溯编号为"' + objIds + '"的数据项?').then(function() {
return delQualityTrace(objIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
handleExport() {
this.download('base/qualityTrace/export', { ...this.queryParams }, `qualityTrace_${new Date().getTime()}.xlsx`);
},
loadProductLineList() {
findProductLineList().then(response => {
this.productLineList = response.data || [];
});
},
loadProcessStationList() {
listProcessStation().then(response => {
this.processStationList = response.rows || [];
this.syncStationNameFromCode(this.form.stationCode);
});
},
handleStationChange(val) {
const station = this.processStationList.find(item => item.processCode === val);
this.form.stationName = station ? station.processName : '';
},
syncStationNameFromCode(code) {
if (!code) {
this.form.stationName = '';
return;
}
const station = this.processStationList.find(item => item.processCode === code);
this.form.stationName = station ? station.processName : '';
}
}
};
</script>

@ -0,0 +1,267 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80">
<el-form-item label="检验单号" prop="inspectionNo">
<el-input v-model="queryParams.inspectionNo" placeholder="请输入检验单号" clearable />
</el-form-item>
<el-form-item label="产品编号" prop="productCode">
<el-input v-model="queryParams.productCode" placeholder="请输入产品编号" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['base:samplingInspection:add']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['base:samplingInspection:edit']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['base:samplingInspection:remove']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['base:samplingInspection:export']"></el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="samplingInspectionList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="检验单号" align="center" prop="inspectionNo" />
<el-table-column label="产品编号" align="center" prop="productCode" />
<el-table-column label="产品名称" align="center" prop="productName" />
<el-table-column label="工单编号" align="center" prop="workOrderNo" />
<el-table-column label="批次号" align="center" prop="batchNo" />
<el-table-column label="批次数量" align="center" prop="batchQty" />
<el-table-column label="样本数量" align="center" prop="sampleSize" />
<el-table-column label="检验员" align="center" prop="inspector" />
<el-table-column label="检验结果" align="center" prop="inspectionResult" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['base:samplingInspection:edit']"></el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['base:samplingInspection:remove']"></el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="检验单号" prop="inspectionNo">
<el-input v-model="form.inspectionNo" placeholder="请输入检验单号" />
</el-form-item>
<el-form-item label="产品编号" prop="productCode">
<el-input v-model="form.productCode" placeholder="请输入产品编号" />
</el-form-item>
<el-form-item label="产品名称" prop="productName">
<el-input v-model="form.productName" placeholder="请输入产品名称" />
</el-form-item>
<el-form-item label="工单编号" prop="workOrderNo">
<el-input v-model="form.workOrderNo" placeholder="请输入工单编号" />
</el-form-item>
<el-form-item label="批次号" prop="batchNo">
<el-input v-model="form.batchNo" placeholder="请输入批次号" />
</el-form-item>
<el-form-item label="批次数量" prop="batchQty">
<el-input-number v-model="form.batchQty" :min="0" />
</el-form-item>
<el-form-item label="抽样方案" prop="samplingPlanCode">
<el-select v-model="form.samplingPlanCode" placeholder="请选择抽样方案" clearable filterable>
<el-option
v-for="item in samplingPlanList"
:key="item.planCode"
:label="item.planCode + ' - ' + item.planName"
:value="item.planCode"
/>
</el-select>
</el-form-item>
<el-form-item label="样本数量" prop="sampleSize">
<el-input-number v-model="form.sampleSize" :min="0" />
</el-form-item>
<el-form-item label="检验员" prop="inspector">
<el-input v-model="form.inspector" placeholder="请输入检验员" />
</el-form-item>
<el-form-item label="检验时间" prop="inspectionTime">
<el-date-picker clearable v-model="form.inspectionTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="请选择检验时间" />
</el-form-item>
<el-form-item label="检验结果" prop="inspectionResult">
<el-input v-model="form.inspectionResult" placeholder="请输入检验结果" />
</el-form-item>
<el-form-item label="合格数量" prop="qualifiedQty">
<el-input-number v-model="form.qualifiedQty" :min="0" />
</el-form-item>
<el-form-item label="不合格数量" prop="unqualifiedQty">
<el-input-number v-model="form.unqualifiedQty" :min="0" />
</el-form-item>
<el-form-item label="接收数" prop="acceptNumber">
<el-input-number v-model="form.acceptNumber" :min="0" />
</el-form-item>
<el-form-item label="拒收数" prop="rejectNumber">
<el-input-number v-model="form.rejectNumber" :min="0" />
</el-form-item>
<el-form-item label="缺陷描述" prop="defectDescription">
<el-input v-model="form.defectDescription" type="textarea" placeholder="请输入缺陷描述" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-input v-model="form.status" placeholder="请输入状态" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listSamplingInspection, getSamplingInspection, delSamplingInspection, addSamplingInspection, updateSamplingInspection } from "@/api/base/samplingInspection";
import { getSamplingPlanList } from "@/api/base/samplingPlan";
export default {
name: "SamplingInspection",
data() {
return {
loading: true,
ids: [],
single: true,
multiple: true,
showSearch: true,
total: 0,
samplingInspectionList: [],
samplingPlanList: [],
title: "",
open: false,
queryParams: {
pageNum: 1,
pageSize: 10,
inspectionNo: null,
productCode: null,
productName: null,
workOrderNo: null,
batchNo: null,
inspector: null,
inspectionResult: null,
status: null
},
form: {},
rules: {
inspectionNo: [{ required: true, message: "检验单号不能为空", trigger: "blur" }],
productCode: [{ required: true, message: "产品编号不能为空", trigger: "blur" }]
}
};
},
created() {
this.getList();
this.loadSamplingPlanList();
},
methods: {
getList() {
this.loading = true;
listSamplingInspection(this.queryParams).then(response => {
this.samplingInspectionList = response.rows;
this.total = response.total;
this.loading = false;
});
},
cancel() {
this.open = false;
this.reset();
},
reset() {
this.form = {
objId: null,
inspectionNo: null,
productCode: null,
productName: null,
workOrderNo: null,
batchNo: null,
batchQty: null,
samplingPlanCode: null,
sampleSize: null,
inspector: null,
inspectionTime: null,
inspectionResult: null,
qualifiedQty: null,
unqualifiedQty: null,
acceptNumber: null,
rejectNumber: null,
defectDescription: null,
status: null,
remark: null
};
this.resetForm("form");
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
handleSelectionChange(selection) {
this.ids = selection.map(item => item.objId);
this.single = selection.length !== 1;
this.multiple = !selection.length;
},
handleAdd() {
this.reset();
this.open = true;
this.title = "添加抽样检验";
},
handleUpdate(row) {
this.reset();
const objId = row.objId || this.ids;
getSamplingInspection(objId).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改抽样检验";
});
},
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.objId != null) {
updateSamplingInspection(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addSamplingInspection(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
handleDelete(row) {
const objIds = row.objId || this.ids;
this.$modal.confirm('是否确认删除抽样检验编号为"' + objIds + '"的数据项?').then(function() {
return delSamplingInspection(objIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
handleExport() {
this.download('base/samplingInspection/export', { ...this.queryParams }, `samplingInspection_${new Date().getTime()}.xlsx`);
},
loadSamplingPlanList() {
getSamplingPlanList().then(response => {
this.samplingPlanList = response.rows || [];
});
}
}
};
</script>

@ -0,0 +1,219 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80">
<el-form-item label="方案编号" prop="planCode">
<el-input v-model="queryParams.planCode" placeholder="请输入方案编号" clearable />
</el-form-item>
<el-form-item label="方案名称" prop="planName">
<el-input v-model="queryParams.planName" placeholder="请输入方案名称" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['base:samplingPlan:add']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['base:samplingPlan:edit']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['base:samplingPlan:remove']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['base:samplingPlan:export']"></el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="samplingPlanList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="方案编号" align="center" prop="planCode" />
<el-table-column label="方案名称" align="center" prop="planName" />
<el-table-column label="AQL标准" align="center" prop="aqlStandard" />
<el-table-column label="检验水平" align="center" prop="inspectionLevel" />
<el-table-column label="抽样类型" align="center" prop="samplingType" />
<el-table-column label="批次范围" align="center" prop="batchRange" />
<el-table-column label="样本数量" align="center" prop="sampleSize" />
<el-table-column label="接收数" align="center" prop="acceptNumber" />
<el-table-column label="拒收数" align="center" prop="rejectNumber" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['base:samplingPlan:edit']"></el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['base:samplingPlan:remove']"></el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="方案编号" prop="planCode">
<el-input v-model="form.planCode" placeholder="请输入方案编号" />
</el-form-item>
<el-form-item label="方案名称" prop="planName">
<el-input v-model="form.planName" placeholder="请输入方案名称" />
</el-form-item>
<el-form-item label="AQL标准" prop="aqlStandard">
<el-input v-model="form.aqlStandard" placeholder="请输入AQL标准" />
</el-form-item>
<el-form-item label="检验水平" prop="inspectionLevel">
<el-input v-model="form.inspectionLevel" placeholder="请输入检验水平" />
</el-form-item>
<el-form-item label="抽样类型" prop="samplingType">
<el-input v-model="form.samplingType" placeholder="请输入抽样类型" />
</el-form-item>
<el-form-item label="批次范围" prop="batchRange">
<el-input v-model="form.batchRange" placeholder="请输入批次范围" />
</el-form-item>
<el-form-item label="样本数量" prop="sampleSize">
<el-input-number v-model="form.sampleSize" :min="0" />
</el-form-item>
<el-form-item label="接收数" prop="acceptNumber">
<el-input-number v-model="form.acceptNumber" :min="0" />
</el-form-item>
<el-form-item label="拒收数" prop="rejectNumber">
<el-input-number v-model="form.rejectNumber" :min="0" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listSamplingPlan, getSamplingPlan, delSamplingPlan, addSamplingPlan, updateSamplingPlan } from "@/api/base/samplingPlan";
export default {
name: "SamplingPlan",
data() {
return {
loading: true,
ids: [],
single: true,
multiple: true,
showSearch: true,
total: 0,
samplingPlanList: [],
title: "",
open: false,
queryParams: {
pageNum: 1,
pageSize: 10,
planCode: null,
planName: null,
aqlStandard: null,
inspectionLevel: null,
samplingType: null,
isFlag: null
},
form: {},
rules: {
planCode: [{ required: true, message: "方案编号不能为空", trigger: "blur" }],
planName: [{ required: true, message: "方案名称不能为空", trigger: "blur" }]
}
};
},
created() {
this.getList();
},
methods: {
getList() {
this.loading = true;
listSamplingPlan(this.queryParams).then(response => {
this.samplingPlanList = response.rows;
this.total = response.total;
this.loading = false;
});
},
cancel() {
this.open = false;
this.reset();
},
reset() {
this.form = {
objId: null,
planCode: null,
planName: null,
aqlStandard: null,
inspectionLevel: null,
samplingType: null,
batchRange: null,
sampleSize: null,
acceptNumber: null,
rejectNumber: null,
remark: null,
isFlag: null
};
this.resetForm("form");
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
handleSelectionChange(selection) {
this.ids = selection.map(item => item.objId);
this.single = selection.length !== 1;
this.multiple = !selection.length;
},
handleAdd() {
this.reset();
this.open = true;
this.title = "添加抽样方案";
},
handleUpdate(row) {
this.reset();
const objId = row.objId || this.ids;
getSamplingPlan(objId).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改抽样方案";
});
},
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.objId != null) {
updateSamplingPlan(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addSamplingPlan(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
handleDelete(row) {
const objIds = row.objId || this.ids;
this.$modal.confirm('是否确认删除抽样方案编号为"' + objIds + '"的数据项?').then(function() {
return delSamplingPlan(objIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
handleExport() {
this.download('base/samplingPlan/export', { ...this.queryParams }, `samplingPlan_${new Date().getTime()}.xlsx`);
}
}
};
</script>

@ -0,0 +1,228 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80">
<el-form-item label="文档编号" prop="documentCode">
<el-input v-model="queryParams.documentCode" placeholder="请输入文档编号" clearable />
</el-form-item>
<el-form-item label="文档名称" prop="documentName">
<el-input v-model="queryParams.documentName" placeholder="请输入文档名称" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['base:standardDocument:add']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['base:standardDocument:edit']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['base:standardDocument:remove']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['base:standardDocument:export']"></el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="standardDocumentList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="文档编号" align="center" prop="documentCode" />
<el-table-column label="文档名称" align="center" prop="documentName" />
<el-table-column label="文档类型" align="center" prop="documentType" />
<el-table-column label="产品编号" align="center" prop="productCode" />
<el-table-column label="产品名称" align="center" prop="productName" />
<el-table-column label="版本号" align="center" prop="versionNo" />
<el-table-column label="文档大小" align="center" prop="documentSize" />
<el-table-column label="上传人" align="center" prop="uploader" />
<el-table-column label="状态" align="center" prop="status" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['base:standardDocument:edit']"></el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['base:standardDocument:remove']"></el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="文档编号" prop="documentCode">
<el-input v-model="form.documentCode" placeholder="请输入文档编号" />
</el-form-item>
<el-form-item label="文档名称" prop="documentName">
<el-input v-model="form.documentName" placeholder="请输入文档名称" />
</el-form-item>
<el-form-item label="文档类型" prop="documentType">
<el-input v-model="form.documentType" placeholder="请输入文档类型" />
</el-form-item>
<el-form-item label="产品编号" prop="productCode">
<el-input v-model="form.productCode" placeholder="请输入产品编号" />
</el-form-item>
<el-form-item label="产品名称" prop="productName">
<el-input v-model="form.productName" placeholder="请输入产品名称" />
</el-form-item>
<el-form-item label="版本号" prop="versionNo">
<el-input v-model="form.versionNo" placeholder="请输入版本号" />
</el-form-item>
<el-form-item label="文档路径" prop="documentPath">
<el-input v-model="form.documentPath" placeholder="请输入文档路径" />
</el-form-item>
<el-form-item label="文档大小" prop="documentSize">
<el-input-number v-model="form.documentSize" :min="0" />
</el-form-item>
<el-form-item label="生效日期" prop="effectiveDate">
<el-date-picker clearable v-model="form.effectiveDate" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="请选择生效日期" />
</el-form-item>
<el-form-item label="失效日期" prop="expiryDate">
<el-date-picker clearable v-model="form.expiryDate" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="请选择失效日期" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-input v-model="form.status" placeholder="请输入状态" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listStandardDocument, getStandardDocument, delStandardDocument, addStandardDocument, updateStandardDocument } from "@/api/base/standardDocument";
export default {
name: "StandardDocument",
data() {
return {
loading: true,
ids: [],
single: true,
multiple: true,
showSearch: true,
total: 0,
standardDocumentList: [],
title: "",
open: false,
queryParams: {
pageNum: 1,
pageSize: 10,
documentCode: null,
documentName: null,
documentType: null,
productCode: null,
productName: null,
status: null
},
form: {},
rules: {
documentCode: [{ required: true, message: "文档编号不能为空", trigger: "blur" }],
documentName: [{ required: true, message: "文档名称不能为空", trigger: "blur" }]
}
};
},
created() {
this.getList();
},
methods: {
getList() {
this.loading = true;
listStandardDocument(this.queryParams).then(response => {
this.standardDocumentList = response.rows;
this.total = response.total;
this.loading = false;
});
},
cancel() {
this.open = false;
this.reset();
},
reset() {
this.form = {
objId: null,
documentCode: null,
documentName: null,
documentType: null,
productCode: null,
productName: null,
versionNo: null,
documentPath: null,
documentSize: null,
uploader: null,
uploadTime: null,
effectiveDate: null,
expiryDate: null,
status: null,
remark: null
};
this.resetForm("form");
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
handleSelectionChange(selection) {
this.ids = selection.map(item => item.objId);
this.single = selection.length !== 1;
this.multiple = !selection.length;
},
handleAdd() {
this.reset();
this.open = true;
this.title = "添加标准文档";
},
handleUpdate(row) {
this.reset();
const objId = row.objId || this.ids;
getStandardDocument(objId).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改标准文档";
});
},
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.objId != null) {
updateStandardDocument(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addStandardDocument(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
handleDelete(row) {
const objIds = row.objId || this.ids;
this.$modal.confirm('是否确认删除标准文档编号为"' + objIds + '"的数据项?').then(function() {
return delStandardDocument(objIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
handleExport() {
this.download('base/standardDocument/export', { ...this.queryParams }, `standardDocument_${new Date().getTime()}.xlsx`);
}
}
};
</script>

@ -1,10 +1,50 @@
<template>
<div class="app-container">
<!-- 预警通知弹窗 -->
<el-notification
v-for="alert in alertNotifications"
:key="alert.alertId"
:title="getAlertTitle(alert)"
:message="alert.alertContent"
:type="getAlertType(alert)"
:duration="0"
position="top-right"
@close="removeAlertNotification(alert.alertId)"
style="margin-bottom: 10px;"
>
<div slot="default" class="alert-notification-content">
<div class="alert-item">
<span class="alert-label">设备:</span>
<span class="alert-value">{{ alert.deviceName }} ({{ alert.deviceCode }})</span>
</div>
<div class="alert-item">
<span class="alert-label">参数:</span>
<span class="alert-value">{{ alert.paramName }}</span>
</div>
<div class="alert-item">
<span class="alert-label">当前值:</span>
<span class="alert-value alert-value-danger">{{ alert.alertValue }}</span>
</div>
<div class="alert-item">
<span class="alert-label">阈值:</span>
<span class="alert-value">{{ alert.thresholdValue }}</span>
</div>
<div class="alert-actions">
<el-button size="mini" type="primary" @click="viewAlertDetail(alert)"></el-button>
<el-button size="mini" @click="removeAlertNotification(alert.alertId)"></el-button>
</div>
</div>
</el-notification>
<!-- 页面头部 -->
<div class="page-header">
<div class="page-title">设备工艺参数监控</div>
<div class="page-actions">
<span class="page-time">{{ nowTimeStr }}</span>
<!-- 预警提醒图标 -->
<el-badge :value="unreadAlertCount" :hidden="unreadAlertCount === 0" class="alert-badge">
<el-button type="danger" size="mini" icon="el-icon-warning" circle @click="showAlertPanel = !showAlertPanel" />
</el-badge>
<el-switch
v-model="autoRefresh"
active-text="自动刷新开"
@ -17,6 +57,54 @@
</div>
</div>
<!-- 预警面板可折叠 -->
<div v-if="showAlertPanel" class="alert-panel">
<div class="alert-panel-header">
<span class="alert-panel-title">
<i class="el-icon-warning-outline"></i>
实时预警 ({{ unreadAlertCount }} 条未处理)
</span>
<div class="alert-panel-actions">
<el-button v-if="alertList.length > 0" type="text" size="mini" icon="el-icon-check" @click="handleMarkAllProcessed"></el-button>
<el-button type="text" size="mini" icon="el-icon-close" @click="showAlertPanel = false" />
</div>
</div>
<div class="alert-list" v-loading="alertLoading">
<div v-if="alertList.length === 0" class="no-alert">
<i class="el-icon-success"></i>
<span>暂无预警信息</span>
</div>
<div
v-for="alert in alertList"
:key="alert.alertId"
:class="['alert-item', 'alert-level-' + alert.alertLevel]"
>
<div class="alert-item-header">
<el-tag :type="getAlertTagType(alert)" size="mini">{{ getAlertLevelText(alert) }}</el-tag>
<span class="alert-time">{{ parseTime(alert.alertTime, '{h}:{i}:{s}') }}</span>
</div>
<div class="alert-item-content">
<div class="alert-content-row">
<span class="alert-label">设备:</span>
<span class="alert-value">{{ alert.deviceName }} ({{ alert.deviceCode }})</span>
</div>
<div class="alert-content-row">
<span class="alert-label">参数:</span>
<span class="alert-value">{{ alert.paramName }}</span>
</div>
<div class="alert-content-row">
<span class="alert-label">内容:</span>
<span class="alert-value">{{ alert.alertContent }}</span>
</div>
</div>
<div class="alert-item-actions">
<el-button size="mini" type="text" @click="viewAlertDetail(alert)"></el-button>
<el-button size="mini" type="text" @click="markAsRead(alert)"></el-button>
</div>
</div>
</div>
</div>
<!-- 主体内容左侧设备列表 + 右侧参数展示 -->
<div class="main-content">
<!-- 左侧设备列表 -->
@ -112,6 +200,7 @@
<script>
import { getLatestVal } from "@/api/baseDeviceParamVal/val";
import { getDeviceLedgerList } from "@/api/base/deviceLedger";
import { listProcessAlert, handleProcessAlert, checkThresholdAlert, batchMarkAsProcessed } from "@/api/base/processAlert";
export default {
name: "Val",
@ -134,6 +223,14 @@ export default {
deviceParams: [],
paramLoading: false,
paramSearchKey: '',
//
alertList: [],
alertNotifications: [],
alertLoading: false,
showAlertPanel: false,
alertTimer: null,
alertCheckIntervalMs: 30000, // 30
lastAlertIds: [], // ID
};
},
computed: {
@ -166,16 +263,23 @@ export default {
if (this.deviceParams.length === 0) return '-';
const t = this.deviceParams[0].recordTime || this.deviceParams[0].collectTime;
return t ? this.parseTime(t, '{y}-{m}-{d} {h}:{i}:{s}') : '-';
},
//
unreadAlertCount() {
return this.alertList.filter(alert => alert.alertStatus === '0').length;
}
},
created() {
this.tickClock();
this.loadDeviceList();
this.loadAllLatestParams(); //
this.loadAlerts(); //
if (this.autoRefresh) this.startAutoRefresh();
this.startAlertCheck(); //
},
beforeDestroy() {
this.stopAutoRefresh();
this.stopAlertCheck();
if (this.clockTimer) {
clearInterval(this.clockTimer);
this.clockTimer = null;
@ -211,12 +315,28 @@ export default {
this.refreshTimer = null;
}
},
/** 开始定时检查预警 */
startAlertCheck() {
this.stopAlertCheck();
this.alertTimer = setInterval(() => {
this.checkAndLoadAlerts();
}, this.alertCheckIntervalMs);
},
/** 停止定时检查预警 */
stopAlertCheck() {
if (this.alertTimer) {
clearInterval(this.alertTimer);
this.alertTimer = null;
}
},
/** 自动刷新切换 */
onAutoRefreshChange(val) {
if (val) {
this.startAutoRefresh();
this.startAlertCheck();
} else {
this.stopAutoRefresh();
this.stopAlertCheck();
}
},
/** 手动刷新 */
@ -274,6 +394,109 @@ export default {
this.paramLoading = false;
this.deviceParams = [];
});
},
/** 加载预警列表 */
loadAlerts() {
this.alertLoading = true;
listProcessAlert({
pageNum: 1,
pageSize: 20,
alertStatus: '0' //
}).then(response => {
this.alertList = response.rows || [];
this.alertLoading = false;
}).catch(() => {
this.alertLoading = false;
this.alertList = [];
});
},
/** 检查并加载预警(定时调用) */
checkAndLoadAlerts() {
//
checkThresholdAlert().then(() => {
//
const currentAlertIds = this.alertList.map(a => a.alertId);
this.loadAlerts().then(() => {
//
const newAlerts = this.alertList.filter(alert => !currentAlertIds.includes(alert.alertId));
if (newAlerts.length > 0) {
//
newAlerts.forEach(alert => {
this.showAlertNotification(alert);
});
}
});
}).catch(() => {
// 使
this.loadAlerts();
});
},
/** 显示预警通知 */
showAlertNotification(alert) {
//
if (this.alertNotifications.find(n => n.alertId === alert.alertId)) {
return;
}
this.alertNotifications.push(alert);
},
/** 移除预警通知 */
removeAlertNotification(alertId) {
const index = this.alertNotifications.findIndex(n => n.alertId === alertId);
if (index > -1) {
this.alertNotifications.splice(index, 1);
}
},
/** 获取预警标题 */
getAlertTitle(alert) {
return alert.alertLevel === '3' ? '【紧急预警】' : alert.alertLevel === '2' ? '【重要预警】' : '【一般预警】';
},
/** 获取预警类型 */
getAlertType(alert) {
return alert.alertLevel === '3' ? 'error' : alert.alertLevel === '2' ? 'warning' : 'info';
},
/** 获取预警标签类型 */
getAlertTagType(alert) {
return alert.alertLevel === '3' ? 'danger' : alert.alertLevel === '2' ? 'warning' : 'info';
},
/** 获取预警级别文本 */
getAlertLevelText(alert) {
return alert.alertLevel === '3' ? '紧急' : alert.alertLevel === '2' ? '重要' : '一般';
},
/** 查看预警详情 */
viewAlertDetail(alert) {
this.$router.push({
path: '/base/processAlert',
query: { alertId: alert.alertId }
});
},
/** 标记为已读 */
markAsRead(alert) {
handleProcessAlert({
alertId: alert.alertId,
alertStatus: '1',
handleResult: '已查看'
}).then(() => {
this.$message.success('标记成功');
this.loadAlerts();
});
},
/** 全部标记为已处理 */
handleMarkAllProcessed() {
const alertIds = this.alertList.map(alert => alert.alertId);
if (alertIds.length === 0) {
this.$message.warning('暂无预警需要处理');
return;
}
this.$confirm('确认将全部 ' + alertIds.length + ' 条预警标记为已处理?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
batchMarkAsProcessed(alertIds).then(() => {
this.$message.success('标记成功');
this.loadAlerts();
});
}).catch(() => {});
}
}
};
@ -305,6 +528,142 @@ export default {
opacity: 0.9;
}
/* 预警徽章 */
.alert-badge {
margin-right: 4px;
}
/* 预警面板 */
.alert-panel {
background: #fff;
border-radius: 6px;
border: 1px solid #e8e8e8;
margin-bottom: 12px;
max-height: 400px;
overflow: hidden;
}
.alert-panel-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 16px;
border-bottom: 1px solid #f0f0f0;
background: #fafafa;
}
.alert-panel-title {
font-size: 14px;
font-weight: 600;
color: #333;
display: flex;
align-items: center;
gap: 6px;
}
.alert-panel-title i {
color: #f56c6c;
}
.alert-panel-actions {
display: flex;
align-items: center;
gap: 8px;
}
.alert-list {
max-height: 340px;
overflow-y: auto;
padding: 8px;
}
.no-alert {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px 20px;
color: #67c23a;
}
.no-alert i {
font-size: 36px;
margin-bottom: 8px;
}
.alert-item {
background: #fff;
border: 1px solid #e8e8e8;
border-radius: 6px;
padding: 10px;
margin-bottom: 8px;
border-left: 4px solid #909399;
}
.alert-item.alert-level-1 {
border-left-color: #909399;
background: #f5f7fa;
}
.alert-item.alert-level-2 {
border-left-color: #e6a23c;
background: #fdf6ec;
}
.alert-item.alert-level-3 {
border-left-color: #f56c6c;
background: #fef0f0;
}
.alert-item-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.alert-time {
font-size: 12px;
color: #999;
}
.alert-item-content {
margin-bottom: 8px;
}
.alert-content-row {
display: flex;
align-items: center;
margin-bottom: 4px;
font-size: 13px;
}
.alert-label {
color: #999;
min-width: 40px;
}
.alert-value {
color: #333;
flex: 1;
}
.alert-item-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
}
/* 预警通知内容 */
.alert-notification-content {
font-size: 13px;
}
.alert-notification-content .alert-item {
display: flex;
align-items: center;
margin-bottom: 6px;
}
.alert-notification-content .alert-label {
color: #999;
min-width: 50px;
}
.alert-notification-content .alert-value {
color: #333;
flex: 1;
}
.alert-notification-content .alert-value-danger {
color: #f56c6c;
font-weight: 600;
}
.alert-notification-content .alert-actions {
margin-top: 10px;
display: flex;
justify-content: flex-end;
gap: 8px;
}
/* 主体布局 */
.main-content {
display: flex;

@ -21,13 +21,28 @@
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="设备编号" prop="deviceCode">
<el-input v-model="form.deviceCode" placeholder="请输入设备编号" />
<el-form-item label="设备" prop="deviceId">
<el-select
v-model="form.deviceId"
placeholder="请选择设备"
filterable
clearable
@change="handleDeviceChange"
style="width: 100%">
<el-option
v-for="item in deviceList"
:key="item.objId"
:label="item.deviceName"
:value="item.objId">
<span style="float: left">{{ item.deviceCode }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ item.deviceName }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设备名称" prop="deviceName">
<el-input v-model="form.deviceName" placeholder="请输入设备名称" />
<el-form-item label="设备名称">
<el-input v-model="form.deviceName" placeholder="自动填充" disabled />
</el-form-item>
</el-col>
</el-row>
@ -171,6 +186,7 @@
<script>
import { getDispatchPlan, addDispatchPlan, updateDispatchPlan } from '@/api/dms/dispatchPlan'
import { selectUserList } from '@/api/system/user'
import { getDeviceLedgerList } from '@/api/base/deviceLedger'
export default {
name: 'DispatchPlanDetail',
@ -197,6 +213,7 @@ export default {
dispatchMembers: []
},
userList: [],
deviceList: [],
rules: {
dispatchType: [{ required: true, message: '请选择派工类型', trigger: 'change' }],
executorId: [{ required: true, message: '请选择执行人', trigger: 'change' }],
@ -207,6 +224,7 @@ export default {
},
created() {
this.loadUserList()
this.loadDeviceList()
const planId = this.$route.params && this.$route.params.planId
if (planId && planId !== 'new') {
this.loadData(planId)
@ -230,9 +248,21 @@ export default {
},
loadUserList() {
selectUserList({}).then(response => {
this.userList = response.rows
this.userList = (response && response.rows && response.rows.length ? response.rows : response.data) || []
})
},
loadDeviceList() {
getDeviceLedgerList({}).then(response => {
this.deviceList = response.data || []
})
},
handleDeviceChange(deviceId) {
const device = this.deviceList.find(d => d.objId === deviceId)
if (device) {
this.form.deviceCode = device.deviceCode
this.form.deviceName = device.deviceName
}
},
handleDispatchTypeChange(val) {
if (val === '1') {
//

@ -135,8 +135,7 @@
<span
v-for="(item, index) in ledgerList"
:key="index"
:value="item.ledgerList"
v-if="scope.row.deviceId == item.deviceId"
v-if="scope.row.deviceId == item.objId"
>
{{ item.deviceName }}
</span>
@ -206,12 +205,12 @@
<!-- <el-input v-model="form.deviceId" placeholder="请输入巡检设备ID关联dms_base_device_ledger的device_id" />-->
<!-- </el-form-item>-->
<el-form-item label="巡检设备" prop="deviceId" >
<el-select v-model="form.deviceId" placeholder="请输入设备类型">
<el-select v-model="form.deviceId" placeholder="请选择设备" filterable>
<el-option
v-for="item in ledgerList"
:key="item.deviceId"
:key="item.objId"
:label="item.deviceName"
:value="item.deviceId">
:value="item.objId">
</el-option>
</el-select>
</el-form-item>
@ -366,9 +365,9 @@ export default {
routeDetailId: null,
inspectRouteId: this.inspectRouteIdCheck,
lineStep: null,
deviceId: null,
deviceId: '',
machineId: null,
inspectStandard: null,
inspectStandard: '',
isFlag: null,
remark: null
};
@ -401,8 +400,9 @@ export default {
this.reset();
const routeDetailId = row.routeDetailId || this.ids
getDmsInspectRouteDetail(routeDetailId).then(response => {
// 使 Object.assign
Object.assign(this.form, response.data);
const data = response.data;
data.inspectStandard = data.inspectStandard ? data.inspectStandard.toString() : null;
this.form = data;
this.open = true;
this.title = "修改巡检线路明细";
});
@ -411,19 +411,16 @@ export default {
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
// deviceId
if (!this.form.deviceId) {
this.$modal.msgWarning("请选择巡检设备");
return;
}
if (this.form.routeDetailId != null) {
updateDmsInspectRouteDetail(this.form).then(response => {
const formData = { ...this.form };
formData.inspectStandard = formData.inspectStandard ? parseInt(formData.inspectStandard) : null;
if (formData.routeDetailId != null) {
updateDmsInspectRouteDetail(formData).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addDmsInspectRouteDetail(this.form).then(response => {
addDmsInspectRouteDetail(formData).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();

@ -153,8 +153,7 @@
<span
v-for="(item, index) in ledgerList"
:key="index"
:value="item.ledgerList"
v-if="scope.row.deviceId == item.deviceId"
v-if="scope.row.deviceId == item.objId"
>
{{ item.deviceName }}
</span>
@ -276,12 +275,12 @@
<!-- <el-input v-model="form.deviceId" placeholder="请输入设备ID关联dms_base_device_ledger的device_id" />-->
<!-- </el-form-item>-->
<el-form-item label="设备名称" prop="deviceId" >
<el-select v-model="form.deviceId" placeholder="请选择设备">
<el-select v-model="form.deviceId" placeholder="请选择设备" filterable>
<el-option
v-for="item in ledgerList"
:key="item.deviceId"
:key="item.objId"
:label="item.deviceName"
:value="item.deviceId">
:value="item.objId">
</el-option>
</el-select>
</el-form-item>
@ -382,20 +381,14 @@ export default {
planMaintId: [
{ required: true, message: "计划ID关联dms_plan_maint的plan_maint_id不能为空", trigger: "blur" }
],
deviceId: [
{ required: true, message: "设备名称不能为空", trigger: "blur" }
],
maintStationCode: [
{ required: true, message: "保养部位不能为空", trigger: "blur" }
],
maintStandardId: [
{ required: true, message: "保养标准不能为空", trigger: "blur" }
],
// deviceId: [
// { required: true, message: "IDdms_base_device_ledgerdevice_id", trigger: "blur" }
// { required: true, message: "", trigger: "blur" }
// ],
// isFlag: [
// { required: true, message: "1-2-", trigger: "blur" }
// maintStationCode: [
// { required: true, message: "", trigger: "blur" }
// ],
// maintStandardId: [
// { required: true, message: "", trigger: "blur" }
// ],
}
};
@ -467,7 +460,7 @@ export default {
this.form = {
planMaintDetailId: null,
planMaintId: null,
deviceId: null,
deviceId: '',
maintStationId: null,
maintStandardId: null,
operationDescription: null,
@ -508,7 +501,9 @@ export default {
this.reset();
const planMaintDetailId = row.planMaintDetailId || this.ids
getMaintDetail(planMaintDetailId).then(response => {
this.form = response.data;
const data = response.data;
data.maintStationCode = data.maintStationCode ? data.maintStationCode.toString() : null;
this.form = data;
this.open = true;
this.title = "修改保养计划明细信息";
});
@ -528,14 +523,16 @@ export default {
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.planMaintDetailId != null) {
updateMaintDetail(this.form).then(response => {
const formData = { ...this.form };
formData.maintStationCode = formData.maintStationCode ? formData.maintStationCode.toString() : null;
if (formData.planMaintDetailId != null) {
updateMaintDetail(formData).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addMaintDetail(this.form).then(response => {
addMaintDetail(formData).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();

@ -14,8 +14,8 @@
</el-col>
<el-col :span="8">
<el-form-item label="关联故障报修">
<el-input v-model="form.faultInstanceId" placeholder="选择故障报修单" readonly @click.native="selectFaultInstance">
<el-button slot="append" icon="el-icon-search" @click="selectFaultInstance"></el-button>
<el-input v-model="faultInstanceDisplay" placeholder="选择故障报修单" readonly :disabled="isView" @click.native="selectFaultInstance">
<el-button slot="append" icon="el-icon-search" @click="selectFaultInstance" :disabled="isView"></el-button>
</el-input>
</el-form-item>
</el-col>
@ -272,12 +272,62 @@
<el-button @click="goBack"> </el-button>
<el-button type="primary" @click="handleSubmit" v-if="!isView"> </el-button>
</div>
<!-- 故障报修选择对话框 -->
<el-dialog title="选择故障报修单" :visible.sync="faultInstanceDialogVisible" width="900px" append-to-body>
<el-form :model="faultInstanceQuery" ref="faultInstanceQueryForm" :inline="true" size="small">
<el-form-item label="报修单号" prop="billsFaultCode">
<el-input v-model="faultInstanceQuery.billsFaultCode" placeholder="请输入报修单号" clearable @keyup.enter.native="loadFaultInstanceList" />
</el-form-item>
<el-form-item label="设备" prop="deviceCode">
<el-input v-model="faultInstanceQuery.deviceCode" placeholder="请输入设备编号" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="loadFaultInstanceList"></el-button>
<el-button icon="el-icon-refresh" @click="resetFaultInstanceQuery"></el-button>
</el-form-item>
</el-form>
<el-table
:data="faultInstanceList"
border
highlight-current-row
@current-change="handleFaultInstanceSelect"
style="width: 100%"
max-height="400">
<el-table-column label="报修单号" align="center" prop="billsFaultCode" width="160" />
<el-table-column label="设备编号" align="center" prop="deviceCode" width="120" />
<el-table-column label="设备名称" align="center" prop="deviceName" width="150" show-overflow-tooltip />
<el-table-column label="故障类型" align="center" prop="faultType" width="100">
<template slot-scope="scope">
<dict-tag :options="dict.type.dms_fault_type" :value="scope.row.faultType"/>
</template>
</el-table-column>
<el-table-column label="故障描述" align="center" prop="faultDescription" show-overflow-tooltip />
<el-table-column label="报修人" align="center" prop="applyUser" width="100" />
<el-table-column label="报修时间" align="center" prop="applyTime" width="160" />
</el-table>
<pagination
v-show="faultInstanceTotal > 0"
:total="faultInstanceTotal"
:page.sync="faultInstanceQuery.pageNum"
:limit.sync="faultInstanceQuery.pageSize"
@pagination="loadFaultInstanceList"
/>
<div slot="footer" class="dialog-footer">
<el-button @click="faultInstanceDialogVisible = false"> </el-button>
<el-button type="primary" @click="confirmFaultInstance"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getRepairWorkOrder, addRepairWorkOrder, updateRepairWorkOrder } from '@/api/dms/repairWorkOrder'
import { getDeviceLedgerList } from '@/api/base/deviceLedger'
import { listDmsBillsFaultInstance } from '@/api/dms/dmsBillsFaultInstance'
export default {
name: 'RepairWorkOrderDetail',
@ -307,6 +357,19 @@ export default {
repairProjects: [],
repairMaterials: []
},
//
faultInstanceDialogVisible: false,
faultInstanceList: [],
faultInstanceTotal: 0,
faultInstanceQuery: {
pageNum: 1,
pageSize: 10,
billsFaultCode: null,
deviceCode: null
// billsStatus
},
selectedFaultInstance: null,
faultInstanceDisplay: null,
rules: {
deviceId: [
{ required: true, message: '请选择设备', trigger: 'change' }
@ -345,6 +408,10 @@ export default {
Object.assign(this.form, response.data)
if (!this.form.repairProjects) this.form.repairProjects = []
if (!this.form.repairMaterials) this.form.repairMaterials = []
//
if (response.data.billsFaultCode) {
this.faultInstanceDisplay = response.data.billsFaultCode
}
})
},
/** 设备改变 */
@ -359,7 +426,52 @@ export default {
/** 选择故障报修 */
selectFaultInstance() {
if (this.isView) return
this.$message.info('功能开发中...')
this.selectedFaultInstance = null
this.faultInstanceDialogVisible = true
this.loadFaultInstanceList()
},
/** 加载故障报修列表 */
loadFaultInstanceList() {
listDmsBillsFaultInstance(this.faultInstanceQuery).then(response => {
this.faultInstanceList = response.rows || []
this.faultInstanceTotal = response.total || 0
})
},
/** 重置故障报修查询 */
resetFaultInstanceQuery() {
this.faultInstanceQuery = {
pageNum: 1,
pageSize: 10,
billsFaultCode: null,
deviceCode: null,
billsStatus: '0'
}
this.loadFaultInstanceList()
},
/** 选择故障报修记录 */
handleFaultInstanceSelect(row) {
this.selectedFaultInstance = row
},
/** 确认选择故障报修 */
confirmFaultInstance() {
if (!this.selectedFaultInstance) {
this.$message.warning('请选择一条故障报修记录')
return
}
const fault = this.selectedFaultInstance
//
this.form.faultInstanceId = fault.repairInstanceId
this.form.deviceId = fault.deviceId
this.form.deviceCode = fault.deviceCode
this.form.deviceName = fault.deviceName
this.form.faultType = fault.faultType
this.form.faultDescription = fault.faultDescription
this.form.planEndTime = fault.requireEndTime
//
this.faultInstanceDisplay = fault.billsFaultCode
//
this.faultInstanceDialogVisible = false
this.$message.success('已关联故障报修单:' + fault.billsFaultCode)
},
/** 添加工程 */
handleAddProject() {

@ -146,32 +146,28 @@
@pagination="getList"
/>
<!-- 添加或修改安灯看板配置对话框 -->
<!-- 添加或修改安灯看板配置对话框简化版以工位为中心 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-alert
title="看板绑定工位后,将自动展示该工位的安灯事件"
type="info"
:closable="false"
style="margin-bottom: 15px;"
/>
<el-form-item label="看板编码" prop="boardCode">
<el-input v-model="form.boardCode" placeholder="请输入看板编码" />
<el-input v-model="form.boardCode" placeholder="请输入看板编码BOARD001" />
</el-form-item>
<el-form-item label="看板名称" prop="boardName">
<el-input v-model="form.boardName" placeholder="请输入看板名称" />
<el-input v-model="form.boardName" placeholder="请输入看板名称,如:装配工位安灯看板" />
</el-form-item>
<el-form-item label="产品线编码" prop="productLineCode" label-width="120px">
<el-select v-model="form.productLineCode" placeholder="请选择产线" clearable>
<el-option
v-for="item in productLineList"
:key="item.productLineCode"
:label="item.productLineName"
:value="item.productLineCode"
/>
</el-select>
</el-form-item>
<el-form-item label="工位/工序编码" prop="stationCode" label-width="120px">
<el-select v-model="form.stationCode" placeholder="请选择工位/工序" clearable>
<el-form-item label="绑定工位" prop="stationCode">
<el-select v-model="form.stationCode" placeholder="请选择绑定的工位(必填)" filterable style="width: 100%">
<el-option
v-for="item in processStationList"
:key="item.stationCode"
:label="item.stationName"
:value="item.stationCode"
:key="item.processCode"
:label="item.processCode + ' - ' + item.processName"
:value="item.processCode"
/>
</el-select>
</el-form-item>
@ -281,7 +277,7 @@ export default {
},
//
form: {},
//
//
rules: {
boardCode: [
{ required: true, message: "看板编码不能为空", trigger: "blur" }
@ -289,6 +285,9 @@ export default {
boardName: [
{ required: true, message: "看板名称不能为空", trigger: "blur" }
],
stationCode: [
{ required: true, message: "请选择绑定的工位", trigger: "change" }
],
isFlag: [
{ required: true, message: "是否有效不能为空", trigger: "change" }
],

@ -0,0 +1,604 @@
<template>
<div class="dashboard-container">
<!-- 顶部筛选栏 -->
<el-card class="filter-card" shadow="never">
<el-form :inline="true" size="small">
<el-form-item label="产线">
<el-select v-model="productLineCode" placeholder="全部产线" clearable @change="loadData">
<el-option
v-for="item in productLineList"
:key="item.productLineCode"
:label="item.productLineName"
:value="item.productLineCode"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-refresh" @click="loadData"></el-button>
</el-form-item>
<el-form-item>
<span class="update-time">更新时间{{ updateTime }}</span>
</el-form-item>
</el-form>
</el-card>
<!-- 顶部统计卡片 -->
<el-row :gutter="16" class="stat-row">
<el-col :span="6">
<el-card class="stat-card device-card" shadow="hover">
<div class="stat-icon">
<i class="el-icon-cpu"></i>
</div>
<div class="stat-content">
<div class="stat-title">设备状态</div>
<div class="stat-value">{{ safe(deviceStatus.runningDevices) }} / {{ safe(deviceStatus.totalDevices) }}</div>
<div class="stat-desc">
<span class="running">运行 {{ safe(deviceStatus.runningDevices) }}</span>
<span class="fault">故障 {{ safe(deviceStatus.faultDevices) }}</span>
<span class="stopped">停机 {{ safe(deviceStatus.stoppedDevices) }}</span>
</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="stat-card task-card" shadow="hover">
<div class="stat-icon">
<i class="el-icon-document-checked"></i>
</div>
<div class="stat-content">
<div class="stat-title">今日完成率</div>
<div class="stat-value">{{ formatPercent(taskCompletion.todayCompletionRate) }}%</div>
<div class="stat-desc">
完成 {{ safe(taskCompletion.todayCompleteAmount) }} / 计划 {{ safe(taskCompletion.todayPlanAmount) }}
</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="stat-card oee-card" shadow="hover">
<div class="stat-icon">
<i class="el-icon-data-analysis"></i>
</div>
<div class="stat-content">
<div class="stat-title">OEE</div>
<div class="stat-value">{{ formatPercent(oeeSummary.overallOee) }}%</div>
<div class="stat-desc">
可用率 {{ formatPercent(oeeSummary.availability) }}% | 性能 {{ formatPercent(oeeSummary.performance) }}%
</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="stat-card quality-card" shadow="hover">
<div class="stat-icon">
<i class="el-icon-trophy"></i>
</div>
<div class="stat-content">
<div class="stat-title">良品率</div>
<div class="stat-value">{{ formatPercent(qualitySummary.todayYieldRate) }}%</div>
<div class="stat-desc">
良品 {{ safe(qualitySummary.todayGoodCount) }} | 不良 {{ safe(qualitySummary.todayDefectCount) }}
</div>
</div>
</el-card>
</el-col>
</el-row>
<!-- 安灯事件统计 -->
<el-row :gutter="16" class="stat-row">
<el-col :span="24">
<el-card class="andon-stat-card" shadow="hover">
<div slot="header" class="card-header">
<span><i class="el-icon-bell"></i> 安灯事件统计</span>
</div>
<el-row :gutter="16">
<el-col :span="4">
<div class="andon-stat-item">
<div class="andon-stat-label">今日事件</div>
<div class="andon-stat-value total">{{ andonEvents.todayTotal }}</div>
</div>
</el-col>
<el-col :span="4">
<div class="andon-stat-item">
<div class="andon-stat-label">待处理</div>
<div class="andon-stat-value pending">{{ andonEvents.pendingCount }}</div>
</div>
</el-col>
<el-col :span="4">
<div class="andon-stat-item">
<div class="andon-stat-label">处理中</div>
<div class="andon-stat-value processing">{{ andonEvents.processingCount }}</div>
</div>
</el-col>
<el-col :span="4">
<div class="andon-stat-item">
<div class="andon-stat-label">已解决</div>
<div class="andon-stat-value resolved">{{ andonEvents.resolvedCount }}</div>
</div>
</el-col>
<el-col :span="4">
<div class="andon-stat-item">
<div class="andon-stat-label">平均响应</div>
<div class="andon-stat-value">{{ andonEvents.avgResponseMinutes }} 分钟</div>
</div>
</el-col>
<el-col :span="4">
<div class="andon-stat-item">
<div class="andon-stat-label">平均解决</div>
<div class="andon-stat-value">{{ andonEvents.avgResolveMinutes }} 分钟</div>
</div>
</el-col>
</el-row>
</el-card>
</el-col>
</el-row>
<!-- 详细数据区域 -->
<el-row :gutter="16">
<!-- 设备状态详情 -->
<el-col :span="12">
<el-card class="detail-card" shadow="hover">
<div slot="header" class="card-header">
<span><i class="el-icon-cpu"></i> 设备状态详情</span>
</div>
<el-table :data="deviceStatus.deviceDetails" size="small" max-height="300" stripe>
<el-table-column prop="deviceCode" label="设备编码" width="120" />
<el-table-column prop="deviceName" label="设备名称" min-width="150" show-overflow-tooltip />
<el-table-column prop="productLineName" label="产线" width="100" show-overflow-tooltip />
<el-table-column prop="statusName" label="状态" width="80" align="center">
<template slot-scope="scope">
<el-tag :type="getDeviceStatusType(scope.row.status)" size="small">
{{ scope.row.statusName }}
</el-tag>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
<!-- OEE详情 -->
<el-col :span="12">
<el-card class="detail-card" shadow="hover">
<div slot="header" class="card-header">
<span><i class="el-icon-data-analysis"></i> 设备OEE详情</span>
</div>
<el-table :data="oeeSummary.deviceOeeDetails" size="small" max-height="300" stripe>
<el-table-column prop="deviceCode" label="设备编码" width="120" />
<el-table-column prop="deviceName" label="设备名称" min-width="120" show-overflow-tooltip />
<el-table-column prop="oee" label="OEE%" width="80" align="center">
<template slot-scope="scope">
<span :class="getOeeClass(scope.row.oee)">{{ scope.row.oee }}%</span>
</template>
</el-table-column>
<el-table-column prop="availability" label="可用率%" width="80" align="center" />
<el-table-column prop="performance" label="性能%" width="70" align="center" />
<el-table-column prop="quality" label="良率%" width="70" align="center" />
</el-table>
</el-card>
</el-col>
</el-row>
<el-row :gutter="16" style="margin-top: 16px;">
<!-- 产线任务完成情况 -->
<el-col :span="12">
<el-card class="detail-card" shadow="hover">
<div slot="header" class="card-header">
<span><i class="el-icon-document-checked"></i> 产线任务完成情况</span>
</div>
<el-table :data="taskCompletion.lineCompletions" size="small" max-height="300" stripe>
<el-table-column prop="productLineName" label="产线" min-width="120" show-overflow-tooltip />
<el-table-column prop="planAmount" label="计划数" width="90" align="center" />
<el-table-column prop="completeAmount" label="完成数" width="90" align="center" />
<el-table-column prop="completionRate" label="完成率" width="120" align="center">
<template slot-scope="scope">
<el-progress
:percentage="Math.min(scope.row.completionRate, 100)"
:color="getProgressColor(scope.row.completionRate)"
:stroke-width="16"
:text-inside="true"
/>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
<!-- 产线利用率 -->
<el-col :span="12">
<el-card class="detail-card" shadow="hover">
<div slot="header" class="card-header">
<span><i class="el-icon-odometer"></i> 产线利用率</span>
<span class="header-extra">整体利用率{{ utilizationSummary.overallUtilization }}%</span>
</div>
<el-table :data="utilizationSummary.lineUtilizations" size="small" max-height="300" stripe>
<el-table-column prop="productLineName" label="产线" min-width="120" show-overflow-tooltip />
<el-table-column prop="runningMinutes" label="运行(分钟)" width="100" align="center" />
<el-table-column prop="plannedMinutes" label="计划(分钟)" width="100" align="center" />
<el-table-column prop="utilization" label="利用率" width="120" align="center">
<template slot-scope="scope">
<el-progress
:percentage="Math.min(scope.row.utilization, 100)"
:color="getUtilizationColor(scope.row.utilization)"
:stroke-width="16"
:text-inside="true"
/>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
</el-row>
<el-row :gutter="16" style="margin-top: 16px;">
<!-- 产线品质数据 -->
<el-col :span="12">
<el-card class="detail-card" shadow="hover">
<div slot="header" class="card-header">
<span><i class="el-icon-trophy"></i> 产线品质数据</span>
<span class="header-extra">本月良品率{{ qualitySummary.monthYieldRate }}%</span>
</div>
<el-table :data="qualitySummary.lineQualities" size="small" max-height="300" stripe>
<el-table-column prop="productLineName" label="产线" min-width="120" show-overflow-tooltip />
<el-table-column prop="output" label="产量" width="80" align="center" />
<el-table-column prop="goodCount" label="良品" width="80" align="center" />
<el-table-column prop="defectCount" label="不良" width="80" align="center">
<template slot-scope="scope">
<span :class="{ 'defect-highlight': scope.row.defectCount > 0 }">
{{ scope.row.defectCount }}
</span>
</template>
</el-table-column>
<el-table-column prop="yieldRate" label="良品率" width="100" align="center">
<template slot-scope="scope">
<span :class="getYieldClass(scope.row.yieldRate)">{{ scope.row.yieldRate }}%</span>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
<!-- 安灯事件类型统计 -->
<el-col :span="12">
<el-card class="detail-card" shadow="hover">
<div slot="header" class="card-header">
<span><i class="el-icon-pie-chart"></i> 安灯事件类型统计</span>
</div>
<el-table :data="andonEvents.eventTypeStats" size="small" max-height="300" stripe>
<el-table-column prop="callTypeCode" label="类型编码" width="120" />
<el-table-column prop="callTypeName" label="类型名称" min-width="120" show-overflow-tooltip />
<el-table-column prop="count" label="总数" width="80" align="center" />
<el-table-column prop="pendingCount" label="待处理" width="80" align="center">
<template slot-scope="scope">
<span :class="{ 'pending-highlight': scope.row.pendingCount > 0 }">
{{ scope.row.pendingCount }}
</span>
</template>
</el-table-column>
<el-table-column prop="resolvedCount" label="已解决" width="80" align="center" />
</el-table>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import { getDashboardData } from "@/api/production/andonDashboard";
import { findProductLineList } from "@/api/base/productLine";
export default {
name: "AndonDashboard",
data() {
return {
productLineCode: '',
productLineList: [],
updateTime: '',
loading: false,
//
deviceStatus: {
totalDevices: 0,
runningDevices: 0,
stoppedDevices: 0,
faultDevices: 0,
idleDevices: 0,
deviceDetails: []
},
//
taskCompletion: {
todayPlanAmount: 0,
todayCompleteAmount: 0,
todayCompletionRate: 0,
monthPlanAmount: 0,
monthCompleteAmount: 0,
monthCompletionRate: 0,
lineCompletions: []
},
// OEE
oeeSummary: {
overallOee: 0,
availability: 0,
performance: 0,
quality: 0,
plannedTimeMinutes: 0,
downtimeMinutes: 0,
deviceOeeDetails: []
},
//
utilizationSummary: {
overallUtilization: 0,
lineUtilizations: []
},
//
qualitySummary: {
todayOutput: 0,
todayGoodCount: 0,
todayDefectCount: 0,
todayYieldRate: 0,
monthYieldRate: 0,
lineQualities: []
},
//
andonEvents: {
todayTotal: 0,
pendingCount: 0,
processingCount: 0,
resolvedCount: 0,
avgResponseMinutes: 0,
avgResolveMinutes: 0,
eventTypeStats: []
}
};
},
created() {
this.loadProductLines();
this.loadData();
},
beforeDestroy() {
},
methods: {
loadProductLines() {
findProductLineList().then(res => {
this.productLineList = res.data || res.rows || [];
});
},
loadData() {
this.loading = true;
getDashboardData(this.productLineCode).then(res => {
if (res.data) {
const data = res.data;
if (data.deviceStatusSummary) {
this.deviceStatus = data.deviceStatusSummary;
}
if (data.taskCompletionSummary) {
this.taskCompletion = data.taskCompletionSummary;
}
if (data.oeeSummary) {
this.oeeSummary = data.oeeSummary;
}
if (data.utilizationSummary) {
this.utilizationSummary = data.utilizationSummary;
}
if (data.qualitySummary) {
this.qualitySummary = data.qualitySummary;
}
if (data.andonEventSummary) {
this.andonEvents = data.andonEventSummary;
}
}
this.updateTime = this.formatTime(new Date());
this.loading = false;
}).catch(() => {
this.loading = false;
});
},
formatTime(date) {
const y = date.getFullYear();
const m = String(date.getMonth() + 1).padStart(2, '0');
const d = String(date.getDate()).padStart(2, '0');
const h = String(date.getHours()).padStart(2, '0');
const min = String(date.getMinutes()).padStart(2, '0');
const s = String(date.getSeconds()).padStart(2, '0');
return `${y}-${m}-${d} ${h}:${min}:${s}`;
},
getDeviceStatusType(status) {
switch (status) {
case 1: return 'success';
case 0: return 'info';
case 2: return 'danger';
case 3: return 'warning';
default: return 'info';
}
},
getOeeClass(oee) {
if (oee >= 85) return 'oee-excellent';
if (oee >= 70) return 'oee-good';
if (oee >= 50) return 'oee-normal';
return 'oee-low';
},
getYieldClass(rate) {
if (rate >= 98) return 'yield-excellent';
if (rate >= 95) return 'yield-good';
if (rate >= 90) return 'yield-normal';
return 'yield-low';
},
getProgressColor(rate) {
if (rate >= 100) return '#67C23A';
if (rate >= 80) return '#409EFF';
if (rate >= 60) return '#E6A23C';
return '#F56C6C';
},
getUtilizationColor(rate) {
if (rate >= 85) return '#67C23A';
if (rate >= 70) return '#409EFF';
if (rate >= 50) return '#E6A23C';
return '#F56C6C';
},
//
safe(val) {
if (val === null || val === undefined || val === '') return 0;
//
return isNaN(Number(val)) ? val : Number(val);
},
//
formatPercent(val) {
const num = Number(val);
if (isNaN(num)) return 0;
return Number(num.toFixed(2));
}
}
};
</script>
<style scoped>
.dashboard-container {
padding: 16px;
background: #f0f2f5;
min-height: calc(100vh - 84px);
}
.filter-card {
margin-bottom: 16px;
}
.update-time {
color: #909399;
font-size: 12px;
}
.stat-row {
margin-bottom: 16px;
}
.stat-card {
min-height: 140px;
display: flex;
align-items: flex-start;
padding: 16px 20px;
border-radius: 8px;
transition: transform 0.3s, box-shadow 0.3s;
}
.stat-card:hover {
transform: translateY(-4px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.stat-icon {
width: 60px;
height: 60px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 16px;
flex-shrink: 0;
}
.stat-icon i {
font-size: 28px;
color: #fff;
}
.device-card .stat-icon { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }
.task-card .stat-icon { background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%); }
.oee-card .stat-icon { background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); }
.quality-card .stat-icon { background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); }
.stat-content {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
gap: 6px;
}
.stat-title {
font-size: 14px;
color: #909399;
}
.stat-value {
font-size: 28px;
font-weight: bold;
color: #303133;
line-height: 1.2;
}
.stat-desc {
font-size: 12px;
color: #909399;
line-height: 1.4;
word-break: keep-all;
}
.stat-desc .running { color: #67C23A; margin-right: 8px; }
.stat-desc .fault { color: #F56C6C; margin-right: 8px; }
.stat-desc .stopped { color: #909399; }
.andon-stat-card {
border-radius: 8px;
}
.card-header {
display: flex;
align-items: center;
justify-content: space-between;
font-weight: bold;
}
.card-header i {
margin-right: 8px;
}
.header-extra {
font-size: 14px;
color: #409EFF;
font-weight: normal;
}
.andon-stat-item {
text-align: center;
padding: 16px 0;
}
.andon-stat-label {
font-size: 14px;
color: #909399;
margin-bottom: 8px;
}
.andon-stat-value {
font-size: 24px;
font-weight: bold;
color: #303133;
}
.andon-stat-value.total { color: #409EFF; }
.andon-stat-value.pending { color: #F56C6C; }
.andon-stat-value.processing { color: #E6A23C; }
.andon-stat-value.resolved { color: #67C23A; }
.detail-card {
border-radius: 8px;
}
.oee-excellent { color: #67C23A; font-weight: bold; }
.oee-good { color: #409EFF; font-weight: bold; }
.oee-normal { color: #E6A23C; font-weight: bold; }
.oee-low { color: #F56C6C; font-weight: bold; }
.yield-excellent { color: #67C23A; font-weight: bold; }
.yield-good { color: #409EFF; font-weight: bold; }
.yield-normal { color: #E6A23C; font-weight: bold; }
.yield-low { color: #F56C6C; font-weight: bold; }
.defect-highlight {
color: #F56C6C;
font-weight: bold;
}
.pending-highlight {
color: #F56C6C;
font-weight: bold;
}
</style>

@ -642,21 +642,21 @@ export default {
{ key: 0, label: `主键ID`, visible: false },
{ key: 1, label: `安灯呼叫单号`, visible: true },
{ key: 2, label: `呼叫类型编码`, visible: true },
{ key: 3, label: `触发源类型`, visible: true },
{ key: 3, label: `触发源类型`, visible: false },
{ key: 4, label: `触发源引用ID`, visible: false },
{ key: 5, label: `产品线编码`, visible: true },
{ key: 6, label: `工位/工序编码`, visible: true },
{ key: 7, label: `班组编码`, visible: true },
{ key: 8, label: `工单号`, visible: true },
{ key: 9, label: `物料编码`, visible: true },
{ key: 7, label: `班组编码`, visible: false },
{ key: 8, label: `工单号`, visible: false },
{ key: 9, label: `物料编码`, visible: false },
{ key: 10, label: `设备ID`, visible: false },
{ key: 11, label: `设备编码`, visible: true },
{ key: 11, label: `设备编码`, visible: false },
{ key: 12, label: `优先级`, visible: true },
{ key: 13, label: `事件状态`, visible: true },
{ key: 14, label: `呼叫描述`, visible: true },
{ key: 13, label: `事件状态`, visible: false },
{ key: 14, label: `呼叫描述`, visible: false },
{ key: 15, label: `确认人`, visible: true },
{ key: 16, label: `确认时间`, visible: true },
{ key: 17, label: `开始处理时间`, visible: true },
{ key: 17, label: `开始处理时间`, visible: false },
{ key: 18, label: `处理完成/解决时间`, visible: true },
{ key: 19, label: `处理/解决措施`, visible: true },
{ key: 20, label: `取消原因`, visible: false },
@ -664,7 +664,7 @@ export default {
{ key: 22, label: `升级时间`, visible: false },
{ key: 23, label: `确认截止时间`, visible: false },
{ key: 24, label: `解决截止时间`, visible: false },
{ key: 25, label: `是否有效`, visible: true },
{ key: 25, label: `是否有效`, visible: false },
{ key: 26, label: `备注`, visible: true },
{ key: 27, label: `创建人`, visible: false },
{ key: 28, label: `创建时间`, visible: false },

@ -77,6 +77,9 @@
placeholder="请选择完成时间">
</el-date-picker>
</el-form-item>-->
<el-form-item label="只看我的" prop="onlyMine">
<el-switch v-model="onlyMine" @change="handleOnlyMineChange" />
</el-form-item>
<el-form-item label="派工状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择派工状态" clearable>
<el-option
@ -152,7 +155,7 @@
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="andonEventAssignmentList" @selection-change="handleSelectionChange">
<el-table v-loading="loading" :data="andonEventAssignmentList" @selection-change="handleSelectionChange" :row-class-name="tableRowClassName">
<el-table-column type="selection" width="55" align="center" />
<!-- 隐藏主键列减少干扰 -->
<el-table-column label="主键ID" align="center" prop="assignmentId" v-if="columns[0].visible"/>
@ -211,54 +214,26 @@
@pagination="getList"
/>
<!-- 添加或修改安灯派工记录派工即通知/待办对话框 -->
<!-- 添加或修改安灯派工记录对话框只允许修改状态和备注 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<!-- 事件ID改为下拉选择不分页 -->
<el-form-item label="事件ID" prop="eventId">
<el-select v-model="form.eventId" placeholder="请选择事件">
<el-option
v-for="evt in eventOptions"
:key="evt.eventId"
:label="(evt.callCode || ('事件#' + evt.eventId)) + (evt.stationCode ? (' - ' + evt.stationCode) : '')"
:value="evt.eventId"
/>
</el-select>
<el-form-item label="呼叫单号" prop="callCode">
<span class="form-value">{{ getCallCodeByEventId(form.eventId) }}</span>
</el-form-item>
<el-form-item label="被分配用户" prop="assigneeUserId">
<el-select v-model="form.assigneeUserId" placeholder="请选择用户" @change="onAssigneeChange">
<el-option
v-for="u in userOptions"
:key="u.userId"
:label="u.nickName || u.userName || String(u.userId)"
:value="u.userId"
/>
</el-select>
<el-form-item label="工位" prop="stationCode">
<span class="form-value">{{ getStationNameByCode(form.stationCode) }}</span>
</el-form-item>
<el-form-item label="被分配用户姓名" prop="assigneeUserName">
<el-input v-model="form.assigneeUserName" placeholder="请输入被分配用户姓名" />
</el-form-item>
<el-form-item label="被分配角色编码" prop="assigneeRoleKey">
<el-input v-model="form.assigneeRoleKey" placeholder="请输入被分配角色编码" />
</el-form-item>
<el-form-item label="被分配班组编码" prop="assigneeTeamCode">
<el-input v-model="form.assigneeTeamCode" placeholder="请输入被分配班组编码" />
<el-form-item label="分配用户" prop="assigneeUserName">
<span class="form-value">{{ form.assigneeUserName || '-' }}</span>
</el-form-item>
<el-form-item label="分配时间" prop="assignedTime">
<el-date-picker clearable
v-model="form.assignedTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择分配时间">
</el-date-picker>
<span class="form-value">{{ form.assignedTime ? parseTime(form.assignedTime, '{y}-{m}-{d} {h}:{i}:{s}') : '-' }}</span>
</el-form-item>
<!-- 接单时间改为只读展示后端自动维护 -->
<el-form-item label="接单时间">
<span>{{ form.acceptTime ? parseTime(form.acceptTime, '{y}-{m}-{d} {h}:{i}:{s}') : '后端自动维护' }}</span>
<el-form-item label="接单时间" prop="acceptTime">
<span class="form-value">{{ form.acceptTime ? parseTime(form.acceptTime, '{y}-{m}-{d} {h}:{i}:{s}') : '-' }}</span>
</el-form-item>
<!-- 完成时间改为只读展示后端自动维护 -->
<el-form-item label="完成时间">
<span>{{ form.finishTime ? parseTime(form.finishTime, '{y}-{m}-{d} {h}:{i}:{s}') : '后端自动维护' }}</span>
<el-form-item label="完成时间" prop="finishTime">
<span class="form-value">{{ form.finishTime ? parseTime(form.finishTime, '{y}-{m}-{d} {h}:{i}:{s}') : '-' }}</span>
</el-form-item>
<el-form-item label="派工状态" prop="status">
<el-select v-model="form.status" placeholder="请选择派工状态">
@ -270,9 +245,6 @@
></el-option>
</el-select>
</el-form-item>
<el-form-item label="是否有效" prop="isFlag">
<el-input v-model="form.isFlag" placeholder="请输入是否有效" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
@ -289,6 +261,7 @@
import { listAndonEventAssignment, getAndonEventAssignment, delAndonEventAssignment, addAndonEventAssignment, updateAndonEventAssignment } from "@/api/production/andonEventAssignment";
import { getAndonEventList } from "@/api/production/andonEvent";
import { selectUserList } from "@/api/system/user";
import { findProductLineList } from "@/api/base/productLine";
export default {
name: "AndonEventAssignment",
@ -311,8 +284,14 @@ export default {
andonEventAssignmentList: [],
//
eventOptions: [],
//
stationOptions: [],
//
userOptions: [],
//
onlyMine: true,
// ID
currentUserId: null,
//
defaultUserId: null,
defaultUserName: null,
@ -350,14 +329,14 @@ export default {
{ key: 0, label: `主键ID`, visible: false },
{ key: 1, label: `事件ID`, visible: false },
{ key: 2, label: `被分配用户ID`, visible: false },
{ key: 3, label: `被分配用户姓名`, visible: true },
{ key: 4, label: `被分配角色编码`, visible: true },
{ key: 5, label: `被分配班组编码`, visible: true },
{ key: 3, label: `被分配用户姓名`, visible: false },
{ key: 4, label: `被分配角色编码`, visible: false },
{ key: 5, label: `被分配班组编码`, visible: false },
{ key: 6, label: `分配时间`, visible: true },
{ key: 7, label: `接单时间`, visible: true },
{ key: 8, label: `完成时间`, visible: true },
{ key: 9, label: `派工状态`, visible: true },
{ key: 10, label: `是否有效`, visible: true },
{ key: 10, label: `是否有效`, visible: false },
{ key: 11, label: `备注`, visible: true },
{ key: 12, label: `创建人`, visible: false },
{ key: 13, label: `创建时间`, visible: false },
@ -367,6 +346,12 @@ export default {
};
},
created() {
// ID
this.currentUserId = this.$store.getters.userId;
//
if (this.onlyMine && this.currentUserId) {
this.queryParams.assigneeUserId = this.currentUserId;
}
this.getList();
//
getAndonEventList({ isFlag: '1' }).then(res => {
@ -381,6 +366,10 @@ export default {
this.defaultUserName = u.nickName || u.userName || String(u.userId);
}
});
//
findProductLineList({ productLineType: 2 }).then(res => {
this.stationOptions = res.rows || res.data || [];
});
},
methods: {
/** 查询安灯派工记录(派工即通知/待办)列表 */
@ -392,6 +381,25 @@ export default {
this.loading = false;
});
},
/** 切换“只看我的”开关 */
handleOnlyMineChange(val) {
if (val && this.currentUserId) {
this.queryParams.assigneeUserId = this.currentUserId;
} else {
this.queryParams.assigneeUserId = null;
}
this.handleQuery();
},
/** 表格行样式:未完成的记录高亮显示 */
tableRowClassName({ row }) {
// status: 0=, 1=, 2=, 3=
if (row.status === '0' || row.status === 0) {
return 'warning-row'; // -
} else if (row.status === '1' || row.status === 1) {
return 'info-row'; //
}
return '';
},
//
cancel() {
this.open = false;
@ -494,7 +502,36 @@ export default {
this.download('production/andonEventAssignment/export', {
...this.queryParams
}, `andonEventAssignment_${new Date().getTime()}.xlsx`)
},
/** 根据事件ID获取呼叫单号 */
getCallCodeByEventId(eventId) {
if (!eventId) return '-';
const event = this.eventOptions.find(e => e.eventId === eventId);
return event ? event.callCode || '-' : '-';
},
/** 根据工位编码获取工位名称 */
getStationNameByCode(stationCode) {
if (!stationCode) return '-';
const station = this.stationOptions ? this.stationOptions.find(s => s.stationCode === stationCode) : null;
return station ? station.stationName : stationCode;
}
}
};
</script>
<style scoped>
/* 待接单记录高亮 - 红色背景 */
::v-deep .el-table .warning-row {
background-color: #fef0f0 !important;
}
::v-deep .el-table .warning-row:hover > td {
background-color: #fde2e2 !important;
}
/* 处理中记录 - 蓝色背景 */
::v-deep .el-table .info-row {
background-color: #f0f9eb !important;
}
::v-deep .el-table .info-row:hover > td {
background-color: #e1f3d8 !important;
}
</style>

@ -139,56 +139,40 @@
@pagination="getList"
/>
<!-- 添加或修改安灯规则配置对话框 -->
<!-- 添加或修改安灯规则配置对话框简化版PDA绑定工位触发安灯 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="规则名称" prop="ruleName" label-width="100px">
<el-input v-model="form.ruleName" placeholder="请输入规则名称" />
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-alert
title="手持PDA绑定工位后点击安灯按钮将自动匹配此规则并派工给通知用户"
type="info"
:closable="false"
style="margin-bottom: 15px;"
/>
<el-form-item label="规则名称" prop="ruleName">
<el-input v-model="form.ruleName" placeholder="请输入规则名称,如:装配工位-设备故障" />
</el-form-item>
<el-form-item label="呼叫类型编码" prop="callTypeCode" label-width="120px">
<el-input v-model="form.callTypeCode" placeholder="请输入呼叫类型编码" />
</el-form-item>
<el-form-item label="适用产线" prop="productLineCode"label-width="100px">
<el-select v-model="form.productLineCode" placeholder="请选择产线" clearable>
<el-option
v-for="item in productLineList"
:key="item.productLineCode"
:label="item.productLineName"
:value="item.productLineCode"
/>
</el-select>
</el-form-item>
<el-form-item label="适用工位/工序" prop="stationCode"label-width="100px">
<el-select v-model="form.stationCode" placeholder="请选择工位/工序" clearable>
<el-form-item label="绑定工位" prop="stationCode">
<el-select v-model="form.stationCode" placeholder="请选择绑定的工位(必填)" filterable style="width: 100%">
<el-option
v-for="item in processStationList"
:key="item.stationCode"
:label="item.stationName"
:label="item.stationName + ' (' + item.stationCode + ')'"
:value="item.stationCode"
/>
</el-select>
</el-form-item>
<el-form-item label="适用班组" prop="teamCode"label-width="100px">
<el-select v-model="form.teamCode" placeholder="请选择班组" clearable>
<el-form-item label="呼叫类型" prop="callTypeCode">
<el-select v-model="form.callTypeCode" placeholder="请选择呼叫类型">
<el-option
v-for="item in teamMembersList"
:key="item.teamCode"
:label="item.teamName"
:value="item.teamCode"
v-for="dict in dict.type.andon_call_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="确认时限(分钟)" prop="ackTimeoutMin">
<el-input-number v-model="form.ackTimeoutMin" :min="0" placeholder="请输入确认时限" style="width: 100%" />
</el-form-item>
<el-form-item label="解决时限(分钟)" prop="resolveTimeoutMin">
<el-input-number v-model="form.resolveTimeoutMin" :min="0" placeholder="请输入解决时限" style="width: 100%" />
</el-form-item>
<el-form-item label="默认优先级" prop="priorityDefault">
<el-input-number v-model="form.priorityDefault" :min="1" :max="5" placeholder="请输入默认优先级(1-5)" style="width: 100%" />
</el-form-item>
<el-form-item label="通知用户" prop="notifyUsers">
<el-select v-model="formNotifyUsersArr" multiple filterable placeholder="请选择通知用户">
<el-select v-model="formNotifyUsersArr" multiple filterable placeholder="请选择派工通知的用户(必填)">
<el-option
v-for="u in userOptions"
:key="u.userId"
@ -197,8 +181,21 @@
/>
</el-select>
</el-form-item>
<el-divider content-position="left">时限设置可选</el-divider>
<el-form-item label="确认时限" prop="ackTimeoutMin">
<el-input-number v-model="form.ackTimeoutMin" :min="0" placeholder="分钟" style="width: 100%" />
<span style="color: #909399; font-size: 12px;">接单确认的时限分钟</span>
</el-form-item>
<el-form-item label="解决时限" prop="resolveTimeoutMin">
<el-input-number v-model="form.resolveTimeoutMin" :min="0" placeholder="分钟" style="width: 100%" />
<span style="color: #909399; font-size: 12px;">问题解决的时限分钟</span>
</el-form-item>
<el-form-item label="默认优先级" prop="priorityDefault">
<el-input-number v-model="form.priorityDefault" :min="1" :max="5" style="width: 100%" />
<span style="color: #909399; font-size: 12px;">1最高5最低</span>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
@ -219,6 +216,7 @@ import { getDeviceLedgerList } from "@/api/base/deviceLedger";
export default {
name: "AndonRule",
dicts: ['andon_call_type'],
data() {
return {
//
@ -275,37 +273,40 @@ export default {
},
//
form: {},
//
//
rules: {
ruleName: [
{ required: true, message: "规则名称不能为空", trigger: "blur" }
],
stationCode: [
{ required: true, message: "请选择绑定的工位", trigger: "change" }
],
callTypeCode: [
{ required: true, message: "呼叫类型编码不能为空", trigger: "blur" }
{ required: true, message: "请选择呼叫类型", trigger: "change" }
]
},
columns: [
{ key: 0, label: `主键ID`, visible: false },
{ key: 1, label: `规则名称`, visible: true },
{ key: 2, label: `呼叫类型编码`, visible: true },
{ key: 3, label: `适用产线编码`, visible: true },
{ key: 3, label: `适用产线编码`, visible: false },
{ key: 4, label: `适用工位/工序编码`, visible: true },
{ key: 5, label: `适用班组编码`, visible: true },
{ key: 6, label: `限定触发源类型`, visible: true },
{ key: 5, label: `适用班组编码`, visible: false },
{ key: 6, label: `限定触发源类型`, visible: false },
{ key: 7, label: `确认时限`, visible: true },
{ key: 8, label: `解决时限`, visible: true },
{ key: 9, label: `默认优先级`, visible: true },
{ key: 10, label: `通知角色`, visible: true },
{ key: 10, label: `通知角色`, visible: false },
{ key: 11, label: `通知用户`, visible: true },
{ key: 12, label: `升级链`, visible: true },
{ key: 13, label: `生效开始时间`, visible: true },
{ key: 14, label: `生效结束时间`, visible: true },
{ key: 15, label: `是否有效`, visible: true },
{ key: 12, label: `升级链`, visible: false },
{ key: 13, label: `生效开始时间`, visible: false },
{ key: 14, label: `生效结束时间`, visible: false },
{ key: 15, label: `是否有效`, visible: false },
{ key: 16, label: `备注`, visible: true },
{ key: 17, label: `创建人`, visible: true },
{ key: 18, label: `创建时间`, visible: true },
{ key: 19, label: `更新人`, visible: true },
{ key: 20, label: `更新时间`, visible: true },
{ key: 19, label: `更新人`, visible: false },
{ key: 20, label: `更新时间`, visible: false },
]
};
},
@ -443,7 +444,7 @@ export default {
return ids.map(id => nameMap.get(String(id)) || id).join(', ');
},
/** 删除按钮操作 */
handleDelete(row) {
handleDelete(row) {listProcessStation
const ruleIds = row.ruleId || this.ids;
this.$modal.confirm('是否确认删除安灯规则配置编号为"' + ruleIds + '"的数据项?').then(function() {
return delAndonRule(ruleIds);
@ -468,7 +469,7 @@ export default {
},
/** 加载工位/工序下拉选项 */
loadProcessStations() {
listProcessStation({}).then(res => {
findProductLineList({ productLineType: 2 }).then(res => {
this.processStationList = res.data || res.rows || [];
}).catch(() => {
this.processStationList = [];

@ -0,0 +1,749 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
<el-form-item label="年第周" prop="yearWeek">
<el-input
v-model="queryParams.yearWeek"
placeholder="如202501"
clearable
style="width: 120px"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="周一日期" prop="weekStartDate">
<el-date-picker clearable
v-model="queryParams.weekStartDate"
type="date"
value-format="yyyy-MM-dd"
style="width: 150px"
:picker-options="mondayPickerOptions"
placeholder="选择周一日期">
</el-date-picker>
</el-form-item>
<el-form-item label="编码" prop="itemCode">
<el-input
v-model="queryParams.itemCode"
placeholder="请输入编码"
clearable
style="width: 130px"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="订单号" prop="orderNo">
<el-input
v-model="queryParams.orderNo"
placeholder="请输入订单号"
clearable
style="width: 130px"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="工厂" prop="plantCode">
<el-input
v-model="queryParams.plantCode"
placeholder="请输入工厂"
clearable
style="width: 100px"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['production:plan:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['production:plan:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['production:plan:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="el-icon-upload2"
size="mini"
@click="handleImport"
v-hasPermi="['production:plan:import']"
>导入</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="openExportDialog"
v-hasPermi="['production:plan:export']"
>导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-check"
size="mini"
:disabled="!hasChanges"
@click="handleBatchSave"
v-hasPermi="['production:plan:edit']"
>保存修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-document-copy"
size="mini"
:disabled="multiple"
@click="openBatchFillDialog"
v-hasPermi="['production:plan:edit']"
>批量填充</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="planList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="年第周" align="center" prop="yearWeek" width="90" v-if="columns[0].visible"/>
<el-table-column label="周一日期" align="center" prop="weekStartDate" width="110" v-if="columns[1].visible">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.weekStartDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="序号" align="center" prop="seqNo" width="60" v-if="columns[2].visible"/>
<el-table-column label="编码" align="center" prop="itemCode" width="110" v-if="columns[3].visible"/>
<el-table-column label="描述" align="center" prop="itemDesc" min-width="150" :show-overflow-tooltip="true" v-if="columns[4].visible"/>
<el-table-column label="工厂" align="center" prop="plantCode" width="70" v-if="columns[5].visible"/>
<el-table-column label="订单号" align="center" prop="orderNo" width="90" v-if="columns[6].visible"/>
<el-table-column label="行号" align="center" prop="orderLineNo" width="60" v-if="columns[7].visible"/>
<el-table-column label="1日" align="center" width="80" v-if="columns[8].visible">
<template slot-scope="scope">
<el-input-number v-model="scope.row.planD1" :min="0" :precision="0" :controls="false" size="mini" style="width: 60px" :class="{'changed-cell': changedIds.has(scope.row.id)}" @change="markChanged(scope.row)" />
</template>
</el-table-column>
<el-table-column label="2日" align="center" width="80" v-if="columns[9].visible">
<template slot-scope="scope">
<el-input-number v-model="scope.row.planD2" :min="0" :precision="0" :controls="false" size="mini" style="width: 60px" :class="{'changed-cell': changedIds.has(scope.row.id)}" @change="markChanged(scope.row)" />
</template>
</el-table-column>
<el-table-column label="3日" align="center" width="80" v-if="columns[10].visible">
<template slot-scope="scope">
<el-input-number v-model="scope.row.planD3" :min="0" :precision="0" :controls="false" size="mini" style="width: 60px" :class="{'changed-cell': changedIds.has(scope.row.id)}" @change="markChanged(scope.row)" />
</template>
</el-table-column>
<el-table-column label="4日" align="center" width="80" v-if="columns[11].visible">
<template slot-scope="scope">
<el-input-number v-model="scope.row.planD4" :min="0" :precision="0" :controls="false" size="mini" style="width: 60px" :class="{'changed-cell': changedIds.has(scope.row.id)}" @change="markChanged(scope.row)" />
</template>
</el-table-column>
<el-table-column label="5日" align="center" width="80" v-if="columns[12].visible">
<template slot-scope="scope">
<el-input-number v-model="scope.row.planD5" :min="0" :precision="0" :controls="false" size="mini" style="width: 60px" :class="{'changed-cell': changedIds.has(scope.row.id)}" @change="markChanged(scope.row)" />
</template>
</el-table-column>
<el-table-column label="6日" align="center" width="80" v-if="columns[13].visible">
<template slot-scope="scope">
<el-input-number v-model="scope.row.planD6" :min="0" :precision="0" :controls="false" size="mini" style="width: 60px" :class="{'changed-cell': changedIds.has(scope.row.id)}" @change="markChanged(scope.row)" />
</template>
</el-table-column>
<el-table-column label="7日" align="center" width="80" v-if="columns[14].visible">
<template slot-scope="scope">
<el-input-number v-model="scope.row.planD7" :min="0" :precision="0" :controls="false" size="mini" style="width: 60px" :class="{'changed-cell': changedIds.has(scope.row.id)}" @change="markChanged(scope.row)" />
</template>
</el-table-column>
<el-table-column label="周合计" align="center" width="80" v-if="columns[15].visible">
<template slot-scope="scope">
<span>{{ calcRowTotal(scope.row) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="120" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['production:plan:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['production:plan:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改周排产计划对话框 -->
<el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="90px">
<el-row>
<el-col :span="8">
<el-form-item label="年第周" prop="yearWeek">
<el-input v-model="form.yearWeek" placeholder="如202501" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="周一日期" prop="weekStartDate">
<el-date-picker clearable
v-model="form.weekStartDate"
type="date"
value-format="yyyy-MM-dd"
style="width: 100%"
placeholder="选择周一日期">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="序号" prop="seqNo">
<el-input-number v-model="form.seqNo" :min="1" controls-position="right" style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="编码" prop="itemCode">
<el-input v-model="form.itemCode" placeholder="请输入编码" />
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="描述" prop="itemDesc">
<el-input v-model="form.itemDesc" placeholder="请输入描述" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="工厂" prop="plantCode">
<el-input v-model="form.plantCode" placeholder="请输入工厂" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="订单号" prop="orderNo">
<el-input v-model="form.orderNo" placeholder="请输入订单号" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="行号" prop="orderLineNo">
<el-input v-model="form.orderLineNo" placeholder="请输入行号" />
</el-form-item>
</el-col>
</el-row>
<el-divider content-position="left">每日计划量</el-divider>
<el-row>
<el-col :span="6">
<el-form-item label="1日" prop="planD1" label-width="40px">
<el-input-number v-model="form.planD1" :min="0" controls-position="right" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="2日" prop="planD2" label-width="40px">
<el-input-number v-model="form.planD2" :min="0" controls-position="right" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="3日" prop="planD3" label-width="40px">
<el-input-number v-model="form.planD3" :min="0" controls-position="right" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="4日" prop="planD4" label-width="40px">
<el-input-number v-model="form.planD4" :min="0" controls-position="right" style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="6">
<el-form-item label="5日" prop="planD5" label-width="40px">
<el-input-number v-model="form.planD5" :min="0" controls-position="right" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="6日" prop="planD6" label-width="40px">
<el-input-number v-model="form.planD6" :min="0" controls-position="right" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="7日" prop="planD7" label-width="40px">
<el-input-number v-model="form.planD7" :min="0" controls-position="right" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="合计" label-width="40px">
<el-input :value="weekTotal" disabled style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 导入对话框 -->
<el-dialog :title="upload.title" :visible.sync="upload.open" width="450px" append-to-body>
<el-form label-width="100px">
<el-form-item label="周一日期" required>
<el-date-picker
v-model="upload.weekStartDate"
type="date"
value-format="yyyy-MM-dd"
:picker-options="mondayPickerOptions"
placeholder="请选择周一日期"
style="width: 100%"
/>
</el-form-item>
</el-form>
<el-upload
ref="upload"
:limit="1"
accept=".xlsx, .xls"
:headers="upload.headers"
:action="upload.url"
:data="{ weekStartDate: upload.weekStartDate }"
:disabled="upload.isUploading"
:on-progress="handleFileUploadProgress"
:on-success="handleFileSuccess"
:auto-upload="false"
drag
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<div class="el-upload__tip text-center" slot="tip">
<span>仅允许导入xlsxlsx格式文件</span>
<el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;" @click="importTemplate"></el-link>
</div>
</el-upload>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitFileForm"> </el-button>
<el-button @click="upload.open = false"> </el-button>
</div>
</el-dialog>
<!-- 导出对话框 -->
<el-dialog title="导出周排产计划" :visible.sync="exportOpen" width="450px" append-to-body>
<el-form label-width="100px">
<el-form-item label="开始周一" required>
<el-date-picker
v-model="exportParams.startDate"
type="date"
value-format="yyyy-MM-dd"
:picker-options="mondayPickerOptions"
placeholder="选择开始周一日期"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="结束周一" required>
<el-date-picker
v-model="exportParams.endDate"
type="date"
value-format="yyyy-MM-dd"
:picker-options="mondayPickerOptions"
placeholder="选择结束周一日期"
style="width: 100%"
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="handleExport"> </el-button>
<el-button @click="exportOpen = false"> </el-button>
</div>
</el-dialog>
<!-- 批量填充对话框 -->
<el-dialog title="批量填充" :visible.sync="batchFillOpen" width="400px" append-to-body>
<el-form label-width="100px">
<el-form-item label="已选行数">
<span class="el-tag el-tag--info">{{ selectedRows.length }} </span>
</el-form-item>
<el-form-item label="填充列" required>
<el-checkbox-group v-model="batchFill.columns">
<el-checkbox label="planD1">1</el-checkbox>
<el-checkbox label="planD2">2</el-checkbox>
<el-checkbox label="planD3">3</el-checkbox>
<el-checkbox label="planD4">4</el-checkbox>
<el-checkbox label="planD5">5</el-checkbox>
<el-checkbox label="planD6">6</el-checkbox>
<el-checkbox label="planD7">7</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="填充数值" required>
<el-input-number v-model="batchFill.value" :min="0" :precision="0" controls-position="right" style="width: 100%" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="handleBatchFill"> </el-button>
<el-button @click="batchFillOpen = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listPlan, getPlan, delPlan, addPlan, updatePlan, batchUpdatePlan } from "@/api/production/plan";
import { getToken } from "@/utils/auth";
export default {
name: "Plan",
data() {
return {
//
loading: true,
//
ids: [],
//
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//
planList: [],
// ID
changedIds: new Set(),
//
title: "",
//
open: false,
//
exportOpen: false,
//
exportParams: {
startDate: null,
endDate: null
},
//
batchFillOpen: false,
//
batchFill: {
columns: [],
value: 0
},
//
selectedRows: [],
//
mondayPickerOptions: {
disabledDate(time) {
return time.getDay() !== 1;
}
},
//
queryParams: {
pageNum: 1,
pageSize: 10,
yearWeek: null,
weekStartDate: null,
itemCode: null,
orderNo: null,
plantCode: null
},
//
form: {},
//
rules: {
yearWeek: [
{ required: true, message: "年第周不能为空", trigger: "blur" }
],
weekStartDate: [
{ required: true, message: "周一日期不能为空", trigger: "blur" }
],
itemCode: [
{ required: true, message: "编码不能为空", trigger: "blur" }
],
},
//
upload: {
open: false,
title: "周排产计划导入",
isUploading: false,
weekStartDate: null,
headers: { Authorization: "Bearer " + getToken() },
url: process.env.VUE_APP_BASE_API + "/production/plan/importData"
},
columns: [
{ key: 0, label: `年第周`, visible: true },
{ key: 1, label: `周一日期`, visible: true },
{ key: 2, label: `序号`, visible: true },
{ key: 3, label: `编码`, visible: true },
{ key: 4, label: `描述`, visible: true },
{ key: 5, label: `工厂`, visible: true },
{ key: 6, label: `订单号`, visible: true },
{ key: 7, label: `行号`, visible: true },
{ key: 8, label: `1日`, visible: true },
{ key: 9, label: `2日`, visible: true },
{ key: 10, label: `3日`, visible: true },
{ key: 11, label: `4日`, visible: true },
{ key: 12, label: `5日`, visible: true },
{ key: 13, label: `6日`, visible: true },
{ key: 14, label: `7日`, visible: true },
{ key: 15, label: `周合计`, visible: true },
]
};
},
computed: {
weekTotal() {
return (this.form.planD1 || 0) + (this.form.planD2 || 0) + (this.form.planD3 || 0) +
(this.form.planD4 || 0) + (this.form.planD5 || 0) + (this.form.planD6 || 0) +
(this.form.planD7 || 0);
},
hasChanges() {
return this.changedIds.size > 0;
}
},
created() {
this.getList();
},
methods: {
/** 查询周排产计划列表 */
getList() {
this.loading = true;
this.changedIds = new Set();
listPlan(this.queryParams).then(response => {
this.planList = response.rows;
this.total = response.total;
this.loading = false;
});
},
/** 标记行已修改 */
markChanged(row) {
// Vue 2 Set
const newSet = new Set(this.changedIds);
newSet.add(row.id);
this.changedIds = newSet;
},
/** 计算行合计 */
calcRowTotal(row) {
return (Number(row.planD1) || 0) + (Number(row.planD2) || 0) + (Number(row.planD3) || 0) +
(Number(row.planD4) || 0) + (Number(row.planD5) || 0) + (Number(row.planD6) || 0) +
(Number(row.planD7) || 0);
},
/** 批量保存修改 */
handleBatchSave() {
const changedRows = this.planList.filter(row => this.changedIds.has(row.id));
if (changedRows.length === 0) {
this.$modal.msgWarning("没有需要保存的修改");
return;
}
this.$modal.confirm('是否确认保存 ' + changedRows.length + ' 条修改的数据?').then(() => {
batchUpdatePlan(changedRows).then(response => {
this.$modal.msgSuccess(response.msg);
this.changedIds = new Set();
this.getList();
});
}).catch(() => {});
},
//
cancel() {
this.open = false;
this.reset();
},
//
reset() {
this.form = {
id: null,
yearWeek: null,
weekStartDate: null,
seqNo: 1,
itemCode: null,
itemDesc: null,
plantCode: null,
orderNo: null,
orderLineNo: null,
planD1: 0,
planD2: 0,
planD3: 0,
planD4: 0,
planD5: 0,
planD6: 0,
planD7: 0
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.selectedRows = selection
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 打开批量填充对话框 */
openBatchFillDialog() {
if (this.selectedRows.length === 0) {
this.$modal.msgWarning("请先选择要填充的行");
return;
}
this.batchFill.columns = [];
this.batchFill.value = 0;
this.batchFillOpen = true;
},
/** 执行批量填充 */
handleBatchFill() {
if (this.batchFill.columns.length === 0) {
this.$modal.msgWarning("请选择要填充的列");
return;
}
//
this.selectedRows.forEach(row => {
this.batchFill.columns.forEach(col => {
row[col] = this.batchFill.value;
});
this.markChanged(row);
});
this.batchFillOpen = false;
this.$modal.msgSuccess(`已填充 ${this.selectedRows.length} 行数据`);
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加周排产计划";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id || this.ids
getPlan(id).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改周排产计划";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.id != null) {
updatePlan(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addPlan(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids;
this.$modal.confirm('是否确认删除周排产计划编号为"' + ids + '"的数据项?').then(function() {
return delPlan(ids);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 打开导出对话框 */
openExportDialog() {
this.exportParams.startDate = null;
this.exportParams.endDate = null;
this.exportOpen = true;
},
/** 导出按钮操作 */
handleExport() {
if (!this.exportParams.startDate || !this.exportParams.endDate) {
this.$modal.msgWarning("请选择导出的时间范围");
return;
}
if (this.exportParams.startDate > this.exportParams.endDate) {
this.$modal.msgWarning("开始日期不能大于结束日期");
return;
}
this.exportOpen = false;
this.download('production/plan/export', {
...this.queryParams,
'params[beginWeekStartDate]': this.exportParams.startDate,
'params[endWeekStartDate]': this.exportParams.endDate
}, `周排产计划_${new Date().getTime()}.xlsx`)
},
/** 导入按钮操作 */
handleImport() {
this.upload.open = true;
},
/** 下载模板操作 */
importTemplate() {
this.download('production/plan/importTemplate', {}, `周排产计划模板_${new Date().getTime()}.xlsx`)
},
/** 文件上传中处理 */
handleFileUploadProgress(event, file, fileList) {
this.upload.isUploading = true;
},
/** 文件上传成功处理 */
handleFileSuccess(response, file, fileList) {
this.upload.open = false;
this.upload.isUploading = false;
this.$refs.upload.clearFiles();
this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true });
this.getList();
},
/** 提交上传文件 */
submitFileForm() {
this.$refs.upload.submit();
}
}
};
</script>
<style scoped>
.changed-cell ::v-deep .el-input__inner {
background-color: #fffbe6 !important;
border-color: #faad14 !important;
}
</style>

@ -0,0 +1,705 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="90px">
<el-form-item label="年第周" prop="yearWeek">
<el-input
v-model="queryParams.yearWeek"
placeholder="如202501"
clearable
style="width: 120px"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="周一日期" prop="weekStartDate">
<el-date-picker clearable
v-model="queryParams.weekStartDate"
type="date"
value-format="yyyy-MM-dd"
style="width: 150px"
:picker-options="mondayPickerOptions"
placeholder="选择周一日期">
</el-date-picker>
</el-form-item>
<el-form-item label="物料编码" prop="itemCode">
<el-input
v-model="queryParams.itemCode"
placeholder="请输入物料编码"
clearable
style="width: 150px"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="物料描述" prop="itemDesc">
<el-input
v-model="queryParams.itemDesc"
placeholder="请输入物料描述"
clearable
style="width: 150px"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['production:req:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['production:req:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['production:req:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="el-icon-upload2"
size="mini"
@click="handleImport"
v-hasPermi="['production:req:import']"
>导入</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="openExportDialog"
v-hasPermi="['production:req:export']"
>导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-check"
size="mini"
:disabled="!hasChanges"
@click="handleBatchSave"
v-hasPermi="['production:req:edit']"
>保存修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-document-copy"
size="mini"
:disabled="multiple"
@click="openBatchFillDialog"
v-hasPermi="['production:req:edit']"
>批量填充</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="reqList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="年第周" align="center" prop="yearWeek" width="90" v-if="columns[0].visible"/>
<el-table-column label="周一日期" align="center" prop="weekStartDate" width="110" v-if="columns[1].visible">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.weekStartDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="物料编码" align="center" prop="itemCode" width="120" v-if="columns[2].visible"/>
<el-table-column label="物料描述" align="center" prop="itemDesc" min-width="180" :show-overflow-tooltip="true" v-if="columns[3].visible"/>
<el-table-column label="周一" align="center" width="90" v-if="columns[4].visible">
<template slot-scope="scope">
<el-input-number v-model="scope.row.reqMon" :min="0" :precision="0" :controls="false" size="mini" style="width: 70px" :class="{'changed-cell': changedIds.has(scope.row.id)}" @change="markChanged(scope.row)" />
</template>
</el-table-column>
<el-table-column label="周二" align="center" width="90" v-if="columns[5].visible">
<template slot-scope="scope">
<el-input-number v-model="scope.row.reqTue" :min="0" :precision="0" :controls="false" size="mini" style="width: 70px" :class="{'changed-cell': changedIds.has(scope.row.id)}" @change="markChanged(scope.row)" />
</template>
</el-table-column>
<el-table-column label="周三" align="center" width="90" v-if="columns[6].visible">
<template slot-scope="scope">
<el-input-number v-model="scope.row.reqWed" :min="0" :precision="0" :controls="false" size="mini" style="width: 70px" :class="{'changed-cell': changedIds.has(scope.row.id)}" @change="markChanged(scope.row)" />
</template>
</el-table-column>
<el-table-column label="周四" align="center" width="90" v-if="columns[7].visible">
<template slot-scope="scope">
<el-input-number v-model="scope.row.reqThu" :min="0" :precision="0" :controls="false" size="mini" style="width: 70px" :class="{'changed-cell': changedIds.has(scope.row.id)}" @change="markChanged(scope.row)" />
</template>
</el-table-column>
<el-table-column label="周五" align="center" width="90" v-if="columns[8].visible">
<template slot-scope="scope">
<el-input-number v-model="scope.row.reqFri" :min="0" :precision="0" :controls="false" size="mini" style="width: 70px" :class="{'changed-cell': changedIds.has(scope.row.id)}" @change="markChanged(scope.row)" />
</template>
</el-table-column>
<el-table-column label="周六" align="center" width="90" v-if="columns[9].visible">
<template slot-scope="scope">
<el-input-number v-model="scope.row.reqSat" :min="0" :precision="0" :controls="false" size="mini" style="width: 70px" :class="{'changed-cell': changedIds.has(scope.row.id)}" @change="markChanged(scope.row)" />
</template>
</el-table-column>
<el-table-column label="周日" align="center" width="90" v-if="columns[10].visible">
<template slot-scope="scope">
<el-input-number v-model="scope.row.reqSun" :min="0" :precision="0" :controls="false" size="mini" style="width: 70px" :class="{'changed-cell': changedIds.has(scope.row.id)}" @change="markChanged(scope.row)" />
</template>
</el-table-column>
<el-table-column label="周合计" align="center" width="80" v-if="columns[11].visible">
<template slot-scope="scope">
<span>{{ calcRowTotal(scope.row) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="120" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['production:req:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['production:req:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改子件物料周需求对话框 -->
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-row>
<el-col :span="12">
<el-form-item label="年第周" prop="yearWeek">
<el-input v-model="form.yearWeek" placeholder="如202501" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="周一日期" prop="weekStartDate">
<el-date-picker clearable
v-model="form.weekStartDate"
type="date"
value-format="yyyy-MM-dd"
style="width: 100%"
placeholder="选择周一日期">
</el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="物料编码" prop="itemCode">
<el-input v-model="form.itemCode" placeholder="请输入物料编码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="物料描述" prop="itemDesc">
<el-input v-model="form.itemDesc" placeholder="请输入物料描述" />
</el-form-item>
</el-col>
</el-row>
<el-divider content-position="left">每日需求量</el-divider>
<el-row>
<el-col :span="6">
<el-form-item label="周一" prop="reqMon" label-width="50px">
<el-input-number v-model="form.reqMon" :min="0" controls-position="right" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="周二" prop="reqTue" label-width="50px">
<el-input-number v-model="form.reqTue" :min="0" controls-position="right" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="周三" prop="reqWed" label-width="50px">
<el-input-number v-model="form.reqWed" :min="0" controls-position="right" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="周四" prop="reqThu" label-width="50px">
<el-input-number v-model="form.reqThu" :min="0" controls-position="right" style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="6">
<el-form-item label="周五" prop="reqFri" label-width="50px">
<el-input-number v-model="form.reqFri" :min="0" controls-position="right" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="周六" prop="reqSat" label-width="50px">
<el-input-number v-model="form.reqSat" :min="0" controls-position="right" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="周日" prop="reqSun" label-width="50px">
<el-input-number v-model="form.reqSun" :min="0" controls-position="right" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="合计" label-width="50px">
<el-input :value="weekTotal" disabled style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 导入对话框 -->
<el-dialog :title="upload.title" :visible.sync="upload.open" width="450px" append-to-body>
<el-form label-width="100px">
<el-form-item label="周一日期" required>
<el-date-picker
v-model="upload.weekStartDate"
type="date"
value-format="yyyy-MM-dd"
:picker-options="mondayPickerOptions"
placeholder="请选择周一日期"
style="width: 100%"
/>
</el-form-item>
</el-form>
<el-upload
ref="upload"
:limit="1"
accept=".xlsx, .xls"
:headers="upload.headers"
:action="upload.url"
:data="{ weekStartDate: upload.weekStartDate }"
:disabled="upload.isUploading"
:on-progress="handleFileUploadProgress"
:on-success="handleFileSuccess"
:auto-upload="false"
drag
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<div class="el-upload__tip text-center" slot="tip">
<span>仅允许导入xlsxlsx格式文件</span>
<el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;" @click="importTemplate"></el-link>
</div>
</el-upload>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitFileForm"> </el-button>
<el-button @click="upload.open = false"> </el-button>
</div>
</el-dialog>
<!-- 导出对话框 -->
<el-dialog title="导出子件物料周需求" :visible.sync="exportOpen" width="450px" append-to-body>
<el-form label-width="100px">
<el-form-item label="开始周一" required>
<el-date-picker
v-model="exportParams.startDate"
type="date"
value-format="yyyy-MM-dd"
:picker-options="mondayPickerOptions"
placeholder="选择开始周一日期"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="结束周一" required>
<el-date-picker
v-model="exportParams.endDate"
type="date"
value-format="yyyy-MM-dd"
:picker-options="mondayPickerOptions"
placeholder="选择结束周一日期"
style="width: 100%"
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="handleExport"> </el-button>
<el-button @click="exportOpen = false"> </el-button>
</div>
</el-dialog>
<!-- 批量填充对话框 -->
<el-dialog title="批量填充" :visiblse.sync="batchFillOpen" width="400px" append-to-body>
<el-form label-width="100px">
<el-form-item label="已选行数">
<span class="el-tag el-tag--info">{{ selectedRows.length }} </span>
</el-form-item>
<el-form-item label="填充列" required>
<el-checkbox-group v-model="batchFill.columns">
<el-checkbox label="reqMon">周一</el-checkbox>
<el-checkbox label="reqTue">周二</el-checkbox>
<el-checkbox label="reqWed">周三</el-checkbox>
<el-checkbox label="reqThu">周四</el-checkbox>
<el-checkbox label="reqFri">周五</el-checkbox>
<el-checkbox label="reqSat">周六</el-checkbox>
<el-checkbox label="reqSun">周日</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="填充数值" required>
<el-input-number v-model="batchFill.value" :min="0" :precision="0" controls-position="right" style="width: 100%" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="handleBatchFill"> </el-button>
<el-button @click="batchFillOpen = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listReq, getReq, delReq, addReq, updateReq, batchUpdateReq } from "@/api/production/req";
import { getToken } from "@/utils/auth";
export default {
name: "Req",
data() {
return {
//
loading: true,
//
ids: [],
//
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//
reqList: [],
// ID
changedIds: new Set(),
//
title: "",
//
open: false,
//
exportOpen: false,
//
exportParams: {
startDate: null,
endDate: null
},
//
batchFillOpen: false,
//
batchFill: {
columns: [],
value: 0
},
//
selectedRows: [],
//
mondayPickerOptions: {
disabledDate(time) {
return time.getDay() !== 1;
}
},
//
queryParams: {
pageNum: 1,
pageSize: 10,
yearWeek: null,
weekStartDate: null,
itemCode: null,
itemDesc: null
},
//
form: {},
//
rules: {
yearWeek: [
{ required: true, message: "年第周不能为空", trigger: "blur" }
],
weekStartDate: [
{ required: true, message: "周一日期不能为空", trigger: "blur" }
],
itemCode: [
{ required: true, message: "物料编码不能为空", trigger: "blur" }
],
},
//
upload: {
open: false,
title: "子件物料周需求导入",
isUploading: false,
weekStartDate: null,
headers: { Authorization: "Bearer " + getToken() },
url: process.env.VUE_APP_BASE_API + "/production/req/importData"
},
columns: [
{ key: 0, label: `年第周`, visible: true },
{ key: 1, label: `周一日期`, visible: true },
{ key: 2, label: `物料编码`, visible: true },
{ key: 3, label: `物料描述`, visible: true },
{ key: 4, label: `周一`, visible: true },
{ key: 5, label: `周二`, visible: true },
{ key: 6, label: `周三`, visible: true },
{ key: 7, label: `周四`, visible: true },
{ key: 8, label: `周五`, visible: true },
{ key: 9, label: `周六`, visible: true },
{ key: 10, label: `周日`, visible: true },
{ key: 11, label: `周合计`, visible: true },
]
};
},
computed: {
weekTotal() {
return (this.form.reqMon || 0) + (this.form.reqTue || 0) + (this.form.reqWed || 0) +
(this.form.reqThu || 0) + (this.form.reqFri || 0) + (this.form.reqSat || 0) +
(this.form.reqSun || 0);
},
hasChanges() {
return this.changedIds.size > 0;
}
},
created() {
this.getList();
},
methods: {
/** 查询子件物料周需求列表 */
getList() {
this.loading = true;
this.changedIds = new Set();
listReq(this.queryParams).then(response => {
this.reqList = response.rows;
this.total = response.total;
this.loading = false;
});
},
/** 标记行已修改 */
markChanged(row) {
// Vue 2 Set
const newSet = new Set(this.changedIds);
newSet.add(row.id);
this.changedIds = newSet;
},
/** 计算行合计 */
calcRowTotal(row) {
return (Number(row.reqMon) || 0) + (Number(row.reqTue) || 0) + (Number(row.reqWed) || 0) +
(Number(row.reqThu) || 0) + (Number(row.reqFri) || 0) + (Number(row.reqSat) || 0) +
(Number(row.reqSun) || 0);
},
/** 批量保存修改 */
handleBatchSave() {
const changedRows = this.reqList.filter(row => this.changedIds.has(row.id));
if (changedRows.length === 0) {
this.$modal.msgWarning("没有需要保存的修改");
return;
}
this.$modal.confirm('是否确认保存 ' + changedRows.length + ' 条修改的数据?').then(() => {
batchUpdateReq(changedRows).then(response => {
this.$modal.msgSuccess(response.msg);
this.changedIds = new Set();
this.getList();
});
}).catch(() => {});
},
//
cancel() {
this.open = false;
this.reset();
},
//
reset() {
this.form = {
id: null,
yearWeek: null,
weekStartDate: null,
itemCode: null,
itemDesc: null,
reqMon: 0,
reqTue: 0,
reqWed: 0,
reqThu: 0,
reqFri: 0,
reqSat: 0,
reqSun: 0
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.selectedRows = selection
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 打开批量填充对话框 */
openBatchFillDialog() {
if (this.selectedRows.length === 0) {
this.$modal.msgWarning("请先选择要填充的行");
return;
}
this.batchFill.columns = [];
this.batchFill.value = 0;
this.batchFillOpen = true;
},
/** 执行批量填充 */
handleBatchFill() {
if (this.batchFill.columns.length === 0) {
this.$modal.msgWarning("请选择要填充的列");
return;
}
//
this.selectedRows.forEach(row => {
this.batchFill.columns.forEach(col => {
row[col] = this.batchFill.value;
});
this.markChanged(row);
});
this.batchFillOpen = false;
this.$modal.msgSuccess(`已填充 ${this.selectedRows.length} 行数据`);
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加子件物料周需求";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id || this.ids
getReq(id).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改子件物料周需求";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.id != null) {
updateReq(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addReq(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids;
this.$modal.confirm('是否确认删除子件物料周需求编号为"' + ids + '"的数据项?').then(function() {
return delReq(ids);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 打开导出对话框 */
openExportDialog() {
this.exportParams.startDate = null;
this.exportParams.endDate = null;
this.exportOpen = true;
},
/** 导出按钮操作 */
handleExport() {
if (!this.exportParams.startDate || !this.exportParams.endDate) {
this.$modal.msgWarning("请选择导出的时间范围");
return;
}
if (this.exportParams.startDate > this.exportParams.endDate) {
this.$modal.msgWarning("开始日期不能大于结束日期");
return;
}
this.exportOpen = false;
this.download('production/req/export', {
...this.queryParams,
'params[beginWeekStartDate]': this.exportParams.startDate,
'params[endWeekStartDate]': this.exportParams.endDate
}, `子件物料周需求_${new Date().getTime()}.xlsx`)
},
/** 导入按钮操作 */
handleImport() {
this.upload.open = true;
},
/** 下载模板操作 */
importTemplate() {
this.download('production/req/importTemplate', {}, `子件物料周需求模板_${new Date().getTime()}.xlsx`)
},
/** 文件上传中处理 */
handleFileUploadProgress(event, file, fileList) {
this.upload.isUploading = true;
},
/** 文件上传成功处理 */
handleFileSuccess(response, file, fileList) {
this.upload.open = false;
this.upload.isUploading = false;
this.$refs.upload.clearFiles();
this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true });
this.getList();
},
/** 提交上传文件 */
submitFileForm() {
this.$refs.upload.submit();
}
}
};
</script>
<style scoped>
.changed-cell ::v-deep .el-input__inner {
background-color: #fffbe6 !important;
border-color: #faad14 !important;
}
</style>
Loading…
Cancel
Save