lb #19

Merged
g7hoo merged 80 commits from lb into test 2023-09-11 15:05:16 +08:00
12 changed files with 2231 additions and 0 deletions
Showing only changes of commit 21fbd88a32 - Show all commits

View File

@ -0,0 +1,54 @@
import request from '@/utils/request'
// 创建设备报警日志
export function createEquipmentAlarmLog(data) {
return request({
url: '/monitoring/equipment-alarm-log/create',
method: 'post',
data: data
})
}
// 更新设备报警日志
export function updateEquipmentAlarmLog(data) {
return request({
url: '/monitoring/equipment-alarm-log/update',
method: 'put',
data: data
})
}
// 删除设备报警日志
export function deleteEquipmentAlarmLog(id) {
return request({
url: '/monitoring/equipment-alarm-log/delete?id=' + id,
method: 'delete'
})
}
// 获得设备报警日志
export function getEquipmentAlarmLog(id) {
return request({
url: '/monitoring/equipment-alarm-log/get?id=' + id,
method: 'get'
})
}
// 获得设备报警日志分页
export function getEquipmentAlarmLogPage(query) {
return request({
url: '/monitoring/equipment-alarm-log/page',
method: 'get',
params: query
})
}
// 导出设备报警日志 Excel
export function exportEquipmentAlarmLogExcel(query) {
return request({
url: '/monitoring/equipment-alarm-log/export-excel',
method: 'get',
params: query,
responseType: 'blob'
})
}

View File

@ -0,0 +1,54 @@
import request from '@/utils/request'
// 创建设备报警实时信息
export function createEquipmentAlarmRealtime(data) {
return request({
url: '/monitoring/equipment-alarm-realtime/create',
method: 'post',
data: data
})
}
// 更新设备报警实时信息
export function updateEquipmentAlarmRealtime(data) {
return request({
url: '/monitoring/equipment-alarm-realtime/update',
method: 'put',
data: data
})
}
// 删除设备报警实时信息
export function deleteEquipmentAlarmRealtime(id) {
return request({
url: '/monitoring/equipment-alarm-realtime/delete?id=' + id,
method: 'delete'
})
}
// 获得设备报警实时信息
export function getEquipmentAlarmRealtime(id) {
return request({
url: '/monitoring/equipment-alarm-realtime/get?id=' + id,
method: 'get'
})
}
// 获得设备报警实时信息分页
export function getEquipmentAlarmRealtimePage(query) {
return request({
url: '/monitoring/equipment-alarm-realtime/page',
method: 'get',
params: query
})
}
// 导出设备报警实时信息 Excel
export function exportEquipmentAlarmRealtimeExcel(query) {
return request({
url: '/monitoring/equipment-alarm-realtime/export-excel',
method: 'get',
params: query,
responseType: 'blob'
})
}

View File

@ -0,0 +1,89 @@
<!--
filename: index.vue
author: liubin
date: 2023-08-29 14:39:40
description: 状态时序图
-->
<template>
<div class="sequence-graph">
<SequenceGraphItem v-for="eq in Object.keys(list)" :key="eq" />
</div>
</template>
<script>
import SequenceGraphItem from './sequenceGraphItem.vue';
export default {
name: 'SequenceGraph',
components: { SequenceGraphItem },
props: {
colors: {
type: Array,
default: () => ['', '', '', '', '', ''], //
},
},
data() {
return {
list: {
打孔机: {
equipmentId: 1,
equipmentName: 'EQ1',
status: '',
startTime: '',
duration: '',
startPos: '',
relativeDuring: '',
},
磨边机: {
equipmentId: 12,
equipmentName: 'EQ2',
status: '',
startTime: '',
duration: '',
startPos: '',
relativeDuring: '',
},
清洗机: {
equipmentId: 13,
equipmentName: 'EQ3',
status: '',
startTime: '',
duration: '',
startPos: '',
relativeDuring: '',
},
窑炉: {
equipmentId: 14,
equipmentName: 'EQ4',
status: '',
startTime: '',
duration: '',
startPos: '',
relativeDuring: '',
},
AGV: {
equipmentId: 15,
equipmentName: 'EQ5',
status: '',
startTime: '',
duration: '',
startPos: '',
relativeDuring: '',
},
},
};
},
computed: {},
methods: {},
};
</script>
<style scoped lang="scss">
.sequence-graph {
padding: 24px;
background: #fff;
border-radius: 6px;
margin: 12px;
box-shadow: 0 0 32px 8px rgba($color: #000000, $alpha: 0.2);
}
</style>

View File

@ -0,0 +1,51 @@
<!--
filename: sequenceGraphItem.vue
author: liubin
date: 2023-08-29 14:40:51
description: 时序图最小单元
-->
<template>
<div class="sequence-graph-item" :style="styles">
<span v-if="time != null">{{ time }}</span>
</div>
</template>
<script>
export default {
name: 'SequenceGraphItem',
components: {},
props: {
color: {
type: String,
default: 'black',
},
time: {
type: String,
default: null
}
},
computed: {
styles() {
return {
color: this.color
}
}
},
data() {
return {};
},
computed: {},
methods: {},
};
</script>
<style scoped lang="scss">
.sequence-graph-item {
background: #fff;
padding: 12px;
width: 40px;
height: 32px;
display: inline-block;
}
</style>

View File

@ -46,6 +46,8 @@ export default {
.app-main { .app-main {
/* 84 = navbar + tags-view = 50 + 34 */ /* 84 = navbar + tags-view = 50 + 34 */
min-height: calc(100vh - 120px - 8px); min-height: calc(100vh - 120px - 8px);
display: flex;
flex-direction: column;
} }
.fixed-header + .app-main { .fixed-header + .app-main {

View File

@ -0,0 +1,285 @@
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<SearchBar
:formConfigs="searchBarFormConfig"
ref="search-bar"
@headBtnClick="handleSearchBarBtnClick" />
<!-- 列表 -->
<base-table
:table-props="tableProps"
:page="queryParams.pageNo"
:limit="queryParams.pageSize"
:table-data="list"
@emitFun="handleEmitFun">
<method-btn
v-if="tableBtn.length"
slot="handleBtn"
label="操作"
:method-list="tableBtn"
@clickBtn="handleTableBtnClick" />
</base-table>
<!-- 分页组件 -->
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNo"
:limit.sync="queryParams.pageSize"
@pagination="getList" />
<!-- 对话框(添加 / 修改) -->
<!-- <base-dialog
:dialogTitle="title"
:dialogVisible="open"
width="500px"
@close="cancel"
@cancel="cancel"
@confirm="submitForm">
<DialogForm v-if="open" ref="form" :dataForm="form" :rows="rows" />
</base-dialog> -->
</div>
</template>
<script>
import {
createEquipmentAlarmLog,
updateEquipmentAlarmLog,
deleteEquipmentAlarmLog,
getEquipmentAlarmLog,
getEquipmentAlarmLogPage,
exportEquipmentAlarmLogExcel,
} from '@/api/monitoring/equipmentAlarmLog';
import Editor from '@/components/Editor';
import moment from 'moment';
import basicPageMixin from '@/mixins/lb/basicPageMixin';
import { getAccessToken } from '@/utils/auth';
import { publicFormatter } from '@/utils/dict';
export default {
name: 'EquipmentAlarmLog',
components: {
Editor,
},
mixins: [basicPageMixin],
data() {
return {
searchBarKeys: ['checkTime'],
tableBtn: [
this.$auth.hasPermi('base:equipment-alarm-log:update')
? {
type: 'edit',
btnName: '修改',
}
: undefined,
this.$auth.hasPermi('base:equipment-alarm-log:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
tableProps: [
{ width: 128, prop: 'productionLine', label: '产线', align: 'center' },
{ width: 128, prop: 'workshopSection', label: '工段', align: 'center' },
{ width: 128, prop: 'equipment', label: '设备名称', align: 'center' },
{
prop: 'alarmGrade',
label: '报警级别',
align: 'center',
filter: publicFormatter(this.DICT_TYPE.EQU_ALARM_LEVEL),
},
{
prop: 'createTime',
label: '报警时间',
width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
},
{ prop: 'alarmContent', label: '报警内容', align: 'center' },
// {
// _action: 'equipment-group-show-alert',
// label: '',
// align: 'center',
// subcomponent: {
// props: ['injectData'],
// render: function (h) {
// const _this = this;
// return h(
// 'el-button',
// {
// props: { type: 'text', size: 'mini' },
// on: {
// click: function () {
// console.log('inejctdata', _this.injectData);
// _this.$emit('emitData', {
// action: _this.injectData._action,
// // value: _this.injectData.id,
// value: _this.injectData,
// });
// },
// },
// },
// ''
// );
// },
// },
// },
],
searchBarFormConfig: [
{
type: 'datePicker',
label: '时间段',
dateType: 'daterange', // datetimerange
// format: 'yyyy-MM-dd HH:mm:ss',
format: 'yyyy-MM-dd',
valueFormat: 'yyyy-MM-dd HH:mm:ss',
rangeSeparator: '-',
startPlaceholder: '开始日期',
endPlaceholder: '结束日期',
defaultTime: ['00:00:00', '23:59:59'],
param: 'createTime',
// width: 350,
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
],
//
open: false,
//
queryParams: {
pageNo: 1,
pageSize: 10,
createTime: [],
},
//
form: {},
//
rules: {},
};
},
created() {
this.getList();
},
methods: {
/** 重写 basicPageMixin 里的 handleSearchBarBtnClick */
handleSearchBarBtnClick(btn) {
//
this.queryParams.createTime = btn.createTime;
this.handleQuery();
},
/** 查询列表 */
getList() {
this.loading = true;
//
getEquipmentAlarmLogPage(this.queryParams).then((response) => {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
/** 取消按钮 */
cancel() {
this.open = false;
this.reset();
},
/** 表单重置 */
reset() {
this.form = {
id: undefined,
alarmId: undefined,
alarmContent: undefined,
alarmValue: undefined,
alarmEquipmentId: undefined,
remark: undefined,
};
this.resetForm('form');
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm');
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = '添加设备报警日志';
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id;
getEquipmentAlarmLog(id).then((response) => {
this.form = response.data;
this.open = true;
this.title = '修改设备报警日志';
});
},
/** 提交按钮 */
submitForm() {
this.$refs['form'].validate((valid) => {
if (!valid) {
return;
}
//
if (this.form.id != null) {
updateEquipmentAlarmLog(this.form).then((response) => {
this.$modal.msgSuccess('修改成功');
this.open = false;
this.getList();
});
return;
}
//
createEquipmentAlarmLog(this.form).then((response) => {
this.$modal.msgSuccess('新增成功');
this.open = false;
this.getList();
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal
.confirm('是否确认删除设备报警日志编号为"' + id + '"的数据项?')
.then(function () {
return deleteEquipmentAlarmLog(id);
})
.then(() => {
this.getList();
this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
//
let params = { ...this.queryParams };
params.pageNo = undefined;
params.pageSize = undefined;
this.$modal
.confirm('是否确认导出所有设备报警日志数据项?')
.then(() => {
this.exportLoading = true;
return exportEquipmentAlarmLogExcel(params);
})
.then((response) => {
this.$download.excel(response, '设备报警日志.xls');
this.exportLoading = false;
})
.catch(() => {});
},
},
};
</script>

View File

@ -0,0 +1,326 @@
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<el-form
:model="queryParams"
ref="queryForm"
size="small"
:inline="true"
v-show="showSearch"
label-width="68px">
<el-form-item label="创建时间" prop="createTime">
<el-date-picker
v-model="queryParams.createTime"
style="width: 240px"
value-format="yyyy-MM-dd HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="['00:00:00', '23:59:59']" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">
搜索
</el-button>
<el-button icon="el-icon-refresh" @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="['monitoring:equipment-alarm-realtime:create']">
新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['monitoring:equipment-alarm-realtime:export']">
导出
</el-button>
</el-col>
<right-toolbar
:showSearch.sync="showSearch"
@queryTable="getList"></right-toolbar>
</el-row>
<!-- 列表 -->
<el-table v-loading="loading" :data="list">
<el-table-column label="id" align="center" prop="id" />
<el-table-column
label="报警信息ID关联base_equipment_group_alarm表"
align="center"
prop="alarmId" />
<el-table-column
label="字符型报警编码"
align="center"
prop="alarmContent" />
<el-table-column label="报警详细描述" align="center" prop="description" />
<el-table-column
label="报警设备id 关联equipment表"
align="center"
prop="alarmEquipmentId" />
<el-table-column label="实时报警值" align="center" prop="alarmValue" />
<el-table-column
label="状态0 正常 1 报警中"
align="center"
prop="alarmStatus" />
<el-table-column
label="创建时间"
align="center"
prop="createTime"
width="180">
<template v-slot="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column
label="操作"
align="center"
class-name="small-padding fixed-width">
<template v-slot="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['monitoring:equipment-alarm-realtime:update']">
修改
</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['monitoring:equipment-alarm-realtime:delete']">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNo"
:limit.sync="queryParams.pageSize"
@pagination="getList" />
<!-- 对话框(添加 / 修改) -->
<el-dialog
:title="title"
:visible.sync="open"
width="500px"
v-dialogDrag
append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item
label="报警信息ID关联base_equipment_group_alarm表"
prop="alarmId">
<el-input
v-model="form.alarmId"
placeholder="请输入报警信息ID关联base_equipment_group_alarm表" />
</el-form-item>
<el-form-item label="字符型报警编码">
<editor v-model="form.alarmContent" :min-height="192" />
</el-form-item>
<el-form-item label="报警详细描述">
<editor v-model="form.description" :min-height="192" />
</el-form-item>
<el-form-item
label="报警设备id 关联equipment表"
prop="alarmEquipmentId">
<el-input
v-model="form.alarmEquipmentId"
placeholder="请输入报警设备id 关联equipment表" />
</el-form-item>
<el-form-item label="实时报警值" prop="alarmValue">
<el-input v-model="form.alarmValue" placeholder="请输入实时报警值" />
</el-form-item>
<el-form-item label="状态0 正常 1 报警中" prop="alarmStatus">
<el-radio-group v-model="form.alarmStatus">
<el-radio label="1">请选择字典生成</el-radio>
</el-radio-group>
</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 {
createEquipmentAlarmRealtime,
updateEquipmentAlarmRealtime,
deleteEquipmentAlarmRealtime,
getEquipmentAlarmRealtime,
getEquipmentAlarmRealtimePage,
exportEquipmentAlarmRealtimeExcel,
} from '@/api/monitoring/equipmentAlarmRealtime';
import Editor from '@/components/Editor';
export default {
name: 'EquipmentAlarmRealtime',
components: {
Editor,
},
data() {
return {
//
loading: true,
//
exportLoading: false,
//
showSearch: true,
//
total: 0,
//
list: [],
//
title: '',
//
open: false,
//
queryParams: {
pageNo: 1,
pageSize: 10,
createTime: [],
},
//
form: {},
//
rules: {},
};
},
created() {
this.getList();
},
methods: {
/** 查询列表 */
getList() {
this.loading = true;
//
getEquipmentAlarmRealtimePage(this.queryParams).then((response) => {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
/** 取消按钮 */
cancel() {
this.open = false;
this.reset();
},
/** 表单重置 */
reset() {
this.form = {
id: undefined,
alarmId: undefined,
alarmContent: undefined,
description: undefined,
alarmEquipmentId: undefined,
alarmValue: undefined,
alarmStatus: undefined,
};
this.resetForm('form');
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm');
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = '添加设备报警实时信息';
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id;
getEquipmentAlarmRealtime(id).then((response) => {
this.form = response.data;
this.open = true;
this.title = '修改设备报警实时信息';
});
},
/** 提交按钮 */
submitForm() {
this.$refs['form'].validate((valid) => {
if (!valid) {
return;
}
//
if (this.form.id != null) {
updateEquipmentAlarmRealtime(this.form).then((response) => {
this.$modal.msgSuccess('修改成功');
this.open = false;
this.getList();
});
return;
}
//
createEquipmentAlarmRealtime(this.form).then((response) => {
this.$modal.msgSuccess('新增成功');
this.open = false;
this.getList();
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal
.confirm('是否确认删除设备报警实时信息编号为"' + id + '"的数据项?')
.then(function () {
return deleteEquipmentAlarmRealtime(id);
})
.then(() => {
this.getList();
this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
//
let params = { ...this.queryParams };
params.pageNo = undefined;
params.pageSize = undefined;
this.$modal
.confirm('是否确认导出所有设备报警实时信息数据项?')
.then(() => {
this.exportLoading = true;
return exportEquipmentAlarmRealtimeExcel(params);
})
.then((response) => {
this.$download.excel(response, '设备报警实时信息.xls');
this.exportLoading = false;
})
.catch(() => {});
},
},
};
</script>

View File

@ -0,0 +1,497 @@
<!--
filename: index.vue
author: liubin
date: 2023-08-31 09:14:19
description: 设备全参数查询
-->
<template>
<div class="app-container full-param-page">
<SearchBar
:formConfigs="searchBarFormConfig"
ref="search-bar"
@headBtnClick="handleSearchBarBtnClick" />
<div class="tables">
<base-table
:key="1 + '__basetable'"
:table-props="table1.tableProps"
:page="1"
:limit="999"
:table-data="table1.data"
@emitFun="(val) => handleEmitFun(table1, val)"></base-table>
<base-table
:key="2 + '__basetable'"
:table-props="table2.tableProps"
:page="1"
:limit="999"
:table-data="table2.data"
@emitFun="(val) => handleEmitFun(table2, val)"></base-table>
<base-table
:key="3 + '__basetable'"
:table-props="table3.tableProps"
:page="1"
:limit="999"
:table-data="table3.data"
@emitFun="(val) => handleEmitFun(table3, val)"></base-table>
<base-table
:key="4 + '__basetable'"
:table-props="table4.tableProps"
:page="1"
:limit="999"
:table-data="table4.data"
@emitFun="(val) => handleEmitFun(table4, val)"></base-table>
<base-table
:key="5 + '__basetable'"
:table-props="table5.tableProps"
:page="1"
:limit="999"
:table-data="table5.data"
@emitFun="(val) => handleEmitFun(table5, val)"></base-table>
<base-table
:key="6 + '__basetable'"
:table-props="table6.tableProps"
:page="1"
:limit="999"
:table-data="table6.data"
@emitFun="(val) => handleEmitFun(table6, val)"></base-table>
<base-table
:key="7 + '__basetable'"
:table-props="table7.tableProps"
:page="1"
:limit="999"
:table-data="table7.data"
@emitFun="(val) => handleEmitFun(table7, val)"></base-table>
</div>
<!-- <div class="tables">
<div class="table-wrapper" v-for="table in tableList" :key="table.key">
<div class="table-title">PLC 1</div>
<base-table
:key="table.key + '__basetable'"
:table-props="table.tableProps"
:page="1"
:limit="999"
:table-data="table.data"
@emitFun="(val) => handleEmitFun(table, val)">
</base-table>
<pagination
v-show="table.total > 0"
:total="table.total"
:page.sync="table.queryParams.pageNo"
:limit.sync="table.queryParams.pageSize"
@pagination="(val) => getListFor(table, val)" />
</div>
</div> -->
</div>
</template>
<script>
export default {
name: 'EquipmentFullParams',
components: {},
props: {},
data() {
const now = new Date();
const [y, m, d] = [now.getFullYear(), now.getMonth(), now.getDate()];
const today = new Date(y, m, d, 0, 0, 0, 0).getTime();
const aWeekAgo = today - 3600 * 1000 * 24 * 7;
return {
tableList: [],
searchBarFormConfig: [
{
type: 'input',
label: '设备名称',
placeholder: '请输入设备名称',
param: 'name',
disabled: true,
},
{
type: 'input',
label: '设备编码',
placeholder: '请输入设备编码',
param: 'code',
disabled: true,
},
{
type: 'datePicker',
label: '时间段',
dateType: 'daterange', // datetimerange
format: 'yyyy-MM-dd HH:mm:ss',
// valueFormat: 'yyyy-MM-dd HH:mm:ss',
valueFormat: 'timestamp',
rangeSeparator: '-',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间',
defaultTime: ['00:00:00', '23:59:59'],
param: 'timeVal',
width: 350,
// defaultSelect: [new Date(aWeekAgo), new Date(today)],
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
],
queryParams: {
id: null,
time: [new Date(aWeekAgo), new Date(today)],
},
table1: {
tableProps: [
{
prop: 'time',
label: '时间',
},
{
prop: 'plcCode',
label: 'PLC编码',
},
{
prop: 'val1',
label: '数值1',
},
{
prop: 'bol1',
label: '布尔1',
},
{
prop: 'val2',
label: '数值2',
},
{
prop: 'bol2',
label: '布尔2',
},
{
prop: 'val3',
label: '数值3',
},
{
prop: 'bol3',
label: '布尔3',
},
{
prop: 'val4',
label: '数值4',
},
{
prop: 'bol4',
label: '布尔4',
},
],
data: [
{
time: 1111111111111111,
plcCode: 2,
val1: 3,
bol1: 4,
val2: 5,
bol2: 6,
},
{
time: 1,
plcCode: 22222222222222,
val1: 3,
bol1: 4,
val2: 5,
bol2: 6,
},
{
time: 1,
plcCode: 2,
val1: 33333333333333,
bol1: 4,
val2: 5,
bol2: 6,
},
{
time: 1,
plcCode: 2,
val1: 3,
bol1: 44444444444444,
val2: 5,
bol2: 6,
},
{
time: 1,
plcCode: 2,
val1: 3,
bol1: 4,
val2: 5555555555555,
bol2: 6,
},
{
time: 1,
plcCode: 2,
val1: 3,
bol1: 4,
val2: 5,
bol2: 6666666666666666666,
},
{ time: 1, plcCode: 2, val1: 3, bol1: 4, val2: 5, bol2: 6 },
{ time: 1, plcCode: 2, val1: 3, bol1: 4, val2: 5, bol2: 6 },
{ time: 1, plcCode: 2, val1: 3, bol1: 4, val2: 5, bol2: 6 },
{ time: 1, plcCode: 2, val1: 3, bol1: 4, val2: 5, bol2: 6 },
{ time: 1, plcCode: 2, val1: 3, bol1: 4, val2: 5, bol2: 6 },
{ time: 1, plcCode: 2, val1: 3, bol1: 4, val2: 5, bol2: 6 },
{ time: 1, plcCode: 2, val1: 3, bol1: 4, val2: 5, bol2: 6 },
{ time: 1, plcCode: 2, val1: 3, bol1: 4, val2: 5, bol2: 6 },
{ time: 1, plcCode: 2, val1: 3, bol1: 4, val2: 5, bol2: 6 },
{ time: 1, plcCode: 2, val1: 3, bol1: 4, val2: 5, bol2: 6 },
{ time: 1, plcCode: 2, val1: 3, bol1: 4, val2: 5, bol2: 6 },
],
},
table2: {
tableProps: [
{
prop: 'time',
label: '时间',
},
{
prop: 'plcCode',
label: 'PLC编码',
},
{
prop: 'val1',
label: '数值1',
},
{
prop: 'bol1',
label: '布尔1',
},
{
prop: 'val2',
label: '数值2',
},
{
prop: 'bol2',
label: '布尔2',
},
],
data: [],
},
table3: {
tableProps: [
{
prop: 'time',
label: '时间',
},
{
prop: 'plcCode',
label: 'PLC编码',
},
{
prop: 'val1',
label: '数值1',
},
{
prop: 'bol1',
label: '布尔1',
},
{
prop: 'val2',
label: '数值2',
},
{
prop: 'bol2',
label: '布尔2',
},
],
data: [],
},
table4: {
tableProps: [
{
prop: 'time',
label: '时间',
},
{
prop: 'plcCode',
label: 'PLC编码',
},
{
prop: 'val1',
label: '数值1',
},
{
prop: 'bol1',
label: '布尔1',
},
{
prop: 'val2',
label: '数值2',
},
{
prop: 'bol2',
label: '布尔2',
},
],
data: [],
},
table5: {
tableProps: [
{
prop: 'time',
label: '时间',
},
{
prop: 'plcCode',
label: 'PLC编码',
},
{
prop: 'val1',
label: '数值1',
},
{
prop: 'bol1',
label: '布尔1',
},
{
prop: 'val2',
label: '数值2',
},
{
prop: 'bol2',
label: '布尔2',
},
],
data: [],
},
table6: {
tableProps: [
{
prop: 'time',
label: '时间',
},
{
prop: 'plcCode',
label: 'PLC编码',
},
{
prop: 'val1',
label: '数值1',
},
{
prop: 'bol1',
label: '布尔1',
},
{
prop: 'val2',
label: '数值2',
},
{
prop: 'bol2',
label: '布尔2',
},
],
data: [],
},
table7: {
tableProps: [
{
prop: 'time',
label: '时间',
},
{
prop: 'plcCode',
label: 'PLC编码',
},
{
prop: 'val1',
label: '数值1',
},
{
prop: 'bol1',
label: '布尔1',
},
{
prop: 'val2',
label: '数值2',
},
{
prop: 'bol2',
label: '布尔2',
},
],
data: [],
},
};
},
computed: {
id() {
return this.$route.params.equipmentId;
},
code() {
return this.$route.params.equipmentCode;
},
name() {
return this.$route.params.equipmentName;
},
},
mounted() {
if (this.id) this.$set(this.queryParams, 'id', this.id);
if (this.code)
this.$set(this.searchBarFormConfig[0], 'defaultSelect', this.code);
if (this.name)
this.$set(this.searchBarFormConfig[1], 'defaultSelect', this.name);
},
methods: {
/** 查询 */
async handleQuery() {
const { data } = this.$axios({
url: '/monitoring/equipment-monitor/runLog',
method: 'get',
params: this.queryParams,
});
console.log('data', data);
},
async handleSearchBarBtnClick({ btnName, timeVal }) {
if (timeVal && timeVal.length > 0) {
this.queryParams.time = timeVal;
} else {
this.queryParams.time = [];
}
await this.handleQuery();
},
handleEmitFun(table, val) {
console.log('table val', table, val);
},
/** 构造 props */
buildProps() {
this.tableList.forEach((table) => {
this.buildTableProp(table);
});
},
/** 构造一个 tableProps - 根据动态结构 */
buildTableProp(table) {},
/** 为某个 table 获取 list 数据 */
getListFor(table, val) {
console.log('get list for', table, val);
},
},
};
</script>
<style scoped>
.full-param-page {
position: relative;
}
.tables {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 18px;
}
.tables >>> .baseTable {
overflow-x: hidden;
}
</style>

View File

@ -0,0 +1,69 @@
<!--
filename: graph.vue
author: liubin
date: 2023-08-31 14:00:02
description:
-->
<template>
<div class="chart-wrapper">
<h4>line graph</h4>
<div class="chart" ref="chart"></div>
</div>
</template>
<script>
import * as echarts from 'echarts';
export default {
name: 'LineChartInEquipmentProcessAmount',
components: {},
props: {},
data() {
return {
chart: null,
option: {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
},
yAxis: {
type: 'value',
},
series: [
{
data: [120, 200, 150, 80, 70, 110, 130],
type: 'bar',
showBackground: true,
backgroundStyle: {
color: 'rgba(180, 180, 180, 0.2)',
},
},
],
},
};
},
mounted() {
if (!this.chart) this.chart = echarts.init(this.$refs.chart);
this.chart.setOption(this.option);
},
beforeDestroy() {
this.chart.dispose();
},
methods: {},
};
</script>
<style scoped lang="scss">
.chart-wrapper {
height: 100%;
flex: 1;
background: #f1f1f1;
padding: 12px;
}
.chart {
height: 100%;
width: 100%;
}
</style>

View File

@ -0,0 +1,340 @@
<!--
filename: index.vue
author: liubin
date: 2023-08-30 14:02:49
description: 设备加工数量
-->
<template>
<div style="flex: 1; display: flex; background: #f2f4f9">
<div
class="app-container"
style="margin-right: 12px; border-radius: 8px; background: #fff">
<!-- side bar -->
<div
class="side-bar__left"
style="width: 240px; padding: 12px; height: 100%">
<el-tree
:data="sidebarContent"
:props="treeProps"
@node-click="handleSidebarItemClick" />
</div>
</div>
<div
class="app-container equipment-process-amount"
style="flex: 1; border-radius: 8px; background: #fff">
<!-- main area -->
<div class="main-content" style="display: flex; flex-direction: column">
<SearchBar
:formConfigs="searchBarFormConfig"
ref="search-bar"
@headBtnClick="handleSearchBarBtnClick" />
<transition appear name="vvv" mode="out-in">
<base-table
v-if="mode == 'table'"
:table-props="tableProps"
:page="1"
:limit="999"
:table-data="list"
@emitFun="handleEmitFun">
<!-- <method-btn
v-if="tableBtn.length"
slot="handleBtn"
label="操作"
:method-list="tableBtn"
@clickBtn="handleTableBtnClick" /> -->
</base-table>
<div class="graph" style="height: 56vh;" v-else>
<!-- graph -->
<Graph />
</div>
</transition>
</div>
</div>
</div>
</template>
<script>
import Graph from './graph.vue';
export default {
name: 'EquipmentProcessAmount',
components: { Graph },
props: {},
data() {
return {
sidebarContent: [
// {
// id: 'fc1',
// name: '',
// lines: [
// {
// name: '线1',
// id: 'pl1',
// sections: [
// {
// name: '1',
// id: 'pl1ws1',
// equipments: [
// {
// name: '1',
// id: 'pl1ws1--eq1',
// },
// {
// name: '2',
// id: 'pl1ws1--eq2',
// },
// {
// name: '3',
// id: 'pl1ws1--eq3',
// },
// ],
// },
// {
// name: '2',
// id: 'pl1ws2',
// equipments: [
// {
// name: '1',
// id: 'pl2ws1--eq1',
// },
// {
// name: '2',
// id: 'pl2ws1--eq2',
// },
// {
// name: '3',
// id: 'pl2ws1--eq3',
// },
// ],
// },
// {
// name: '3',
// id: 'pl1ws3',
// equipments: [
// {
// name: '1',
// id: 'pl3ws1--eq1',
// },
// {
// name: '2',
// id: 'pl3ws1--eq2',
// },
// {
// name: '3',
// id: 'pl3ws1--eq3',
// },
// ],
// },
// ],
// },
// {
// name: '线2',
// id: 'pl2',
// sections: [
// {
// name: '1',
// id: 'pl2ws1',
// },
// {
// name: '2',
// id: 'pl2ws2',
// },
// {
// name: '3',
// id: 'pl2ws3',
// },
// ],
// },
// ],
// },
],
searchBarFormConfig: [
{
type: 'datePicker',
label: '时间段',
dateType: 'daterange', // datetimerange
format: 'yyyy-MM-dd',
valueFormat: 'yyyy-MM-dd HH:mm:ss',
rangeSeparator: '-',
startPlaceholder: '开始日期',
endPlaceholder: '结束日期',
defaultTime: ['00:00:00', '23:59:59'],
param: 'timeVal',
width: 350,
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: 'button',
btnName: '表格',
name: 'table',
plain: true,
color: 'success',
},
{
type: 'button',
btnName: '图表',
name: 'graph',
plain: true,
color: 'warning',
},
// {
// type: this.$auth.hasPermi('base:equipment-group:export') ? 'button' : '',
// btnName: '',
// name: 'export',
// color: 'warning',
// },
],
tableProps: [
{ prop: 'lineName', label: '产线', align: 'center' },
{ prop: 'sectionName', label: '工段', align: 'center' },
{ prop: 'externalCode', label: '设备编码', align: 'center' },
{ prop: 'equipmentName', label: '设备名称', align: 'center' },
{ prop: 'totalQuantity', label: '加工数量', align: 'center' },
],
mode: 'table', // table | graph
queryParams: {
// pageNo: 1,
// pageSize: 999,
recordTime: [],
equipmentId: null,
lineId: null,
sectionId: null,
productId: null,
},
list: [],
treeProps: {
children: 'children',
label: 'label',
},
};
},
mounted() {
this.getTree();
},
methods: {
/** build side bar tree */
buildTree(data) {
data.forEach((factory) => {
this.$set(factory, 'label', factory.name);
this.$set(factory, 'type', '工厂');
delete factory.name;
factory.children = factory.lines;
delete factory.lines;
factory.children?.forEach((line) => {
this.$set(line, 'label', line.name);
this.$set(line, 'type', '产线');
delete line.name;
line.children = line.sections;
delete line.sections;
line.children?.forEach((ws) => {
this.$set(ws, 'label', ws.name);
this.$set(ws, 'type', '工段');
delete ws.name;
ws.children = ws.equipments;
delete ws.equipments;
ws.children?.forEach((eq) => {
this.$set(eq, 'label', eq.name);
this.$set(eq, 'type', '设备');
delete eq.name;
});
});
});
});
},
async getTree() {
const { data } = await this.$axios('/base/factory/getTree');
this.sidebarContent = data;
this.buildTree(data);
},
handleSidebarItemClick({ label, id, type }) {
console.log('lable clicked!', label, id, type);
switch (type) {
case '设备':
this.queryParams.equipmentId = id;
break;
case '工段':
this.queryParams.equipmentId = null;
this.queryParams.sectionId = id;
break;
case '产线':
this.queryParams.equipmentId = null;
this.queryParams.sectionId = null;
this.queryParams.lineId = id;
break;
case '工厂':
this.queryParams.equipmentId = null;
this.queryParams.sectionId = null;
this.queryParams.lineId = null;
break;
}
},
handleEmitFun() {},
handleSearchBarBtnClick(btn) {
switch (btn.btnName) {
case 'table':
this.mode = 'table';
break;
case 'graph':
this.mode = 'graph';
break;
case 'search':
if (btn.timeVal != null && btn.timeVal.length > 0)
this.queryParams.recordTime = btn.timeVal;
else this.queryParams.recordTime = null;
this.handleQuery();
break;
}
},
async handleQuery() {
console.log('queryParams', this.queryParams);
const { data } = await this.$axios({
url: '/monitoring/equipment-monitor/quantity-det-list',
method: 'get',
params: this.queryParams,
});
this.list = data;
},
},
};
</script>
<style scoped>
.side-bar__left >>> .is-current {
color: #111;
background: #f2f4f7;
}
.vvv-enter,
.vvv-leave-to {
/* transform: translateY(24px) scaleY(0); */
transform: translateY(24px);
opacity: 0;
}
.vvv-enter-active,
.vvv-leave-active {
transition: all 0.3s ease-out;
}
.vvv-enter-to,
.vvv-leave {
/* transform: translateY(0) scaleY(1); */
transform: translateY(0);
}
</style>

View File

@ -0,0 +1,181 @@
<!--
filename: index.vue
author: liubin
date: 2023-08-04 14:44:58
description: 设备24小时生产记录
-->
<template>
<div class="app-container">
<SearchBar
:formConfigs="[{ label: '设备近24小时生产记录', type: 'title' }]"
ref="search-bar" />
<el-skeleton v-if="initing" :rows="6" animated />
<base-table
v-else
:span-method="mergeColumnHandler"
:table-props="tableProps"
:table-data="list"
@emitFun="handleEmitFun"></base-table>
<!-- :page="queryParams.pageNo"
:limit="queryParams.pageSize" -->
</div>
</template>
<script>
export default {
name: 'QualityRecentHours',
components: {},
props: {},
data() {
return {
initing: false,
queryParams: {
pageNo: 1,
pageSize: 10,
},
list: [],
tableProps: [],
spanInfo: {},
};
},
computed: {},
mounted() {
this.getList();
},
methods: {
/** 构建tableProps - 依据第一个元素所提供的信息 */
buildProps(item) {
const {
data: [{ hourData }],
} = item;
const props = [
{ prop: 'productLine', label: '产线', align: 'center' },
{ prop: 'specification', label: '规格', align: 'center' },
{ prop: 'equipmentName', label: '设备', align: 'center' },
{ prop: 'totalQuantity', label: '生产总数', align: 'center' },
];
for (const key of Object.keys(hourData).sort()) {
const subprop = {
label: key,
align: 'center',
children: [
{ prop: key + '__in', label: '进数据', align: 'center' },
{ prop: key + '__out', label: '出数据', align: 'center' },
{ prop: key + '__nok', label: '报废数据', align: 'center' },
{
prop: key + '__ratio',
label: '报废率',
align: 'center',
filter: (val) => (val != null ? val + ' %' : '-'),
},
],
};
props.push(subprop);
}
this.tableProps = props;
},
/** 把 list 里的数据转换成 tableProps 对应的格式 */
convertList(list) {
this.list.splice(0);
let rowIndex = 0;
for (const line of list) {
const { productLine, specification, data } = line;
// span
this.spanInfo[rowIndex] = data.length;
for (const equipment of data) {
const { equipmentName, totalQuantity } = equipment;
let row = {
productLine,
specification: specification.join('、'),
equipmentName,
totalQuantity,
};
rowIndex += 1;
for (const [key, hourData] of Object.entries(equipment.hourData)) {
const { inQuantity, outQuantity, nokQuantity, scrapRatio } =
hourData;
row[key + '__in'] = inQuantity;
row[key + '__out'] = outQuantity;
row[key + '__nok'] = nokQuantity;
row[key + '__ratio'] = scrapRatio;
}
this.list.push(row);
}
}
},
buildData(data) {
this.convertList(data);
},
/** 合并table列的规则 */
mergeColumnHandler({ row, column, rowIndex, columnIndex }) {
if (columnIndex == 0 || columnIndex == 1) {
if (this.spanInfo[rowIndex]) {
return [
this.spanInfo[rowIndex], // row span
1, // col span
];
} else {
return [0, 0];
}
}
},
async getList() {
const { data } = await this.$axios({
url: '/monitoring/equipment-monitor/recent-24-hours',
method: 'get',
});
// const data = this.res.data;
// console.log('recent-24', data);
this.initing = true;
this.buildProps(data[0]);
this.buildData(data);
this.queryParams.pageSize = this.list.length;
setTimeout(() => {
this.initing = false;
}, 1000);
},
handleEmitFun(payload) {
console.log('payload', payload);
},
},
};
</script>
<style scoped lang="scss">
::-webkit-scrollbar {
display: none;
}
pre {
margin: 10px;
background: #f6f8faf6;
border: 1px solid #e1e4e8;
padding: 12px;
border-radius: 12px;
position: fixed;
// top: 15vh;
top: 10vh;
left: 0;
max-height: 80vh;
overflow-y: auto;
z-index: 100000;
box-shadow: 0 0 32px 12px #0001;
}
code {
font-family: 'IntelOne Mono', 'Ubuntu', 'Courier New', Courier, monospace;
}
</style>

View File

@ -0,0 +1,283 @@
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<SearchBar
:formConfigs="searchBarFormConfig"
ref="search-bar"
@headBtnClick="handleSearchBarBtnClick"
@select-changed="handleSearchBarItemChange" />
<!-- 列表 -->
<base-table
:table-props="tableProps"
:page="queryParams.pageNo"
:limit="queryParams.pageSize"
:table-data="list"
@emitFun="handleEmitFun">
<method-btn
v-if="tableBtn.length"
slot="handleBtn"
label="操作"
:method-list="tableBtn"
@clickBtn="handleTableBtnClick" />
</base-table>
<!-- 分页组件 -->
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNo"
:limit.sync="queryParams.pageSize"
@pagination="getList" />
<!-- 对话框(添加 / 修改) -->
<!-- <base-dialog
:dialogTitle="title"
:dialogVisible="open"
width="500px"
@close="cancel"
@cancel="cancel"
@confirm="submitForm">
<DialogForm v-if="open" ref="form" :dataForm="form" :rows="rows" />
</base-dialog> -->
</div>
</template>
<script>
import moment from 'moment';
import basicPageMixin from '@/mixins/lb/basicPageMixin';
import { publicFormatter } from '@/utils/dict';
export default {
name: 'EquipmentStatusAndParams',
mixins: [basicPageMixin],
data() {
return {
searchBarKeys: ['equipmentId', 'productionLineId'],
tableBtn: [
this.$auth.hasPermi('base:equipment-alarm-log:update')
? {
type: 'edit',
btnName: '修改',
}
: undefined,
this.$auth.hasPermi('base:equipment-alarm-log:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
tableProps: [
{
width: 128,
prop: 'equipmentName',
label: '设备名称',
align: 'center',
},
{
width: 128,
prop: 'equipmentCode',
label: '设备编码',
align: 'center',
},
{ width: 128, prop: 'inQuantity', label: '投入数', align: 'center' },
{ width: 128, prop: 'outQuantity', label: '产出数', align: 'center' },
{
width: 128,
prop: 'run',
label: '是否运行',
align: 'center',
filter: (val) => (val != null ? (val ? '是' : '否') : '-'),
},
{
width: 128,
prop: 'status',
label: '状态',
align: 'center',
filter: (val) =>
val != null ? ['正常', '计划停机', '故障'][val] : '-',
},
{
width: 128,
prop: 'error',
label: '是否故障',
align: 'center',
filter: (val) => (val != null ? (val ? '是' : '否') : '-'),
},
{
prop: 'quantityRecordTime',
label: '生产量记录时间',
width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
},
{
prop: 'statusRecordTime',
label: '状态量记录时间',
width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
},
{
_action: 'params-monitor',
label: '参数监控',
align: 'center',
subcomponent: {
props: ['injectData'],
render: function (h) {
const _this = this;
return h(
'el-button',
{
props: { type: 'text', size: 'mini' },
on: {
click: function () {
console.log('inejctdata', _this.injectData);
_this.$emit('emitData', {
action: _this.injectData._action,
// value: _this.injectData.id,
value: _this.injectData,
});
},
},
},
'查看监控'
);
},
},
},
],
searchBarFormConfig: [
// {
// type: 'datePicker',
// label: '',
// dateType: 'daterange', // datetimerange
// // format: 'yyyy-MM-dd HH:mm:ss',
// format: 'yyyy-MM-dd',
// valueFormat: 'yyyy-MM-dd HH:mm:ss',
// rangeSeparator: '-',
// startPlaceholder: '',
// endPlaceholder: '',
// defaultTime: ['00:00:00', '23:59:59'],
// param: 'createTime',
// // width: 350,
// },
{
type: 'select',
label: '产线',
onchange: true,
placeholder: '请选择产线',
selectOptions: [],
param: 'productionLineId',
},
{
type: 'select',
label: '设备',
placeholder: '请选择设备',
param: 'equipmentId',
selectOptions: [],
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
],
//
open: false,
//
queryParams: {
pageNo: 1,
pageSize: 10,
productionLineId: null,
equipmentId: null,
},
total: 0,
//
form: {},
//
rules: {},
};
},
created() {
this.getLineList();
this.getList();
},
methods: {
/** 获取产线 */
async getLineList() {
const { data } = await this.$axios({
url: '/base/production-line/listAll',
method: 'get',
});
this.searchBarFormConfig[0].selectOptions = data.map((line) => ({
name: line.name,
id: line.id,
}));
},
/** 根据产线获取设备 */
async getEquipmentList(id) {
const { data } = await this.$axios({
url: '/base/equipment/listByLine',
method: 'get',
query: { id },
});
return data;
},
/** 监听 search bar 的产线下拉框改变 */
async handleSearchBarItemChange({ param, value: id }) {
if (param == 'productionLineId') {
if (id == '') {
//
this.searchBarFormConfig[1].selectOptions = [];
return;
}
const list = await this.getEquipmentList(id);
this.searchBarFormConfig[1].selectOptions = list.map((eq) => ({
name: eq.name,
id: eq.id,
}));
}
},
handleSearchBarBtnClick(btn) {
const { equipmentId, productionLineId } = btn;
if (equipmentId) this.queryParams.equipmentId = equipmentId;
else this.queryParams.equipmentId = null;
if (productionLineId)
this.queryParams.productionLineId = productionLineId;
else this.queryParams.productionLineId = null;
this.getList();
},
/** 查询列表 */
async getList() {
this.loading = true;
const { data } = await this.$axios({
url: '/monitoring/equipment-monitor/realtime-page',
method: 'get',
params: this.queryParams,
});
this.list = data.list;
this.total = data.total;
},
handleEmitFun({ action, value }) {
if (action == 'params-monitor') {
const { equipmentId, equipmentName, equipmentCode } = value;
this.$router.push({
name: 'equipmentFullParams',
params: {
equipmentId,
equipmentCode,
equipmentName,
},
});
}
},
},
};
</script>