Merge pull request 'projects/mesxc-lb' (#149) from projects/mesxc-lb into projects/mesxc-test

Reviewed-on: #149
This commit is contained in:
g7hoo 2023-12-19 09:02:24 +08:00
commit 4e064e4b01
56 changed files with 11018 additions and 11 deletions

View File

@ -86,8 +86,8 @@
</span>
<!-- :file-list="uploadedFileList" -->
<el-upload
class="upload-in-dialog"
v-if="col.upload"
class="upload-in-dialog"
:key="col.prop + '__el-upload'"
:action="uploadUrl"
:headers="uploadHeaders"
@ -101,7 +101,7 @@
}
"
v-bind="col.bind">
<el-button size="mini" :disabled="col.bind?.disabled || false">
<el-button size="mini" :disabled="disabled || col.bind?.disabled || false">
<svg-icon
icon-class="icon-upload"
style="color: inherit"></svg-icon>
@ -117,6 +117,7 @@
v-for="file in form[col.prop]"
:file="file"
:key="file.fileUrl"
:disabled="disabled"
@delete="!disabled && handleDeleteFile(file, col.prop)" />
</div>
</el-form-item>
@ -142,6 +143,12 @@ function findMaxLabelWidth(rows) {
if (!opt.label) return 0;
if (opt.label.length > max) {
max = opt.label.length;
<<<<<<< HEAD
if (opt.label.includes('(')) {
max = max - 3;
}
=======
>>>>>>> projects/mesxc-test
}
});
});
@ -150,7 +157,7 @@ function findMaxLabelWidth(rows) {
const uploadedFile = {
name: 'UploadedFile',
props: ['file'],
props: ['file', 'disabled'],
data() {
return {};
},
@ -195,13 +202,15 @@ const uploadedFile = {
display: 'inline-block',
}}>
{this.file.fileName}
<el-button
type="text"
icon="el-icon-close"
style="float: right; position: relative; top: 2px; left: 8px; z-index: 100"
class="dialog__upload_component__close"
onClick={this.handleDelete}
/>
{!this.disabled && (
<el-button
type="text"
icon="el-icon-close"
style="float: right; position: relative; top: 2px; left: 8px; z-index: 100"
class="dialog__upload_component__close"
onClick={this.handleDelete}
/>
)}
</div>
);
},

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@ -0,0 +1,97 @@
<!--
filename: Container.vue
author: liubin
date: 2023-12-05 14:29:53
description: 窑炉容器
-->
<template>
<div class="kiln-container" :class="['kiln-container__' + size]">
<div class="container-hd" style="display: flex; align-items: center">
<i
class=""
style="display: inline-block; margin-left: 12px; padding-top: 4px">
<img :src="imgSrc" width="18" height="16" alt="" />
</i>
<span
style="
color: #fff;
font-size: 20px;
line-height: 2;
margin-left: 6px;
display: inline-block;
">
{{ name }}
</span>
</div>
<div class="container-body">
<slot>
<div class="test-body">something test....</div>
</slot>
</div>
</div>
</template>
<script>
export default {
name: 'KilnContainer',
components: {},
props: ['name', 'width', 'size'],
data() {
return {};
},
computed: {
imgSrc() {
switch (this.name) {
case '原料用量统计':
return require('../assets/move.png');
case '风机运行频率':
return require('../assets/flow.png');
case 'ISRA缺陷检测':
return require('../assets/gas.png');
case '能耗':
return require('../assets/gas.png');
case '窑炉信息':
return require('../assets/gas.png');
case '烟气处理':
return require('../assets/gas.png');
}
},
},
methods: {},
};
</script>
<style scoped lang="scss">
.kiln-container {
display: inline-block;
width: 100%;
height: 100%;
padding: 8px;
display: flex;
flex-direction: column;
position: relative;
&__small {
background: url(../assets/short.png) no-repeat;
background-size: 100% 100%;
background-position: 0 0;
}
&__middle {
background: url(../assets/middle.png) no-repeat;
background-size: 100% 100%;
background-position: 0 0;
}
&__large {
background: url(../assets/high.png) no-repeat;
background-size: 100% 100%;
background-position: 0 0;
}
}
.container-body {
flex: 1;
}
</style>

View File

@ -0,0 +1,84 @@
<!--
filename: DateBtnGroup.vue
author: liubin
date: 2023-12-05 14:35:14
description: 日期按钮组
-->
<template>
<div class="date-btn-group">
<button
class="btn"
:class="{ 'btn-active': active == '日' }"
@click="handleClick('日')">
</button>
<button
class="btn"
:class="{ 'btn-active': active == '周' }"
@click="handleClick('周')">
</button>
<button
class="btn"
:class="{ 'btn-active': active == '月' }"
@click="handleClick('月')">
</button>
</div>
</template>
<script>
export default {
name: 'DateBtnGroup',
data() {
return {
active: '日',
};
},
methods: {
handleClick(v) {
this.active = v;
this.$emit('change', v);
},
},
};
</script>
<style scoped lang="scss">
button {
appearance: none;
border: none;
outline: none;
background: none;
padding: 6px 8px;
}
.date-btn-group {
// position: absolute;
// top: 40px;
// right: 100px;
// border: 1px solid #ccc;
// padding: 12px;
display: flex;
align-items: center;
gap: 12px;
}
.btn {
cursor: pointer;
border: 1px solid #11e8e4;
border-radius: 4px;
color: #11e8e4;
transition: all 0.3s ease-in-out;
&:hover {
background: #11e8e4;
color: #013433;
}
}
.btn-active {
background: #11e8e4;
color: #013433;
}
</style>

View File

@ -0,0 +1,150 @@
<!--
filename: GasChart.vue
author: liubin
date: 2023-12-12 10:53:49
description:
-->
<template>
<div class="gas-chart"></div>
</template>
<script>
import * as echarts from 'echarts';
export default {
name: 'GasChart',
components: {},
props: {},
data() {
const colors = [
'#12FFF5',
'#2760FF',
'#FFD160',
'#E80091',
'#8064ff',
'#ff8a3b',
'#8cd26d',
'#2aa1ff',
];
return {
chart: null,
option: {
color: colors,
grid: { top: 32, right: 12, bottom: 20, left: 48 },
xAxis: {
type: 'category',
data: Array(7)
.fill(1)
.map((_, index) => {
const today = new Date();
const dtimestamp = today - index * 24 * 60 * 60 * 1000;
return `${new Date(dtimestamp).getMonth() + 1}.${new Date(
dtimestamp
).getDate()}`;
})
.reverse(),
axisLabel: {
color: '#fff',
fontSize: 12,
},
axisTick: { show: false },
axisLine: {
lineStyle: {
width: 1,
color: '#213259',
},
},
},
yAxis: {
name: '单位m³/h',
nameTextStyle: {
color: '#fff',
fontSize: 10,
align: 'right',
},
type: 'value',
axisLabel: {
color: '#fff',
fontSize: 12,
},
axisLine: {
show: true,
lineStyle: {
color: '#213259',
},
},
splitLine: {
lineStyle: {
color: '#213259a0',
},
},
},
series: [
Array(7)
.fill(1)
.map((_) => Math.ceil(Math.random() * 100)),
Array(7)
.fill(1)
.map((_) => Math.ceil(Math.random() * 100)),
Array(7)
.fill(1)
.map((_) => Math.ceil(Math.random() * 100)),
].map((v, i) => ({
name: ['总量', '白班', '夜班'][i],
data: v,
type: 'line',
symbol: 'circle',
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
// i % 8 8
{ offset: 0, color: colors[i % 8] + '40' },
{ offset: 0.5, color: colors[i % 8] + '20' },
{ offset: 1, color: colors[i % 8] + '00' },
]),
},
})),
tooltip: {
trigger: 'axis',
},
},
};
},
inject: ['resizeChart'],
computed: {
sidebarStatus() {
return this.$store.state.app.sidebar.opened;
},
},
watch: {
sidebarStatus(val) {
console.log('sidebarStatus', val);
this.chart && this.chart.dispose();
setTimeout(() => {
this.chart = echarts.init(this.$el);
this.chart.setOption(this.option);
}, 500);
},
// resizeChart(val) {
// console.log('resizeChart', val);
// val && this.chart && this.chart.resize();
// },
},
mounted() {
this.$el.addEventListener('resize', () => {
console.log('resziing.....');
});
this.chart = echarts.init(this.$el);
this.chart.setOption(this.option);
},
methods: {},
};
</script>
<style scoped lang="scss">
.gas-chart {
width: 100%;
height: 100%;
}
</style>

View File

@ -0,0 +1,75 @@
<!--
filename: Header.vue
author: liubin
date: 2023-12-05 14:30:46
description: 顶部标题
-->
<template>
<header class="kiln-header">
<h1
style="
font-size: 32px;
margin-bottom: 36px;
color: #0ee8e4;
letter-spacing: 5px;
">
窑炉生产运行驾驶舱
</h1>
<!-- left: 312px; -->
<div
class="firm"
style="
position: absolute;
bottom: 24px;
left: 16.5vw;
color: #fff;
font-size: 16px;
letter-spacing: 1px;
">
单位: 河南汇融科技服务有限公司
</div>
<div
class="datetime"
style="
position: absolute;
bottom: 18px;
right: 15.5vw;
color: #fff;
font-size: 16px;
letter-spacing: 1px;
display: flex;
align-items: center;
gap: 16px;
">
<DateBtnGroup />
{{ new Date().toLocaleString() }}
</div>
</header>
</template>
<script>
import DateBtnGroup from './DateBtnGroup.vue';
export default {
name: 'KilnHeader',
components: { DateBtnGroup },
props: {},
data() {
return {};
},
computed: {},
methods: {},
};
</script>
<style scoped lang="scss">
.kiln-header {
background: url('../assets/head.png') no-repeat;
height: 88px;
background-size: 100%;
background-position: 0 0;
display: grid;
place-content: center;
position: relative;
}
</style>

View File

@ -0,0 +1,235 @@
<!--
filename: ISRAChart.vue
author: liubin
date: 2023-12-12 09:05:25
description:
-->
<template>
<div class="isra-chart"></div>
</template>
<script>
import * as echarts from 'echarts';
export default {
name: 'ISRAChart',
components: {},
props: {},
data() {
return {
chart: null,
option: {
color: ['#2760ff', '#518eec', '#0ee8e4', '#ddb523'],
tooltip: {
trigger: 'item',
},
title: {
text: 11234,
subtext: '总数',
top: '43%',
left: '49%',
textAlign: 'center',
textStyle: {
fontSize: 32,
lineHeight: 16,
color: '#fff',
},
subtextStyle: {
fontSize: 16,
color: '#fff7',
},
},
series: [
{
name: 'Access From',
type: 'pie',
radius: ['60%', '85%'],
avoidLabelOverlap: true,
label: {
show: true,
position: 'outside',
formatter: ({ dataIndex, percent }) => {
// console.log(
// ['#2760ff', '#518eec', '#0ee8e4', '#ddb523'][dataIndex % 4],
// percent
// );
const styleName = ['a', 'b', 'c', 'd'][dataIndex % 4];
return `{${styleName}|${percent}%}`;
},
rich: {
a: {
color: '#2760ff',
fontSize: 18,
borderWidth: 0,
textBorderWidth: 0,
},
b: {
color: '#518eec',
fontSize: 18,
borderWidth: 0,
textBorderWidth: 0,
},
c: {
color: '#0ee8e4',
fontSize: 18,
borderWidth: 0,
textBorderWidth: 0,
},
d: {
color: '#ddb523',
fontSize: 18,
borderWidth: 0,
textBorderWidth: 0,
},
},
},
labelLine: {
show: true,
},
itemStyle: {
borderRadius: 12,
// borderColor: 'transparent',
// borderWidth: 20
},
data: [
{
value: 1048,
name: '缺陷1',
itemStyle: {
color: {
type: 'linear',
x: 1,
y: 1,
x2: 0,
y2: 0,
colorStops: [
{
offset: 0,
color: '#2760ff', // 0%
},
// {
// offset: 0.6,
// color: 'transparent', // 80%
// },
{
offset: 1,
color: '#2760ff33', // 100%
},
],
global: false, // false
},
},
},
{
value: 735,
name: '缺陷2',
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 1,
y2: 0,
colorStops: [
{
offset: 0,
color: '#518eec', // 0%
},
// {
// offset: 0.6,
// color: 'transparent', // 80%
// },
{
offset: 1,
color: '#518eec33', // 100%
},
],
global: false, // false
},
},
},
{
value: 580,
name: '缺陷3',
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 1,
y2: 1,
colorStops: [
{
offset: 0,
color: '#0ee8e4', // 0%
},
// {
// offset: 0.6,
// color: 'transparent', // 80%
// },
{
offset: 1,
color: '#0ee8e433', // 100%
},
],
global: false, // false
},
},
},
{
value: 484,
name: '缺陷4',
itemStyle: {
color: {
type: 'linear',
x: 1,
y: 0,
x2: 0,
y2: 0,
colorStops: [
{
offset: 0,
color: '#ddb523', // 0%
},
// {
// offset: 0.6,
// color: 'transparent', // 70%
// },
{
offset: 1,
color: '#ddb52333', // 100%
},
],
global: false, // false
},
},
},
],
},
],
},
};
},
mounted() {
this.initChart();
},
activated() {
// this.initChart();
},
computed: {},
methods: {
initChart() {
this.chart = echarts.init(this.$el);
this.chart.setOption(this.option);
},
},
};
</script>
<style scoped lang="scss">
.isra-chart {
width: 100%;
height: 100%;
}
</style>

View File

@ -0,0 +1,69 @@
<!--
filename: SelectorBtnGroup.vue
author: liubin
date: 2023-12-05 14:28:24
description: 选项按钮组
-->
<template>
<div class="selector-btn-group">
<button
class="btn"
v-for="opt in options"
:key="opt"
@click="active = opt"
:class="active == opt ? 'btn-active' : ''">
{{ opt }}
</button>
</div>
</template>
<script>
export default {
name: 'SelectorBtnGroup',
components: {},
props: ['options'],
data() {
return {
active: this.options[0] || 'default'
};
},
computed: {},
methods: {},
};
</script>
<style scoped lang="scss">
button {
border: none;
appearance: none;
outline: none;
color: red;
font-size: 14px;
padding: 8px 12px;
}
button:first-child {
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
}
button:last-child {
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
}
.selector-btn-group {
}
.btn {
background: #03233c;
color: #fff;
cursor: pointer;
transition: all 0.3s ease-out;
&.btn-active,
&:hover {
background: #0f3d5c;
}
}
</style>

View File

@ -0,0 +1,71 @@
<!--
filename: ShadowRect.vue
author: liubin
date: 2023-12-05 14:28:57
description: 阴影矩形
-->
<template>
<div class="shadow-rect" :style="{ borderRadius: rounded ? '8px' : '2px' }">
<slot>
<div
class="test-data"
style="flex: 1; display: flex; align-items: center">
<span
style="
flex: 7;
color: #fff;
text-align: right;
font-size: 18px;
line-height: 1.12;
letter-spacing: 1px;
padding-right: 12px;
">
窑炉压力碹顶加权
</span>
<span
style="
flex: 3;
color: #fff;
text-align: left;
font-size: 18px;
line-height: 1.12;
padding-right: 8px;
">
92Kpa
</span>
</div>
</slot>
</div>
</template>
<script>
export default {
name: '',
components: {},
props: ['rounded'],
data() {
return {};
},
watch: {
rounded(val) {
if (val) {
console.log('val', val);
}
},
},
computed: {},
methods: {},
};
</script>
<style scoped lang="scss">
.shadow-rect {
padding: 8px;
border-radius: 2px;
box-shadow: inset 0 0 8px 2px #ccc3;
color: white;
display: flex;
align-items: center;
}
</style>

View File

@ -0,0 +1,57 @@
<!--
filename: Switcher.vue
author: liubin
date: 2023-12-05 14:29:29
description: 开关
-->
<template>
<div class="switcher" style="display: flex; align-items: center; gap: 12px">
<el-switch v-model="value"></el-switch>
<span style="color: #fff; font-size: 16px">{{ mode }}</span>
;
</div>
</template>
<script>
export default {
name: 'Switcher',
components: {},
props: {},
data() {
return {
value: true,
};
},
computed: {
mode() {
return this.value ? '历史详情' : '实时数据';
},
},
methods: {},
};
</script>
<style scoped lang="scss">
.switcher {
:deep(.el-switch__core) {
border: none;
background-color: #213d566b;
&::after {
background-color: #02457e;
}
}
:deep(.is-checked) {
.el-switch__core {
border: none;
background-color: #b4fffc;
&::after {
background-color: #08d8cd;
}
}
}
}
</style>

View File

@ -0,0 +1,16 @@
export default {
name: 'KilnLine',
props: ['horizontal'],
render: function (h) {
return (
<div
class="line"
style={{
width: this.horizontal ? '100%' : '4px',
height: this.horizontal ? '4px' : '100%',
background:
'radial-gradient(ellipse at center, #3CE7FF, #3CE7FF66, transparent, transparent)',
}}></div>
);
},
};

View File

@ -0,0 +1,101 @@
<!--
filename: MaterialCost.vue
author: liubin
date: 2023-12-06 09:09:27
description:
-->
<template>
<Container name="能耗" size="middle" style="">
<EnergeTop />
<SplitLine :horizontal="true" />
<div class="" style="flex: 2; padding: 8px">
<div
class="header-line"
style="margin-bottom: 8px; display: flex; align-items: center">
<h2 class="" style="margin: 0; color: #0ee8fe; margin-right: 12px">
烟气趋势图
</h2>
<Switcher />
<div>
<span class="lgd lgd-total">总量</span>
<!-- <span class="lgd lgd-day">白班</span>
<span class="lgd lgd-night">夜班</span> -->
</div>
</div>
<div
class="select-line"
style="
display: flex;
align-items: center;
justify-content: space-between;
">
<SelectorBtnGroup
:options="['氧气含量', '二氧化硫', '一氧化氢', '二氧化氢']" />
<SelectorBtnGroup :options="['日', '周', '月', '年']" />
</div>
<div class="chart" style="height: 150px; margin-top: 8px;">
<GasChart />
</div>
</div>
</Container>
</template>
<script>
import Container from '../components/Container.vue';
import ShadowRect from '../components/ShadowRect.vue';
import SplitLine from '../components/line';
import Switcher from '../components/Switcher.vue';
import EnergeTop from './EnergeTop.vue';
import GasChart from '../components/GasChart.vue';
import SelectorBtnGroup from '../components/SelectorBtnGroup.vue';
export default {
name: 'EnergeCost',
components: {
Container,
ShadowRect,
SplitLine,
Switcher,
EnergeTop,
GasChart,
SelectorBtnGroup,
},
props: {},
data() {
return {};
},
computed: {},
methods: {},
};
</script>
<style scoped lang="scss">
.lgd {
color: #fff;
&:not(:last-child) {
margin-right: 12px;
}
}
.lgd::before {
content: '';
display: inline-block;
width: 8px;
height: 8px;
margin-right: 4px;
border-radius: 2px;
}
.lgd.lgd-total::before {
background-color: #ff9e00;
}
.lgd.lgd-day::before {
background-color: #08d8cd;
}
.lgd.lgd-night::before {
background-color: #0b58ff;
}
</style>

View File

@ -0,0 +1,123 @@
<!--
filename: EnergeTop.vue
author: liubin
date: 2023-12-11 09:31:41
description:
-->
<template>
<div
class="energe-top"
style="
flex: 1;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: auto;
gap: 8px;
padding: 4px;
">
<ShadowRect
style="grid-row: 1 / 3; flex-direction: column; justify-content: center">
<span
style="
font-size: 16px;
line-height: 1.55;
text-align: right;
padding-right: 8px;
letter-spacing: 1px;
">
余热发电
</span>
<span
style="
font-size: 16px;
line-height: 1.55;
text-align: right;
padding-right: 8px;
letter-spacing: 1px;
">
1023kWh
</span>
</ShadowRect>
<ShadowRect>
<div
style="
font-size: 16px;
line-height: 1.25;
flex: 1.2;
text-align: right;
padding-right: 8px;
letter-spacing: 3px;
">
<p style="margin: 0; line-height: inherit">水耗量</p>
</div>
<span style="font-size: 16px; line-height: 1.24; flex: 1">32Km³</span>
</ShadowRect>
<ShadowRect>
<div
style="
font-size: 16px;
line-height: 1.25;
flex: 1.2;
text-align: right;
padding-right: 8px;
letter-spacing: 3px;
">
<p style="margin: 0; line-height: inherit">天然气I</p>
</div>
<span style="font-size: 16px; line-height: 1.24; flex: 1">322Km³</span>
</ShadowRect>
<ShadowRect>
<div
style="
font-size: 16px;
line-height: 1.25;
flex: 1.2;
text-align: right;
padding-right: 8px;
letter-spacing: 3px;
">
<p style="margin: 0; line-height: inherit">电耗量</p>
</div>
<span style="font-size: 16px; line-height: 1.24; flex: 1">132kWh</span>
</ShadowRect>
<ShadowRect>
<div
style="
font-size: 16px;
line-height: 1.25;
flex: 1.2;
text-align: right;
padding-right: 8px;
letter-spacing: 3px;
">
<p style="margin: 0; line-height: inherit">天然气II</p>
</div>
<span style="font-size: 16px; line-height: 1.24; flex: 1">992Km³</span>
</ShadowRect>
</div>
</template>
<script>
import ShadowRect from '../components/ShadowRect.vue';
export default {
name: 'EnergeTop',
components: { ShadowRect },
props: {},
data() {
return {};
},
computed: {},
methods: {},
};
</script>
<style scoped lang="scss">
.energe-top {
}
</style>

View File

@ -0,0 +1,58 @@
<!--
filename: FanSequence.vue
author: liubin
date: 2023-12-06 09:40:51
description:
-->
<template>
<Container name="风机运行频率" size="middle" style="">
<div class="" style="position: absolute; top: 18px; left: 180px">
<Switcher />
</div>
<div
class="absolute"
style="
padding: 12px;
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-auto-rows: auto;
gap: 8px;
">
<ShadowRect v-for="n in 14" :key="n" :rounded="false">
<span
style="
font-size: 16px;
line-height: 1.24;
flex: 1.2;
text-align: right;
padding-right: 8px;
letter-spacing: 1px;
">
{{ n }}#风机
</span>
<span style="font-size: 16px; line-height: 1.24; flex: 1">
{{ Math.floor(Math.random() * 100) }}Hz
</span>
</ShadowRect>
</div>
</Container>
</template>
<script>
import Container from '../components/Container.vue';
import ShadowRect from '../components/ShadowRect.vue';
import Switcher from '../components/Switcher.vue';
export default {
name: 'FanSequence',
components: { Container, ShadowRect, Switcher },
props: {},
data() {
return {};
},
computed: {},
methods: {},
};
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,176 @@
<!--
filename: GasHandle.vue
author: liubin
date: 2023-12-11 09:02:40
description:
-->
<template>
<div class="gas-handle" style="flex: 2">
<Container name="烟气处理" size="large" style="">
<div
class=""
style="
flex: 1;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: auto;
gap: 8px;
padding: 8px;
">
<ShadowRect>
<span
style="
font-size: 16px;
line-height: 1.24;
flex: 1.2;
text-align: right;
padding-right: 8px;
letter-spacing: 1px;
">
氧气含量
</span>
<span style="font-size: 16px; line-height: 1.24; flex: 1">82%</span>
</ShadowRect>
<ShadowRect>
<div
style="
font-size: 16px;
line-height: 1.5;
flex: 1.2;
text-align: right;
padding-right: 8px;
letter-spacing: 3px;
">
<p style="margin: 0; line-height: inherit">一氧化氮</p>
<p style="margin: 0; line-height: inherit">排放浓度</p>
</div>
<span style="font-size: 16px; line-height: 1.24; flex: 1">82%</span>
</ShadowRect>
<ShadowRect>
<div
style="
font-size: 16px;
line-height: 1.5;
flex: 1.2;
text-align: right;
padding-right: 8px;
letter-spacing: 3px;
">
<p style="margin: 0; line-height: inherit">二氧化硫</p>
<p style="margin: 0; line-height: inherit">排放浓度</p>
</div>
<span style="font-size: 16px; line-height: 1.24; flex: 1">82%</span>
</ShadowRect>
<ShadowRect>
<div
style="
font-size: 16px;
line-height: 1.5;
flex: 1.2;
text-align: right;
padding-right: 8px;
letter-spacing: 3px;
">
<p style="margin: 0; line-height: inherit">二氧化氮</p>
<p style="margin: 0; line-height: inherit">排放浓度</p>
</div>
<span style="font-size: 16px; line-height: 1.24; flex: 1">82%</span>
</ShadowRect>
</div>
<KilnLine :horizontal="true" />
<div class="" style="flex: 2; padding: 8px">
<div
class="header-line"
style="margin-bottom: 8px; display: flex; align-items: center">
<h2 class="" style="margin: 0; color: #0ee8fe; margin-right: 12px">
烟气趋势图
</h2>
<Switcher />
<div>
<span class="lgd lgd-total">总量</span>
<span class="lgd lgd-day">白班</span>
<span class="lgd lgd-night">夜班</span>
</div>
</div>
<div
class="select-line"
style="
display: flex;
align-items: center;
justify-content: space-between;
">
<SelectorBtnGroup
:options="['氧气含量', '二氧化硫', '一氧化氢', '二氧化氢']" />
<SelectorBtnGroup :options="['日', '周', '月', '年']" />
</div>
<div class="chart" style="height: 220px">
<GasChart />
</div>
</div>
</Container>
</div>
</template>
<script>
import Container from '../components/Container.vue';
import ShadowRect from '../components/ShadowRect.vue';
import KilnLine from '../components/line';
import Switcher from '../components/Switcher.vue';
import SelectorBtnGroup from '../components/SelectorBtnGroup.vue';
import GasChart from '../components/GasChart.vue';
export default {
name: 'GasHandle',
components: {
Container,
ShadowRect,
KilnLine,
Switcher,
SelectorBtnGroup,
GasChart,
},
props: {},
data() {
return {};
},
computed: {},
methods: {},
};
</script>
<style scoped lang="scss">
.gas-handle {
}
.lgd {
color: #fff;
&:not(:last-child) {
margin-right: 12px;
}
}
.lgd::before {
content: '';
display: inline-block;
width: 8px;
height: 8px;
margin-right: 4px;
border-radius: 2px;
}
.lgd.lgd-total::before {
background-color: #ff9e00;
}
.lgd.lgd-day::before {
background-color: #08d8cd;
}
.lgd.lgd-night::before {
background-color: #0b58ff;
}
</style>

View File

@ -0,0 +1,84 @@
<!--
filename: IsraCheck.vue
author: liubin
date: 2023-12-06 09:50:13
description:
-->
<template>
<Container name="ISRA缺陷检测" size="middle" style="">
<div style="padding: 12px; display: flex; flex-direction: column; gap: 8px; height: 100%;">
<div class="f" style="flex: 9;">
<ISRAChart />
</div>
<ul
class="legend"
style="
flex: 1;
padding: 8px;
display: flex;
justify-content: center;
gap: 20px;
color: #fff;
font-size: 14px;
">
<li class="fault-1">缺陷1</li>
<li class="fault-2">缺陷2</li>
<li class="fault-3">缺陷3</li>
<li class="fault-4">缺陷4</li>
</ul>
</div>
</Container>
</template>
<script>
import Container from '../components/Container.vue';
import ShadowRect from '../components/ShadowRect.vue';
import ISRAChart from '../components/ISRAChart.vue';
export default {
name: 'IsraCheck',
components: { Container, ShadowRect, ISRAChart },
props: {},
data() {
return {};
},
computed: {},
methods: {},
};
</script>
<style scoped lang="scss">
ul,
li {
margin: 0;
padding: 0;
list-style: none;
position: relative;
}
li::before {
content: '';
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
background: #ccc;
position: absolute;
top: 30%;
left: -12px;
}
li.fault-1::before {
background: #2760ff;
}
li.fault-2::before {
background: #518eec;
}
li.fault-3::before {
background: #0ee8e4;
}
li.fault-4::before {
background: #ddb523;
}
</style>

View File

@ -0,0 +1,71 @@
<!--
filename: KilnInfo.vue
author: liubin
date: 2023-12-11 09:01:15
description:
-->
<template>
<div class="kiln-info" style="flex: 1">
<Container name="窑炉信息" size="small" style="">
<div
class="absolute"
style="
padding: 12px;
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-auto-rows: auto;
gap: 8px;
">
<ShadowRect v-for="info in kilnInfo" :key="info.name" :rounded="false">
<span
style="
font-size: 16px;
line-height: 1.45;
flex: 1.2;
text-align: right;
padding-right: 8px;
letter-spacing: 1px;
">
{{ info.name }}
</span>
<span style="font-size: 16px; line-height: 1.45; flex: 1">
{{ info.value }}
<!-- {{ Math.floor(Math.random() * 100) }}Hz -->
</span>
</ShadowRect>
</div>
</Container>
</div>
</template>
<script>
import Container from '../components/Container.vue';
import ShadowRect from '../components/ShadowRect.vue';
export default {
name: 'KilnInfo',
components: { Container, ShadowRect },
props: {},
data() {
return {
kilnInfo: [
{ name: '窑炉压力', value: '83Kpa' },
{ name: '循环水温度', value: '53℃' },
{ name: '循环水流量', value: '23m³/h' },
{ name: '循环水压力', value: '33Kpa' },
{ name: '助燃风压力', value: '12Kpa' },
{ name: '碹顶加权温度', value: '32℃' },
{ name: '压缩气压力', value: '83Kpa' },
{ name: '融化加权温度', value: '123℃' },
],
};
},
computed: {},
methods: {},
};
</script>
<style scoped lang="scss">
.kiln-info {
}
</style>

View File

@ -0,0 +1,41 @@
<!--
filename: LeftFour.vue
author: liubin
date: 2023-12-06 09:35:30
description:
-->
<template>
<div
class="left-four"
style="
display: grid;
gap: 16px;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
">
<MaterialCost />
<IsraCheck />
<EnergeCost />
<FanSequence />
</div>
</template>
<script>
import MaterialCost from './MaterialCost.vue';
import FanSequence from './FanSequence.vue';
import IsraCheck from './IsraCheck.vue';
import EnergeCost from './EnergeCost.vue';
export default {
name: 'LeftFour',
components: { MaterialCost, EnergeCost, IsraCheck, FanSequence },
props: {},
data() {
return {};
},
computed: {},
methods: {},
};
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,58 @@
<!--
filename: MaterialCost.vue
author: liubin
date: 2023-12-06 09:09:27
description:
-->
<template>
<Container name="原料用量统计" size="middle" style="">
<div
class="absolute"
style="
padding: 12px;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: auto;
gap: 8px;
">
<ShadowRect v-for="n in 9" :key="n" :rounded="false">
<div
class="material"
style="
flex: 1;
padding: 6px;
display: flex;
flex-direction: column;
gap: 4px;
align-items: center;
justify-content: center;
">
<span style="color: #0ee8e4; font-weight: 500; font-size: 32px">
234
</span>
<span style="color: #fff; font-size: 14px; letter-spacing: 1px">
- 原料1/ -
</span>
</div>
</ShadowRect>
</div>
</Container>
</template>
<script>
import Container from '../components/Container.vue';
import ShadowRect from '../components/ShadowRect.vue';
export default {
name: 'MaterialCost',
components: { Container, ShadowRect },
props: {},
data() {
return {};
},
computed: {},
methods: {},
};
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,37 @@
<!--
filename: RightTwo.vue
author: liubin
date: 2023-12-06 10:19:00
description:
-->
<template>
<div
class="right-two"
style="display: flex; gap: 16px; flex-direction: column">
<KilnInfo />
<GasHandle />
</div>
</template>
<script>
import Container from '../components/Container.vue';
import ShadowRect from '../components/ShadowRect.vue';
import KilnLine from '../components/line';
import Switcher from '../components/Switcher.vue';
import SelectorBtnGroup from '../components/SelectorBtnGroup.vue';
import KilnInfo from './KilnInfo.vue';
import GasHandle from './GasHandle.vue';
export default {
name: 'RightTwo',
components: { Container, Switcher, SelectorBtnGroup, KilnLine, ShadowRect, KilnInfo, GasHandle },
props: {},
data() {
return {};
},
computed: {},
methods: {},
};
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,70 @@
<!--
filename: KilnDataBoard.vue
author: liubin
date: 2023-12-04 16:51:00
description:
-->
<template>
<div
class="KilnDataBoard"
style="
position: absolute;
top: -8px;
left: -16px;
width: calc(100% + 28px);
height: calc(100% + 38px);
display: flex;
flex-direction: column;
gap: 16px;
">
<KHeader />
<div
class="main-body"
style="flex: 1; display: flex; gap: 16px; padding: 8px 16px">
<div class="left-side" style="flex: 2">
<LeftFour />
</div>
<div class="right-side" style="flex: 1">
<RightTwo />
</div>
</div>
</div>
</template>
<script>
import KHeader from '../components/Header.vue';
import LeftFour from './LeftFour.vue';
import RightTwo from './RightTwo.vue';
export default {
name: 'KilnDataBoard',
components: {
KHeader,
LeftFour,
RightTwo,
},
// provide() {
// return {
// resizeChart: null,
// };
// },
mounted() {
// this.$el.addEventListener('resize', () => {
// console.log('resizzzze...')
// this.resizeChart = Math.random();
// });
},
data() {
return {};
},
};
</script>
<style scoped lang="scss">
.KilnDataBoard {
background: url(../assets/bg.png) no-repeat;
background-size: cover;
background-position: 0 0;
}
</style>

View File

@ -116,7 +116,7 @@
style="position: absolute; top: -40px; right: 0">
<el-button @click="handleAddAttr" type="text">
<i class="el-icon-plus"></i>
添加属性
添加参数
</el-button>
</div>
<base-table

View File

@ -0,0 +1,522 @@
<!--
filename: SpecialEquipmentForFireFighting.vue
author: liubin
date: 2023-12-12 13:51:23
description:
-->
<template>
<div class="app-container SpecialEquipmentForFireFighting">
<!-- 搜索工作栏 -->
<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"
:width="120"
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"
@close="cancel"
@cancel="cancel"
width="45%"
@confirm="submitForm">
<DialogForm
v-if="open"
key="index-dialog-form"
ref="form"
label-position="top"
size="small"
v-model="form"
:has-files="true"
:disabled="editMode === 'detail'"
:rows="computedRows" />
<!-- :has-files="['files', 'files2']" -->
</base-dialog>
<!-- 设备 详情 - 编辑 -->
<!-- <EquipmentDrawer
v-if="editVisible"
ref="drawer"
:mode="editMode"
@update-mode="editMode = $event"
:data-id="form.id"
:sections="[
{
name: '基本信息',
key: 'base',
rows: computedRows,
url: '/base/core-equipment/get',
urlUpdate: '/base/core-equipment/update',
urlCreate: '/base/core-equipment/create',
queryParams: { id: form.id },
},
{
name: '属性列表',
key: 'attrs',
props: drawerListProps,
url: '/base/core-equipment-attr/page',
urlCreate: '/base/core-equipment-attr/create',
urlUpdate: '/base/core-equipment-attr/update',
urlDelete: '/base/core-equipment-attr/delete',
urlDetail: '/base/core-equipment-attr/get',
queryParams: {
equipmentId: form.id,
pageNo: 1,
pageSize: 10,
},
tableBtn: [
this.$auth.hasPermi('base:core-equipment-attr:update')
? {
type: 'edit',
btnName: '修改',
}
: undefined,
this.$auth.hasPermi('base:core-equipment-attr:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
allowAdd: true,
},
]"
@refreshDataList="getList"
@cancel="cancelEdit"
@destroy="cancelEdit" /> -->
</div>
</template>
<script>
import moment from 'moment';
import basicPageMixin from '@/mixins/lb/basicPageMixin';
import EquipmentDrawer from '../components/EquipmentDrawer';
import {
createEquipment,
updateEquipment,
deleteEquipment,
getEquipment,
getEquipmentPage,
exportEquipmentExcel,
} from '@/api/base/equipment';
import Editor from '@/components/Editor';
import AssetsUpload from '../components/AssetsUpload.vue';
export default {
name: 'SpecialEquipmentForFireFighting',
components: {
Editor,
EquipmentDrawer,
},
mixins: [basicPageMixin],
data() {
return {
searchBarKeys: ['name', 'code'],
tableBtn: [
this.$auth.hasPermi(`base:core-equipment:update`)
? {
type: 'detail',
btnName: '详情',
}
: undefined,
this.$auth.hasPermi('base:core-equipment:update')
? {
type: 'edit',
btnName: '修改',
}
: undefined,
this.$auth.hasPermi('base:core-equipment:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
tableProps: [
// {
// prop: 'createTime',
// label: '',
// fixed: true,
// width: 180,
// filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
// },
{ prop: 'name', label: '设备名称' },
{ width: 256, prop: 'code', label: '设备编码' },
{ prop: 'location', label: '位置' },
{ prop: 'responsiblePeopleName', label: '负责人' },
{ prop: 'dueDate', label: '有效期至' },
{ prop: 'remark', label: '备注' },
],
searchBarFormConfig: [
{
type: 'input',
label: '名称',
placeholder: '请输入设备名称',
param: 'name',
},
{
type: 'input',
label: '编码',
placeholder: '请输入设备编码',
param: 'code',
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: this.$auth.hasPermi('base:core-equipment:export')
? 'button'
: '',
btnName: '导出',
name: 'export',
plain: true,
color: 'primary',
},
{
type: this.$auth.hasPermi('base:core-equipment:create')
? 'button'
: '',
btnName: '新增',
name: 'add',
plain: true,
color: 'success',
},
],
rows: [
[
{
input: true,
label: '设备名称',
prop: 'name',
rules: [
{ required: true, message: '设备名称不能为空', trigger: 'blur' },
],
},
{
input: true,
label: '设备编码',
prop: 'code',
url: '/base/core-equipment/getCode',
rules: [
{ required: true, message: '设备编码不能为空', trigger: 'blur' },
],
},
],
[
{
input: true,
label: '所在区域',
prop: 'location',
},
{
select: true,
label: '负责人',
prop: 'responsiblePeopleId',
url: '/base/core-worker/listAll',
},
],
[
{
datetime: true,
label: '有效期至',
prop: 'dueDate',
bind: { clearable: true },
},
{},
],
[{ input: true, label: '备注', prop: 'remark' }],
[
{
upload: true,
label: '设备图片',
prop: 'files',
fileType: 1,
},
],
],
editVisible: false,
editMode: 'edit', // 'edit', 'detail'
// drawer
drawerListProps: [
{
prop: 'createTime',
label: '添加时间',
fixed: true,
width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
},
{ prop: 'name', label: '属性名称' },
{ prop: 'value', label: '属性值' },
],
//
open: false,
//
queryParams: {
pageNo: 1,
pageSize: 10,
code: '',
name: '',
},
//
form: {
id: null,
files: [],
},
showUploadComponents: false, //
};
},
computed: {
computedRows() {
return this.showUploadComponents
? [
...this.rows,
[
{
assetUpload: true,
key: 'eq-assets', //
label: '上传资料',
fieldName: 'assets',
subcomponent: AssetsUpload,
prop: 'uploadedAssets',
default: [],
bind: {
'is-pic-mode': false,
},
},
],
[
{
assetUpload: true,
key: 'eq-pics', //
label: '上传图片',
fieldName: 'images',
subcomponent: AssetsUpload,
// prop: '',
// default: [],
bind: {
'is-pic-mode': true,
},
},
],
]
: this.rows;
},
},
mounted() {
this.getList();
},
activated() {
this.getList();
},
methods: {
/** 查询列表 */
getList() {
this.loading = true;
//
getEquipmentPage({
...this.queryParams,
specialType: 2,
special: true,
}).then((response) => {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
/** 取消按钮 */
cancel() {
this.open = false;
this.reset();
},
cancelEdit() {
this.showUploadComponents = false;
this.editVisible = false;
},
/** 表单重置 */
reset() {
this.form = {
id: undefined,
code: undefined,
name: undefined,
enName: undefined,
abbr: undefined,
enterTime: undefined,
productionTime: undefined,
equipmentTypeId: undefined,
groupId: undefined,
tvalue: undefined,
processingTime: undefined,
manufacturer: undefined,
spec: undefined,
description: undefined,
remark: undefined,
files: [],
files2: [],
};
this.resetForm('form');
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.showUploadComponents = false;
this.title = '添加设备';
this.editMode = 'add';
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
this.showUploadComponents = false;
this.editMode = 'edit';
const id = row.id;
getEquipment(id).then((response) => {
this.form = response.data;
this.open = true;
this.title = '修改设备';
});
},
handleDetail(row) {
this.reset();
this.showUploadComponents = false;
const id = row.id;
this.editMode = 'detail';
getEquipment(id).then((response) => {
this.form = response.data;
this.open = true;
this.title = '查看详情';
});
},
/** 提交按钮 */
submitForm() {
this.$refs['form'].validate((valid) => {
if (!valid) {
return;
}
const payload = Object.assign(
{ special: true, specialType: 2 },
this.form
);
// payload.files = [...payload.files, ...payload.files2];
// delete payload.files2;
//
if (this.form.id != null) {
updateEquipment(payload).then((response) => {
this.$modal.msgSuccess('修改成功');
this.open = false;
this.getList();
});
return;
}
//
createEquipment(payload).then((response) => {
this.$modal.msgSuccess('新增成功');
this.open = false;
this.getList();
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal
.confirm('是否确认删除设备名称为"' + row.name + '"的数据项?')
.then(function () {
return deleteEquipment(id);
})
.then(() => {
this.getList();
this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
//
let params = { ...this.queryParams, special: true, specialType: 2 };
params.pageNo = undefined;
params.pageSize = undefined;
this.$modal
.confirm('是否确认导出所有设备数据项?')
.then(() => {
this.exportLoading = true;
return exportEquipmentExcel(params);
})
.then((response) => {
this.$download.excel(response, '消防设备.xls');
this.exportLoading = false;
})
.catch(() => {});
},
//
viewDetail(id) {
this.reset();
this.editMode = 'detail';
this.showUploadComponents = true;
this.form.id = id;
this.editVisible = true;
this.$nextTick(() => {
this.$refs['drawer'].init();
});
},
// overwrite basicPageMixin
// handleTableBtnClick({ data, type }) {
// switch (type) {
// case 'edit':
// this.reset();
// this.editMode = 'edit';
// this.showUploadComponents = true;
// this.form.id = data.id;
// this.editVisible = true;
// this.$nextTick(() => {
// this.$refs['drawer'].init();
// });
// break;
// case 'delete':
// this.handleDelete(data);
// break;
// case 'detail':
// const { id } = data;
// this.viewDetail(id);
// break;
// }
// },
},
};
</script>
<style scoped lang="scss">
.SpecialEquipmentForFireFighting {
}
</style>

View File

@ -0,0 +1,512 @@
<!--
filename: SpecialEquipmentManagement.vue
author: liubin
date: 2023-12-12 13:51:23
description:
-->
<template>
<div class="app-container SpecialEquipmentManagement">
<!-- 搜索工作栏 -->
<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"
:width="120"
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"
@close="cancel"
@cancel="cancel"
width="45%"
@confirm="submitForm">
<DialogForm
v-if="open"
key="index-dialog-form"
ref="form"
label-position="top"
size="small"
v-model="form"
:has-files="true"
:disabled="editMode === 'detail'"
:rows="computedRows" />
<!-- :has-files="['files', 'files2']" -->
</base-dialog>
<!-- 设备 详情 - 编辑 -->
<!-- <EquipmentDrawer
v-if="editVisible"
ref="drawer"
:mode="editMode"
@update-mode="editMode = $event"
:data-id="form.id"
:sections="[
{
name: '基本信息',
key: 'base',
rows: computedRows,
url: '/base/core-equipment/get',
urlUpdate: '/base/core-equipment/update',
urlCreate: '/base/core-equipment/create',
queryParams: { id: form.id },
},
{
name: '属性列表',
key: 'attrs',
props: drawerListProps,
url: '/base/core-equipment-attr/page',
urlCreate: '/base/core-equipment-attr/create',
urlUpdate: '/base/core-equipment-attr/update',
urlDelete: '/base/core-equipment-attr/delete',
urlDetail: '/base/core-equipment-attr/get',
queryParams: {
equipmentId: form.id,
pageNo: 1,
pageSize: 10,
},
tableBtn: [
this.$auth.hasPermi('base:core-equipment-attr:update')
? {
type: 'edit',
btnName: '修改',
}
: undefined,
this.$auth.hasPermi('base:core-equipment-attr:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
allowAdd: true,
},
]"
@refreshDataList="getList"
@cancel="cancelEdit"
@destroy="cancelEdit" /> -->
</div>
</template>
<script>
import moment from 'moment';
import basicPageMixin from '@/mixins/lb/basicPageMixin';
import EquipmentDrawer from '../components/EquipmentDrawer';
import {
createEquipment,
updateEquipment,
deleteEquipment,
getEquipment,
getEquipmentPage,
exportEquipmentExcel,
} from '@/api/base/equipment';
import Editor from '@/components/Editor';
import AssetsUpload from '../components/AssetsUpload.vue';
export default {
name: 'SpecialEquipmentManagement',
components: {
Editor,
EquipmentDrawer,
},
mixins: [basicPageMixin],
data() {
return {
searchBarKeys: ['name', 'code'],
tableBtn: [
this.$auth.hasPermi(`base:core-equipment:update`)
? {
type: 'detail',
btnName: '详情',
}
: undefined,
this.$auth.hasPermi('base:core-equipment:update')
? {
type: 'edit',
btnName: '修改',
}
: undefined,
this.$auth.hasPermi('base:core-equipment:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
tableProps: [
// {
// prop: 'createTime',
// label: '',
// fixed: true,
// width: 180,
// filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
// },
{ prop: 'name', label: '设备名称' },
{ width: 256, prop: 'code', label: '设备编码' },
{ prop: 'location', label: '位置' },
{ prop: 'responsiblePeopleName', label: '负责人' },
{ prop: 'remark', label: '备注' },
],
searchBarFormConfig: [
{
type: 'input',
label: '名称',
placeholder: '请输入设备名称',
param: 'name',
},
{
type: 'input',
label: '编码',
placeholder: '请输入设备编码',
param: 'code',
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: this.$auth.hasPermi('base:core-equipment:export')
? 'button'
: '',
btnName: '导出',
name: 'export',
plain: true,
color: 'primary',
},
{
type: this.$auth.hasPermi('base:core-equipment:create')
? 'button'
: '',
btnName: '新增',
name: 'add',
plain: true,
color: 'success',
},
],
rows: [
[
{
input: true,
label: '设备名称',
prop: 'name',
rules: [
{ required: true, message: '设备名称不能为空', trigger: 'blur' },
],
},
{
input: true,
label: '设备编码',
prop: 'code',
url: '/base/core-equipment/getCode',
rules: [
{ required: true, message: '设备编码不能为空', trigger: 'blur' },
],
},
],
[
{
input: true,
label: '所在区域',
prop: 'location',
},
{
select: true,
label: '负责人',
prop: 'responsiblePeopleId',
url: '/base/core-worker/listAll',
},
],
[{ input: true, label: '备注', prop: 'remark' }],
[
{
upload: true,
label: '设备图片',
prop: 'files',
fileType: 1,
},
],
],
editVisible: false,
editMode: 'edit', // 'edit', 'detail'
// drawer
drawerListProps: [
{
prop: 'createTime',
label: '添加时间',
fixed: true,
width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
},
{ prop: 'name', label: '属性名称' },
{ prop: 'value', label: '属性值' },
],
//
open: false,
//
queryParams: {
pageNo: 1,
pageSize: 10,
code: '',
name: '',
},
//
form: {
id: null,
files: [],
},
showUploadComponents: false, //
};
},
computed: {
computedRows() {
return this.showUploadComponents
? [
...this.rows,
[
{
assetUpload: true,
key: 'eq-assets', //
label: '上传资料',
fieldName: 'assets',
subcomponent: AssetsUpload,
prop: 'uploadedAssets',
default: [],
bind: {
'is-pic-mode': false,
},
},
],
[
{
assetUpload: true,
key: 'eq-pics', //
label: '上传图片',
fieldName: 'images',
subcomponent: AssetsUpload,
// prop: '',
// default: [],
bind: {
'is-pic-mode': true,
},
},
],
]
: this.rows;
},
},
mounted() {
this.getList();
},
activated() {
this.getList();
},
methods: {
/** 查询列表 */
getList() {
this.loading = true;
//
getEquipmentPage({
...this.queryParams,
specialType: 3,
special: true,
}).then((response) => {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
/** 取消按钮 */
cancel() {
this.open = false;
this.reset();
},
cancelEdit() {
this.showUploadComponents = false;
this.editVisible = false;
},
/** 表单重置 */
reset() {
this.form = {
id: undefined,
code: undefined,
name: undefined,
enName: undefined,
abbr: undefined,
enterTime: undefined,
productionTime: undefined,
equipmentTypeId: undefined,
groupId: undefined,
tvalue: undefined,
processingTime: undefined,
manufacturer: undefined,
spec: undefined,
description: undefined,
remark: undefined,
files: [],
files2: [],
};
this.resetForm('form');
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.showUploadComponents = false;
this.title = '添加设备';
this.editMode = 'add';
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
this.showUploadComponents = false;
this.editMode = 'edit';
const id = row.id;
getEquipment(id).then((response) => {
this.form = response.data;
this.open = true;
this.title = '修改设备';
});
},
handleDetail(row) {
this.reset();
this.showUploadComponents = false;
const id = row.id;
this.editMode = 'detail';
getEquipment(id).then((response) => {
this.form = response.data;
this.open = true;
this.title = '查看详情';
});
},
/** 提交按钮 */
submitForm() {
this.$refs['form'].validate((valid) => {
if (!valid) {
return;
}
const payload = Object.assign(
{ special: true, specialType: 3 },
this.form
);
// payload.files = [...payload.files, ...payload.files2];
// delete payload.files2;
//
if (this.form.id != null) {
updateEquipment(payload).then((response) => {
this.$modal.msgSuccess('修改成功');
this.open = false;
this.getList();
});
return;
}
//
createEquipment(payload).then((response) => {
this.$modal.msgSuccess('新增成功');
this.open = false;
this.getList();
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal
.confirm('是否确认删除设备名称为"' + row.name + '"的数据项?')
.then(function () {
return deleteEquipment(id);
})
.then(() => {
this.getList();
this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
//
let params = { ...this.queryParams, special: true, specialType: 3 };
params.pageNo = undefined;
params.pageSize = undefined;
this.$modal
.confirm('是否确认导出所有设备数据项?')
.then(() => {
this.exportLoading = true;
return exportEquipmentExcel(params);
})
.then((response) => {
this.$download.excel(response, '特种设备.xls');
this.exportLoading = false;
})
.catch(() => {});
},
//
viewDetail(id) {
this.reset();
this.editMode = 'detail';
this.showUploadComponents = true;
this.form.id = id;
this.editVisible = true;
this.$nextTick(() => {
this.$refs['drawer'].init();
});
},
// overwrite basicPageMixin
// handleTableBtnClick({ data, type }) {
// switch (type) {
// case 'edit':
// this.reset();
// this.editMode = 'edit';
// this.showUploadComponents = true;
// this.form.id = data.id;
// this.editVisible = true;
// this.$nextTick(() => {
// this.$refs['drawer'].init();
// });
// break;
// case 'delete':
// this.handleDelete(data);
// break;
// case 'detail':
// const { id } = data;
// this.viewDetail(id);
// break;
// }
// },
},
};
</script>
<style scoped lang="scss">
.SpecialEquipmentManagement {
}
</style>

View File

@ -0,0 +1,512 @@
<!--
filename: Safety.vue
author: liubin
date: 2023-12-12 13:51:23
description:
-->
<template>
<div class="app-container SpecialEquipmentForSafety">
<!-- 搜索工作栏 -->
<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"
:width="120"
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"
@close="cancel"
@cancel="cancel"
width="45%"
@confirm="submitForm">
<DialogForm
v-if="open"
key="index-dialog-form"
ref="form"
label-position="top"
size="small"
v-model="form"
:has-files="true"
:disabled="editMode === 'detail'"
:rows="computedRows" />
<!-- :has-files="['files', 'files2']" -->
</base-dialog>
<!-- 设备 详情 - 编辑 -->
<!-- <EquipmentDrawer
v-if="editVisible"
ref="drawer"
:mode="editMode"
@update-mode="editMode = $event"
:data-id="form.id"
:sections="[
{
name: '基本信息',
key: 'base',
rows: computedRows,
url: '/base/core-equipment/get',
urlUpdate: '/base/core-equipment/update',
urlCreate: '/base/core-equipment/create',
queryParams: { id: form.id },
},
{
name: '属性列表',
key: 'attrs',
props: drawerListProps,
url: '/base/core-equipment-attr/page',
urlCreate: '/base/core-equipment-attr/create',
urlUpdate: '/base/core-equipment-attr/update',
urlDelete: '/base/core-equipment-attr/delete',
urlDetail: '/base/core-equipment-attr/get',
queryParams: {
equipmentId: form.id,
pageNo: 1,
pageSize: 10,
},
tableBtn: [
this.$auth.hasPermi('base:core-equipment-attr:update')
? {
type: 'edit',
btnName: '修改',
}
: undefined,
this.$auth.hasPermi('base:core-equipment-attr:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
allowAdd: true,
},
]"
@refreshDataList="getList"
@cancel="cancelEdit"
@destroy="cancelEdit" /> -->
</div>
</template>
<script>
import moment from 'moment';
import basicPageMixin from '@/mixins/lb/basicPageMixin';
import EquipmentDrawer from '../components/EquipmentDrawer';
import {
createEquipment,
updateEquipment,
deleteEquipment,
getEquipment,
getEquipmentPage,
exportEquipmentExcel,
} from '@/api/base/equipment';
import Editor from '@/components/Editor';
import AssetsUpload from '../components/AssetsUpload.vue';
export default {
name: 'SpecialEquipmentForSafety',
components: {
Editor,
EquipmentDrawer,
},
mixins: [basicPageMixin],
data() {
return {
searchBarKeys: ['name', 'code'],
tableBtn: [
this.$auth.hasPermi(`base:core-equipment:update`)
? {
type: 'detail',
btnName: '详情',
}
: undefined,
this.$auth.hasPermi('base:core-equipment:update')
? {
type: 'edit',
btnName: '修改',
}
: undefined,
this.$auth.hasPermi('base:core-equipment:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
tableProps: [
// {
// prop: 'createTime',
// label: '',
// fixed: true,
// width: 180,
// filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
// },
{ prop: 'name', label: '设备名称' },
{ width: 256, prop: 'code', label: '设备编码' },
{ prop: 'location', label: '位置' },
{ prop: 'responsiblePeopleName', label: '负责人' },
{ prop: 'remark', label: '备注' },
],
searchBarFormConfig: [
{
type: 'input',
label: '名称',
placeholder: '请输入设备名称',
param: 'name',
},
{
type: 'input',
label: '编码',
placeholder: '请输入设备编码',
param: 'code',
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: this.$auth.hasPermi('base:core-equipment:export')
? 'button'
: '',
btnName: '导出',
name: 'export',
plain: true,
color: 'primary',
},
{
type: this.$auth.hasPermi('base:core-equipment:create')
? 'button'
: '',
btnName: '新增',
name: 'add',
plain: true,
color: 'success',
},
],
rows: [
[
{
input: true,
label: '设备名称',
prop: 'name',
rules: [
{ required: true, message: '设备名称不能为空', trigger: 'blur' },
],
},
{
input: true,
label: '设备编码',
prop: 'code',
url: '/base/core-equipment/getCode',
rules: [
{ required: true, message: '设备编码不能为空', trigger: 'blur' },
],
},
],
[
{
input: true,
label: '所在区域',
prop: 'location',
},
{
select: true,
label: '负责人',
prop: 'responsiblePeopleId',
url: '/base/core-worker/listAll',
},
],
[{ input: true, label: '备注', prop: 'remark' }],
[
{
upload: true,
label: '设备图片',
prop: 'files',
fileType: 1,
},
],
],
editVisible: false,
editMode: 'edit', // 'edit', 'detail'
// drawer
drawerListProps: [
{
prop: 'createTime',
label: '添加时间',
fixed: true,
width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
},
{ prop: 'name', label: '属性名称' },
{ prop: 'value', label: '属性值' },
],
//
open: false,
//
queryParams: {
pageNo: 1,
pageSize: 10,
code: '',
name: '',
},
//
form: {
id: null,
files: [],
},
showUploadComponents: false, //
};
},
computed: {
computedRows() {
return this.showUploadComponents
? [
...this.rows,
[
{
assetUpload: true,
key: 'eq-assets', //
label: '上传资料',
fieldName: 'assets',
subcomponent: AssetsUpload,
prop: 'uploadedAssets',
default: [],
bind: {
'is-pic-mode': false,
},
},
],
[
{
assetUpload: true,
key: 'eq-pics', //
label: '上传图片',
fieldName: 'images',
subcomponent: AssetsUpload,
// prop: '',
// default: [],
bind: {
'is-pic-mode': true,
},
},
],
]
: this.rows;
},
},
mounted() {
this.getList();
},
activated() {
this.getList();
},
methods: {
/** 查询列表 */
getList() {
this.loading = true;
//
getEquipmentPage({
...this.queryParams,
specialType: 1,
special: true,
}).then((response) => {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
/** 取消按钮 */
cancel() {
this.open = false;
this.reset();
},
cancelEdit() {
this.showUploadComponents = false;
this.editVisible = false;
},
/** 表单重置 */
reset() {
this.form = {
id: undefined,
code: undefined,
name: undefined,
enName: undefined,
abbr: undefined,
enterTime: undefined,
productionTime: undefined,
equipmentTypeId: undefined,
groupId: undefined,
tvalue: undefined,
processingTime: undefined,
manufacturer: undefined,
spec: undefined,
description: undefined,
remark: undefined,
files: [],
files2: [],
};
this.resetForm('form');
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.showUploadComponents = false;
this.title = '添加设备';
this.editMode = 'add';
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
this.showUploadComponents = false;
this.editMode = 'edit';
const id = row.id;
getEquipment(id).then((response) => {
this.form = response.data;
this.open = true;
this.title = '修改设备';
});
},
handleDetail(row) {
this.reset();
this.showUploadComponents = false;
const id = row.id;
this.editMode = 'detail';
getEquipment(id).then((response) => {
this.form = response.data;
this.open = true;
this.title = '查看详情';
});
},
/** 提交按钮 */
submitForm() {
this.$refs['form'].validate((valid) => {
if (!valid) {
return;
}
const payload = Object.assign(
{ special: true, specialType: 1 },
this.form
);
// payload.files = [...payload.files, ...payload.files2];
// delete payload.files2;
//
if (this.form.id != null) {
updateEquipment(payload).then((response) => {
this.$modal.msgSuccess('修改成功');
this.open = false;
this.getList();
});
return;
}
//
createEquipment(payload).then((response) => {
this.$modal.msgSuccess('新增成功');
this.open = false;
this.getList();
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal
.confirm('是否确认删除设备名称为"' + row.name + '"的数据项?')
.then(function () {
return deleteEquipment(id);
})
.then(() => {
this.getList();
this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
//
let params = { ...this.queryParams, special: true, specialType: 1 };
params.pageNo = undefined;
params.pageSize = undefined;
this.$modal
.confirm('是否确认导出所有设备数据项?')
.then(() => {
this.exportLoading = true;
return exportEquipmentExcel(params);
})
.then((response) => {
this.$download.excel(response, '安全设备.xls');
this.exportLoading = false;
})
.catch(() => {});
},
//
viewDetail(id) {
this.reset();
this.editMode = 'detail';
this.showUploadComponents = true;
this.form.id = id;
this.editVisible = true;
this.$nextTick(() => {
this.$refs['drawer'].init();
});
},
// overwrite basicPageMixin
// handleTableBtnClick({ data, type }) {
// switch (type) {
// case 'edit':
// this.reset();
// this.editMode = 'edit';
// this.showUploadComponents = true;
// this.form.id = data.id;
// this.editVisible = true;
// this.$nextTick(() => {
// this.$refs['drawer'].init();
// });
// break;
// case 'delete':
// this.handleDelete(data);
// break;
// case 'detail':
// const { id } = data;
// this.viewDetail(id);
// break;
// }
// },
},
};
</script>
<style scoped lang="scss">
.SpecialEquipmentForSafety {
}
</style>

View File

@ -0,0 +1,436 @@
<!--
filename: Content.vue
author: liubin
date: 2023-12-12 13:53:22
description:
-->
<template>
<div class="app-container SpecialEquipmentCheckConfig">
<!-- 搜索工作栏 -->
<SearchBar
:formConfigs="searchBarFormConfig"
ref="search-bar"
@select-changed="handleSearchBarChange"
@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="操作"
:width="180"
: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"
@close="cancel"
@cancel="cancel"
@confirm="handleConfirm">
<add ref="add" @refreshDataList="successSubmit" />
</base-dialog>
<!-- 添加巡检查看详情 -->
<addOrUpdata
v-if="addOrUpdateVisible"
ref="addOrUpdate"
@refreshDataList="getList" />
</div>
</template>
<script>
import basicPageMixin from '@/mixins/lb/basicPageMixin';
import addOrUpdata from './add-or-updata.vue';
import add from './add.vue';
export default {
name: 'SpecialEquipmentCheckConfig',
components: { addOrUpdata, add },
mixins: [basicPageMixin],
data() {
return {
addOrUpdateVisible: false,
addOrEditTitle: '',
searchBarKeys: ['equipmentId', 'name', 'specialType'],
tableBtn: [
this.$auth.hasPermi('equipment:check-setting:addInsp')
? {
type: 'add',
btnName: '添加',
showTip: '添加巡检',
}
: undefined,
this.$auth.hasPermi('equipment:check-setting:update')
? {
type: 'edit',
btnName: '修改',
}
: undefined,
this.$auth.hasPermi('equipment:check-setting:update')
? {
type: 'detail',
btnName: '查看详情',
}
: undefined,
this.$auth.hasPermi('equipment:check-setting:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
tableProps: [
{
prop: 'name',
label: '配置名',
width: 110,
showOverflowtooltip: true,
},
{ prop: 'lineName', label: '产线', showOverflowtooltip: true },
{
prop: 'equipmentCategory',
label: '设备大类',
filter: (val) =>
val != null ? ['-', '安全', '消防', '特种'][val] : '-',
},
{ prop: 'equipmentName', label: '设备', showOverflowtooltip: true },
{
prop: 'equipmentCode',
label: '设备编码',
minWidth: 150,
showOverflowtooltip: true,
},
{ prop: 'responsible', label: '负责人' },
{ prop: 'remark', label: '描述' },
{ prop: 'checkNumber', label: '巡检条数' }, // TODO:
],
searchBarFormConfig: [
{
type: 'input',
label: '配置名称',
placeholder: '请输入配置名称',
param: 'name',
},
{
type: 'select',
label: '设备大类',
placeholder: '请选择设备大类',
param: 'specialType',
onchange: true,
selectOptions: [
{ id: 1, name: '安全设备' },
{ id: 2, name: '消防设备' },
{ id: 3, name: '特种设备' },
],
filterable: true,
},
{
type: 'select',
label: '设备名称',
placeholder: '请选择设备',
param: 'equipmentId',
filterable: true,
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: this.$auth.hasPermi('equipment:check-setting:create')
? 'button'
: '',
btnName: '新增',
name: 'add',
plain: true,
color: 'success',
},
// {
// type: this.$auth.hasPermi('equipment:check-setting:export')
// ? 'button'
// : '',
// btnName: '',
// name: 'export',
// color: 'warning',
// },
],
rows: [
[
{
input: true,
label: '配置名称',
prop: 'name',
rules: [
{ required: true, message: '配置名称不能为空', trigger: 'blur' },
],
},
{
input: true,
label: '配置编码',
prop: 'code',
url: '/base/equipment-check-config/getCode',
rules: [
{ required: true, message: '配置编码不能为空', trigger: 'blur' },
],
},
],
[
{
select: true,
label: '设备名称',
prop: 'equipmentId',
url: '/base/core-equipment/listAll',
bind: {
filterable: true,
clearable: true,
},
rules: [
{
required: true,
message: '设备名称不能为空',
trigger: 'change',
},
],
},
{
input: true,
label: '设备编码', // TODO:
prop: 'equipmentCode',
},
],
],
//
open: false,
//
queryParams: {
pageNo: 1,
pageSize: 10,
equipmentId: null,
name: null,
special: true,
specialType: null,
},
//
form: {},
basePath: '/base/equipment-check-config',
mode: null,
allSpecialEquipments: [],
};
},
created() {
this.initSearchBar();
this.getList();
},
methods: {
handleConfirm() {
this.$refs.add.dataFormSubmit();
},
successSubmit() {
this.cancel();
this.getList();
},
initSearchBar() {
this.http('/base/core-equipment/listAll', 'get').then(({ data }) => {
this.allSpecialEquipments = data.filter((item) => item.special);
this.setSearchBarEquipmentList(data.filter((item) => item.special));
});
},
//
handleSearchBarChange({ param, value }) {
if ('specialType' === param) {
if (!value) {
this.setSearchBarEquipmentList(this.allSpecialEquipments);
return;
}
this.setSearchBarEquipmentList(
this.allSpecialEquipments.filter((item) => item.specialType == value)
);
}
},
setSearchBarEquipmentList(eqList) {
this.$set(
this.searchBarFormConfig[2],
'selectOptions',
eqList.map((item) => ({
name: item.name,
id: item.id,
}))
);
},
/** 查询列表 */
getList() {
this.loading = true;
//
this.recv(this.queryParams).then((response) => {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
/** 取消按钮 */
cancel() {
this.$refs.add.formClear();
this.open = false;
this.title = '';
// this.reset();
},
/** 表单重置 */
reset() {
this.form = {
id: null,
name: null,
content: null,
program: null,
remark: null,
};
this.resetForm('form');
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm');
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
// this.reset();
this.open = true;
this.title = '添加巡检设置';
this.$nextTick(() => {
this.$refs.add.init();
});
},
/** 修改按钮操作 */
handleUpdate(row) {
// this.reset();
// const id = row.id;
// this.info({ id }).then((response) => {
// this.form = response.data;
// this.open = true;
// this.title = '';
// });
this.open = true;
this.title = '修改巡检设置';
this.$nextTick(() => {
this.$refs.add.init(row.id);
});
},
/** 提交按钮 */
submitForm() {
this.$refs['form'].validate((valid) => {
if (!valid) {
return;
}
//
if (this.form.id != null) {
this.put(this.form).then((response) => {
this.$modal.msgSuccess('修改成功');
this.open = false;
this.getList();
});
return;
}
//
this.post(this.form).then((response) => {
this.$modal.msgSuccess('新增成功');
this.open = false;
this.getList();
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal
.confirm('是否确认删除配置名为"' + row.name + '"的数据项?')
.then(() => {
return this.del({ id });
})
.then(() => {
this.getList();
this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
},
//
handleTableBtnClick({ data, type }) {
switch (type) {
case 'edit':
this.handleUpdate(data);
break;
case 'delete':
this.handleDelete(data);
break;
case 'detail':
this.handleDetail(data);
break;
case 'add':
this.handleAddDetail(data);
break;
}
},
handleDetail({ id }) {
this.addOrUpdateVisible = true;
this.addOrEditTitle = '详情';
this.$nextTick(() => {
this.$refs.addOrUpdate.init(id, true);
});
},
handleAddDetail({ id }) {
this.addOrUpdateVisible = true;
this.addOrEditTitle = '添加巡检';
this.$nextTick(() => {
this.$refs.addOrUpdate.init(id);
});
},
/** 导出按钮操作 */
handleExport() {
//
let params = { ...this.queryParams };
params.pageNo = undefined;
params.pageSize = undefined;
this.$modal
.confirm('是否确认导出所有巡检设置?')
.then(() => {
this.exportLoading = true;
return exportEquipmentTypeExcel(params);
})
.then((response) => {
this.$download.excel(response, '巡检设置.xls');
this.exportLoading = false;
})
.catch(() => {});
},
},
};
</script>
<style scoped lang="scss">
.SpecialEquipmentCheckConfig {
}
</style>

View File

@ -0,0 +1,334 @@
<!--
filename: Content.vue
author: liubin
date: 2023-12-12 13:53:22
description:
-->
<template>
<div class="app-container SpecialEquipmentCheckContent">
<!-- 搜索工作栏 -->
<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="操作"
:width="120"
: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"
@close="cancel"
@cancel="cancel"
@confirm="submitForm">
<DialogForm
v-if="open"
ref="form"
v-model="form"
:disabled="mode == 'detail'"
:has-files="false"
:rows="rows" />
</base-dialog>
</div>
</template>
<script>
import moment from 'moment';
import basicPageMixin from '@/mixins/lb/basicPageMixin';
import { deleteCheck } from '@/api/equipment/base/inspection/settings';
export default {
name: 'SpecialEquipmentCheckContent',
components: {},
mixins: [basicPageMixin],
data() {
return {
searchBarKeys: ['content'],
tableBtn: [
// this.$auth.hasPermi('equipment:check:update')
// ? {
// type: 'detail',
// btnName: '',
// }
// : undefined,
this.$auth.hasPermi('equipment:check:update')
? {
type: 'edit',
btnName: '修改',
}
: undefined,
this.$auth.hasPermi('equipment:check:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
tableProps: [
{ prop: 'program', label: '巡检项目', showOverflowtooltip: true },
{
prop: 'content',
label: '巡检内容',
minWidth: 150,
showOverflowtooltip: true,
},
{ prop: 'code', label: '巡检内容编码', showOverflowtooltip: true },
{ prop: 'remark', label: '备注', showOverflowtooltip: true },
],
searchBarFormConfig: [
{
type: 'input',
label: '巡检内容',
placeholder: '请输入巡检内容',
param: 'content',
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: this.$auth.hasPermi('equipment:check:create') ? 'button' : '',
btnName: '新增',
name: 'add',
plain: true,
color: 'success',
},
// {
// type: this.$auth.hasPermi('equipment:check:export')
// ? 'button'
// : '',
// btnName: '',
// name: 'export',
// color: 'warning',
// },
],
rows: [
[
{
input: true,
label: '巡检内容编号',
prop: 'code',
url: '/base/equipment-check/getCode',
rules: [
{
required: true,
message: '巡检内容编号不能为空',
trigger: 'blur',
},
],
},
{
input: true,
label: '巡检项目',
prop: 'program',
rules: [
{ required: true, message: '巡检项目不能为空', trigger: 'blur' },
],
},
],
[
{
input: true,
label: '巡检内容',
prop: 'content',
rules: [
{ required: true, message: '巡检内容不能为空', trigger: 'blur' },
],
},
{
input: true,
label: '备注',
prop: 'remark',
},
],
],
//
open: false,
//
queryParams: {
pageNo: 1,
pageSize: 10,
content: null,
},
//
form: {
code: '',
program: '',
id: undefined,
content: '',
},
basePath: '/base/equipment-check',
mode: null,
};
},
created() {
// this.initSearchBar();
this.getList();
},
methods: {
// initSearchBar() {
// this.http('/base/core-equipment/listAll', 'get').then(({ data }) => {
// this.$set(
// this.searchBarFormConfig[0],
// 'selectOptions',
// data.map((item) => ({
// name: item.name,
// id: item.id,
// }))
// );
// });
// },
/** 查询列表 */
getList() {
this.loading = true;
//
this.recv(this.queryParams).then((response) => {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
/** 取消按钮 */
cancel() {
this.open = false;
this.mode = null;
this.reset();
},
/** 表单重置 */
reset() {
this.form = {
id: null,
name: null,
content: null,
program: null,
remark: null,
};
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;
this.info({ 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) {
this.put(this.form).then((response) => {
this.$modal.msgSuccess('修改成功');
this.open = false;
this.getList();
});
return;
}
//
this.post(this.form).then((response) => {
this.$modal.msgSuccess('新增成功');
this.open = false;
this.getList();
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal
.confirm('是否确认删除该巡检项目?')
.then(function () {
// return this.del({ id });
return deleteCheck(id);
})
.then(() => {
this.getList();
this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
},
handleDetail({ id }) {
this.reset();
this.mode = 'detail';
this.info({ id }).then((response) => {
this.form = response.data;
this.open = true;
this.title = '修改巡检内容';
});
},
/** 导出按钮操作 */
handleExport() {
//
let params = { ...this.queryParams };
params.pageNo = undefined;
params.pageSize = undefined;
this.$modal
.confirm('是否确认导出所有巡检内容?')
.then(() => {
this.exportLoading = true;
return exportEquipmentTypeExcel(params);
})
.then((response) => {
this.$download.excel(response, '巡检内容.xls');
this.exportLoading = false;
})
.catch(() => {});
},
},
};
</script>
<style scoped lang="scss">
.SpecialEquipmentCheckContent {
}
</style>

View File

@ -0,0 +1,491 @@
<!--
filename: dialogForm.vue
author: liubin
date: 2023-10-31 15:55:13
description:
-->
<template>
<el-drawer
ref="drawer"
:visible.sync="visible"
:show-close="false"
:wrapper-closable="isdetail"
class="drawer"
size="55%"
@closed="$emit('destroy')">
<small-title slot="title" :no-padding="true">
{{ isdetail ? '查看详情' : !dataForm.id ? '新增' : '编辑' }}
</small-title>
<el-form
ref="dataForm"
style="margin: 0 16px; padding: 0 16px"
:model="dataForm"
:rules="dataRule"
label-width="100px"
label-position="top"
v-loading="formLoading">
<el-row :gutter="20">
<el-col :span="8">
<el-form-item
label="设备大类"
prop="equipmentCategory"
:rules="[
{ required: true, message: '请选择设备大类', trigger: 'blur' },
]">
<el-select
v-model="dataForm.equipmentCategory"
:disabled="isdetail"
:placeholder="`请选择设备大类`"
filterable
@change="handleEqTypeChange">
<el-option
v-for="opt in equipmentTypeOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备名称" prop="equipmentId">
<el-select
v-model="dataForm.equipmentId"
filterable
:disabled="isdetail"
style="width: 100%"
placeholder="请选择设备名称"
@change="setConfig">
<el-option
v-for="dict in equipmentOptions"
:key="dict.value"
:label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<!-- <el-form-item label="物料名称" prop="name">
<el-input v-model="dataForm.name" :disabled="isdetail" clearable placeholder="请输入物料名称" />
</el-form-item> -->
<el-form-item label="巡检配置名称" prop="configId">
<el-select
v-model="dataForm.configId"
filterable
:disabled="isdetail"
style="width: 100%"
placeholder="请选择巡检配置"
@change="setInspectionContet">
<el-option
v-for="dict in configList"
:key="dict.id"
:label="dict.name"
:value="dict.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备编码" prop="equipmentCode">
<el-input
v-model="dataForm.equipmentCode"
disabled
clearable
placeholder="请输入设备编码" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="巡检人" prop="responsible">
<el-input
v-model="dataForm.responsible"
:disabled="isdetail"
clearable
placeholder="请输入巡检人" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="巡检时间" prop="actualTime">
<el-date-picker
v-model="dataForm.actualTime"
type="datetime"
:disabled="isdetail"
format="yyyy-MM-dd HH:mm:ss"
value-format="timestamp"
placeholder="选择巡检时间" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="数据来源" prop="origin">
<el-select
v-model="dataForm.origin"
filterable
:disabled="isdetail"
style="width: 100%"
placeholder="请选择数据来源">
<el-option key="1" label="手动" :value="1" />
<el-option key="2" label="PDA" :value="2" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="巡检内容">
<base-table
:table-props="tableProps"
:page="listQuery.pageNo"
:limit="listQuery.pageSize"
:table-data="list" />
</el-form-item>
<el-form-item label="巡检详情" prop="description">
<editor
v-if="!isdetail"
v-model="dataForm.description"
:min-height="150" />
<div
v-else
v-html="dataForm.description"
style="padding: 5px; margin-left: 5px; border: 1px solid #dfdfdf" />
</el-form-item>
<el-form-item label="附件">
<FileUpload
v-model="file"
:limit="1"
:f-name="fileName"
:disabled="isdetail"
@name="setFileName" />
</el-form-item>
</el-form>
<div v-if="!isdetail" class="drawer-body__footer">
<el-button @click="goback()">取消</el-button>
<el-button type="primary" @click="dataFormSubmit()">确定</el-button>
</div>
</el-drawer>
</template>
<script>
import SmallTitle from './SmallTitle.vue';
import {
createCheckLog,
updateCheckLog,
getcheckConfigByEqList,
getEqCheckLog,
} from '@/api/equipment/base/inspection/record';
import { getEquipmentAll } from '@/api/base/equipment';
import Editor from '@/components/Editor';
import { getCheckDetPage } from '@/api/equipment/base/inspection/settings';
// import FileUpload from "@/components/FileUpload";
// import { parseTime } from '../../../../core/mixins/code-filter';
// import attrAdd from './attr-add';
import FileUpload from '@/components/FileUpload';
const tableBtn = [
{
type: 'delete',
btnName: '删除',
},
];
const tableProps = [
{
prop: 'program',
label: '巡检项目',
},
{
prop: 'content',
label: '巡检内容',
},
];
export default {
name: 'AddRecord',
model: {
prop: 'dataForm',
event: 'update',
},
emits: ['update'],
components: { SmallTitle, Editor, FileUpload },
props: {
// dataForm: {
// type: Object,
// default: () => ({}),
// },
// disabled: {
// type: Boolean,
// default: false
// },
},
data() {
return {
tableBtn,
tableProps,
addOrUpdateVisible: false,
formLoading: true,
visible: false,
isdetail: false,
dataForm: {
id: undefined,
configId: undefined,
equipmentId: undefined,
actualTime: undefined,
responsible: undefined,
description: undefined,
equipmentCode: undefined,
equipmentCategory: undefined,
origin: 1,
files: [],
},
equipmentTypeOptions: [
{ label: '安全设备', value: 1 },
{ label: '消防设备', value: 2 },
{ label: '特种设备', value: 3 },
],
list: [],
eqList: [],
configList: [],
listQuery: {
pageSize: 10,
pageNo: 1,
total: 0,
},
file: '',
fileName: '',
dataRule: {
responsible: [
{ required: true, message: '巡检人不能为空', trigger: 'blur' },
],
actualTime: [
{ required: true, message: '巡检时间不能为空', trigger: 'blur' },
],
},
};
},
mounted() {
this.getDict();
},
methods: {
setFileName(val) {
this.fileName = val;
},
async getDict() {
const res = await getEquipmentAll();
this.eqList = res.data;
this.handleEqTypeChange();
const configres = await getcheckConfigByEqList();
this.configList = configres.data;
},
async setConfig() {
const configres = await getcheckConfigByEqList({
equipmentId: this.dataForm.equipmentId,
});
this.configList = configres.data;
this.dataForm.configId =
this.configList.filter((it) => {
return it.id === this.dataForm.configId;
})[0]?.id ?? undefined;
this.dataForm.equipmentCode =
this.eqList.filter((item) => {
return item.id === this.dataForm.equipmentId;
})[0]?.code ?? undefined;
},
goback() {
this.$emit('refreshDataList');
this.visible = false;
},
goEdit() {
this.isdetail = false;
},
/** 模拟透传 ref */
validate(cb) {
return this.$refs.dataForm.validate(cb);
},
resetFields(args) {
return this.$refs.dataForm.resetFields(args);
},
initData() {
this.list = [];
this.file = '';
this.fileName = '';
},
init(id, isdetail) {
this.initData();
this.isdetail = isdetail || false;
this.dataForm.id = id || undefined;
this.visible = true;
// const scrollContainer = this.$refs.dataForm;
// const scrollPosition = scrollContainer.scrollTop;
// console.log('12', scrollPosition);
this.$nextTick(() => {
this.$refs['dataForm'].resetFields();
if (this.dataForm.id) {
//
getEqCheckLog(this.dataForm.id).then((response) => {
this.formLoading = false;
this.dataForm = response.data;
if (this.dataForm.files.length > 0) {
this.file = this.dataForm.files[0].fileUrl;
this.fileName = this.dataForm.files[0].fileName;
}
this.dataForm.description = this.dataForm.description || '无';
this.setConfig();
this.setInspectionContet();
});
} else {
// if (this.urlOptions.isGetCode) {
// this.getCode()
// }
}
});
this.formLoading = false;
},
setInspectionContet() {
//
getCheckDetPage({
pageNo: 1,
pageSize: 99,
configId: this.dataForm.configId,
}).then((response) => {
this.list = response.data.list;
this.listQuery.total = response.data.total;
});
},
// /
addNew(id) {
this.addOrUpdateVisible = true;
this.$nextTick(() => {
this.$refs.addOrUpdate.init(id);
});
},
handleEqTypeChange(type) {
this.dataForm.equipmentId = null;
this.dataForm.equipmentCode = null;
if (type) {
this.equipmentOptions = this.eqList
.filter((item) => item.special)
.filter((item) => item.specialType === type)
.map((item) => ({ label: item.name, value: item.id }));
} else
this.equipmentOptions = this.eqList
// .filter((item) => item.special)
.map((item) => ({
label: item.name,
value: item.id,
}));
// this.$emit('update', this.form)
},
//
dataFormSubmit() {
this.$refs['dataForm'].validate((valid) => {
if (!valid) {
return false;
}
if (this.file) {
const temp = this.file.split(','); //
let arry = [];
temp.forEach((item, index) => {
arry.push({
fileName: this.fileName,
fileType: 2,
fileUrl: item,
});
});
this.dataForm.files = arry;
} else {
this.dataForm.files = [];
}
//
if (this.dataForm.id) {
updateCheckLog(this.dataForm).then((response) => {
this.$modal.msgSuccess('修改成功');
this.visible = false;
this.$emit('refreshDataList');
});
return;
}
//
createCheckLog(this.dataForm).then((response) => {
this.$modal.msgSuccess('新增成功');
this.visible = false;
this.$emit('refreshDataList');
});
});
},
},
};
</script>
<style scoped>
.el-date-editor,
.el-select {
width: 100%;
}
.drawer-body__footer {
display: flex;
justify-content: flex-end;
padding: 18px;
}
.action_btn {
float: right;
margin: 5px 15px;
font-size: 14px;
}
.add {
color: #0b58ff;
}
.drawer >>> .el-drawer {
border-radius: 8px 0 0 8px;
display: flex;
flex-direction: column;
}
.drawer >>> .el-form-item__label {
padding: 0;
}
.drawer >>> .el-drawer__header {
margin: 0;
padding: 32px 32px 24px;
border-bottom: 1px solid #dcdfe6;
}
.drawer >>> .el-drawer__body {
flex: 1;
height: 1px;
margin: 10px 0;
display: flex;
flex-direction: column;
}
.drawer >>> .content {
padding: 30px 24px;
flex: 1;
display: flex;
flex-direction: column;
/* height: 100%; */
}
.drawer >>> .visual-part {
flex: 1 auto;
max-height: 76vh;
overflow: hidden;
overflow-y: scroll;
padding-right: 10px; /* 调整滚动条样式 */
}
.drawer >>> .el-form,
.drawer >>> .attr-list {
padding: 0 16px;
}
.drawer-body__footer {
display: flex;
justify-content: flex-end;
padding: 18px;
}
</style>

View File

@ -0,0 +1,449 @@
<!--
filename: Record.vue
author: liubin
date: 2023-12-12 13:53:22
description:
-->
<template>
<div class="app-container SpecialEquipmentCheckRecord">
<!-- 搜索工作栏 -->
<SearchBar
:formConfigs="searchBarFormConfig"
ref="search-bar"
@select-changed="handleSearchBarChange"
@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="操作"
:width="120"
: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"
@close="cancel"
@cancel="cancel"
@confirm="submitForm">
<DialogForm
v-if="open"
ref="form"
v-model="form"
:disabled="mode == 'detail'"
:has-files="true"
:rows="rows" />
</base-dialog>
<addRecord
v-if="addOrUpdateVisible"
ref="addOrUpdate"
@refreshDataList="getList"
@destroy="addOrUpdateVisible = false" />
</div>
</template>
<script>
import moment from 'moment';
import basicPageMixin from '@/mixins/lb/basicPageMixin';
import addRecord from './Record-add.vue';
import {
exportCheckLogExcel,
deleteEqCheckLog,
} from '@/api/equipment/base/inspection/record';
import { parseTime } from '../../core/mixins/code-filter';
const timeFilter = (val) => moment(val).format('yyyy-MM-DD HH:mm:ss');
export default {
name: 'SpecialEquipmentCheckRecord',
components: { addRecord },
mixins: [basicPageMixin],
data() {
return {
addOrUpdateVisible: false,
searchBarKeys: ['equipmentId', 'actualTime', 'specialType'],
tableBtn: [
this.$auth.hasPermi('equipment:check-record:detail')
? {
type: 'detail',
btnName: '详情',
}
: undefined,
this.$auth.hasPermi('equipment:check-record:update')
? {
type: 'edit',
btnName: '修改',
}
: undefined,
this.$auth.hasPermi('equipment:check-record:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
tableProps: [
{ prop: 'configName', label: '配置名称' },
{ prop: 'equipmentName', label: '设备名称' },
{
prop: 'origin',
label: '数据来源',
filter: (val) => ['', '手动', 'PDA'][val],
},
// { prop: 'sectionName', label: '' },
{ prop: 'actualTime', label: '实际巡检时间', filter: parseTime },
// { prop: 'maintenanceDetail', label: '' },
{ prop: 'responsible', label: '巡检人' },
],
searchBarFormConfig: [
{
type: 'select',
label: '设备大类',
placeholder: '请选择设备大类',
param: 'specialType',
onchange: true,
selectOptions: [
{ id: 1, name: '安全设备' },
{ id: 2, name: '消防设备' },
{ id: 3, name: '特种设备' },
],
filterable: true,
},
{
type: 'select',
label: '设备',
placeholder: '请选择设备',
param: 'equipmentId',
filterable: true,
},
//
{
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: 'actualTime',
// width: 350,
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: this.$auth.hasPermi('equipment:check-record:export')
? 'button'
: '',
btnName: '导出',
name: 'export',
plain: true,
color: 'primary',
},
{
type: this.$auth.hasPermi('equipment:check-record:create')
? 'button'
: '',
btnName: '新增',
name: 'add',
plain: true,
},
],
rows: [
[
{
input: true,
label: '维修单号',
prop: 'repairOrderNumber',
},
{
select: true,
label: '设备名称',
prop: 'equipmentId',
url: '/base/core-equipment/listAll',
bind: {
filterable: true,
clearable: true,
},
rules: [
{ required: true, message: '设备名称不能为空', trigger: 'blur' },
],
},
],
[
{
// TODO:
select: true,
label: '维修工',
prop: 'repairman',
// url: '/base/core-equipment/listAll',
bind: {
filterable: true,
clearable: true,
multiple: true,
},
rules: [
{ required: true, message: '维修工不能为空', trigger: 'blur' },
],
},
{
input: true,
label: '联系方式',
prop: 'repairmanPhone',
},
],
[
{
datetime: true,
label: '故障发生时间',
prop: 'faultTime',
rules: [
{
required: true,
message: '故障发生时间不能为空',
trigger: 'blur',
},
],
bind: {
format: 'yyyy-MM-dd HH:mm:ss',
'value-format': 'timestamp',
// 'value-format': 'yyyy-MM-dd HH:mm:ss',
clearable: true,
},
},
{
select: true,
label: '故障级别',
prop: 'faultLevel', //
options: this.getDictDatas(this.DICT_TYPE.FAULT_LEVEL),
},
],
],
//
open: false,
//
queryParams: {
pageNo: 1,
pageSize: 10,
maintenanceStatus: null,
createTime: null,
equipmentId: null,
special: true,
specialType: null,
},
//
form: {},
basePath: '/base/equipment-check-log',
mode: null,
allSpecialEquipments: [],
};
},
created() {
this.initSearchBar();
this.getList();
},
methods: {
initSearchBar() {
this.http('/base/core-equipment/listAll', 'get').then(({ data }) => {
this.allSpecialEquipments = data.filter((item) => item.special);
this.setSearchBarEquipmentList(data.filter((item) => item.special));
});
},
//
handleSearchBarChange({ param, value }) {
if ('specialType' === param) {
if (!value) {
this.setSearchBarEquipmentList(this.allSpecialEquipments);
return;
}
this.setSearchBarEquipmentList(
this.allSpecialEquipments.filter((item) => item.specialType == value)
);
}
},
setSearchBarEquipmentList(eqList) {
this.$set(
this.searchBarFormConfig[1],
'selectOptions',
eqList.map((item) => ({
name: item.name,
id: item.id,
}))
);
},
/** 查询列表 */
getList() {
this.loading = true;
//
this.recv(this.queryParams).then((response) => {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
/** 取消按钮 */
cancel() {
this.open = false;
this.mode = null;
this.reset();
},
/** 表单重置 */
reset() {
this.form = {
id: null,
repairOrderNumber: null,
equipmentId: null,
repairman: null,
repairmanPhone: null,
faultTime: null,
faultLevel: null,
maintenanceStartTime: null,
maintenanceFinishTime: null,
faultType: null,
repairMode: null,
maintenanceStatus: null,
faultDetail: null,
maintenanceDetail: null,
remark: null,
files: [
// {
// fileName: '',
// fileType: '',
// fileUrl: '',
// },
],
};
this.resetForm('form');
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm');
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
// this.reset();
// this.open = true;
// this.title = '';
this.addOrUpdateVisible = true;
this.$nextTick(() => {
this.$refs.addOrUpdate.init();
});
},
/** 修改按钮操作 */
handleUpdate(row) {
// this.reset();
// const id = row.id;
// this.info({ id }).then((response) => {
// this.form = response.data;
// this.open = true;
// this.title = '';
// });
this.addOrUpdateVisible = true;
this.$nextTick(() => {
this.$refs.addOrUpdate.init(row.id);
});
},
/** 提交按钮 */
submitForm() {
this.$refs['form'].validate((valid) => {
if (!valid) {
return;
}
//
if (this.form.id != null) {
this.put(this.form).then((response) => {
this.$modal.msgSuccess('修改成功');
this.open = false;
this.getList();
});
return;
}
//
this.post(this.form).then((response) => {
this.$modal.msgSuccess('新增成功');
this.open = false;
this.getList();
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal
.confirm(
'是否删除设备巡检记录配置名称为"' + row.configName + '"的数据项?'
)
.then(function () {
return deleteEqCheckLog(id);
})
.then(() => {
this.getList();
this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
},
handleDetail({ id }) {
this.addOrUpdateVisible = true;
this.$nextTick(() => {
this.$refs.addOrUpdate.init(id, true);
});
},
/** 导出按钮操作 */
handleExport() {
//
let params = { ...this.queryParams };
params.pageNo = undefined;
params.pageSize = undefined;
this.$modal
.confirm('是否确认导出所有设备巡检记录?')
.then(() => {
this.exportLoading = true;
return exportCheckLogExcel(params);
})
.then((response) => {
this.$download.excel(response, '设备巡检记录.xls');
this.exportLoading = false;
})
.catch(() => {});
},
},
};
</script>
<style scoped lang="scss">
.SpecialEquipmentCheckRecord {
}
</style>

View File

@ -0,0 +1,65 @@
<!--
* @Author: zwq
* @Date: 2023-08-01 15:27:31
* @LastEditors: zwq
* @LastEditTime: 2023-08-01 16:25:54
* @Description:
-->
<template>
<div :class="[className, { 'p-0': noPadding }]">
<slot />
</div>
</template>
<script>
export default {
props: {
size: {
// : xl lg md sm
type: String,
default: 'de',
validator: function (val) {
return ['xl', 'lg', 'de', 'md', 'sm'].indexOf(val) !== -1;
},
},
noPadding: {
type: Boolean,
default: false,
},
},
computed: {
className: function () {
return `${this.size}-title`;
},
},
};
</script>
<style lang="scss" scoped>
$pxls: (xl, 28px) (lg, 24px) (de, 20px) (md, 18px) (sm, 16px);
$mgr: 8px;
@each $size, $height in $pxls {
.#{$size}-title {
font-size: 18px;
line-height: $height;
color: #000;
font-weight: 500;
font-family: '微软雅黑', 'Microsoft YaHei', Arial, Helvetica, sans-serif;
&::before {
content: '';
display: inline-block;
vertical-align: top;
width: 4px;
height: $height + 2px;
border-radius: 1px;
margin-right: $mgr;
background-color: #0b58ff;
}
}
}
.p-0 {
padding: 0;
}
</style>

View File

@ -0,0 +1,341 @@
<!--
* @Author: zwq
* @Date: 2021-11-18 14:16:25
* @LastEditors: DY
* @LastEditTime: 2023-12-01 11:02:43
* @Description:
-->
<template>
<el-drawer
:visible.sync="visible"
:show-close="false"
:wrapper-closable="true"
class="drawer"
size="50%">
<small-title slot="title" :no-padding="true">
{{ isdetail ? '详情' : '添加巡检' }}
</small-title>
<div class="content">
<div class="visual-part">
<el-form
:model="dataForm"
:rules="dataRule"
ref="dataForm"
@keyup.enter.native="dataFormSubmit()"
label-position="top">
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="设备大类" prop="equipmentCategory">
<span>
{{
['-', '安全设备', '消防设备', '特种设备'][
dataForm.equipmentCategory || 0
]
}}
</span>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备名称" prop="equipmentName">
{{ dataForm.equipmentName }}
<!-- <el-input v-model="dataForm.equipmentName" disabled clearable placeholder="请输入设备名称" /> -->
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备编码" prop="equipmentCode">
{{ dataForm.equipmentCode }}
<!-- <el-input
v-model="dataForm.equipmentCode"
clearable
disabled
placeholder="请输入设备编码" /> -->
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<el-divider />
<div class="attr-list">
<small-title
style="margin: 16px 0; padding-left: 8px"
:no-padding="true">
巡检项目
</small-title>
<div v-if="!isdetail" class="action_btn">
<template>
<span style="display: inline-block">
<el-button type="text" @click="addNew()" icon="el-icon-plus">
添加
</el-button>
</span>
</template>
</div>
<base-table
:table-props="tableProps"
:page="listQuery.pageNo"
:limit="listQuery.pageSize"
:table-data="checkDetList">
<method-btn
v-if="!isdetail"
slot="handleBtn"
:width="120"
label="操作"
:method-list="tableBtn"
@clickBtn="handleClick" />
</base-table>
<pagination
v-show="listQuery.total > 0"
:total="listQuery.total"
:page.sync="listQuery.pageNo"
:limit.sync="listQuery.pageSize"
:page-sizes="[5, 10, 15]"
@pagination="getList" />
<!-- <div class="drawer-body__footer">
<el-button type="primary" @click="goback()">关闭</el-button>
</div> -->
</div>
</div>
<attr-add
v-if="addOrUpdateVisible"
ref="addOrUpdate"
:config-id="dataForm.id"
@refreshDataList="getList" />
</el-drawer>
</template>
<script>
import {
getEqCheck,
getCheckDetPage,
deleteCheckDet,
} from '@/api/equipment/base/inspection/settings';
import SmallTitle from './SmallTitle';
import attrAdd from './attr-add';
import { DICT_TYPE, getDictDatas } from '@/utils/dict';
const tableBtn = [
{
type: 'edit',
btnName: '编辑',
},
{
type: 'delete',
btnName: '删除',
},
];
const tableProps = [
{
prop: 'program',
label: '巡检项目',
},
{
prop: 'content',
label: '巡检内容',
},
{
prop: 'code',
label: '巡检内容编码',
},
{
prop: 'description',
label: '备注',
},
];
export default {
components: { SmallTitle, attrAdd },
data() {
return {
tableBtn,
tableProps,
addOrUpdateVisible: false,
urlOptions: {
infoURL: getEqCheck,
},
listQuery: {
pageSize: 10,
pageNo: 1,
total: 0,
},
dataForm: {
id: undefined,
code: undefined,
name: '',
materialType: undefined,
productType: undefined,
area: undefined,
specifications: undefined,
processTime: 0,
remark: undefined,
unit: undefined,
},
checkDetList: [],
visible: false,
isdetail: false,
dataRule: {
code: [
{ required: true, message: '物料编码不能为空', trigger: 'blur' },
],
name: [
{ required: true, message: '物料名称不能为空', trigger: 'blur' },
],
materialType: [
{ required: true, message: '物料类型不能为空', trigger: 'change' },
],
productType: [
{ required: true, message: '产品类型不能为空', trigger: 'change' },
],
processTime: [
{
required: true,
message: '产线生产单位用时不能为空',
trigger: 'blur',
},
],
},
};
},
mounted() {},
methods: {
initData() {
this.checkDetList.splice(0);
this.listQuery.total = 0;
},
handleClick(raw) {
if (raw.type === 'delete') {
this.$confirm(
`是否确认删除巡检项目名称为"${raw.data.program}"的数据项?`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(() => {
deleteCheckDet(raw.data.id).then(({ data }) => {
this.$message({
message: '操作成功',
type: 'success',
duration: 1500,
onClose: () => {
this.getList();
},
});
});
})
.catch(() => {});
} else {
this.addNew(raw.data.id);
}
},
getList() {
//
getCheckDetPage({
...this.listQuery,
configId: this.dataForm.id,
}).then((response) => {
this.checkDetList = response.data.list;
this.listQuery.total = response.data.total;
});
},
init(id, isdetail) {
this.initData();
this.isdetail = isdetail || false;
this.dataForm.id = id || undefined;
this.visible = true;
this.$nextTick(() => {
this.$refs['dataForm'].resetFields();
if (this.dataForm.id) {
//
this.urlOptions.infoURL(id).then((response) => {
this.dataForm = response.data;
});
//
this.getList();
} else {
if (this.urlOptions.isGetCode) {
this.getCode();
}
}
});
},
goback() {
this.$emit('refreshDataList');
this.visible = false;
// this.initData();
},
goEdit() {
this.isdetail = false;
},
// /
addNew(id) {
this.addOrUpdateVisible = true;
this.$nextTick(() => {
this.$refs.addOrUpdate.init(id);
});
},
},
};
</script>
<style scoped>
.drawer >>> .el-drawer {
border-radius: 8px 0 0 8px;
display: flex;
flex-direction: column;
}
.drawer >>> .el-form-item__label {
padding: 0;
}
.drawer >>> .el-drawer__header {
margin: 0;
padding: 32px 32px 24px;
border-bottom: 1px solid #dcdfe6;
}
.drawer >>> .el-drawer__body {
flex: 1;
height: 1px;
display: flex;
flex-direction: column;
}
.drawer >>> .content {
padding: 30px 24px;
flex: 1;
display: flex;
flex-direction: column;
/* height: 100%; */
}
.drawer >>> .visual-part {
/* flex: 1 auto; */
padding-right: 10px; /* 调整滚动条样式 */
}
.drawer >>> .el-form {
padding: 0 16px;
}
.drawer-body__footer {
display: flex;
justify-content: flex-end;
padding: 18px;
}
.action_btn {
float: right;
margin: -40px 15px;
font-size: 14px;
}
.add {
color: #0b58ff;
}
</style>

View File

@ -0,0 +1,167 @@
<!--
* @Author: zwq
* @Date: 2021-11-18 14:16:25
* @LastEditors: DY
* @LastEditTime: 2023-11-25 16:23:13
* @Description:
-->
<template>
<el-form
:model="dataForm"
:rules="dataRule"
ref="dataForm"
@keyup.enter.native="dataFormSubmit()"
label-width="80px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="配置名称" prop="name">
<el-input v-model="dataForm.name" placeholder="请输入配置名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="配置编码" prop="code">
<el-input v-model="dataForm.code" placeholder="请输入配置编码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="设备大类"
prop="equipmentCategory"
:rules="[
{ required: true, message: '请选择设备大类', trigger: 'blur' },
]">
<el-select
v-model="dataForm.equipmentCategory"
:placeholder="`请选择设备大类`"
@change="handleEqTypeChange">
<el-option
v-for="opt in equipmentTypeOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设备名称" prop="equipmentId">
<el-select
v-model="dataForm.equipmentId"
filterable
style="width: 100%"
placeholder="请选择设备名称"
@change="setCode">
<el-option
v-for="d in equipmentOptions"
:key="d.value"
:label="d.label"
:value="d.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设备编码" prop="equipmentCode">
<el-input
v-model="dataForm.equipmentCode"
disabled
placeholder="请输入设备编码" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
import basicAdd from '../../core/mixins/basic-add';
import {
getEqCheck,
getCode,
createCheckConfig,
updateCheckConfig,
} from '@/api/equipment/base/inspection/settings';
import { getEquipmentAll } from '@/api/base/equipment';
export default {
mixins: [basicAdd],
data() {
return {
urlOptions: {
isGetCode: true,
codeURL: getCode,
createURL: createCheckConfig,
updateURL: updateCheckConfig,
infoURL: getEqCheck,
},
dataForm: {
id: undefined,
code: undefined,
name: undefined,
equipmentId: undefined,
equipmentCode: undefined,
equipmentCategory: undefined,
},
eqList: [],
dataRule: {
equipmentId: [
{ required: true, message: '设备不能为空', trigger: 'blur' },
],
code: [
{ required: true, message: '配置编码不能为空', trigger: 'blur' },
],
name: [
{ required: true, message: '配置名称不能为空', trigger: 'blur' },
],
},
equipmentOptions: [],
equipmentTypeOptions: [
{ label: '安全设备', value: 1 },
{ label: '消防设备', value: 2 },
{ label: '特种设备', value: 3 },
],
};
},
mounted() {
this.getDict();
},
methods: {
async getDict() {
//
const res = await getEquipmentAll();
this.eqList = res.data;
this.$nextTick(() => {
this.handleEqTypeChange();
});
},
setCode() {
const chooseM = this.eqList.filter((item) => {
return item.id === this.dataForm.equipmentId;
});
this.dataForm.equipmentCode = chooseM[0].code;
},
// handlers
handleEqTypeChange(type) {
this.dataForm.equipmentId = null;
this.dataForm.equipmentCode = null;
if (type) {
this.equipmentOptions = this.eqList
.filter((item) => item.special)
.filter((item) => item.specialType === type)
.map((item) => ({ label: item.name, value: item.id }));
} else
this.equipmentOptions = this.eqList
.filter((item) => item.special)
.map((item) => ({
label: item.name,
value: item.id,
}));
// this.$emit('update', this.form)
},
},
};
</script>
<style scoped lang="scss">
.el-date-editor,
.el-select {
width: 100%;
}
</style>

View File

@ -0,0 +1,145 @@
<template>
<el-dialog
:visible.sync="visible"
:width="'30%'"
:append-to-body="true"
:close-on-click-modal="false"
class="dialog">
<template #title>
<slot name="title">
<div class="titleStyle">
{{ !dataForm.id ? '新增' : '编辑' }}
</div>
</slot>
</template>
<el-form
ref="dataForm"
:model="dataForm"
:rules="dataRule"
label-width="60px"
@keyup.enter.native="dataFormSubmit()">
<el-form-item label="巡检" prop="checkId">
<el-select v-model="dataForm.checkId" filterable placeholder="请选择巡检" style="width: 100%">
<el-option v-for="dict in checkList" :key="dict.id" :label="dict.content"
:value="dict.id" />
</el-select>
</el-form-item>
<el-form-item label="备注" prop="description">
<el-input
v-model="dataForm.description"
placeholder="请输入备注"
clearable />
</el-form-item>
</el-form>
<el-row style="text-align: right">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="dataFormSubmit()">确定</el-button>
</el-row>
</el-dialog>
</template>
<script>
import { getCheckDet, createCheckDet, updateCheckDet, getcheckList } from "@/api/equipment/base/inspection/settings";
export default {
props: {
configId: {
type: String,
default: '',
},
},
data() {
return {
visible: false,
dataForm: {
id: undefined,
checkId: undefined,
configId: undefined,
description: ''
},
checkList: [],
dataRule: {
checkId: [{ required: true, message: '巡检不能为空', trigger: 'blur' }],
},
};
},
mounted() {
this.getDict()
},
methods: {
async getDict() {
const res = await getcheckList()
this.checkList = res.data
},
init(id) {
this.dataForm.id = id || '';
this.visible = true;
this.$nextTick(() => {
this.$refs['dataForm'].resetFields();
if (this.dataForm.id) {
getCheckDet(this.dataForm.id).then((res) => {
// const { name, value } = res.data;
// this.dataForm.name = name;
// this.dataForm.value = value;
this.dataForm = res.data
});
}
});
},
//
dataFormSubmit() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
//
if (this.dataForm.id) {
updateCheckDet({
...this.dataForm,
configId: this.configId
}).then((response) => {
this.$modal.msgSuccess('修改成功');
this.visible = false;
this.$emit('refreshDataList');
});
return;
}
//
createCheckDet({
...this.dataForm,
configId: this.configId,
}).then((response) => {
this.$modal.msgSuccess('新增成功');
this.visible = false;
this.$emit('refreshDataList');
});
}
});
},
},
};
</script>
<style scoped>
.dialog >>> .el-dialog__body {
padding: 30px 24px;
}
.dialog >>> .el-dialog__header {
font-size: 16px;
color: rgba(0, 0, 0, 0.85);
font-weight: 500;
padding: 13px 24px;
border-bottom: 1px solid #e9e9e9;
}
.dialog >>> .el-dialog__header .titleStyle::before {
content: '';
display: inline-block;
width: 4px;
height: 16px;
background-color: #0b58ff;
border-radius: 1px;
margin-right: 8px;
position: relative;
top: 2px;
}
</style>

View File

@ -0,0 +1,399 @@
<!--
filename: AssetsUpload.vue
author: liubin
date: 2023-10-12 16:40:14
description: 上传资料/图片 组件
-->
<template>
<div class="assets-upload">
<section class="operations">
<el-button type="text" class="expand-btn" @click="expand = !expand">
<i class="el-icon-folder-opened" v-if="expand"></i>
<i class="el-icon-folder" v-else></i>
展开
</el-button>
<!-- <div class="preview-btn">
<i class="el-icon-view"></i>
预览
</div> -->
</section>
<section
class="file-area"
:style="{
height: expand ? 'auto' : isPicMode ? '180px' : '152px',
gap: isPicMode ? '0 24px' : '24px',
gridAutoRows: isPicMode ? '180px' : '152px',
}">
<el-upload
class="equipment-upload"
:disabled="disabled"
drag
:action="uploadUrl"
:headers="headers"
multiple
:show-file-list="false"
:before-upload="beforeUpload"
:on-success="handleSuccess">
<i class="el-icon-upload"></i>
<div class="el-upload__text">
<span>将文件拖到此处或</span>
<em>点击上传</em>
</div>
<div class="el-upload__tip" slot="tip">
{{
isPicMode ? '仅支持上传 .jpg .png 格式文件, 且' : ''
}}文件大小不超过2MB
</div>
</el-upload>
<div
v-for="(file, index) in files"
:key="file.fileName"
style="width: 100%">
<div
class="file-list__item"
v-if="!isPicMode"
:style="{
background: isPicMode
? `url(${file.fileUrl}) no-repeat`
: `url(${defaultBg}) no-repeat`,
backgroundSize: isPicMode ? '100% 100%' : '64px',
backgroundPosition: isPicMode ? '0% 0%' : 'center',
}"
@click="handleDownload(file)"
:data-name="file.fileName">
<el-button
v-if="!disabled"
type="text"
class="el-icon-delete"
style="padding: 0"
@click="(e) => handleDelete(file)" />
</div>
<el-image
v-else
class="file-list__item"
style="width: 100%"
:src="file.fileUrl"
:preview-src-list="files.map((item) => item.fileUrl)"></el-image>
</div>
</section>
</div>
</template>
<script>
import { getAccessToken } from '@/utils/auth';
import defaultBg from '../../../assets/images/default-file-icon.png';
function checkSize(file, message) {
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
message.error('上传文件大小不能超过 2MB!');
}
return isLt2M;
}
function checkPic(file, message) {
const isJPG = file.type === 'image/jpeg';
const isPNG = file.type === 'image/png';
const isPic = isJPG || isPNG;
if (!isPic) {
message.error('上传图片只能是 JPG/PNG 格式!');
}
return isPic;
}
export default {
name: 'AssetsUpload',
components: {},
model: {
prop: 'dataSource',
event: 'update',
},
props: {
type: {
type: String,
default: 'image',
},
dataSource: {
type: Array,
default: () => [],
},
equipmentId: {
type: String,
default: '',
},
isPicMode: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
},
emits: ['update-filelist'],
data() {
return {
defaultBg,
expand: false,
headers: { Authorization: 'Bearer ' + getAccessToken() }, //
fileList: [],
uploadUrl: process.env.VUE_APP_BASE_API + '/admin-api/infra/file/upload',
files: [],
updateTimer: null,
};
},
watch: {
dataSource: {
handler(val) {
this.files = JSON.parse(JSON.stringify(val));
},
immediate: true,
deep: true,
},
},
mounted() {},
methods: {
// handle success, per file!
handleSuccess(response, file, fileList) {
this.$notify({
title: '成功',
message: '上传成功! 点击确认保存上传结果',
type: 'success',
});
if (
response == null ||
!('data' in response) ||
response.data == null ||
response.data.trim() == ''
) {
this.$message.error('上传出错了!');
return;
}
this.files.push({
fileName: file.name,
fileUrl: response.data,
fileType: this.isPicMode ? 1 : 2,
});
// debugger;
//
if (this.updateTimer) {
clearTimeout(this.updateTimer);
}
this.updateTimer = setTimeout(() => {
// console.log('[AssetsUpload] ');
this.emitFilelist();
clearTimeout(this.updateTimer);
this.updateTimer = null;
}, 500);
},
async handleDownload(file) {
if (this.isPicMode) {
// this.$emit('preview', file);
const link = document.createElement('a');
link.href = file.fileUrl;
link.target = '_blank';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} else {
// this.$emit('download', file);
const data = await this.$axios({
url: file.fileUrl,
method: 'get',
responseType: 'blob',
});
const link = document.createElement('a');
link.href = window.URL.createObjectURL(new Blob([data]));
link.download = file.fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(link.href);
}
},
emitFilelist() {
this.$emit('update', this.files);
},
handleRemove(file, fileList) {
debugger;
},
handleDelete(file) {
// fileName fileType fileUrl
this.files = this.files.filter((item) => item.fileUrl != file.fileUrl);
this.$notify({
title: '成功',
message: '删除成功! 需点击确认保存删除结果',
type: 'success',
});
this.emitFilelist();
},
beforeUpload(file) {
if (this.isPicMode) {
return checkPic(file, this.$message) && checkSize(file, this.$message);
}
return checkSize(file, this.$message);
},
handleUpload() {
switch (this.type) {
case 'image':
break;
case 'asset':
break;
}
},
updateFileList(appendFilelist) {
// Array
this.$emit('update-filelist', this.appendFilelist);
},
},
};
</script>
<style scoped lang="scss">
.assets-upload {
position: relative;
}
.operations {
position: absolute;
top: -36px;
right: 0;
display: flex;
align-items: center;
}
.expand-btn,
.preview-btn {
font-size: 14px;
line-height: 1.2;
display: inline-block;
padding-left: 20px;
cursor: pointer;
z-index: 1000;
}
.expand-btn {
margin-right: 12px;
}
.preview-btn {
color: #ccc;
}
.expand-btn,
.preview-btn:hover,
.preview-btn.active {
// color: #0042d0;
color: #0b58ff;
}
:deep(.equipment-upload) {
.el-upload-dragger {
width: 188px;
height: 128px;
}
.el-icon-upload {
margin: 12px 0;
font-size: 48px;
}
.el-upload__text {
font-size: 12px;
line-height: 2px;
display: flex;
flex-direction: column;
em {
margin-top: 12px;
}
}
.el-upload__tip {
font-size: 12px;
line-height: 1.5;
color: #d1d1d1;
margin: 0 0 12px;
transform: translateY(-12px);
user-select: none;
}
}
.equipment-upload {
margin-bottom: 24px;
}
.file-list {
padding: 12px;
border: 1px solid #ccc;
}
// custom
.file-area {
display: grid;
grid-template-columns: repeat(auto-fill, 188px);
grid-auto-rows: 152px;
gap: 48px 24px;
overflow: hidden;
}
.file-list__item {
height: 128px;
background-color: #fff;
border: 1px dashed #d9d9d9;
border-radius: 6px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
text-align: center;
cursor: pointer;
position: relative;
// overflow: hidden;
&:hover {
.el-icon-delete {
display: block;
}
}
.el-icon-delete {
color: #ccc;
position: absolute;
top: 8px;
right: 8px;
display: none;
&:hover {
color: rgb(210, 41, 41);
}
}
}
.file-list__item:hover {
border-color: #0b58ff;
}
.file-list__item::after {
content: attr(data-name);
position: absolute;
left: 0;
bottom: -26px;
font-size: 14px;
line-height: 2;
color: #616161;
}
.default-icon {
background: url(../../../assets/images/default-file-icon.png) no-repeat;
background-position: center;
background-size: 64px;
}
</style>

View File

@ -0,0 +1,313 @@
<!--
filename: dialogForm.vue
author: liubin
date: 2023-08-15 10:32:36
description: 弹窗的表单组件
-->
<template>
<el-form
ref="form"
:model="form"
:label-width="`${labelWidth}px`"
:size="size"
:label-position="labelPosition"
v-loading="formLoading">
<el-row :gutter="20" v-for="(row, rindex) in rows" :key="rindex">
<el-col v-for="col in row" :key="col.label" :span="24 / row.length">
<el-form-item :label="col.label" :prop="col.prop" :rules="col.rules">
<el-input
v-if="col.input"
v-model="form[col.prop]"
@change="$emit('update', form)"
:placeholder="`请输入${col.label}`"
v-bind="col.bind" />
<el-input
v-if="col.textarea"
type="textarea"
v-model="form[col.prop]"
@change="$emit('update', form)"
:placeholder="`请输入${col.label}`"
v-bind="col.bind" />
<el-select
v-if="col.select"
v-model="form[col.prop]"
:placeholder="`请选择${col.label}`"
@change="$emit('update', form)"
v-bind="col.bind">
<el-option
v-for="opt in optionListOf[col.prop]"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
<el-date-picker
v-if="col.datetime"
v-model="form[col.prop]"
type="datetime"
:placeholder="`请选择${col.label}`"
value-format="timestamp"
v-bind="col.bind"></el-date-picker>
<el-upload
class="upload-in-dialog"
v-if="col.upload"
:file-list="uploadedFileList"
:action="col.url"
:on-success="handleUploadSuccess"
v-bind="col.bind">
<el-button
size="small"
type="primary"
:disabled="col.bind?.disabled || false">
点击上传
</el-button>
<div class="el-upload__tip" slot="tip" v-if="col.uploadTips">
{{ col.uploadTips || '只能上传jpg/png文件大小不超过2MB' }}
</div>
</el-upload>
<el-switch
v-if="col.switch"
v-model="form[col.prop]"
active-color="#0b58ff"
inactive-color="#e1e1e1"
v-bind="col.bind"></el-switch>
<component
v-if="col.subcomponent"
:key="col.key"
:is="col.subcomponent"
v-bind="col.bind"
:inlineStyle="col.style"></component>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
/**
* 找到最长的label
* @param {*} options
*/
function findMaxLabelWidth(rows) {
let max = 0;
rows.forEach((row) => {
row.forEach((opt) => {
// debugger;
if (!opt.label) return 0;
if (opt.label.length > max) {
max = opt.label.length;
}
});
});
return max;
}
export default {
name: 'DialogForm',
model: {
prop: 'dataForm',
event: 'update',
},
emits: ['update'],
components: {},
props: {
rows: {
type: Array,
default: () => [],
},
dataForm: {
type: Object,
default: () => ({}),
},
disabled: {
type: Boolean,
default: false,
},
labelPosition: {
type: String,
default: 'right',
},
size: {
type: String,
default: '',
},
},
data() {
return {
formLoading: true,
optionListOf: {},
uploadedFileList: [],
dataLoaded: false,
};
},
computed: {
labelWidth() {
let max = findMaxLabelWidth(this.rows);
// 20px
return max * 20;
// return max * 20 + 'px';
},
form: {
get() {
// if (this.dataLoaded) return this.dataForm;
// else return {}
return this.dataForm;
},
set(val) {
console.log('set form', val);
},
},
},
watch: {
rows: {
handler() {
console.log('watch triggered!');
this.$nextTick(() => {
this.handleOptions('watch');
});
},
deep: true,
immediate: false,
},
},
mounted() {
// options
this.handleOptions();
},
methods: {
/** 模拟透传 ref */
validate(cb) {
return this.$refs.form.validate(cb);
},
resetFields(args) {
return this.$refs.form.resetFields(args);
},
// getCode
async getCode(url) {
const response = await this.$axios(url);
return response.data;
},
async handleOptions(trigger = 'monuted') {
console.log('[dialogForm:handleOptions]');
const promiseList = [];
this.rows.forEach((cols) => {
cols.forEach((opt) => {
if (opt.value && !this.form[opt.prop]) {
//
this.form[opt.prop] = opt.value;
}
if (opt.options) {
this.$set(this.optionListOf, opt.prop, opt.options);
} else if (opt.url) {
// dependswatcher
if (opt.depends) {
console.log('[handleOptions] setting watch');
this.$watch(
() => this.form[opt.depends],
(id) => {
console.log('<', opt.depends, '>', 'changed', id);
if (id == null) return;
//
this.form[opt.prop] = null;
//
this.$axios({
url: `${opt.url}?id=${id}`,
}).then((res) => {
this.$set(
this.optionListOf,
opt.prop,
res.data.map((item) => ({
label: item[opt.labelKey ?? 'name'],
value: item[opt.valueKey ?? 'id'],
}))
);
});
},
{
immediate: true,
}
);
return;
}
//
if (opt.select || (opt.input && !this.form?.id)) {
promiseList.push(async () => {
const response = await this.$axios(opt.url, {
method: opt.method ?? 'get',
});
console.log('[dialogForm:handleOptions:response]', response);
if (opt.select) {
//
const list =
'list' in response.data
? response.data.list
: response.data;
this.$set(
this.optionListOf,
opt.prop,
list.map((item) => ({
label: item[opt.labelKey ?? 'name'],
value: item[opt.valueKey ?? 'id'],
}))
);
} else if (opt.input) {
console.log('setting code: ', response.data);
//
this.form[opt.prop] = response.data;
}
});
}
}
});
});
console.log('[dialogForm:handleOptions] done!');
// watch
if (trigger == 'watch') {
this.formLoading = false;
return;
}
try {
await Promise.all(promiseList.map((fn) => fn()));
this.formLoading = false;
this.dataLoaded = true;
// console.log("[dialogForm:handleOptions:optionListOf]", this.optionListOf)
} catch (error) {
console.log('[dialogForm:handleOptions:error]', error);
this.formLoading = false;
}
if (!promiseList.length) this.formLoading = false;
},
//
beforeUpload() {},
// bind
handleUploadSuccess(response, file, fileList) {
console.log(
'[dialogForm:handleUploadSuccess]',
response,
file,
fileList,
this.form
);
//
if ('fileNames' in this.form) this.form.fileNames.push(file.name);
//
if ('fileUrls' in this.form) this.form.fileUrls.push(response.data);
this.$modal.msgSuccess('上传成功');
},
getFileName(fileUrl) {
return fileUrl.split('/').pop();
},
},
};
</script>
<style scoped lang="scss">
.el-date-editor,
.el-select {
width: 100%;
}
</style>

View File

@ -0,0 +1,550 @@
<!--
filename: EquipmentDrawer.vue
author: liubin
date: 2023-08-22 14:38:56
description:
-->
<template>
<el-drawer
:visible="visible"
:show-close="false"
:wrapper-closable="false"
class="drawer"
custom-class="mes-drawer"
size="60%"
@closed="$emit('destroy')">
<SmallTitle slot="title">
{{
mode.includes('detail')
? '详情'
: mode.includes('edit')
? '编辑'
: '新增'
}}
</SmallTitle>
<div class="drawer-body flex">
<div class="drawer-body__content">
<section v-for="(section, index) in sections" :key="section.key">
<SmallTitle v-if="index != 0">{{ section.name }}</SmallTitle>
<div
class="form-part"
v-if="section.key == 'base'"
style="margin-bottom: 32px">
<el-skeleton v-if="!showForm" animated />
<EquipmentInfoForm
key="drawer-dialog-form"
v-if="showForm"
:disabled="mode.includes('detail')"
:sync-filelist="syncFileListFlag"
v-model="form" />
</div>
<div
v-if="section.key == 'attrs'"
style="margin-top: 12px; position: relative">
<div
v-if="!mode.includes('detail')"
style="position: absolute; top: -40px; right: 0">
<el-button @click="handleAddAttr" type="text">
<i class="el-icon-plus"></i>
添加属性
</el-button>
</div>
<base-table
v-loading="attrListLoading"
:table-props="section.props"
:page="attrQuery?.params.pageNo || 1"
:limit="attrQuery?.params.pageSize || 10"
:table-data="list"
@emitFun="handleEmitFun">
<!-- :add-button-show="mode.includes('detail') ? null : '添加属性'"
@emitButtonClick="handleAddAttr" -->
<method-btn
v-if="section.tableBtn"
slot="handleBtn"
label="操作"
:method-list="tableBtn"
@clickBtn="handleTableBtnClick" />
</base-table>
<!-- 分页组件 -->
<pagination
v-show="total > 0"
:total="total"
:page.sync="attrQuery.params.pageNo"
:limit.sync="attrQuery.params.pageSize"
@pagination="getAttrList" />
</div>
</section>
</div>
<div class="drawer-body__footer">
<el-button style="" @click="handleCancel">取消</el-button>
<el-button v-if="mode == 'detail'" type="primary" @click="toggleEdit">
编辑
</el-button>
<el-button v-else type="primary" @click="handleConfirm">保存</el-button>
<!-- sections的第二项必须是 属性列表 -->
<!-- <el-button
v-if="sections[1].allowAdd"
type="primary"
@click="handleAddAttr">
添加属性
</el-button> -->
</div>
</div>
<!-- 属性对话框 -->
<base-dialog
v-if="sections[1].allowAdd"
:dialogTitle="attrTitle"
:dialogVisible="attrFormVisible"
width="35%"
:append-to-body="true"
custom-class="baseDialog"
@close="closeAttrForm"
@cancel="closeAttrForm"
@confirm="submitAttrForm">
<DialogForm
v-if="attrFormVisible"
ref="attrForm"
:dataForm="attrForm"
:rows="attrRows" />
</base-dialog>
</el-drawer>
</template>
<script>
import DialogForm from './DialogForm';
import EquipmentInfoForm from './EquipmentInfoForm.vue';
const SmallTitle = {
name: 'SmallTitle',
props: ['size'],
components: {},
data() {
return {};
},
methods: {},
render: function (h) {
return h(
'span',
{
class: 'small-title',
style: {
fontSize: '18px',
lineHeight:
this.size == 'lg' ? '24px' : this.size == 'sm' ? '18px' : '20px',
fontWeight: 500,
fontFamily: '微软雅黑, Microsoft YaHei, Arial, Helvetica, sans-serif',
},
},
this.$slots.default
);
},
};
export default {
components: { SmallTitle, DialogForm, EquipmentInfoForm },
props: ['sections', 'mode', 'dataId'], // dataId id
data() {
return {
visible: false,
showForm: false,
btnLoading: false,
total: 0,
form: {},
list: [],
attrTitle: '',
attrForm: {
id: null,
equipmentId: null,
name: '',
value: '',
},
attrFormVisible: false,
attrRows: [
[
{
input: true,
label: '属性名称',
prop: 'name',
rules: [
{ required: true, message: '属性名称不能为空', trigger: 'blur' },
],
},
],
[
{
input: true,
label: '属性值',
prop: 'value',
},
],
],
attrQuery: {
params: {
pageNo: 1,
pageSize: 10,
},
}, //
infoQuery: null, //
attrFormSubmitting: false,
attrListLoading: false,
syncFileListFlag: null,
};
},
computed: {
formRows() {
return this.sections[0].rows.map((row) => {
return row.map((col) => {
if (col.key == 'eq-pics') {
//
return {
...col,
bind: {
...col.bind,
},
style: {
left: 0,
right: 'unset',
},
};
}
return {
...col,
bind: {
...col.bind,
//
disabled: this.mode == 'detail',
},
};
});
});
},
tableBtn() {
return this.mode == 'detail' ? [] : this.sections[1].tableBtn;
},
},
mounted() {
for (const section of this.sections) {
//
if ('url' in section) {
const query = {
url: section.url,
method: section.method || 'get',
params: section.queryParams || null,
data: section.data || null,
};
this.$axios(query).then(({ data }) => {
if (section.key == 'base') {
this.form = data;
// this.form = {
// code: 'gj',
// name: '',
// enName: 'unload',
// abbr: '',
// equipmentTypeId: 21084,
// remark: '',
// id: '1712367395052384257',
// createTime: 1697095176000,
// enterTime: 0,
// productionTime: 0,
// files: [
// {
// fileName: '.xlsx',
// fileUrl: 'https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2022%2F0108%2F0f0c6f30j00r5cle9000sc000hs00gtc.jpg&thumbnail=660x2147483647&quality=80&type=jpg',
// fileType: 1
// },
// {
// fileName: '2.xlsx',
// fileUrl: 'https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2022%2F0415%2F2cd23619j00racb96000kc000hs00hsc.jpg&thumbnail=660x2147483647&quality=80&type=jpg',
// fileType: 1
// },
// {
// fileName: '3.xlsx',
// fileUrl: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F1fea91a0-d088-409e-b145-e0e61254b28b%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1700031689&t=2e0fe7d1de7f54adff3007efe133d67c',
// fileType: 1
// },
// {
// fileName: '4.xlsx',
// fileUrl: 'https://pics5.baidu.com/feed/b7003af33a87e950cdfb4b4546eed044faf2b40d.jpeg?token=1d7484cfe4b014dd201f8c8725cab945',
// fileType: 2
// },
// {
// fileName: '5.xlsx',
// fileUrl: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2Fe3500876-9c46-4b70-8d37-4799520cdd13%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1700031689&t=4abc1df930e62730e5361a7d3765e0f2',
// fileType: 2
// },
// ],
// tvalue: 0,
// processingTime: 0,
// manufacturer: '',
// spec: '',
// description: '',
// };
this.showForm = true;
this.infoQuery = query;
} else if (section.key == 'attrs') {
this.attrQuery = query;
this.list = data.list;
this.total = data.total;
}
});
}
}
},
methods: {
handleTableBtnClick({ type, data }) {
switch (type) {
case 'edit':
this.handleEditAttr(data.id);
break;
case 'delete':
this.handleDeleteAttr(data.id);
break;
}
},
async handleConfirm() {
this.btnLoading = true;
this.syncFileListFlag = Math.random();
this.$nextTick(async () => {
const { code, data } = await this.$axios({
url: this.sections[0].urlUpdate,
method: 'put',
data: this.form,
});
if (code == 0) {
this.$modal.msgSuccess('更新成功');
}
this.btnLoading = false;
this.handleCancel();
});
},
handleEmitFun(val) {
console.log('handleEmitFun', val);
},
init() {
this.visible = true;
},
async getAttrList() {
this.attrListLoading = true;
const res = await this.$axios(this.attrQuery);
if (res.code == 0) {
this.list = res.data.list;
this.total = res.data.total;
}
this.attrListLoading = false;
},
//
handleSave() {
this.$refs['form'][0].validate(async (valid) => {
if (valid) {
const isEdit = this.mode == 'edit';
await this.$axios({
url: this.sections[0][isEdit ? 'urlUpdate' : 'urlCreate'],
method: isEdit ? 'put' : 'post',
data: this.form,
});
this.$modal.msgSuccess(`${isEdit ? '更新' : '创建'}成功`);
this.visible = false;
this.$emit('refreshDataList');
}
});
},
handleCancel() {
this.visible = false;
},
//
toggleEdit() {
this.$emit('update-mode', 'edit');
},
//
handleAddAttr() {
if (!this.dataId) return this.$message.error('请先创建设备信息');
this.attrForm = {
id: null,
equipmentId: this.dataId,
name: '',
value: '',
};
this.attrTitle = '添加设备属性';
this.attrFormVisible = true;
},
//
async handleEditAttr(attrId) {
const res = await this.$axios({
url: this.sections[1].urlDetail,
method: 'get',
params: { id: attrId },
});
if (res.code == 0) {
this.attrForm = res.data;
this.attrTitle = '编辑设备属性';
this.attrFormVisible = true;
}
},
//
handleDeleteAttr(attrId) {
this.$confirm('确定删除该属性?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(async () => {
const res = await this.$axios({
url: this.sections[1].urlDelete,
method: 'delete',
params: { id: attrId },
});
if (res.code == 0) {
this.$message({
message: '删除成功',
type: 'success',
duration: 1500,
onClose: () => {
this.getAttrList();
},
});
}
})
.catch(() => {});
},
//
submitAttrForm() {
this.$refs['attrForm'].validate(async (valid) => {
if (!valid) {
return;
}
try {
const isEdit = this.attrForm.id != null;
this.attrFormSubmitting = true;
const res = await this.$axios({
url: isEdit
? this.sections[1].urlUpdate
: this.sections[1].urlCreate,
method: isEdit ? 'put' : 'post',
data: this.attrForm,
});
if (res.code == 0) {
this.closeAttrForm();
this.$message({
message: `${isEdit ? '更新' : '创建'}成功`,
type: 'success',
duration: 1500,
onClose: () => {
this.getAttrList();
},
});
}
this.attrFormSubmitting = false;
} catch (err) {
this.$message({
message: err,
type: 'error',
duration: 1500,
});
this.attrFormSubmitting = false;
}
});
},
closeAttrForm() {
this.attrFormVisible = false;
},
handleClick(raw) {
if (raw.type === 'delete') {
this.$confirm(
`确定对${
raw.data.name
? '[名称=' + raw.data.name + ']'
: '[序号=' + raw.data._pageIndex + ']'
}进行删除操作?`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(() => {
deleteProductAttr(raw.data.id).then(({ data }) => {
this.$message({
message: '操作成功',
type: 'success',
duration: 1500,
onClose: () => {
this.getList();
},
});
});
})
.catch(() => {});
} else {
this.addNew(raw.data.id);
}
},
},
};
</script>
<style scoped>
.drawer >>> .el-drawer {
border-radius: 8px 0 0 8px;
}
.drawer >>> .el-drawer__header {
margin: 0;
padding: 32px 32px 24px;
border-bottom: 1px solid #dcdfe6;
margin-bottom: 0px;
}
.small-title::before {
content: '';
display: inline-block;
vertical-align: top;
width: 4px;
height: 22px;
border-radius: 1px;
margin-right: 8px;
background-color: #0b58ff;
}
.drawer-body {
display: flex;
flex-direction: column;
height: 100%;
}
.drawer-body__content {
flex: 1;
/* background: #eee; */
padding: 20px 30px;
overflow-y: auto;
}
.drawer-body__footer {
display: flex;
justify-content: flex-end;
padding: 18px;
}
</style>

View File

@ -0,0 +1,288 @@
<!--
filename: dialogForm.vue
author: liubin
date: 2023-08-15 10:32:36
description: 弹窗的表单组件
-->
<template>
<el-form class="equipment-info-form" ref="form" :model="form" label-width="200px" label-position="top"
v-loading="formLoading">
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="设备名称" prop="name" :rules="[{ required: true, message: '设备名称不能为空', trigger: 'blur' }]">
<el-input v-model="form.name" :disabled="disabled" placeholder="请输入设备名称"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备编码" prop="code" :rules="[]">
<el-input v-model="form.code" :disabled="disabled" placeholder="请输入设备编码"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="英文名称" prop="enName" :rules="[]">
<el-input v-model="form.enName" :disabled="disabled" placeholder="请输入英文名称"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="缩写" prop="abbr" :rules="[]">
<el-input v-model="form.abbr" :disabled="disabled" placeholder="请输入名称缩写"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备类型" prop="equipmentTypeId"
:rules="[{ required: true, message: '设备类型不能为空', trigger: 'blur' }]">
<el-select v-model="form.equipmentTypeId" :disabled="disabled" filterable placeholder="请选择设备类型">
<el-option v-for="eqType in eqTypeList" :key="eqType.id" :label="eqType.name"
:value="eqType.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="预计生产时间(min/天)" prop="workTime" :rules="[
{ required: true, message: '预计生产时间不能为空', trigger: 'blur' },
{
type: 'number',
message: '请输入正确的数字值',
trigger: 'blur',
transform: (val) => Number(val),
},
]">
<el-input v-model="form.workTime" :disabled="disabled" placeholder="请输入预计生产时间"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="生产日期" prop="productionTime" :rules="[]">
<el-date-picker v-model="form.enterTime" :disabled="disabled" type="datetime" placeholder="请选择生产日期"
value-format="timestamp"></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="进场日期" prop="enterTime" :rules="[]">
<el-date-picker v-model="form.enterTime" :disabled="disabled" type="datetime" placeholder="请选择进场日期"
value-format="timestamp"></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备TT值" prop="tvalue" :rules="[
{ required: true, message: '设备TT值不能为空', trigger: 'blur' },
{
type: 'number',
message: '请输入正确的数字值',
trigger: 'blur',
transform: (val) => Number(val),
},
]">
<el-input v-model="form.tvalue" :disabled="disabled" placeholder="请输入设备TT值"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="产品加工时间(s)" prop="processingTime" :rules="[
{ required: true, message: '产品加工时间不能为空', trigger: 'blur' },
{
type: 'number',
message: '请输入正确的数字值',
trigger: 'blur',
transform: (val) => Number(val),
},
]">
<el-input v-model="form.processingTime" :disabled="disabled" placeholder="请输入产品加工时间"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="制造商" prop="manufacturer" :rules="[]">
<el-input v-model="form.manufacturer" :disabled="disabled" placeholder="请输入制造商"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备规格" prop="spec" :rules="[]">
<el-input v-model="form.spec" :disabled="disabled" placeholder="请输入设备规格"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<!-- 功能描述 -->
<el-col>
<el-form-item label="功能描述" prop="description" :rules="[]">
<el-input type="textarea" :disabled="disabled" v-model="form.description"
placeholder="请填写功能描述"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<!-- 功能描述 -->
<el-col>
<el-form-item label="备注" prop="remark" :rules="[]">
<el-input v-model="form.remark" :disabled="disabled" placeholder="请输入备注"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<!-- 上传资料 -->
<el-col>
<el-form-item label="上传资料" prop="assets" :rules="[]">
<AssetsUpload v-model="form.assets" :disabled="disabled" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<!-- 上传图片 -->
<el-col>
<el-form-item label="上传图片" prop="pics" :rules="[]">
<AssetsUpload :is-pic-mode="true" v-model="form.pics" :disabled="disabled" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
import AssetsUpload from './AssetsUpload.vue';
export default {
name: 'EquipmentInfoForm',
model: {
prop: 'dataForm',
event: 'update',
},
emits: ['update'],
components: { AssetsUpload },
props: {
dataForm: {
type: Object,
default: () => ({}),
},
disabled: {
type: Boolean,
default: false,
},
syncFilelist: {
type: Number,
default: null,
required: false,
},
},
data() {
return {
formLoading: false,
form: {
name: '',
code: '',
enName: '',
abbr: '',
equipmentTypeId: '',
remark: '',
productionTime: '',
workTime: '',
enterTime: '',
tvalue: '',
processingTime: '',
manufacturer: '',
spec: '',
description: '',
assets: [],
pics: [],
},
eqTypeList: [],
dataLoaded: false,
};
},
watch: {
dataForm: {
handler(val) {
// debugger;
this.form = JSON.parse(JSON.stringify(val));
this.form.assets =
this.form.files?.filter((item) => item.fileType == '2') || [];
this.form.pics =
this.form.files?.filter((item) => item.fileType == '1') || [];
delete this.form.files;
},
immediate: true,
deep: true,
},
syncFilelist: {
handler(val) {
if (val != null) {
this.updateForm();
}
},
immediate: true,
},
},
mounted() {
this.getEqTypeList();
},
methods: {
updateForm() {
console.log('update form ==> ');
this.form.files = [...this.form.assets, ...this.form.pics];
delete this.form.assets;
delete this.form.pics;
this.$emit('update', this.form);
},
async getEqTypeList() {
this.formLoading = true;
const { code, data } = await this.$axios(
'/base/core-equipment-type/page?pageNo=1&pageSize=100'
);
// debugger;
if (code == 0) {
this.eqTypeList = data.list;
}
this.formLoading = false;
},
/** 模拟透传 ref */
validate(cb) {
return this.$refs.form.validate(cb);
},
resetFields(args) {
return this.$refs.form.resetFields(args);
},
// getCode
async getCode(url) {
const response = await this.$axios(url);
return response.data;
},
//
beforeUpload() { },
// bind
handleUploadSuccess(response, file, fileList) {
//
if ('fileNames' in this.form) this.form.fileNames.push(file.name);
//
if ('fileUrls' in this.form) this.form.fileUrls.push(response.data);
this.$modal.msgSuccess('上传成功');
},
getFileName(fileUrl) {
return fileUrl.split('/').pop();
},
},
};
</script>
<style scoped lang="scss">
.el-date-editor,
.el-select {
width: 100%;
}
</style>

View File

@ -0,0 +1,399 @@
<template>
<el-drawer
:visible.sync="visible"
:show-close="false"
:wrapper-closable="disabled"
class="drawer"
custom-class="mes-drawer"
size="65%"
@closed="$emit('destroy')">
<small-title slot="title" :no-padding="true">
{{
disabled ? '查看详情' : !dataForm.maintenanceStatus ? '修改' : '完成'
}}
</small-title>
<div class="drawer-body flex">
<div class="drawer-body__content">
<el-form
ref="form"
:model="dataForm"
label-width="100px"
label-position="top"
v-loading="formLoading">
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="维修单号" prop="repairOrderNumber">
<span>{{ dataForm.repairOrderNumber }}</span>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备大类" prop="equipmentCategory">
<span>
{{
['-', '安全设备', '消防设备', '特种设备'][
dataForm.equipmentCategory || 0
]
}}
</span>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备名称" prop="equipmentName">
<span>{{ dataForm.equipmentName }}</span>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="维修工" prop="repairman">
<span>{{ dataForm.repairman }}</span>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="故障发生时间" prop="faultTime">
<span>{{ parseTime(dataForm.faultTime) }}</span>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="故障级别" prop="faultLevel">
<span>
{{ getDictDataLabel('fault-level', dataForm.faultLevel) }}
</span>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="联系方式" prop="repairmanPhone">
<span>{{ dataForm.repairmanPhone }}</span>
</el-form-item>
</el-col>
</el-row>
<el-divider />
<div
v-if="
disabled && dataForm.maintenanceStatus === 1
? true
: !disabled
? true
: false
">
<small-title
style="margin: 16px 0; padding-left: 8px"
:no-padding="true">
{{ '设备维修信息' }}
</small-title>
<el-row :gutter="20">
<el-col :span="6">
<el-form-item
label="维修开始时间"
prop="maintenanceStartTime"
:rules="[
{
required: true,
message: '维修开始时间不能为空',
trigger: 'blur',
},
]">
<el-date-picker
v-model="dataForm.maintenanceStartTime"
type="datetime"
:disabled="disabled"
placeholder="请选择维修开始时间"
value-format="timestamp" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item
label="维修结束时间"
prop="maintenanceFinishTime"
:rules="[
{
required: true,
message: '维修结束时间不能为空',
trigger: 'blur',
},
]">
<el-date-picker
v-model="dataForm.maintenanceFinishTime"
type="datetime"
:disabled="disabled"
placeholder="请选择维修开始时间"
value-format="timestamp" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item
label="维修方式"
prop="repairMode"
:rules="[
{
required: true,
message: '维修方式不能为空',
trigger: 'blur',
},
]">
<el-select
:disabled="disabled"
v-model="dataForm.repairMode"
placeholder="请选择维修方式">
<el-option
v-for="opt in getDictDatas('repair-mode')"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="故障类型" prop="faultType">
<el-select
:disabled="disabled"
v-model="dataForm.faultType"
placeholder="请选择故障类型">
<el-option
v-for="opt in getDictDatas('fault-type')"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col>
<el-form-item
label="故障明细"
prop="faultDetail"
:rules="[
{
required: true,
message: '故障明细不能为空',
trigger: 'blur',
},
]">
<!-- // -->
<editor
v-model="dataForm.faultDetail"
:read-only="disabled"
:min-height="150" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col>
<el-form-item label="维修记录" prop="maintenanceDetail">
<!-- // -->
<editor
v-model="dataForm.maintenanceDetail"
:read-only="disabled"
:min-height="150" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col>
<el-form-item label="维修附件" prop="file">
<FileUpload
v-model="file"
:limit="1"
:f-name="fileName"
:disabled="disabled"
@name="setFileName" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col>
<el-form-item label="备注" prop="remark">
<el-input
v-model="dataForm.remark"
:placeholder="`请输入备注`"
:disabled="disabled" />
</el-form-item>
</el-col>
</el-row>
</div>
</el-form>
<div v-if="!disabled" class="drawer-body__footer">
<el-button style="" @click="goback()">取消</el-button>
<el-button type="primary" @click="dataFormSubmit()">确定</el-button>
</div>
</div>
</div>
</el-drawer>
</template>
<script>
import SmallTitle from './SmallTitle.vue';
import { getEqRepair, updateEqRepair } from '@/api/equipment/base/repair';
import Editor from '@/components/Editor';
import FileUpload from '@/components/FileUpload';
import { getDictDatas } from '@/utils/dict';
import { parseTime } from '@/utils/ruoyi';
import { getDictDataLabel } from '@/utils/dict';
export default {
name: 'DialogForm',
model: {
prop: 'dataForm',
event: 'update',
},
emits: ['update'],
components: { SmallTitle, Editor, FileUpload },
props: {
// dataForm: {
// type: Object,
// default: () => ({}),
// },
// disabled: {
// type: Boolean,
// default: false
// },
},
data() {
return {
formLoading: true,
visible: false,
disabled: false,
dataForm: {},
file: '',
fileName: '',
};
},
mounted() {},
methods: {
setFileName(val) {
this.fileName = val;
},
goback() {
this.$emit('refreshDataList');
this.visible = false;
},
goEdit() {
this.disabled = false;
},
/** 模拟透传 ref */
validate(cb) {
return this.$refs.form.validate(cb);
},
resetFields(args) {
return this.$refs.form.resetFields(args);
},
initData() {
this.file = '';
this.fileName = '';
},
init(row, isdetail) {
this.initData();
this.disabled = isdetail || false;
this.dataForm.id = row.id || undefined;
this.visible = true;
this.$nextTick(() => {
this.$refs['form'].resetFields();
if (this.dataForm.id) {
//
getEqRepair(this.dataForm.id).then((response) => {
this.formLoading = false;
this.dataForm = response.data;
debugger;
this.dataForm.maintenanceStatus =
this.dataForm.maintenanceStatus || 0;
if (this.dataForm.files.length > 0) {
this.file = this.dataForm.files[0].fileUrl;
this.fileName = this.dataForm.files[0].fileName;
}
});
} else {
// if (this.urlOptions.isGetCode) {
// this.getCode()
// }
}
});
},
//
dataFormSubmit() {
this.$refs['form'].validate((valid) => {
if (!valid) {
return false;
}
//
if (this.file) {
const temp = this.file.split(','); //
let arry = [];
temp.forEach((item) => {
arry.push({
fileName: this.fileName,
fileType: 2,
fileUrl: item,
});
});
this.dataForm.files = arry;
}
if (this.dataForm.id) {
updateEqRepair(this.dataForm).then((response) => {
this.$modal.msgSuccess('修改成功');
this.visible = false;
this.$emit('refreshDataList');
});
return;
}
//
// this.urlOptions.createURL(this.dataForm).then(response => {
// this.$modal.msgSuccess("");
// this.visible = false;
// this.$emit("refreshDataList");
// });
});
},
},
};
</script>
<style scoped>
.drawer >>> .el-drawer {
border-radius: 8px 0 0 8px;
}
.drawer >>> .el-drawer__header {
margin: 0;
padding: 32px 32px 24px;
border-bottom: 1px solid #dcdfe6;
margin-bottom: 0px;
}
.small-title::before {
content: '';
display: inline-block;
vertical-align: top;
width: 4px;
height: 22px;
border-radius: 1px;
margin-right: 8px;
background-color: #0b58ff;
}
.drawer-body {
display: flex;
flex-direction: column;
height: 100%;
}
.drawer-body__content {
flex: 1;
/* background: #eee; */
padding: 20px 30px;
overflow-y: auto;
}
.drawer-body__footer {
display: flex;
justify-content: flex-end;
padding: 18px;
}
</style>

View File

@ -0,0 +1,465 @@
<!--
filename: Monitor.vue
author: liubin
date: 2023-12-12 13:54:53
description:
-->
<template>
<div class="app-container SpecialEquipmentMaintainMonitor">
<!-- 搜索工作栏 -->
<SearchBar
:formConfigs="searchBarFormConfig"
ref="search-bar"
@select-changed="handleSearchBarChange"
@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="操作"
:width="120"
: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"
@close="cancel"
@cancel="cancel"
@confirm="submitForm">
<DialogForm
v-if="open"
ref="form"
v-model="form"
:has-files="false"
:rows="rows" />
</base-dialog>
</div>
</template>
<script>
import { publicFormatter } from '@/utils/dict';
// import moment from 'moment';
import basicPageMixin from '@/mixins/lb/basicPageMixin';
import { exportMaintainMonitorExcel } from '@/api/equipment/base/maintain/record';
import { parseTime } from '@/utils/ruoyi';
const remainBox = {
name: 'RemainBox',
props: ['injectData'],
data() {
return {};
},
computed: {
value() {
return this.injectData[this.injectData.prop] || null;
},
color() {
if (this.value) {
const v = +this.value;
return v < 0 ? '#FF5454' : v >= 0 && v < 2 ? '#FFD767' : '#37D97F';
}
return 'unset';
},
},
render: function (h) {
return (
<div
style={`background: ${
this.color
}; position:absolute; inset: 0; padding: 0 10px; display: flex; align-items: center; color: ${
// this.color == 'red' ? '#fff' : 'unset'
'#fff'
}`}>
{this.injectData[this.injectData.prop]?.toFixed(0) || ''}
</div>
);
},
};
const btn = {
name: 'tableBtn',
props: ['injectData'],
data() {
return {};
},
methods: {
handleClick() {
this.$emit('emitData', {
action: this.injectData.label,
value: this.injectData,
});
},
},
render: function (h) {
return (
<el-button type="text" onClick={this.handleClick}>
{this.injectData.name}
</el-button>
);
},
};
export default {
name: 'SpecialEquipmentMaintainMonitor',
components: {},
mixins: [basicPageMixin],
data() {
return {
searchBarKeys: ['planId', 'specialType', 'equipmentId'],
tableProps: [
// {
// prop: 'createTime',
// label: '',
// fixed: true,
// width: 180,
// filter: parseTime(createTime),
// },
{
prop: 'name',
label: '保养计划',
minWidth: 100,
showOverflowtooltip: true,
},
{
prop: 'lineName',
label: '产线名',
minWidth: 100,
showOverflowtooltip: true,
},
{
prop: 'equipmentCategory',
label: '设备大类',
minWidth: 100,
showOverflowtooltip: true,
filter: (val) =>
val != null ? ['-', '安全设备', '消防设备', '特种设备'][val] : '-',
},
{
prop: 'equipmentName',
label: '设备名称',
minWidth: 100,
showOverflowtooltip: true,
},
{ prop: 'maintenancePeriod', label: '保养频率' },
{
prop: 'maintainType',
label: '保养类型',
showOverflowtooltip: true,
filter: publicFormatter(this.DICT_TYPE.MAINTAIN_TYPE),
},
{
prop: 'lastMaintainTime',
label: '上次保养时间',
filter: parseTime,
minWidth: 150,
showOverflowtooltip: true,
},
{
prop: 'nextMaintainTime',
label: '计划下次保养时间',
filter: parseTime,
minWidth: 150,
showOverflowtooltip: true,
},
{
prop: 'remainDays',
label: '距离保养时间(天)',
subcomponent: remainBox,
minWidth: 150,
// showOverflowtooltip: true
},
{
prop: 'opt1',
label: '设备保养',
name: '操作',
subcomponent: btn,
width: 100,
},
{
prop: 'opt2',
label: '保养记录',
name: '查看详情',
subcomponent: btn,
width: 100,
},
],
searchBarFormConfig: [
{
type: 'select',
label: '保养计划',
placeholder: '请选择保养计划',
param: 'planId',
filterable: true,
},
{
type: 'select',
label: '设备大类',
placeholder: '请选择设备大类',
param: 'specialType',
onchange: true,
selectOptions: [
{ id: 1, name: '安全设备' },
{ id: 2, name: '消防设备' },
{ id: 3, name: '特种设备' },
],
filterable: true,
},
{
type: 'select',
label: '设备名',
placeholder: '请选择设备',
param: 'equipmentId',
filterable: true,
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: this.$auth.hasPermi('base:quality-inspection-type:export')
? 'button'
: '',
btnName: '导出',
name: 'export',
plain: true,
color: 'primary',
},
],
//
open: false,
//
queryParams: {
pageNo: 1,
pageSize: 10,
equipmentName: null,
createTime: null,
special: true,
specialType: null,
},
//
form: {},
allSpecialEquipments: [],
};
},
created() {
this.initSearchBar();
this.getList();
},
methods: {
/** 导出按钮操作 */
handleExport() {
//
let params = { ...this.queryParams };
params.pageNo = undefined;
params.pageSize = undefined;
this.$modal
.confirm('是否确认导出所有设备保养监控数据项?')
.then(() => {
this.exportLoading = true;
return exportMaintainMonitorExcel(params);
})
.then((response) => {
this.$download.excel(response, '设备保养监控.xls');
this.exportLoading = false;
})
.catch(() => {});
},
handleSearchBarChange({ param, value }) {
if ('specialType' === param) {
if (!value) {
this.setSearchBarEquipmentList(this.allSpecialEquipments);
return;
}
this.setSearchBarEquipmentList(
this.allSpecialEquipments.filter((item) => item.specialType == value)
);
}
},
setSearchBarEquipmentList(eqList) {
this.$set(
this.searchBarFormConfig[2],
'selectOptions',
eqList.map((item) => ({
name: item.name,
id: item.id,
}))
);
},
initSearchBar() {
this.$watch('current', {});
this.http('/base/core-equipment/listAll', 'get').then(({ data }) => {
this.allSpecialEquipments = data.filter((item) => item.special);
this.setSearchBarEquipmentList(data.filter((item) => item.special));
});
this.http('/base/equipment-maintain-plan/page', 'get', {
pageNo: 1,
pageSize: 100,
special: true,
}).then(({ data }) => {
this.$set(
this.searchBarFormConfig[0],
'selectOptions',
(data?.list || []).map((item) => ({
name: item.name,
id: item.id,
}))
);
});
},
handleEmitFun({ action, value }) {
switch (action) {
//
case '设备保养':
this.$router.push({
path: '/equipment/base/maintain/record',
query: {
addRecord: 1,
row: value,
},
});
break;
case '保养记录':
const queryData = {
equipmentId: value.equipmentId,
maintainPlanId: value.id,
relatePlan: value.lastMaintainTime ? 1 : 2,
};
this.$router.push({
path: '/equipment/base/maintain/record',
query: queryData,
});
break;
}
},
/** 查询列表 */
getList() {
this.loading = true;
//
this.http(
'/base/equipment-maintain-plan/monitor',
'get',
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 = {
code: null,
name: null,
equipmentId: null,
enabled: null,
maintenancePeriod: null,
maintainDuration: null,
maintainType: null,
remark: null,
enabled: 1,
};
this.resetForm('form');
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm');
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = '添加保养计划';
},
handleDetail(id) {
alert('跳转到 保养记录');
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id;
this.info({ 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) {
this.put(this.form).then((response) => {
this.$modal.msgSuccess('修改成功');
this.open = false;
this.getList();
});
return;
}
//
this.post(this.form).then((response) => {
this.$modal.msgSuccess('新增成功');
this.open = false;
this.getList();
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal
.confirm('是否确认删除设备类型"' + row.name + '"?')
.then(function () {
return this.del(id);
})
.then(() => {
this.getList();
this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
},
},
};
</script>
<style scoped lang="scss">
.SpecialEquipmentMaintainMonitor {
}
</style>

View File

@ -0,0 +1,281 @@
<!--
filename: dialogForm.vue
author: liubin
date: 2023-08-15 10:32:36
description: 弹窗的表单组件
-->
<template>
<el-form
ref="form"
:model="form"
:size="size"
:label-position="labelPosition"
v-loading="formLoading">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item
label="计划名称"
prop="name"
:rules="[
{ required: true, message: '请输入计划名称', trigger: 'blur' },
]">
<el-input
v-model="form.name"
@change="$emit('update', form)"
:placeholder="`请输入计划名称`"
:disabled="disabled" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="计划编号"
prop="code"
:rules="[
{ required: true, message: '请输入计划编号', trigger: 'blur' },
]">
<el-input
v-model="form.code"
@change="$emit('update', form)"
:placeholder="`请输入计划编号`"
:disabled="disabled" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="设备大类"
prop="equipmentCategory"
:rules="[
{ required: true, message: '请选择设备大类', trigger: 'blur' },
]">
<el-select
v-model="form.equipmentCategory"
:placeholder="`请选择设备大类`"
:disabled="disabled"
@change="handleEqTypeChange">
<el-option
v-for="opt in equipmentTypeOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="设备"
prop="equipmentId"
:rules="[{ required: true, message: '请选择设备', trigger: 'blur' }]">
<el-select
v-model="form.equipmentId"
:placeholder="`请选择设备`"
:disabled="disabled"
@change="$emit('update', form)">
<el-option
v-for="opt in equipmentOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="保养类型" prop="maintainType">
<el-select
v-model="form.maintainType"
:placeholder="`请选择保养类型`"
:disabled="disabled"
@change="$emit('update', form)">
<el-option
v-for="opt in getDictDatas(DICT_TYPE.MAINTAIN_TYPE)"
:key="opt.value"
:label="opt.label"
:value="+opt.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="保养时长(h)"
prop="maintainDuration"
:rules="[
{
type: 'number',
message: '请输入正确的数字',
trigger: 'blur',
transform: (val) => Number(val),
},
]">
<el-input
v-model="form.maintainDuration"
@change="$emit('update', form)"
:placeholder="`请输入保养时长`"
:disabled="disabled" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="保养频率(天/次)"
prop="maintenancePeriod"
:rules="[
{
type: 'number',
message: '请输入正确的数字',
trigger: 'blur',
transform: (val) => Number(val),
},
{ required: true, message: '保养频率不能为空', trigger: 'blur' },
]">
<el-input
v-model="form.maintenancePeriod"
@change="$emit('update', form)"
:placeholder="`请输入保养频率`"
:disabled="disabled" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input
v-model="form.remark"
@change="$emit('update', form)"
:placeholder="`请输入备注`"
:disabled="disabled" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
export default {
name: 'DialogForm',
model: {
prop: 'dataForm',
event: 'update',
},
emits: ['update'],
components: {},
props: {
rows: {
type: Array,
default: () => [],
},
dataForm: {
type: Object,
default: () => ({}),
},
disabled: {
type: Boolean,
default: false,
},
hasFiles: {
type: Boolean | Array,
default: false,
},
labelPosition: {
type: String,
default: 'right',
},
size: {
type: String,
default: '',
},
},
data() {
return {
form: {},
formLoading: true,
dataLoaded: false,
equipmentList: [],
equipmentOptions: [],
equipmentTypeOptions: [
{ label: '安全设备', value: 1 },
{ label: '消防设备', value: 2 },
{ label: '特种设备', value: 3 },
],
};
},
watch: {
dataForm: {
handler(val) {
this.form = JSON.parse(JSON.stringify(val));
if (this.form.equipmentCategory != null) {
setTimeout(() => {
this.equipmentOptions = this.equipmentList
.filter((item) => item.special)
.filter(
(item) => item.specialType === this.form.equipmentCategory
)
.map((item) => ({ label: item.name, value: item.id }));
}, 1000);
}
if (this.hasFiles) {
if (typeof this.hasFiles == 'boolean' && this.hasFiles) {
this.form.files = this.form.files ?? [];
} else if (Array.isArray(this.hasFiles)) {
this.hasFiles.forEach((prop) => {
this.form[prop] = this.form[prop] ?? [];
});
}
}
},
deep: true,
immediate: true,
},
},
mounted() {
this.getEquipmentList();
this.getCode('/base/equipment-maintain-plan/getCode');
},
methods: {
/** 模拟透传 ref */
validate(cb) {
return this.$refs.form.validate(cb);
},
resetFields(args) {
return this.$refs.form.resetFields(args);
},
// getCode
async getCode(url) {
this.formLoading = true;
const response = await this.$axios(url);
this.formLoading = false;
this.form.code = response.data || '';
},
// initialize
async getEquipmentList() {
this.formLoading = true;
const response = await this.$axios('/base/core-equipment/listAll');
this.equipmentList = response.data || [];
this.equipmentOptions = (response.data || []).map((item) => ({
label: item.name,
value: item.id,
}));
this.formLoading = false;
},
// handlers
handleEqTypeChange(type) {
this.form.equipmentId = null;
if (type) {
this.equipmentOptions = this.equipmentList
.filter((item) => item.special)
.filter((item) => item.specialType === type)
.map((item) => ({ label: item.name, value: item.id }));
} else
this.equipmentOptions = this.equipmentList.map((item) => ({
label: item.name,
value: item.id,
}));
// this.$emit('update', this.form)
},
},
};
</script>
<style scoped lang="scss">
.el-date-editor,
.el-select {
width: 100%;
}
</style>

View File

@ -0,0 +1,416 @@
<!--
filename: PlanConfig.vue
author: liubin
date: 2023-12-12 13:54:53
description:
-->
<template>
<div class="app-container SpecialEquipmentPlanConfig">
<!-- 搜索工作栏 -->
<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="操作"
:width="120"
: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"
@close="cancel"
@cancel="cancel"
@confirm="submitForm">
<DialogForm v-if="open" ref="form" v-model="form" :has-files="false" />
</base-dialog>
</div>
</template>
<script>
import moment from 'moment';
import basicPageMixin from '@/mixins/lb/basicPageMixin';
import { deleteEqMaintainPlan } from '@/api/equipment/base/maintain/record';
import { publicFormatter } from '@/utils/dict';
import PlanConfigAdd from './PlanConfig--add.vue';
export default {
name: 'SpecialEquipmentPlanConfig',
components: { DialogForm: PlanConfigAdd },
mixins: [basicPageMixin],
data() {
const t = new Date();
const [y, m, d] = [t.getFullYear(), t.getMonth(), t.getDate()];
return {
searchBarKeys: ['equipmentName', 'specialType', 'createTime'],
tableBtn: [
{
type: 'detail',
btnName: '保养记录',
},
this.$auth.hasPermi('equipment:plan-config:update')
? {
type: 'edit',
btnName: '修改',
}
: undefined,
this.$auth.hasPermi('equipment:plan-config:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
tableProps: [
// {
// prop: 'createTime',
// label: '',
// fixed: true,
// width: 180,
// filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
// },
{ prop: 'name', label: '计划名称' },
{ prop: 'code', label: '计划编号' },
{
prop: 'enabled',
label: '启用状态',
filter: (val) => ['停用', '启用'][val],
},
{ prop: 'lineName', label: '产线' },
{
prop: 'equipmentCategory',
label: '设备大类',
filter: (val) =>
val != null ? ['-', '安全', '消防', '特种'][val] : '-',
},
{ prop: 'equipmentName', label: '设备名称' },
{ width: 144, prop: 'maintainDuration', label: '计划保养用时(h)' },
{ width: 144, prop: 'maintenancePeriod', label: '保养频率(天/次)' },
{
prop: 'maintainType',
label: '保养类型',
filter: publicFormatter('maintain_type'),
},
{ prop: 'remark', label: '备注' },
],
searchBarFormConfig: [
{
type: 'select',
label: '设备大类',
selectOptions: [
{ id: 1, name: '安全设备' },
{ id: 2, name: '消防设备' },
{ id: 3, name: '特种设备' },
],
placeholder: '请选择设备大类',
param: 'specialType',
},
{
type: 'input',
label: '设备名',
placeholder: '请输入设备名称',
param: 'equipmentName',
},
{
type: 'datePicker',
label: '时间段',
dateType: 'daterange',
format: 'yyyy-MM-dd',
valueFormat: 'yyyy-MM-dd HH:mm:ss',
rangeSeparator: '-',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间',
param: 'createTime',
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: this.$auth.hasPermi('equipment:plan-config:create')
? 'button'
: '',
btnName: '新增',
name: 'add',
plain: true,
color: 'success',
},
// {
// type: this.$auth.hasPermi('base:quality-inspection-type:export')
// ? 'button'
// : '',
// btnName: '',
// name: 'export',
// color: 'warning',
// },
],
rows: [
[
{
input: true,
label: '计划名称',
prop: 'name',
rules: [
{ required: true, message: '计划名称不能为空', trigger: 'blur' },
],
},
{
input: true,
label: '计划编号',
prop: 'code',
url: '/base/equipment-maintain-plan/getCode',
rules: [
{ required: true, message: '计划编号不能为空', trigger: 'blur' },
],
},
],
[
{
select: true,
label: '设备大类',
prop: 'equipmentCategory',
options: [
{ value: 1, label: '安全设备' },
{ value: 2, label: '消防设备' },
{ value: 3, label: '特种设备' },
],
rules: [
{ required: true, message: '设备名称不能为空', trigger: 'blur' },
],
},
{
select: true,
label: '设备名称',
prop: 'equipmentId',
url: '/base/core-equipment/listAll',
rules: [
{ required: true, message: '设备名称不能为空', trigger: 'blur' },
],
},
{
select: true,
label: '保养类型',
prop: 'maintainType',
options: this.getDictDatas(this.DICT_TYPE.MAINTAIN_TYPE),
},
],
[
{
input: true,
label: '保养时长(h)',
prop: 'maintainDuration',
rules: [
{
type: 'number',
trigger: 'blur',
message: '请输入正确的数字',
transform: (val) => Number(val),
},
],
},
{
input: true,
label: '保养频率(天/次)',
prop: 'maintenancePeriod',
rules: [
{
type: 'number',
trigger: 'blur',
message: '请输入正确的数字',
transform: (val) => Number(val),
},
],
rules: [
{ required: true, message: '保养频率不能为空', trigger: 'blur' },
],
},
],
[
{
switch: true,
label: '启用状态',
prop: 'enabled',
bind: {
'active-value': 1,
'inactive-value': 0,
},
},
],
[{ input: true, label: '备注', prop: 'remark' }],
],
//
open: false,
//
queryParams: {
pageNo: 1,
pageSize: 10,
equipmentName: null,
createTime: null,
specialType: null,
},
//
form: {},
basePath: '/base/equipment-maintain-plan',
};
},
created() {
if (this.$route.query) {
this.queryParams.equipmentId =
this.$route.query?.equipmentId ?? undefined;
this.searchBarFormConfig[0].defaultSelect =
this.$route.query.equipmentName ?? undefined;
}
this.getList();
},
methods: {
/** 查询列表 */
getList() {
this.loading = true;
//
this.recv({
...this.queryParams,
special: true,
}).then((response) => {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
/** 取消按钮 */
cancel() {
this.open = false;
this.reset();
},
/** 表单重置 */
reset() {
this.form = {
code: null,
name: null,
equipmentId: null,
enabled: null,
maintenancePeriod: null,
maintainDuration: null,
maintainType: null,
remark: null,
enabled: 1,
equipmentCategory: null,
};
this.resetForm('form');
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm');
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = '添加保养计划';
},
handleDetail(row) {
// alert(' ')
// console.log(row)
const queryData = {
equipmentId: row.equipmentId,
maintainPlanId: row.id,
isAdd: 1,
// relatePlan: row.enabled
};
if (this.queryParams.createTime) {
queryData.createTime = this.queryParams.createTime;
}
this.$router.push({
path: '/equipment/base/maintain/record',
query: queryData,
});
// this.$router.push({ path: '/equipment/base/maintain/record', query: { orderNo: row.orderNo }})
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id;
this.info({ id }).then((response) => {
this.form = response.data;
debugger;
this.open = true;
this.title = '修改保养计划';
});
},
/** 提交按钮 */
submitForm() {
this.$refs['form'].validate((valid) => {
if (!valid) {
return;
}
//
if (this.form.id != null) {
this.put(this.form).then((response) => {
this.$modal.msgSuccess('修改成功');
this.open = false;
this.getList();
});
return;
}
//
this.post(this.form).then((response) => {
this.$modal.msgSuccess('新增成功');
this.open = false;
this.getList();
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal
.confirm('是否确认删除计划名称为"' + row.name + '"的数据项?')
.then(function () {
return deleteEqMaintainPlan(id);
})
.then(() => {
this.getList();
this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
},
},
};
</script>
<style scoped lang="scss">
.SpecialEquipmentPlanConfig {
}
</style>

View File

@ -0,0 +1,591 @@
<!--
filename: dialogForm.vue
author: liubin
date: 2023-08-15 10:32:36
description: 弹窗的表单组件
-->
<template>
<el-form
ref="form"
:model="form"
:label-position="labelPosition"
v-loading="formLoading">
<el-row :gutter="20">
<!-- 是否计划保养 -->
<el-col :span="8">
<el-form-item
label="是否计划保养"
prop="relatePlan"
:rules="[
{
required: true,
message: '是否计划保养不能为空',
trigger: 'blur',
},
]">
<el-select
v-model="form.relatePlan"
:placeholder="`是否计划保养`"
:disabled="disabled"
@change="handlePlanChange">
<el-option
v-for="opt in [
{ label: '是', value: 1 },
{ label: '否', value: 2 },
]"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<!-- 所属计划 -->
<el-col :span="8" v-if="form.relatePlan == 1">
<el-form-item label="所属计划" prop="maintainPlanId">
<el-select
v-model="form.maintainPlanId"
:placeholder="`请选择所属计划`"
:disabled="disabled"
filterable
clearable
@change="$emit('update', form)">
<el-option
v-for="opt in planOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<!-- 设备大类 -->
<el-col :span="8" v-if="form.relatePlan == 1">
<el-form-item
label="设备大类"
prop="equipmentCategory"
:rules="[
{ required: true, message: '设备大类不能为空', trigger: 'blur' },
]">
<el-select
v-model="form.equipmentCategory"
:placeholder="`请选择设备大类`"
:disabled="disabled"
clearable
filterable
@change="handleEqTypeChange">
<el-option
v-for="opt in equipmentTypeOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<!-- 设备名称 -->
<el-col :span="8">
<el-form-item
label="设备名称"
prop="equipmentId"
:rules="[
{ required: true, message: '设备不能为空', trigger: 'blur' },
]">
<el-select
v-model="form.equipmentId"
:placeholder="`请选择设备`"
:disabled="disabled"
filterable
clearable
@change="handleEqChange">
<el-option
v-for="opt in equipmentOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<!-- 开始时间 -->
<el-col :span="8">
<el-form-item
label="开始时间"
prop="startTime"
:rules="[
{ required: true, message: '开始时间不能为空', trigger: 'blur' },
]">
<el-date-picker
v-model="form.startTime"
type="datetime"
:disabled="disabled"
:placeholder="`请选择开始时间`"
value-format="timestamp"
format="yyyy-MM-dd HH:mm:ss"
clearable
@change="$emit('update', form)" />
</el-form-item>
</el-col>
<!-- 结束时间 -->
<el-col :span="8">
<el-form-item
label="结束时间"
prop="endTime"
:rules="[
{ required: true, message: '开始时间不能为空', trigger: 'blur' },
]">
<el-date-picker
v-model="form.endTime"
type="datetime"
:disabled="disabled"
:placeholder="`请选择结束时间`"
value-format="timestamp"
format="yyyy-MM-dd HH:mm:ss"
clearable
@change="$emit('update', form)" />
</el-form-item>
</el-col>
<!-- 保养人员 -->
<el-col :span="8">
<el-form-item
label="保养人员"
prop="maintainWorker"
:rules="[
{ required: true, message: '保养人员不能为空', trigger: 'blur' },
]">
<el-select
v-model="form.maintainWorker"
:placeholder="`请选择保养人员`"
:disabled="disabled"
filterable
clearable
multiple
@change="$emit('update', form)">
<el-option
v-for="opt in workerOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<!-- 保养单号 -->
<el-col :span="8">
<el-form-item label="保养单号" prop="maintainOrderNumber">
<el-input
v-model="form.maintainOrderNumber"
@change="$emit('update', form)"
:placeholder="`请输入保养单号`"
:disabled="disabled" />
</el-form-item>
</el-col>
<!-- 保养用时 -->
<el-col :span="8">
<el-form-item label="保养用时(h)" prop="timeUsed">
<el-input
v-model="form.timeUsed"
@change="$emit('update', form)"
:placeholder="`请输入保养用时(h)`"
:disabled="disabled" />
</el-form-item>
</el-col>
<!-- 上传文件 -->
<el-col :span="24">
<el-form-item label="上传文件" prop="files">
<div
class="upload-area"
:class="uploadOpen ? '' : 'height-48'"
ref="uploadArea">
<span class="close-icon" :class="uploadOpen ? 'open' : ''">
<el-button
type="text"
icon="el-icon-arrow-right"
@click="handleFilesOpen" />
</span>
<!-- :file-list="uploadedFileList" -->
<el-upload
class="upload-in-dialog"
:action="uploadUrl"
:headers="uploadHeaders"
:show-file-list="false"
icon="el-icon-upload2"
:disabled="disabled"
:before-upload="beforeUpload"
:on-success="handleUploadSuccess">
<el-button size="mini" :disabled="disabled">
<svg-icon
icon-class="icon-upload"
style="color: inherit"></svg-icon>
上传文件
</el-button>
<div class="el-upload__tip" slot="tip" v-if="false">
只能上传jpg/png文件, 大小不超过2MB
</div>
</el-upload>
<uploadedFile
class="file"
v-for="file in form.files"
:file="file"
:key="file.fileUrl"
:disabled="disabled"
@delete="!disabled && handleDeleteFile(file)" />
</div>
</el-form-item>
</el-col>
<!-- 保养描述 -->
<el-col :span="24">
<el-form-item label="保养描述" prop="maintenanceDes">
<div style="position: relative">
<div
v-if="disabled"
class="modal"
style="
position: absolute;
top: 0;
left: 0;
z-index: 1000;
width: 100%;
height: 100%;
background: #ccc3;
user-select: none;
cursor: not-allowed;
"></div>
<Editor
class="record-add__editor"
:value="form.maintenanceDes"
:min-height="192"
:disabled="disabled"
@input="handleEditorInput" />
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
import { getAccessToken } from '@/utils/auth';
import Editor from '@/components/Editor';
import tupleImg from '@/assets/images/tuple.png';
const uploadedFile = {
name: 'UploadedFile',
props: ['file', 'disabled'],
data() {
return {};
},
methods: {
handleDelete() {
this.$emit('delete', this.file);
},
async handleDownload() {
const data = await this.$axios({
url: this.file.fileUrl,
method: 'get',
responseType: 'blob',
});
await this.$message.success('开始下载');
// create download link
const url = window.URL.createObjectURL(data);
const link = document.createElement('a');
link.href = url;
link.download = this.file.fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
},
},
mounted() {},
render: function (h) {
return (
<div
title={this.file.fileName}
onClick={this.handleDownload}
style={{
background: `url(${tupleImg}) no-repeat`,
backgroundSize: '14px',
backgroundPosition: '0 55%',
paddingLeft: '20px',
paddingRight: '24px',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
overflow: 'hidden',
cursor: 'pointer',
display: 'inline-block',
}}>
{this.file.fileName}
{!this.disabled && (
<el-button
type="text"
icon="el-icon-close"
style="float: right; position: relative; top: 2px; left: 8px; z-index: 100"
class="dialog__upload_component__close"
onClick={this.handleDelete}
/>
)}
</div>
);
},
};
export default {
name: 'DialogForm',
model: {
prop: 'dataForm',
event: 'update',
},
emits: ['update'],
components: { Editor, uploadedFile },
props: {
dataForm: {
type: Object,
default: () => ({}),
},
disabled: {
type: Boolean,
default: false,
},
labelPosition: {
type: String,
default: 'top',
},
},
data() {
return {
allSpeicalEquipments: [],
uploadOpen: false,
form: {},
formLoading: true,
dataLoaded: false,
equipmentList: [],
equipmentOptions: [],
equipmentTypeOptions: [
{ label: '安全设备', value: 1 },
{ label: '消防设备', value: 2 },
{ label: '特种设备', value: 3 },
],
workerOptions: [],
planOptions: [],
uploadHeaders: { Authorization: 'Bearer ' + getAccessToken() },
uploadUrl: process.env.VUE_APP_BASE_API + '/admin-api/infra/file/upload', // headersurl
};
},
watch: {
dataForm: {
handler(val) {
this.form = JSON.parse(JSON.stringify(val));
if (this.form.equipmentCategory != null) {
setTimeout(() => {
this.equipmentOptions = this.equipmentList
.filter((item) => item.special)
.filter(
(item) => item.specialType === this.form.equipmentCategory
)
.map((item) => ({ label: item.name, value: item.id }));
}, 1000);
}
if (this.hasFiles) {
if (typeof this.hasFiles == 'boolean' && this.hasFiles) {
this.form.files = this.form.files ?? [];
} else if (Array.isArray(this.hasFiles)) {
this.hasFiles.forEach((prop) => {
this.form[prop] = this.form[prop] ?? [];
});
}
}
},
deep: true,
immediate: true,
},
},
mounted() {
this.initOptions();
this.getCode('/base/equipment-maintain-plan/getCode');
},
methods: {
/** 模拟透传 ref */
validate(cb) {
return this.$refs.form.validate(cb);
},
resetFields(args) {
return this.$refs.form.resetFields(args);
},
// getCode
async getCode(url) {
this.formLoading = true;
const response = await this.$axios(url);
this.formLoading = false;
this.form.code = response.data || '';
},
// initialize
async initOptions() {
this.initEquipment();
this.initWorker();
this.initPlan();
},
async initEquipment(type = 'special-equipment') {
this.formLoading = true;
const response = await this.$axios('/base/core-equipment/listAll');
this.equipmentList = response.data || [];
const equipmentOptions = (response.data || [])
.filter((item) => (type == 'special-equipment' ? item.special : true))
.map((item) => ({
label: item.name,
value: item.id,
}));
this.equipmentOptions = equipmentOptions;
this.allSpeicalEquipments = equipmentOptions;
this.formLoading = false;
},
async initWorker() {
this.formLoading = true;
const response = await this.$axios({
url: '/base/core-worker/listAll',
});
this.workerOptions = (response.data || []).map((item) => ({
label: item.name,
value: item.id,
}));
this.formLoading = false;
},
async initPlan() {
this.formLoading = true;
const response = await this.$axios({
url: '/base/equipment-maintain-plan/page',
params: { pageNo: 1, pageSize: 100, speical: true },
});
this.planOptions = (response.data?.list || []).map((item) => ({
label: item.name,
value: item.id,
}));
this.formLoading = false;
},
// handlers
handleEqTypeChange(type) {
this.form.equipmentId = null;
if (type) {
this.equipmentOptions = this.equipmentList
.filter((item) => item.special)
.filter((item) => item.specialType === type)
.map((item) => ({ label: item.name, value: item.id }));
} else
this.equipmentOptions = this.equipmentList.map((item) => ({
label: item.name,
value: item.id,
}));
// this.$emit('update', this.form)
},
handleEqChange() {
this.$emit('update', this.form);
},
//
handlePlanChange(val) {
console.log('handlePlanChange', val);
this.form.equipmentCategory = null;
this.form.equipmentId = null;
this.$emit('update', { ...this.form, relatePlan: val });
this.initEquipment(val == 1 ? 'special-equipment' : null);
},
handleEditorInput(html) {
this.$emit('update', {
...this.form,
maintenanceDes: html,
});
},
// upload
handleFilesOpen() {},
beforeUpload() {},
handleUploadSuccess(response, file) {
this.$modal.msgSuccess('上传成功');
console.log('file', file);
this.form.files.push({
fileName: file.name,
fileUrl: response.data,
});
this.$emit('update', this.form);
},
handleDeleteFile(file) {},
},
};
</script>
<style scoped lang="scss">
.el-date-editor,
.el-select {
width: 100%;
}
.upload-area {
// background: #ccc;
// display: grid;
// grid-auto-rows: 34px;
// grid-template-columns: repeat(6, minmax(32px, max-content));
// gap: 8px;
// align-items: center;
position: relative;
overflow: hidden;
transition: height 0.3s ease-out;
// margin-top: 40px;
}
.upload-in-dialog {
// display: inline-block;
margin-right: 24px;
// background: #ccc;
position: relative;
// top: -13px;
float: left;
}
.close-icon {
// background: #ccc;
position: absolute;
top: 0;
right: 12px;
z-index: 100;
transition: transform 0.3s ease-out;
}
.close-icon.open {
transform: rotateZ(90deg);
}
.dialog__upload_component__close {
color: #ccc;
}
.dialog__upload_component__close:hover {
/* color: #777; */
color: red;
}
.height-48 {
height: 35px !important;
}
:deep(.record-add__editor) {
.ql-picker-label {
display: flex;
}
}
</style>

View File

@ -0,0 +1,670 @@
<!--
filename: MaintainRecord.vue
author: liubin
date: 2023-12-12 13:54:53
description:
-->
<template>
<div class="app-container SpecialEquipmentMaintainRecord">
<!-- 搜索工作栏 -->
<SearchBar
:formConfigs="searchBarFormConfig"
ref="search-bar"
:is-fold="true"
@select-changed="handleSearchBarChange"
@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="操作"
:width="120"
: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="60%"
@close="cancel"
@cancel="cancel"
@confirm="submitForm">
<DialogForm
v-if="open"
ref="form"
v-model="form"
:disabled="mode == 'detail'" />
<el-row v-if="mode === 'detail'" slot="footer" type="flex" justify="end">
<el-col :span="12">
<el-button size="small" class="btnTextStyle" @click="cancel">
关闭
</el-button>
</el-col>
</el-row>
</base-dialog>
</div>
</template>
<script>
import moment from 'moment';
import basicPageMixin from '@/mixins/lb/basicPageMixin';
import Editor from '@/components/Editor';
import DialogForm from './Record--add.vue';
import {
deleteEqMaintainLog,
exportMaintainLogExcel,
} from '@/api/equipment/base/maintain/record';
const timeFilter = (val) => moment(val).format('yyyy-MM-DD HH:mm:ss');
export default {
name: 'SpecialEquipmentMaintainRecord',
components: { DialogForm },
mixins: [basicPageMixin],
data() {
return {
searchBarKeys: [
'maintainPlanId',
'startTime',
'relatePlan',
'equipmentId',
'specialType',
],
tableBtn: [
this.$auth.hasPermi('equipment:maintain-record:update')
? {
type: 'detail',
btnName: '详情',
}
: undefined,
this.$auth.hasPermi('equipment:maintain-record:update')
? {
type: 'edit',
btnName: '修改',
}
: undefined,
this.$auth.hasPermi('equipment:maintain-record:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
tableProps: [
// {
// prop: 'createTime',
// label: '',
// fixed: true,
// width: 150,
// filter: timeFilter,
// },
{
prop: 'maintainOrderNumber',
label: '设备保养单号',
width: 110,
showOverflowtooltip: true,
},
{
prop: 'startTime',
label: '开始时间',
filter: timeFilter,
minWidth: 150,
showOverflowtooltip: true,
},
{
prop: 'endTime',
label: '结束时间',
filter: timeFilter,
minWidth: 150,
showOverflowtooltip: true,
},
{
prop: 'equipmentCategory',
label: '设备大类',
minWidth: 100,
showOverflowtooltip: true,
filter: (val) =>
val != null ? ['-', '安全设备', '消防设备', '特种设备'][val] : '-',
},
{
prop: 'equipmentName',
label: '设备名称',
minWidth: 100,
showOverflowtooltip: true,
},
{
prop: 'maintainWorker',
label: '保养人员',
minWidth: 100,
showOverflowtooltip: true,
},
{
prop: 'relatePlan',
label: '是否计划保养',
width: 120,
filter: (v) => (v != null ? ['', '是', '否'][v] : ''),
},
{
prop: 'planName',
label: '保养计划名称',
minWidth: 120,
showOverflowtooltip: true,
},
{
prop: 'maintainDuration',
label: '计划保养用时(h)',
minWidth: 130,
showOverflowtooltip: true,
},
{ prop: 'timeUsed', label: '实际保养用时(h)', minWidth: 130 },
{
prop: 'remark',
label: '备注',
minWidth: 100,
showOverflowtooltip: true,
},
],
searchBarFormConfig: [
{
type: 'select',
label: '设备大类',
placeholder: '请选择设备大类',
param: 'specialType',
onchange: true,
selectOptions: [
{ id: 1, name: '安全设备' },
{ id: 2, name: '消防设备' },
{ id: 3, name: '特种设备' },
],
filterable: true,
},
{
type: 'select',
label: '设备',
placeholder: '请选择设备',
param: 'equipmentId',
},
{
type: 'select',
label: '计划名称',
placeholder: '请选择计划名称',
param: 'maintainPlanId',
},
//
{
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: 'startTime',
// width: 350,
},
{
type: 'select',
label: '是否计划保养',
selectOptions: [
{ name: '是', id: 1 },
{ name: '否', id: 2 },
],
param: 'relatePlan',
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: this.$auth.hasPermi('equipment:maintain-record:export')
? 'button'
: '',
btnName: '导出',
name: 'export',
plain: true,
color: 'primary',
},
{
type: this.$auth.hasPermi('equipment:maintain-record:create')
? 'button'
: '',
btnName: '新增',
name: 'add',
plain: true,
color: 'success',
},
],
rows: [
[
{
select: true,
label: '设备大类',
prop: 'specialType',
options: [
{ label: '安全设备', value: 1 },
{ label: '消防设备', value: 2 },
{ label: '特种设备', value: 3 },
],
bind: {
filterable: true,
clearable: true,
},
rules: [
{ required: true, message: '设备大类不能为空', trigger: 'blur' },
],
},
{
select: true,
label: '保养设备',
prop: 'equipmentId',
url: '/base/core-equipment/listAll',
bind: {
filterable: true,
clearable: true,
},
rules: [
{ required: true, message: '保养设备不能为空', trigger: 'blur' },
],
},
{
select: true,
label: '保养人员',
prop: 'maintainWorker',
url: '/base/core-worker/listAll',
valueKey: 'name',
bind: {
filterable: true,
clearable: true,
multiple: true,
},
rules: [
{ required: true, message: '保养人员不能为空', trigger: 'blur' },
],
},
{
input: true,
label: '保养单号',
prop: 'maintainOrderNumber',
},
],
[
// {
// switch: true,
// label: '',
// prop: 'relatePlan',
// bind: {
// 'active-value': 1,
// 'inactive-value': 2,
// },
// rules: [{ required: true, message: '', trigger: 'blur' }],
// },
{
select: true,
options: [
{ label: '是', value: 1 },
{ label: '否', value: 2 },
],
label: '是否计划保养',
prop: 'relatePlan',
bind: {
clearable: true,
filterable: true,
},
rules: [
{
required: true,
message: '是否计划保养不能为空',
trigger: 'blur',
},
],
},
{
select: true,
label: '所属计划',
prop: 'maintainPlanId',
url: '/base/equipment-maintain-plan/page',
bind: {
filterable: true,
clearable: true,
},
},
{
input: true,
label: '保养用时',
prop: 'timeUsed',
},
],
[
{
datetime: true,
label: '开始时间',
prop: 'startTime',
rules: [
{ required: true, message: '开始时间不能为空', trigger: 'blur' },
],
bind: {
format: 'yyyy-MM-dd HH:mm:ss',
'value-format': 'timestamp',
// 'value-format': 'yyyy-MM-dd HH:mm:ss',
clearable: true,
},
},
{
datetime: true,
label: '结束时间',
prop: 'endTime',
rules: [
{ required: true, message: '结束时间不能为空', trigger: 'blur' },
],
bind: {
format: 'yyyy-MM-dd HH:mm:ss',
'value-format': 'timestamp',
// 'value-format': 'yyyy-MM-dd HH:mm:ss',
clearable: true,
},
},
{},
],
[
{
upload: true,
label: '上传资料',
prop: 'files',
},
],
[
{
label: '保养描述',
prop: 'maintenanceDes',
subcomponent: Editor,
bind: {
'min-height': 192,
},
},
],
[{ input: true, label: '备注', prop: 'remark' }],
],
//
open: false,
//
queryParams: {
pageNo: 1,
pageSize: 10,
maintainPlanId: null,
maintainPlanId: null,
startTime: null,
relatePlan: null,
equipmentId: null,
special: true,
specialType: null,
},
//
form: {},
basePath: '/base/equipment-maintain-log',
mode: null,
allSpecialEquipments: [],
};
},
created() {
this.initSearchBar();
if (this.$route.query) {
this.queryParams.equipmentId =
this.$route.query?.equipmentId ?? undefined;
this.queryParams.maintainPlanId =
this.$route.query?.maintainPlanId ?? undefined;
this.queryParams.relatePlan = this.$route.query?.relatePlan ?? undefined;
this.queryParams.startTime = this.$route.query?.createTime ?? undefined;
this.searchBarFormConfig[1].defaultSelect =
this.$route.query.equipmentId ?? undefined;
this.searchBarFormConfig[2].defaultSelect =
this.$route.query.maintainPlanId ?? undefined;
this.searchBarFormConfig[3].defaultSelect =
this.$route.query?.createTime ?? undefined;
this.searchBarFormConfig[4].defaultSelect =
Number(this.$route.query.relatePlan) ?? undefined;
}
this.getList();
if (this.$route.query.addRecord) {
this.handleAdd();
}
},
methods: {
handleSearchBarChange({ param, value }) {
if ('specialType' === param) {
if (!value) {
this.setSearchBarEquipmentList(this.allSpecialEquipments);
return;
}
this.setSearchBarEquipmentList(
this.allSpecialEquipments.filter((item) => item.specialType == value)
);
}
},
setSearchBarEquipmentList(eqList) {
this.$set(
this.searchBarFormConfig[1],
'selectOptions',
eqList.map((item) => ({
name: item.name,
id: item.id,
}))
);
},
initSearchBar() {
this.http('/base/core-equipment/listAll', 'get').then(({ data }) => {
this.allSpecialEquipments = data.filter((item) => item.special);
this.setSearchBarEquipmentList(data.filter((item) => item.special));
});
this.http('/base/equipment-maintain-plan/page', 'get', {
pageNo: 1,
pageSize: 100,
special: true,
}).then(({ data }) => {
this.$set(
this.searchBarFormConfig[2],
'selectOptions',
(data?.list || []).map((item) => ({
name: item.name,
id: item.id,
}))
);
});
},
/** 查询列表 */
getList() {
this.loading = true;
//
this.recv(this.queryParams).then((response) => {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
/** 取消按钮 */
cancel() {
this.open = false;
this.mode = null;
this.reset();
},
/** 表单重置 */
reset() {
this.form = {
id: null,
relatePlan: null,
maintainPlanId: null,
equipmentId: null,
maintainWorker: [],
maintainOrderNumber: null,
startTime: null,
endTime: null,
timeUsed: null,
remark: null,
maintenanceDes: null,
files: [
// {
// fileName: '',
// fileType: '',
// fileUrl: '',
// },
],
};
this.resetForm('form');
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm');
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
if (this.$route.query.addRecord) {
//
const tempRow = this.$route.query.row;
this.form.equipmentId = tempRow.equipmentId;
this.form.relatePlan = tempRow.nextMaintainTime ? 1 : 2;
this.form.startTime = tempRow.nextMaintainTime;
this.form.maintainPlanId = tempRow.id;
}
if (this.$route.query.isAdd) {
//
this.form.equipmentId = this.$route.query.equipmentId;
this.form.maintainPlanId = this.$route.query.maintainPlanId;
}
this.open = true;
this.title = '添加保养记录';
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id;
this.info({ id }).then((response) => {
this.form = response.data;
this.open = true;
this.form.maintainWorker = this.form.maintainWorker.split(',');
this.title = '修改保养记录';
});
},
/** 提交按钮 */
submitForm() {
this.$refs['form'].validate((valid) => {
if (!valid) {
return;
}
//
if (this.form.id != null) {
this.put({
...this.form,
maintainWorker: this.form.maintainWorker.join(','),
}).then((response) => {
this.$modal.msgSuccess('修改成功');
this.open = false;
this.getList();
});
return;
}
//
this.post({
...this.form,
maintainWorker: this.form.maintainWorker.join(','),
}).then((response) => {
this.$modal.msgSuccess('新增成功');
//
const toSparePartsMaintain = () => {
this.open = false;
//
};
this.$confirm('是否有备品备件更换?', '提示', {
confirmButtonText: '有',
cancelButtonText: '没有',
})
.then(toSparePartsMaintain)
.catch(() => {
this.open = false;
this.getList();
});
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal
.confirm('是否确认删除设备名称为"' + row.equipmentName + '"的数据项?')
.then(function () {
return deleteEqMaintainLog(id);
})
.then(() => {
this.getList();
this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
},
handleDetail({ id }) {
this.reset();
this.mode = 'detail';
this.info({ id }).then((response) => {
this.form = response.data;
this.open = true;
this.title = '查看保养记录详情';
});
},
/** 导出按钮操作 */
handleExport() {
//
let params = { ...this.queryParams };
params.pageNo = undefined;
params.pageSize = undefined;
this.$modal
.confirm('是否确认导出所有保养记录?')
.then(() => {
this.exportLoading = true;
return exportMaintainLogExcel(params);
})
.then((response) => {
this.$download.excel(response, '设备保养记录.xls');
this.exportLoading = false;
})
.catch(() => {});
},
},
};
</script>
<style scoped lang="scss">
.SpecialEquipmentMaintainRecord {
}
</style>

View File

@ -0,0 +1,402 @@
<!--
filename: dialogForm.vue
author: liubin
date: 2023-08-15 10:32:36
description: 弹窗的表单组件
-->
<template>
<el-form
ref="form"
:model="form"
:label-position="labelPosition"
v-loading="formLoading">
<el-row :gutter="20">
<!-- 维修单号 -->
<el-col :span="12">
<el-form-item
label="维修单号"
prop="repairOrderNumber"
:rules="[
{ required: true, message: '维修单号不能为空', trigger: 'blur' },
]">
<el-input
v-model="form.repairOrderNumber"
@change="$emit('update', form)"
placeholder="请输入维修单号"
:disabled="disabled" />
</el-form-item>
</el-col>
<!-- 维修工 -->
<el-col :span="12">
<el-form-item
label="维修工"
prop="repairman"
:rules="[
{ required: true, message: '维修工不能为空', trigger: 'blur' },
]">
<el-input
v-model="form.repairman"
@change="$emit('update', form)"
placeholder="请输入维修工"
:disabled="disabled" />
</el-form-item>
</el-col>
<!-- 设备大类 -->
<el-col :span="12">
<el-form-item
label="设备大类"
prop="equipmentCategory"
:rules="[
{ required: true, message: '设备大类不能为空', trigger: 'blur' },
]">
<el-select
v-model="form.equipmentCategory"
:placeholder="`请选择设备大类`"
:disabled="disabled"
clearable
filterable
@change="handleEqTypeChange">
<el-option
v-for="opt in equipmentTypeOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<!-- 设备名称 -->
<el-col :span="12">
<el-form-item
label="设备名称"
prop="equipmentId"
:rules="[
{ required: true, message: '设备不能为空', trigger: 'blur' },
]">
<el-select
v-model="form.equipmentId"
:placeholder="`请选择设备`"
:disabled="disabled"
filterable
clearable
@change="$emit('update', form)">
<el-option
v-for="opt in equipmentOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<!-- 故障发生时间 -->
<el-col :span="12">
<el-form-item
label="故障发生时间"
prop="faultTime"
:rules="[
{
required: true,
message: '故障发生时间不能为空',
trigger: 'blur',
},
]">
<el-date-picker
v-model="form.faultTime"
type="datetime"
:disabled="disabled"
:placeholder="`请选择故障发生时间`"
value-format="timestamp"
format="yyyy-MM-dd HH:mm:ss"
clearable
@change="$emit('update', form)" />
</el-form-item>
</el-col>
<!-- 故障级别 -->
<el-col :span="12">
<el-form-item
label="故障级别"
prop="faultLevel"
:rules="[
{
required: true,
message: '故障级别不能为空',
trigger: 'blur',
},
]">
<el-select
v-model="form.faultLevel"
placeholder="故障级别"
:disabled="disabled"
@change="$emit('update', form)">
<el-option
v-for="opt in getDictDatas(DICT_TYPE.FAULT_LEVEL)"
:key="opt.value"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<!-- 联系方式 -->
<el-col :span="24">
<el-form-item
label="联系方式"
prop="repairmanPhone"
:rules="[
{ required: true, message: '联系方式不能为空', trigger: 'blur' },
]">
<el-input
v-model="form.repairmanPhone"
@change="$emit('update', form)"
placeholder="请输入联系方式"
:disabled="disabled" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
export default {
name: 'DialogForm',
model: {
prop: 'dataForm',
event: 'update',
},
emits: ['update'],
components: {},
props: {
dataForm: {
type: Object,
default: () => ({}),
},
disabled: {
type: Boolean,
default: false,
},
labelPosition: {
type: String,
default: 'top',
},
},
data() {
return {
allSpeicalEquipments: [],
uploadOpen: false,
form: {},
formLoading: true,
dataLoaded: false,
equipmentList: [],
equipmentOptions: [],
equipmentTypeOptions: [
{ label: '安全设备', value: 1 },
{ label: '消防设备', value: 2 },
{ label: '特种设备', value: 3 },
],
workerOptions: [],
planOptions: [],
};
},
watch: {
dataForm: {
handler(val) {
this.form = JSON.parse(JSON.stringify(val));
if (this.form.equipmentCategory != null) {
setTimeout(() => {
this.equipmentOptions = this.equipmentList
.filter((item) => item.special)
.filter(
(item) => item.specialType === this.form.equipmentCategory
)
.map((item) => ({ label: item.name, value: item.id }));
}, 1000);
}
if (this.hasFiles) {
if (typeof this.hasFiles == 'boolean' && this.hasFiles) {
this.form.files = this.form.files ?? [];
} else if (Array.isArray(this.hasFiles)) {
this.hasFiles.forEach((prop) => {
this.form[prop] = this.form[prop] ?? [];
});
}
}
},
deep: true,
immediate: true,
},
},
mounted() {
this.initOptions();
// this.getCode('/base/equipment-maintain-plan/getCode');
},
methods: {
/** 模拟透传 ref */
validate(cb) {
return this.$refs.form.validate(cb);
},
resetFields(args) {
return this.$refs.form.resetFields(args);
},
// getCode
// async getCode(url) {
// this.formLoading = true;
// const response = await this.$axios(url);
// this.formLoading = false;
// this.form.code = response.data || '';
// },
// initialize
async initOptions() {
this.initEquipment();
// this.initWorker();
// this.initPlan();
},
async initEquipment(type = 'special-equipment') {
this.formLoading = true;
const response = await this.$axios('/base/core-equipment/listAll');
this.equipmentList = response.data || [];
const equipmentOptions = (response.data || [])
.filter((item) => (type == 'special-equipment' ? item.special : true))
.map((item) => ({
label: item.name,
value: item.id,
}));
this.equipmentOptions = equipmentOptions;
this.allSpeicalEquipments = equipmentOptions;
this.formLoading = false;
},
// async initWorker() {
// this.formLoading = true;
// const response = await this.$axios({
// url: '/base/core-worker/listAll',
// });
// this.workerOptions = (response.data || []).map((item) => ({
// label: item.name,
// value: item.id,
// }));
// this.formLoading = false;
// },
// async initPlan() {
// this.formLoading = true;
// const response = await this.$axios({
// url: '/base/equipment-maintain-plan/page',
// params: { pageNo: 1, pageSize: 100, speical: true },
// });
// this.planOptions = (response.data?.list || []).map((item) => ({
// label: item.name,
// value: item.id,
// }));
// this.formLoading = false;
// },
// handlers
handleEqTypeChange(type) {
this.form.equipmentId = null;
if (type) {
this.equipmentOptions = this.equipmentList
.filter((item) => item.special)
.filter((item) => item.specialType === type)
.map((item) => ({ label: item.name, value: item.id }));
} else
this.equipmentOptions = this.equipmentList.map((item) => ({
label: item.name,
value: item.id,
}));
// this.$emit('update', this.form)
},
handleEqChange() {
this.$emit('update', this.form);
},
//
handlePlanChange(val) {
console.log('handlePlanChange', val);
this.form.equipmentCategory = null;
this.form.equipmentId = null;
this.$emit('update', { ...this.form, relatePlan: val });
this.initEquipment(val == 1 ? 'special-equipment' : null);
},
handleEditorInput(html) {
this.$emit('update', {
...this.form,
maintenanceDes: html,
});
},
// upload
handleFilesOpen() {},
beforeUpload() {},
handleUploadSuccess(response, file) {
this.$modal.msgSuccess('上传成功');
console.log('file', file);
this.form.files.push({
fileName: file.name,
fileUrl: response.data,
});
this.$emit('update', this.form);
},
handleDeleteFile(file) {},
},
};
</script>
<style scoped lang="scss">
.el-date-editor,
.el-select {
width: 100%;
}
.upload-area {
position: relative;
overflow: hidden;
transition: height 0.3s ease-out;
}
.upload-in-dialog {
margin-right: 24px;
position: relative;
float: left;
}
.close-icon {
position: absolute;
top: 0;
right: 12px;
z-index: 100;
transition: transform 0.3s ease-out;
}
.close-icon.open {
transform: rotateZ(90deg);
}
.dialog__upload_component__close {
color: #ccc;
}
.dialog__upload_component__close:hover {
/* color: #777; */
color: red;
}
.height-48 {
height: 35px !important;
}
:deep(.record-add__editor) {
.ql-picker-label {
display: flex;
}
}
</style>

View File

@ -0,0 +1,477 @@
<!--
filename: Repair.vue
author: liubin
date: 2023-12-12 13:54:53
description:
-->
<template>
<div class="app-container SpecialEquipmentRepair">
<!-- 搜索工作栏 -->
<SearchBar
:formConfigs="searchBarFormConfig"
ref="search-bar"
@select-changed="handleSearchBarChange"
@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="操作"
:width="120"
: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"
@close="cancel"
@cancel="cancel"
@confirm="submitForm">
<DialogForm
v-if="open"
ref="form"
v-model="form"
:disabled="mode == 'detail'" />
</base-dialog>
<CustomDialogForm
v-if="addOrUpdateVisible"
ref="addOrUpdate"
@refreshDataList="getList"
@destroy="addOrUpdateVisible = false" />
</div>
</template>
<script>
import basicPageMixin from '@/mixins/lb/basicPageMixin';
import CustomDialogForm from './CustomDialogForm.vue';
import {
deleteRepair,
exportRepairLogExcel,
} from '@/api/equipment/base/repair';
import { parseTime } from '@/utils/ruoyi';
import htmls from './htmls.vue';
import DialogForm from './Repair--add.vue';
export default {
name: 'SpecialEquipmentRepair',
components: { CustomDialogForm, DialogForm },
mixins: [basicPageMixin],
data() {
return {
addOrUpdateVisible: false,
searchBarKeys: [
'maintenanceStatus',
'createTime',
'equipmentId',
'specialType',
],
tableBtn: [
this.$auth.hasPermi('equipment:repair:finish')
? {
type: 'finish',
btnName: '完成',
}
: undefined,
this.$auth.hasPermi('equipment:repair:update')
? {
type: 'detail',
btnName: '详情',
}
: undefined,
// this.$auth.hasPermi('equipment:repair:update')
// ? {
// type: 'edit',
// btnName: '',
// }
// : undefined,
this.$auth.hasPermi('equipment:repair:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
tableProps: [
{
prop: 'createTime',
label: '添加时间',
fixed: true,
width: 150,
filter: parseTime,
},
{
prop: 'repairOrderNumber',
label: '设备维修单号',
minWidth: 120,
showOverflowtooltip: true,
},
{
prop: 'maintenanceStartTime',
label: '开始时间',
filter: parseTime,
minWidth: 150,
showOverflowtooltip: true,
},
{
prop: 'maintenanceFinishTime',
label: '结束时间',
filter: parseTime,
minWidth: 150,
showOverflowtooltip: true,
},
{
prop: 'maintenanceStatus',
label: '维修状态',
filter: (v) => (v != null ? ['未完成', '完成', '进行中'][v] : ''),
},
{ prop: 'maintenanceDuration', label: '维修时长(h)', width: 110 },
{ prop: 'lineName', label: '产线' },
{ prop: 'sectionName', label: '工段' },
{
prop: 'equipmentName',
label: '设备名称',
minWidth: 100,
showOverflowtooltip: true,
},
{
prop: 'maintenanceDetail',
label: '维修明细',
subcomponent: htmls,
minWidth: 100,
showOverflowtooltip: true,
},
{
prop: 'repairman',
label: '维修工',
minWidth: 100,
showOverflowtooltip: true,
},
{
prop: 'repairmanPhone',
label: '联系方式',
minWidth: 100,
showOverflowtooltip: true,
},
{
prop: 'remark',
label: '备注',
minWidth: 120,
showOverflowtooltip: true,
},
],
searchBarFormConfig: [
{
type: 'select',
label: '设备大类',
placeholder: '请选择设备大类',
param: 'specialType',
onchange: true,
selectOptions: [
{ id: 1, name: '安全设备' },
{ id: 2, name: '消防设备' },
{ id: 3, name: '特种设备' },
],
filterable: true,
},
{
type: 'select',
label: '设备',
placeholder: '请选择设备',
param: 'equipmentId',
filterable: true,
},
{
type: 'select',
label: '状态',
placeholder: '请选择状态',
param: 'maintenanceStatus',
selectOptions: [
{ name: '未完成', id: '0' },
{ name: '完成', id: '1' },
{ name: '进行中', id: '2' },
],
},
//
{
type: 'datePicker',
label: '时间段',
dateType: 'daterange', // datetimerange
format: 'yyyy-MM-dd',
valueFormat: 'yyyy-MM-dd HH:mm:ss',
// valueFormat: 'timestamp',
rangeSeparator: '-',
startPlaceholder: '开始日期',
endPlaceholder: '结束日期',
defaultTime: ['00:00:00', '23:59:59'],
param: 'createTime',
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: this.$auth.hasPermi('equipment:repair:export') ? 'button' : '',
btnName: '导出',
name: 'export',
plain: true,
color: 'primary',
},
{
type: this.$auth.hasPermi('equipment:repair:create') ? 'button' : '',
btnName: '新增',
name: 'add',
plain: true,
color: 'success',
},
],
//
open: false,
//
queryParams: {
pageNo: 1,
pageSize: 10,
maintenanceStatus: null,
createTime: null,
equipmentId: null,
special: true,
specialType: null,
},
//
form: {},
basePath: '/base/equipment-repair-log',
mode: null,
allSpecialEquipments: [],
};
},
created() {
this.initSearchBar();
this.getList();
},
methods: {
initSearchBar() {
this.http('/base/core-equipment/listAll', 'get').then(({ data }) => {
this.allSpecialEquipments = data.filter((item) => item.special);
this.setSearchBarEquipmentList(data.filter((item) => item.special));
});
},
/** 查询列表 */
getList() {
this.loading = true;
//
this.recv(this.queryParams).then((response) => {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
/** 取消按钮 */
cancel() {
this.open = false;
this.mode = null;
this.reset();
},
/** 表单重置 */
reset() {
this.form = {
id: null,
repairOrderNumber: null,
equipmentId: null,
repairman: null,
repairmanPhone: null,
faultTime: null,
faultLevel: null,
maintenanceStartTime: null,
maintenanceFinishTime: null,
faultType: null,
repairMode: null,
maintenanceStatus: null,
faultDetail: null,
maintenanceDetail: null,
remark: null,
files: [
// {
// fileName: '',
// fileType: '',
// fileUrl: '',
// },
],
};
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;
// this.info({ id }).then((response) => {
// this.form = response.data;
// // this.form.repairman = this.form.repairman.split(',')
// this.open = true;
// this.title = '';
// });
this.addOrUpdateVisible = true;
this.$nextTick(() => {
this.$refs.addOrUpdate.init({ id: row.id });
});
},
/** 完成按钮操作 */
handlFinish(row) {
this.addOrUpdateVisible = true;
const params = {
id: row.id,
maintenanceStatus: 1,
};
this.$nextTick(() => {
this.$refs.addOrUpdate.init(params);
});
},
/** 提交按钮 */
submitForm() {
this.$refs['form'].validate((valid) => {
if (!valid) {
return;
}
// if (this.form.repairman) {
// this.form.repairman = this.form.repairman.join(',')
// }
//
if (this.form.id != null) {
this.put(this.form).then((response) => {
this.$modal.msgSuccess('修改成功');
this.open = false;
this.getList();
});
return;
}
//
this.post(this.form).then((response) => {
this.$modal.msgSuccess('新增成功');
this.open = false;
this.getList();
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal
.confirm('是否确认删除维修单号为"' + row.repairOrderNumber + '"的数据?')
.then(() => {
return deleteRepair(id);
})
.then(() => {
this.getList();
this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
},
handleDetail({ id }) {
this.addOrUpdateVisible = true;
this.$nextTick(() => {
this.$refs.addOrUpdate.init({ id: id }, true);
});
},
/** 导出按钮操作 */
handleExport() {
//
let params = { ...this.queryParams };
params.pageNo = undefined;
params.pageSize = undefined;
this.$modal
.confirm('是否确认导出所有维修记录?')
.then(() => {
this.exportLoading = true;
return exportRepairLogExcel(params);
})
.then((response) => {
this.$download.excel(response, '设备维修.xls');
this.exportLoading = false;
})
.catch(() => {});
},
//
handleTableBtnClick({ data, type }) {
console.log('nihc', data, type);
switch (type) {
case 'edit':
this.handleUpdate(data);
break;
case 'delete':
this.handleDelete(data);
break;
case 'detail':
this.handleDetail(data);
break;
case 'finish':
this.handlFinish(data);
break;
}
},
//
handleSearchBarChange({ param, value }) {
if ('specialType' === param) {
if (!value) {
this.setSearchBarEquipmentList(this.allSpecialEquipments);
return;
}
this.setSearchBarEquipmentList(
this.allSpecialEquipments.filter((item) => item.specialType == value)
);
}
},
setSearchBarEquipmentList(eqList) {
this.$set(
this.searchBarFormConfig[1],
'selectOptions',
eqList.map((item) => ({
name: item.name,
id: item.id,
}))
);
},
},
};
</script>
<style scoped lang="scss">
.SpecialEquipmentRepair {
}
</style>

View File

@ -0,0 +1,65 @@
<!--
* @Author: zwq
* @Date: 2023-08-01 15:27:31
* @LastEditors: zwq
* @LastEditTime: 2023-08-01 16:25:54
* @Description:
-->
<template>
<div :class="[className, { 'p-0': noPadding }]">
<slot />
</div>
</template>
<script>
export default {
props: {
size: {
// : xl lg md sm
type: String,
default: 'de',
validator: function (val) {
return ['xl', 'lg', 'de', 'md', 'sm'].indexOf(val) !== -1;
},
},
noPadding: {
type: Boolean,
default: false,
},
},
computed: {
className: function () {
return `${this.size}-title`;
},
},
};
</script>
<style lang="scss" scoped>
$pxls: (xl, 28px) (lg, 24px) (de, 20px) (md, 18px) (sm, 16px);
$mgr: 8px;
@each $size, $height in $pxls {
.#{$size}-title {
font-size: 18px;
line-height: $height;
color: #000;
font-weight: 500;
font-family: '微软雅黑', 'Microsoft YaHei', Arial, Helvetica, sans-serif;
&::before {
content: '';
display: inline-block;
vertical-align: top;
width: 4px;
height: $height + 2px;
border-radius: 1px;
margin-right: $mgr;
background-color: #0b58ff;
}
}
}
.p-0 {
padding: 0;
}
</style>

View File

@ -0,0 +1,35 @@
<!--
* @Author: zhp
* @Date: 2023-11-08 14:00:52
* @LastEditTime: 2023-12-01 10:12:27
* @LastEditors: DY
* @Description:
-->
<template>
<div v-html="content" />
</template>
<script>
export default {
props: {
injectData: {
type: Object,
default: () => ({})
}
},
data() {
return {
content: ''
}
},
mounted() {
this.getContent()
},
methods: {
getContent() {
this.content = this.injectData[this.injectData.prop] ?? ''
}
}
}
</script>