Compare commits

..

3 Commits

37 changed files with 6107 additions and 1274 deletions

View File

@ -8,7 +8,15 @@ export function getEnergyTrend(data) {
data: data data: data
}) })
} }
// 导出走势分析数据
export function exportTrend(data) {
return request({
url: '/analysis/energy-analysis/exportTrend',
method: 'post',
data: data,
responseType: 'blob'
})
}
// 获取对比分析数据 // 获取对比分析数据
export function getCompare(data) { export function getCompare(data) {
return request({ return request({
@ -34,4 +42,4 @@ export function getQoq(data) {
method: 'post', method: 'post',
data: data data: data
}) })
} }

54
src/api/home.js Normal file
View File

@ -0,0 +1,54 @@
/*
* @Author: zwq
* @Date: 2024-09-12 13:38:33
* @LastEditors: zwq
* @LastEditTime: 2024-09-13 15:25:07
* @Description:
*/
import request from '@/utils/request'
// 获得首页生产总览以及工单监控
export function getHomeOrder(data) {
return request({
url: '/base/core-work-order/homeOrder',
method: 'post',
data: data
})
}
// 获得首页生产总览-完成订单数量
export function getHomeOrderNum(data) {
return request({
url: '/base/order/homeOrder',
method: 'post',
data: data
})
}
// 首页设备总览
export function getHomeEquipment() {
return request({
url: '/monitoring/equipment-monitor/homeEquipment',
method: 'get'
})
}
// 首页设备报警信息
export function getHomeEquipmentAlarmList() {
return request({
url: '/base/equipment-alarm-realtime/homeEquipmentAlarmList',
method: 'get'
})
}
// 获取是否存在报警(右上角红点)
export function getHomeGetAlarm() {
return request({
url: '/base/core-alarm-log/homeGetAlarm',
method: 'get'
})
}
// 条件查询获得异常警告列表
export function getHomeAlarmList(query) {
return request({
url: '/base/core-alarm-log/listbyfilter',
method: 'get',
params: query
})
}

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title></title>
<g id="主界面" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="主页" transform="translate(-1713.000000, -32.000000)">
<g id="icon/banner/消息" transform="translate(1713.000000, 32.000000)">
<g id="编组">
<rect id="矩形" x="0" y="0" width="24" height="24"></rect>
<path d="M13.875,20.6585751 L13.9796526,20.6647179 C14.3523487,20.7094224 14.6,20.9943408 14.6,21.3949387 C14.6,21.793137 14.3546839,22.079785 13.9805499,22.1250542 L13.8720425,22.1313899 L10.125,22.1313023 L10.0203474,22.1251595 C9.64765132,22.080455 9.4,21.7955365 9.4,21.3949387 C9.4,20.9967404 9.64531608,20.7100924 10.0194501,20.6648232 L10.1279575,20.6584875 L13.875,20.6585751 Z M12,0.930991914 L12.114202,0.938656892 C12.4461465,0.982430206 12.6786924,1.21840343 12.7188472,1.56053658 L12.7250824,1.6705356 L12.724,2.83025932 L12.975759,2.90430031 L13.2244725,2.9413468 C16.687784,3.51732717 19.3536312,6.48703662 19.5838508,10.0724929 L19.5959741,10.3244915 L19.6000064,10.5775585 L19.6,18.0623023 L20.7499628,18.1131205 L20.8641749,18.1204751 C21.1961465,18.1642484 21.4286924,18.4002216 21.4688472,18.7423548 L21.4750824,18.8523538 L21.4678171,18.9675593 C21.4246486,19.3025982 21.1922705,19.5388574 20.8555499,19.5795997 L20.7470425,19.5859353 L3.25,19.5859353 L3.14534744,19.5797049 C2.77265132,19.5350005 2.525,19.250082 2.525,18.8494841 C2.525,18.4512975 2.77030543,18.1646386 3.1443756,18.1193685 L3.25285992,18.113033 L4.35003719,18.1123023 L4.4,10.5767569 L4.40403631,10.3246942 C4.524824,6.55675169 7.34298069,3.38911146 11.0266305,2.90405757 L11.229889,2.87995432 L11.275,1.66770897 L11.2823355,1.55103724 C11.3211556,1.24947788 11.5116242,1.02739927 11.7956288,0.955808301 L11.897531,0.937079811 L12,0.930991914 Z M12,4.31312051 C8.70150639,4.31312051 5.97362451,6.99932148 5.85407645,10.3480678 L5.85000794,10.5758657 L5.849,18.0622956 L18.099,18.1123023 L18.15,10.5767635 L18.1459233,10.3480647 C18.0266869,7.00812062 15.3071214,4.31312051 12,4.31312051 Z" id="形状结合" fill="#FFFFFF" fill-rule="nonzero"></path>
</g>
<circle id="Oval-1-Copy-2" fill="#F5222D" cx="18" cy="6" r="3"></circle>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -8,8 +8,7 @@
<rect id="矩形" x="0" y="0" width="24" height="24"></rect> <rect id="矩形" x="0" y="0" width="24" height="24"></rect>
<path d="M13.875,20.6585751 L13.9796526,20.6647179 C14.3523487,20.7094224 14.6,20.9943408 14.6,21.3949387 C14.6,21.793137 14.3546839,22.079785 13.9805499,22.1250542 L13.8720425,22.1313899 L10.125,22.1313023 L10.0203474,22.1251595 C9.64765132,22.080455 9.4,21.7955365 9.4,21.3949387 C9.4,20.9967404 9.64531608,20.7100924 10.0194501,20.6648232 L10.1279575,20.6584875 L13.875,20.6585751 Z M12,0.930991914 L12.114202,0.938656892 C12.4461465,0.982430206 12.6786924,1.21840343 12.7188472,1.56053658 L12.7250824,1.6705356 L12.724,2.83025932 L12.975759,2.90430031 L13.2244725,2.9413468 C16.687784,3.51732717 19.3536312,6.48703662 19.5838508,10.0724929 L19.5959741,10.3244915 L19.6000064,10.5775585 L19.6,18.0623023 L20.7499628,18.1131205 L20.8641749,18.1204751 C21.1961465,18.1642484 21.4286924,18.4002216 21.4688472,18.7423548 L21.4750824,18.8523538 L21.4678171,18.9675593 C21.4246486,19.3025982 21.1922705,19.5388574 20.8555499,19.5795997 L20.7470425,19.5859353 L3.25,19.5859353 L3.14534744,19.5797049 C2.77265132,19.5350005 2.525,19.250082 2.525,18.8494841 C2.525,18.4512975 2.77030543,18.1646386 3.1443756,18.1193685 L3.25285992,18.113033 L4.35003719,18.1123023 L4.4,10.5767569 L4.40403631,10.3246942 C4.524824,6.55675169 7.34298069,3.38911146 11.0266305,2.90405757 L11.229889,2.87995432 L11.275,1.66770897 L11.2823355,1.55103724 C11.3211556,1.24947788 11.5116242,1.02739927 11.7956288,0.955808301 L11.897531,0.937079811 L12,0.930991914 Z M12,4.31312051 C8.70150639,4.31312051 5.97362451,6.99932148 5.85407645,10.3480678 L5.85000794,10.5758657 L5.849,18.0622956 L18.099,18.1123023 L18.15,10.5767635 L18.1459233,10.3480647 C18.0266869,7.00812062 15.3071214,4.31312051 12,4.31312051 Z" id="形状结合" fill="#FFFFFF" fill-rule="nonzero"></path> <path d="M13.875,20.6585751 L13.9796526,20.6647179 C14.3523487,20.7094224 14.6,20.9943408 14.6,21.3949387 C14.6,21.793137 14.3546839,22.079785 13.9805499,22.1250542 L13.8720425,22.1313899 L10.125,22.1313023 L10.0203474,22.1251595 C9.64765132,22.080455 9.4,21.7955365 9.4,21.3949387 C9.4,20.9967404 9.64531608,20.7100924 10.0194501,20.6648232 L10.1279575,20.6584875 L13.875,20.6585751 Z M12,0.930991914 L12.114202,0.938656892 C12.4461465,0.982430206 12.6786924,1.21840343 12.7188472,1.56053658 L12.7250824,1.6705356 L12.724,2.83025932 L12.975759,2.90430031 L13.2244725,2.9413468 C16.687784,3.51732717 19.3536312,6.48703662 19.5838508,10.0724929 L19.5959741,10.3244915 L19.6000064,10.5775585 L19.6,18.0623023 L20.7499628,18.1131205 L20.8641749,18.1204751 C21.1961465,18.1642484 21.4286924,18.4002216 21.4688472,18.7423548 L21.4750824,18.8523538 L21.4678171,18.9675593 C21.4246486,19.3025982 21.1922705,19.5388574 20.8555499,19.5795997 L20.7470425,19.5859353 L3.25,19.5859353 L3.14534744,19.5797049 C2.77265132,19.5350005 2.525,19.250082 2.525,18.8494841 C2.525,18.4512975 2.77030543,18.1646386 3.1443756,18.1193685 L3.25285992,18.113033 L4.35003719,18.1123023 L4.4,10.5767569 L4.40403631,10.3246942 C4.524824,6.55675169 7.34298069,3.38911146 11.0266305,2.90405757 L11.229889,2.87995432 L11.275,1.66770897 L11.2823355,1.55103724 C11.3211556,1.24947788 11.5116242,1.02739927 11.7956288,0.955808301 L11.897531,0.937079811 L12,0.930991914 Z M12,4.31312051 C8.70150639,4.31312051 5.97362451,6.99932148 5.85407645,10.3480678 L5.85000794,10.5758657 L5.849,18.0622956 L18.099,18.1123023 L18.15,10.5767635 L18.1459233,10.3480647 C18.0266869,7.00812062 15.3071214,4.31312051 12,4.31312051 Z" id="形状结合" fill="#FFFFFF" fill-rule="nonzero"></path>
</g> </g>
<circle id="Oval-1-Copy-2" fill="#F5222D" cx="18" cy="6" r="3"></circle>
</g> </g>
</g> </g>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,132 @@
<!--
filename: index.vue
author: liubin
date: 2024-04-02 09:49:36
description:
-->
<template>
<!-- 按钮切换 -->
<div v-if="buttonMode" class="button-nav">
<button
v-for="m in menus"
:key="m"
@click="currentMenu = m"
:data-text="m"
:class="[m === currentMenu ? 'active' : '']"
></button>
</div>
<!-- 标签切换 -->
<div v-else class="custom-tabs" style="height: 100%; width: 100%">
<el-tabs class="tag-nav" v-model="currentMenu" style="height: 100%">
<el-tab-pane
v-for="(m, idx) in menus"
:key="m"
:label="idx == 0 ? `\u2002${m}\u2002` : `\u3000${m}\u3000`"
:name="m"
>
<slot :name="`tab${idx + 1}`"></slot>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
export default {
name: "ButtonNav",
props: {
menus: {
type: Array,
required: true,
default: () => [],
validator: (val) => {
return val.length > 0;
},
},
buttonMode: {
type: Boolean,
default: true,
},
},
data() {
return {
currentMenu: "",
};
},
created() {
this.currentMenu = this.menus[0];
},
watch: {
currentMenu(val) {
this.$emit("change", val);
},
},
};
</script>
<style scoped lang="scss">
.button-nav {
width: 100%;
display: flex;
gap: 12px;
* {
user-select: none;
}
button {
cursor: pointer;
appearance: none;
outline: none;
border: none;
background: #fff;
border-radius: 8px;
padding: 15px;
color: #888;
letter-spacing: 2px;
flex: 1;
box-sizing: padding-box;
position: relative;
&::after {
content: attr(data-text);
position: absolute;
top: 5px;
left: 50%;
font-size: 16px;
font-weight: 500;
transform: translate(-50%);
}
&.active {
color: #111;
//border-bottom: 2px solid #0b58ff;
box-shadow: 0px 2px 1px 1px #0b58ff;
}
}
}
</style>
<style scoped>
.custom-tabs >>> .el-tabs__header {
margin-bottom: 8px;
display: inline-block;
/* transform: translateY(-12px); */
}
.custom-tabs >>> .el-tabs__item {
padding-left: 0px !important;
padding-right: 0px !important;
line-height: 36px !important;
height: 36px;
}
.custom-tabs >>> .el-tabs__content {
height: calc(100% - 42px);
}
.custom-tabs >>> .el-tab-pane {
box-sizing: border-box;
height: 100%;
padding: 20px;
border: 10px solid #f002;
}
</style>

View File

@ -0,0 +1,22 @@
<!--
* @Author: zwq
* @Date: 2024-09-12 14:55:26
* @LastEditors: zwq
* @LastEditTime: 2024-09-12 15:00:14
* @Description:
-->
<template>
<dict-tag
:type="DICT_TYPE.EQU_ALARM_LEVEL"
:value="injectData.alarmGrade" />
</template>
<script>
export default {
props: {
injectData: {
type: Object,
default: () => ({}),
},
},
};
</script>

View File

@ -34,6 +34,12 @@
import Navbar from './components/Navbar'; import Navbar from './components/Navbar';
import moment from 'moment'; import moment from 'moment';
import tableHeightMixin from '@/mixins/tableHeightMixin'; import tableHeightMixin from '@/mixins/tableHeightMixin';
import { listData } from '@/api/system/dict/data';
import alarmGrade from './alarmGrade.vue'
import {
getHomeAlarmList
} from '@/api/home';
export default { export default {
name: 'AbnormalWarning', name: 'AbnormalWarning',
mixins: [tableHeightMixin], mixins: [tableHeightMixin],
@ -45,25 +51,28 @@ export default {
type: 'input', type: 'input',
label: '报警来源', label: '报警来源',
placeholder: '报警来源', placeholder: '报警来源',
param: 'content', param: 'alarmSource',
}, },
{ {
type: 'select', type: 'datePicker',
label: '时间段', label: '时间段',
selectOptions: [], dateType: 'daterange',
labelField: 'name', format: 'yyyy-MM-dd',
valueField: 'id', valueFormat: 'timestamp',
param: 'typeId', rangeSeparator: '-',
filterable: true, startPlaceholder: '开始时间',
endPlaceholder: '结束时间',
param: 'alarmTime',
}, },
{ {
type: 'select', type: 'select',
label: '报警级别', label: '报警级别',
selectOptions: [], selectOptions: [],
labelField: 'name', param: 'alarmGrade',
valueField: 'id', defaultSelect: '',
param: 'typeId',
filterable: true, filterable: true,
labelField: 'label',
valueField: 'value',
}, },
{ {
type: 'button', type: 'button',
@ -75,60 +84,79 @@ export default {
heightNum: 280, heightNum: 280,
tableProps: [ tableProps: [
{ {
prop: 'createTime', prop: 'alarmTime',
label: '报警时间', label: '报警时间',
width: 180, width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'), filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
}, },
{ {
prop: 'productionLineName1', prop: 'alarmSource',
label: '报警来源', label: '报警来源',
showOverflowtooltip: true, showOverflowtooltip: true,
}, },
{ {
prop: 'productionLineName2', prop: 'alarmType',
label: '报警类型', label: '报警类型',
showOverflowtooltip: true, showOverflowtooltip: true,
}, },
{ {
prop: 'productionLineName3', prop: 'alarmGrade',
label: '报警级别', label: '报警级别',
showOverflowtooltip: true, showOverflowtooltip: true,
subcomponent: alarmGrade
}, },
{ {
prop: 'productionLineName4', prop: 'alarmReason',
label: '报警原因', label: '报警原因',
showOverflowtooltip: true, showOverflowtooltip: true,
}, },
{ {
prop: 'sectionName5', prop: 'alarmContent',
label: '报警详情', label: '报警详情',
showOverflowtooltip: true, showOverflowtooltip: true,
}, },
], ],
list: [ list: [],
{ productionLineName: 1 }, listQuery: {
{ productionLineName: 1 }, alarmSource: undefined,
{ productionLineName: 1 }, alarmTime: undefined,
{ productionLineName: 1 }, alarmGrade: undefined,
{ productionLineName: 1 }, }
{ productionLineName: 1 },
{ productionLineName: 1 },
{ productionLineName: 1 },
{ productionLineName: 1 },
{ productionLineName: 1 },
{ productionLineName: 1 },
{ productionLineName: 1 },
{ productionLineName: 1 },
{ productionLineName: 1 },
{ productionLineName: 1 },
{ productionLineName: 1 },
],
}; };
}, },
created() {}, created() {
const queryParams = {
pageNo: 1,
pageSize: 99,
dictType: 'equ_alarm_level',
};
listData(queryParams).then((response) => {
this.formConfig[2].selectOptions = response.data.list;
});
this.getDataList()
},
methods: { methods: {
buttonClick(val) {}, buttonClick(val) {
switch (val.btnName) {
case 'search':
this.listQuery.alarmSource = val.alarmSource;
this.listQuery.alarmGrade = val.alarmGrade;
this.listQuery.alarmTime = val.alarmTime ? val.alarmTime : null;
this.getDataList();
break;
default:
console.log(val);
}
},
getDataList(){
getHomeAlarmList(this.listQuery).then(response => {
if(response.hasOwnProperty('data')){
this.list = response.data;
}else{
this.list = []
}
});
},
toHome() { toHome() {
this.$router.push({ path: '/' }); this.$router.push({ path: '/' });
}, },

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,689 @@
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<SearchBar
:formConfigs="searchBarFormConfig"
ref="search-bar"
@headBtnClick="handleSearchBarBtnClick" />
<!-- 列表 -->
<base-table
:table-props="tableProps"
:page="queryParams.pageNo"
:limit="queryParams.pageSize"
:table-data="list"
@emitFun="handleEmitFun">
<method-btn
v-if="tableBtn.length"
slot="handleBtn"
: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="60%"
@confirm="submitForm">
<DialogForm
v-if="open"
key="index-dialog-form"
ref="form"
label-position="top"
size="small"
v-model="form"
:has-files="['files', 'files2']"
:rows="computedRows" />
</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: 'Equipment',
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: 'equipmentTypeName', label: '设备类型' },
{ prop: 'enName', label: '英文名称' },
{ prop: 'abbr', label: '缩写' },
// {
// action: 'show-detail',
// label: '',
// subcomponent: {
// props: ['injectData'],
// render: function (h) {
// const _this = this;
// return h(
// 'el-button',
// {
// props: { type: 'text', size: 'mini' },
// on: {
// click: function () {
// console.log('inejctdata', _this.injectData);
// _this.$emit('emitData', {
// action: _this.injectData.action,
// value: _this.injectData.id,
// });
// },
// },
// },
// ''
// );
// },
// },
// },
],
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' },
],
// bind: {
// disabled: this.editMode == 'detail', // some condition, like detail mode...
// }
},
{
input: true,
label: '设备编码',
prop: 'code',
url: '/base/core-equipment/getCode',
},
{
input: true,
label: '英文名称',
prop: 'enName',
},
],
[
{
input: true,
label: '缩写',
prop: 'abbr',
},
{
select: true,
label: '设备类型',
prop: 'equipmentTypeId',
url: '/base/core-equipment-type/page?pageNo=1&pageSize=100',
rules: [
{ required: true, message: '设备类型不能为空', trigger: 'blur' },
],
bind: {
filterable: true,
},
},
{
input: true,
label: '预计生产时间(min/天)',
prop: 'workTime',
rules: [
{
required: true,
message: '预计生产时间不能为空',
trigger: 'blur',
},
{
type: 'number',
message: '请输入正确的数字值',
trigger: 'blur',
transform: (val) => Number(val),
},
],
},
// {
// select: true,
// label: '',
// prop: 'groupId',
// url: '/base/core-equipment-group/page?pageNo=1&pageSize=100',
// },
],
[
{
datetime: true,
label: '生产日期',
prop: 'productionTime',
bind: {
format: 'yyyy-MM-dd',
clearable: true,
},
},
{
datetime: true,
label: '进厂日期',
prop: 'enterTime',
bind: {
format: 'yyyy-MM-dd',
clearable: true,
},
},
{
input: true,
prop: 'tvalue',
label: '设备TT值',
rules: [
{ required: true, message: '设备TT值不能为空', trigger: 'blur' },
{
type: 'number',
message: '请输入正确的数字值',
trigger: 'blur',
transform: (val) => Number(val),
},
],
},
],
[
{
input: true,
label: '单件产品加工时间(s)',
prop: 'processingTime',
rules: [
{
required: true,
message: '单件产品加工时间不能为空',
trigger: 'blur',
},
{
type: 'number',
message: '请输入正确的数字值',
trigger: 'blur',
transform: (val) => Number(val),
},
],
},
{
input: true,
label: '制造商',
prop: 'manufacturer',
},
{
input: true,
label: '规格描述',
prop: 'spec',
},
],
[
{
textarea: true,
label: '功能描述',
prop: 'description',
},
],
[
{
upload: true,
label: '设备资料',
prop: 'files',
},
],
[
{
upload: true,
label: '设备图片',
prop: 'files2',
fileType: 1,
},
],
[{ input: true, label: '备注', prop: 'remark' }],
// [
// {
// assetUpload: true,
// label: '',
// fieldName: 'assets',
// subcomponent: AssetsUpload
// },
// ],
// [
// {
// assetUpload: true,
// label: '',
// fieldName: 'images',
// subcomponent: AssetsUpload
// },
// ],
// [
// {
// upload: true,
// label: '',
// prop: 'uploadFiles',
// url: process.env.VUE_APP_BASE_API + '/admin-api/infra/file/upload', //
// uploadFnName: 'assetsUpload', //
// bind: {
// headers: { Authorization: 'Bearer ' + getAccessToken() },
// 'show-file-list': false,
// },
// },
// {
// diy: true,
// key: 'eq-assets',
// label: '',
// prop: 'fileNames',
// subcomponent: EquipmentAssets,
// },
// ],
// [
// {
// upload: true,
// label: '',
// prop: 'uploadImages',
// url: process.env.VUE_APP_BASE_API + '/admin-api/infra/file/upload', //
// uploadFnName: 'imagesUpload', //
// bind: {
// headers: { Authorization: 'Bearer ' + getAccessToken() },
// 'show-file-list': false,
// },
// },
// {
// diy: true,
// key: 'eq-pics',
// label: '',
// prop: 'fileUrls',
// subcomponent: EquipmentPics,
// pictures: async () => {
// // some async request
// return [];
// },
// },
// ],
// [
// {
// diy: true,
// key: 'eq-pics',
// label: '',
// prop: 'fileUrls',
// subcomponent: EquipmentPics,
// pictures: async () => {
// // some async request
// return [];
// },
// },
// ],
],
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, //
};
},
created() {
this.getList();
},
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;
},
},
methods: {
/** 查询列表 */
getList() {
this.loading = true;
//
getEquipmentPage(this.queryParams).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 = '添加设备';
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
this.showUploadComponents = true;
const id = row.id;
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({}, 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
.delConfirm(row.name)
.then(function () {
return deleteEquipment(id);
})
.then(() => {
this.getList();
this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
//
let params = { ...this.queryParams };
params.pageNo = undefined;
params.pageSize = undefined;
this.$modal
.confirm('是否确认导出所有设备数据项?')
.then(() => {
this.exportLoading = true;
return 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>

View File

@ -0,0 +1,370 @@
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<SearchBar
:formConfigs="searchBarFormConfig"
ref="search-bar"
@headBtnClick="handleSearchBarBtnClick" />
<!-- 列表 -->
<base-table
:table-props="tableProps"
:page="queryParams.pageNo"
:limit="queryParams.pageSize"
:table-data="list"
@emitFun="handleEmitFun">
<method-btn
v-if="tableBtn.length"
slot="handleBtn"
label="操作"
:width="100"
: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 moment from 'moment';
import basicPageMixin from '@/mixins/lb/basicPageMixin';
// import { getAccessToken } from '@/utils/auth';
export default {
name: 'EquipmentLineBind',
components: {},
mixins: [basicPageMixin],
data() {
return {
basePath: '/base/core-equipment-bind-section',
searchBarKeys: ['equipmentName', 'productionLineId'],
tableBtn: [
this.$auth.hasPermi('base:core-equipment-bind-section:update')
? {
type: 'edit',
btnName: '修改',
}
: undefined,
this.$auth.hasPermi('base:core-equipment-bind-section:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
tableProps: [
{
prop: 'createTime',
label: '添加时间',
fixed: true,
width: 150,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
},
{ prop: 'productionLineName', label: '产线名称' },
{ prop: 'workshopSectionName', label: '工段名称' },
{ prop: 'equipmentName', label: '设备名称' },
{ prop: 'sort', label: '工段中排序' },
{
prop: 'lineDataType',
label: '产线统计类型',
width:120,
filter: (val) =>
val != null ? ['无类型', '进片数量统计', '出片数量统计'][val] : '',
},
{
prop: 'sectionDataType',
label: '工段统计类型',
width:120,
filter: (val) =>
val != null ? ['无类型', '进片数量统计', '出片数量统计'][val] : '',
},
// { prop: 'remark', label: '' },
],
searchBarFormConfig: [
{
type: 'select',
label: '产线',
placeholder: '请选择产线',
param: 'productionLineId',
selectOptions: [],
filterable: true,
},
{
type: 'input',
label: '设备名',
placeholder: '请输入设备名称',
param: 'equipmentName',
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: this.$auth.hasPermi('base:core-equipment-bind-section: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: [
[
{
select: true,
label: '产线',
prop: 'productionLineId',
rules: [{ required: true, message: '产线名不能为空', trigger: 'blur' }],
url: '/base/core-production-line/listAll',
bind: { clearable: true, filterable: true },
// watch: 'workshopSectionId'
},
{
select: true,
label: '工段',
prop: 'workshopSectionId',
depends: 'productionLineId',
rules: [{ required: true, message: '工段不能为空', trigger: 'blur' }],
bind: { clearable: true, filterable: true },
url: '/base/core-workshop-section/listByParentId',
},
],
[
{
select: true,
label: '设备',
prop: 'equipmentId',
rules: [{ required: true, message: '设备名不能为空', trigger: 'blur' }],
bind: { clearable: true, filterable: true },
url: '/base/core-equipment/listAll',
},
{
input: true,
label: '工段排序',
prop: 'sort',
},
],
[
{
select: true,
options: [
{ label: '无类型', value: 0 },
{ label: '进片数量统计', value: 1 },
{ label: '出片数量统计', value: 2 },
],
label: '产线统计类型',
prop: 'lineDataType',
bind: {
clearable: true, filterable: true
},
rules: [{ required: true, message: '产线统计类型不能为空', trigger: 'change' }],
},
{
select: true,
options: [
{ label: '无类型', value: 0 },
{ label: '进片数量统计', value: 1 },
{ label: '出片数量统计', value: 2 },
],
label: '工段统计类型',
prop: 'sectionDataType',
bind: {
clearable: true, filterable: true
},
rules: [{ required: true, message: '工段统计类型不能为空', trigger: 'change' }],
},
],
],
//
open: false,
//
queryParams: {
pageNo: 1,
pageSize: 10,
equipmentName: null,
productionLineId: null,
},
//
form: {},
};
},
created() {
this.initSearchOptions();
this.getList();
},
methods: {
/** 初始化查询条件 */
async initSearchOptions() {
this.http('/base/core-production-line/listAll', 'get').then(
({ code, data }) => {
if (code == 0) {
this.searchBarFormConfig[0].selectOptions = data.map((item) => {
return {
name: item.name,
id: item.id,
};
});
}
}
);
},
/** 查询列表 */
getList() {
this.loading = true;
//
this.recv(this.queryParams).then(({ code, data }) => {
// if (code == 0) {
this.list = data.list;
this.total = data.total;
this.loading = false;
// }
});
// .catch(err => {
// this.list = [];
// this.total = 0;
// this.loading = false;
// })
},
/** 取消按钮 */
cancel() {
this.open = false;
this.reset();
},
/** 表单重置 */
reset() {
this.form = {
id: undefined,
productionLineId: undefined,
//
workshopSectionId: undefined,
//
equipmentId: undefined,
//
sort: undefined,
// 线
lineDataType: undefined,
//
sectionDataType: undefined,
};
this.resetForm('form');
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm');
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = '添加设备工段绑定';
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id;
this.info({ id }).then(({ code, data }) => {
this.form = 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(({ code, data }) => {
this.$modal.msgSuccess('修改成功');
this.open = false;
this.getList();
});
return;
}
this.post(this.form).then(({ code, data }) => {
this.$modal.msgSuccess('修改成功');
this.open = false;
this.getList();
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal
.delConfirm(row.equipmentName)
.then(function () {
return deleteEquipmentType(id);
})
.then(() => {
this.getList();
this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
//
let params = { ...this.queryParams };
params.pageNo = undefined;
params.pageSize = undefined;
this.$modal
.confirm('是否确认导出所有设备工段绑定?')
.then(() => {
this.exportLoading = true;
// return exportEquipmentTypeExcel(params);
})
.then((response) => {
this.$download.excel(response, '设备工段绑定.xls');
this.exportLoading = false;
})
.catch(() => {});
},
},
};
</script>

View File

@ -0,0 +1,312 @@
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<SearchBar
:formConfigs="searchBarFormConfig"
ref="search-bar"
@headBtnClick="handleSearchBarBtnClick" />
<!-- 列表 -->
<base-table
:table-props="tableProps"
:page="queryParams.pageNo"
:limit="queryParams.pageSize"
:table-data="list"
@emitFun="handleEmitFun">
<method-btn
v-if="tableBtn.length"
slot="handleBtn"
label="操作"
: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="true"
:rows="rows" />
</base-dialog>
</div>
</template>
<script>
import moment from 'moment';
import basicPageMixin from '@/mixins/lb/basicPageMixin';
import {
createEquipmentType,
updateEquipmentType,
deleteEquipmentType,
getEquipmentType,
getEquipmentTypePage,
exportEquipmentTypeExcel,
} from '@/api/base/equipmentType';
// import { getAccessToken } from '@/utils/auth';
export default {
name: 'EquipmentType',
components: {},
mixins: [basicPageMixin],
data() {
return {
searchBarKeys: ['name'],
tableBtn: [
this.$auth.hasPermi('base:core-equipment-type:update')
? {
type: 'edit',
btnName: '修改',
}
: undefined,
this.$auth.hasPermi('base:core-equipment-type:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
tableProps: [
{
prop: 'createTime',
label: '添加时间',
fixed: true,
width: 150,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
},
{ prop: 'name', label: '类型名称' },
{ prop: 'code', label: '类型编号', width: 210 },
{ prop: 'remark', label: '备注' },
],
searchBarFormConfig: [
{
type: 'input',
label: '设备类型',
placeholder: '设备类型',
param: 'name',
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: this.$auth.hasPermi('base:core-equipment-type: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' },
],
// bind: {
// disabled: true, // some condition, like detail mode...
// }
},
{
input: true,
label: '类型编号',
prop: 'code',
url: '/base/core-equipment-type/getCode',
rules: [
{ required: true, message: '类型编号不能为空', trigger: 'blur' },
],
},
],
[
{
select: true,
label: '父类',
prop: 'parentId',
url: '/base/core-equipment-type/page?pageNo=1&pageSize=100',
},
{},
],
[
{
upload: true,
label: '上传资料',
prop: 'files',
},
],
[{ input: true, label: '备注', prop: 'remark' }],
],
//
open: false,
//
queryParams: {
pageNo: 1,
pageSize: 10,
name: '',
},
//
form: {
code: undefined,
name: undefined,
id: undefined,
parentId: undefined,
remark: undefined,
},
};
},
watch: {
// form: {
// handler: function (val, oldVal) {
// console.log('[watch:form]', val, oldVal);
// },
// deep: true,
// },
},
created() {
this.getList();
},
methods: {
/** 查询列表 */
getList() {
this.loading = true;
//
getEquipmentTypePage(this.queryParams).then((response) => {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
/** 取消按钮 */
cancel() {
this.open = false;
this.reset();
},
/** 表单重置 */
reset() {
this.form = {
id: undefined,
code: undefined,
name: undefined,
parentId: undefined,
remark: undefined,
};
this.resetForm('form');
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm');
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = '添加设备类型';
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id;
getEquipmentType(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) {
updateEquipmentType(this.form).then((response) => {
this.$modal.msgSuccess('修改成功');
this.open = false;
this.getList();
});
return;
}
//
createEquipmentType(this.form).then((response) => {
this.$modal.msgSuccess('新增成功');
this.open = false;
this.getList();
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal
.delConfirm(row.name)
.then(function () {
return deleteEquipmentType(id);
})
.then(() => {
this.getList();
this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
//
let params = { ...this.queryParams };
params.pageNo = undefined;
params.pageSize = undefined;
this.$modal
.confirm('是否确认导出所有设备类型数据项?')
.then(() => {
this.exportLoading = true;
return exportEquipmentTypeExcel(params);
})
.then((response) => {
this.$download.excel(response, '设备类型.xls');
this.exportLoading = false;
})
.catch(() => {});
},
},
};
</script>

View File

@ -0,0 +1,163 @@
<!--
* @Author: zwq
* @Date: 2021-11-18 14:16:25
* @LastEditors: zwq
* @LastEditTime: 2024-09-25 10:24:33
* @Description:
-->
<template>
<el-form
:model="dataForm"
:rules="dataRule"
ref="dataForm"
@keyup.enter.native="dataFormSubmit()"
label-width="100px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="产线名称" prop="name">
<el-input
v-model="dataForm.name"
clearable
placeholder="请输入产线名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="产线编号" prop="code">
<el-input
v-model="dataForm.code"
clearable
placeholder="请输入产线编号" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="工厂名称" prop="factoryId">
<el-select
v-model="dataForm.factoryId"
filterable
placeholder="请选择工厂"
style="width: 100%">
<el-option
v-for="dict in factoryList"
:key="dict.id"
:label="dict.name"
:value="dict.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="归属部门" prop="deptId">
<treeselect
v-model="dataForm.deptId"
:options="deptOptions"
:show-count="true"
:clearable="false"
placeholder="请选择归属部门"
:normalizer="normalizer" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="产线TT值(h)" prop="tvalue">
<el-input
v-model.number="dataForm.tvalue"
type="number"
placeholder="TT值" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="描述信息" prop="description">
<el-input
v-model="dataForm.description"
placeholder="请输入描述信息" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="备注" prop="remark">
<el-input v-model="dataForm.remark" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
import basicAdd from '@/mixins/basic-add';
import {
createCorePL,
updateCorePL,
getCorePL,
getCode,
} from '@/api/base/coreProductionLine';
import { getFactoryList } from '@/api/core/base/factory';
import { listSimpleDepts } from '@/api/system/dept';
import Treeselect from '@riophae/vue-treeselect';
import '@riophae/vue-treeselect/dist/vue-treeselect.css';
export default {
mixins: [basicAdd],
components: { Treeselect },
data() {
return {
urlOptions: {
isGetCode: true,
codeURL: getCode,
createURL: createCorePL,
updateURL: updateCorePL,
infoURL: getCorePL,
},
//
deptOptions: undefined,
dataForm: {
id: undefined,
code: undefined,
name: undefined,
description: undefined,
tvalue: 0,
factoryId: undefined,
deptId: undefined,
remark: undefined,
},
factoryList: [],
dataRule: {
code: [
{ required: true, message: '产线编号不能为空', trigger: 'blur' },
],
name: [
{ required: true, message: '产线名称不能为空', trigger: 'blur' },
],
factoryId: [
{ required: true, message: '工厂不能为空', trigger: 'blur' },
],
},
};
},
mounted() {
this.getDict();
this.getTreeselect()
},
methods: {
async getDict() {
//
const factoryRes = await getFactoryList();
this.factoryList = factoryRes.data;
},
/** 查询部门下拉树结构 */
getTreeselect() {
listSimpleDepts().then((response) => {
// deptOptions
this.deptOptions = [];
this.deptOptions.push(...this.handleTree(response.data, 'id'));
});
},
//
normalizer(node) {
return {
id: node.id,
label: node.name,
children: node.children,
};
},
},
};
</script>

View File

@ -0,0 +1,204 @@
<template>
<div class="app-container">
<search-bar
:formConfigs="formConfig"
ref="searchBarForm"
@headBtnClick="buttonClick" />
<base-table
v-loading="dataListLoading"
:table-props="tableProps"
:page="listQuery.pageNo"
:limit="listQuery.pageSize"
:table-data="tableData">
<method-btn
v-if="tableBtn.length"
slot="handleBtn"
:width="120"
label="操作"
:method-list="tableBtn"
@clickBtn="handleClick" />
</base-table>
<pagination
:limit.sync="listQuery.pageSize"
:page.sync="listQuery.pageNo"
:total="listQuery.total"
@pagination="getDataList" />
<base-dialog
:dialogTitle="addOrEditTitle"
:dialogVisible="addOrUpdateVisible"
@cancel="handleCancel"
@confirm="handleConfirm"
:before-close="handleCancel"
width="50%">
<add-or-update
ref="addOrUpdate"
@refreshDataList="successSubmit"></add-or-update>
</base-dialog>
</div>
</template>
<script>
import AddOrUpdate from './add-or-updata';
import basicPage from '@/mixins/basic-page';
import { parseTime } from '@/mixins/code-filter';
import codeFilter from '@/mixins/code-filter';
import { getCorePLPage, deleteCorePL } from '@/api/base/coreProductionLine';
import { getStatus } from '@/api/core/base/productionLine';
const tableProps = [
{
prop: 'createTime',
label: '添加时间',
filter: parseTime,
width: 150,
},
{
prop: 'factoryName',
label: '工厂',
},
{
prop: 'departmentName',
label: '归属部门',
},
{
prop: 'name',
label: '产线名称',
},
{
prop: 'code',
label: '产线编码',
width: 150,
},
{
prop: 'enabled',
label: '当前状态',
filter: codeFilter('lineStatus'),
},
{
prop: 'tvalue',
label: '产线TT值(h)',
width: 100,
},
{
prop: 'description',
label: '描述',
},
{
prop: 'remark',
label: '备注',
},
];
export default {
mixins: [basicPage],
data() {
return {
urlOptions: {
getDataListURL: getCorePLPage,
deleteURL: deleteCorePL,
},
tableProps,
tableBtn: [
this.$auth.hasPermi(`base:core-production-line:update`)
? {
type: 'edit',
btnName: '编辑',
}
: undefined,
this.$auth.hasPermi(`base:core-production-line:delete`)
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
tableData: [],
formConfig: [
{
type: 'input',
label: '产线名称',
placeholder: '产线名称',
param: 'name',
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: this.$auth.hasPermi('base:core-production-line:create')
? 'button'
: '',
btnName: '新增',
name: 'add',
color: 'success',
plain: true,
},
],
};
},
components: {
AddOrUpdate,
},
created() {},
methods: {
//
getDataList() {
this.dataListLoading = true;
this.urlOptions.getDataListURL(this.listQuery).then((response) => {
// this.tableData = response.data.list;
this.getStatus(response.data.list);
this.listQuery.total = response.data.total;
this.dataListLoading = false;
});
},
getStatus(list) {
const ids = list.map((i) => {
return i.id;
});
console.log('111', ids);
getStatus(ids).then((response) => {
response.forEach((a) => {
list.forEach((b) => {
if (b.id === a.id) b.enabled = a.status;
});
});
this.tableData = list;
});
},
buttonClick(val) {
switch (val.btnName) {
case 'search':
this.listQuery.pageNo = 1;
this.listQuery.pageSize = 10;
this.listQuery.name = val.name ? val.name : undefined;
this.getDataList();
break;
case 'reset':
this.$refs.searchBarForm.resetForm();
this.listQuery = {
pageSize: 10,
pageNo: 1,
total: 1,
};
this.getDataList();
break;
case 'add':
this.addOrEditTitle = '新增';
this.addOrUpdateVisible = true;
this.addOrUpdateHandle();
break;
case 'export':
this.handleExport();
break;
default:
console.log(val);
}
},
},
};
</script>

View File

@ -0,0 +1,105 @@
<!--
* @Author: zwq
* @Date: 2021-11-18 14:16:25
* @LastEditors: zwq
* @LastEditTime: 2024-09-24 14:49:25
* @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" clearable placeholder="请输入工段名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="工段编号" prop="code">
<el-input v-model="dataForm.code" clearable placeholder="请输入工段编号" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="产线" prop="productionLineId">
<el-select
v-model="dataForm.productionLineId"
filterable
placeholder="请选择产线">
<el-option
v-for="dict in proLineList"
:key="dict.id"
:label="dict.name"
:value="dict.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="排序" prop="sort">
<el-input-number
v-model="dataForm.sort"
controls-position="right"
placeholder="排序"
style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="备注" prop="remark">
<el-input
v-model="dataForm.remark"
placeholder="请输入备注" />
</el-form-item>
</el-form>
</template>
<script>
import basicAdd from '@/mixins/basic-add';
import { createCWSection, updateCWSection, getCWSection, getCode } from "@/api/base/coreWorkshopSection";
import { getCorePLList } from '@/api/base/coreProductionLine';
export default {
mixins: [basicAdd],
data() {
return {
urlOptions: {
isGetCode: true,
codeURL: getCode,
createURL: createCWSection,
updateURL: updateCWSection,
infoURL: getCWSection
},
dataForm: {
id: undefined,
code: undefined,
name: undefined,
description: undefined,
sort: 0,
productionLineId: undefined,
remark: undefined,
},
proLineList: [],
dataRule: {
code: [{ required: true, message: "工段编号不能为空", trigger: "blur" }],
name: [{ required: true, message: "工段名称不能为空", trigger: "blur" }],
productionLineId: [{ required: true, message: "产线不能为空", trigger: "blur" }],
sort: [{ required: true, message: "排序不能为空", trigger: "blur" }]
}
};
},
mounted() {
this.getDict()
},
methods: {
async getDict() {
// 线
const res = await getCorePLList();
this.proLineList = res.data;
},
}
};
</script>

View File

@ -0,0 +1,165 @@
<template>
<div class="app-container">
<search-bar
:formConfigs="formConfig"
ref="searchBarForm"
@headBtnClick="buttonClick" />
<base-table
v-loading="dataListLoading"
:table-props="tableProps"
:page="listQuery.pageNo"
:limit="listQuery.pageSize"
:table-data="tableData">
<method-btn
v-if="tableBtn.length"
slot="handleBtn"
:width="120"
label="操作"
:method-list="tableBtn"
@clickBtn="handleClick" />
</base-table>
<pagination
:limit.sync="listQuery.pageSize"
:page.sync="listQuery.pageNo"
:total="listQuery.total"
@pagination="getDataList" />
<base-dialog
:dialogTitle="addOrEditTitle"
:dialogVisible="addOrUpdateVisible"
@cancel="handleCancel"
@confirm="handleConfirm"
:before-close="handleCancel"
width="40%">
<add-or-update
ref="addOrUpdate"
@refreshDataList="successSubmit"></add-or-update>
</base-dialog>
</div>
</template>
<script>
import AddOrUpdate from './add-or-updata';
import basicPage from '@/mixins/basic-page';
import { parseTime } from '@/mixins/code-filter';
import {
getCWSectionPage,
deleteCWSection
} from '@/api/base/coreWorkshopSection';
const tableProps = [
{
prop: 'createTime',
label: '添加时间',
filter: parseTime,
width:150
},
{
prop: 'code',
label: '工段编码',
width:150
},
{
prop: 'name',
label: '工段名称'
},
{
prop: 'productionLineName',
label: '产线名'
},
{
prop: 'sort',
label: '排序'
},
{
prop: 'remark',
label: '备注'
},
];
export default {
mixins: [basicPage],
data() {
return {
urlOptions: {
getDataListURL: getCWSectionPage,
deleteURL: deleteCWSection
},
tableProps,
tableBtn: [
this.$auth.hasPermi(`base:core-workshop-section:update`)
? {
type: 'edit',
btnName: '编辑',
}
: undefined,
this.$auth.hasPermi(`base:core-workshop-section:delete`)
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v)=>v),
tableData: [],
formConfig: [
{
type: 'input',
label: '工段名称',
placeholder: '工段名称',
param: 'name'
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: this.$auth.hasPermi('base:core-workshop-section:create') ? 'button' : '',
btnName: '新增',
name: 'add',
color: 'success',
plain: true
},
],
};
},
components: {
AddOrUpdate,
},
created() {},
methods: {
buttonClick(val) {
switch (val.btnName) {
case 'search':
this.listQuery.pageNo = 1;
this.listQuery.pageSize = 10;
this.listQuery.name = val.name ? val.name : undefined;
this.getDataList();
break;
case 'reset':
this.$refs.searchBarForm.resetForm();
this.listQuery = {
pageSize: 10,
pageNo: 1,
total: 1,
};
this.getDataList();
break;
case 'add':
this.addOrEditTitle = '新增';
this.addOrUpdateVisible = true;
this.addOrUpdateHandle();
break;
case 'export':
this.handleExport();
break;
default:
console.log(val);
}
},
},
};
</script>

View File

@ -0,0 +1,90 @@
<!--
* @Author: zwq
* @Date: 2021-11-18 14:16:25
* @LastEditors: DY
* @LastEditTime: 2023-11-03 16:32:52
* @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"
clearable
placeholder="请输入工厂名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="工厂编码" prop="code">
<el-input
v-model="dataForm.code"
clearable
placeholder="请输入工厂编码" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="地址" prop="address">
<el-input v-model="dataForm.address" clearable placeholder="请输入地址" />
</el-form-item>
</el-col>
<!-- <el-form-item label="启用状态" prop="enabled">
<el-select
v-model="dataForm.enabled"
placeholder="请选择启用状态">
<el-option
v-for="dict in this.getDictDatas(DICT_TYPE.INFRA_BOOLEAN_STRING)"
:key="dict.value"
:label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item> -->
<el-col :span="12">
<el-form-item label="备注" prop="remark">
<el-input v-model="dataForm.remark" clearable placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
import basicAdd from '@/mixins/basic-add';
import { createFactory, updateFactory, getFactory, getCode } from "@/api/core/base/factory";
export default {
mixins: [basicAdd],
data() {
return {
urlOptions: {
isGetCode: true,
codeURL: getCode,
createURL: createFactory,
updateURL: updateFactory,
infoURL: getFactory,
},
dataForm: {
id: undefined,
code: undefined,
name: undefined,
address: undefined,
remark: undefined,
},
dataRule: {
code: [{ required: true, message: "工厂编码不能为空", trigger: "blur" }],
name: [{ required: true, message: "工厂名称不能为空", trigger: "blur" }],
}
};
},
methods: {
},
};
</script>

View File

@ -0,0 +1,184 @@
<template>
<div class="app-container">
<search-bar
:formConfigs="formConfig"
ref="searchBarForm"
@headBtnClick="buttonClick" />
<base-table
v-loading="dataListLoading"
:table-props="tableProps"
:page="listQuery.pageNo"
:limit="listQuery.pageSize"
:table-data="tableData">
<method-btn
v-if="tableBtn.length"
slot="handleBtn"
:width="120"
label="操作"
:method-list="tableBtn"
@clickBtn="handleClick" />
</base-table>
<pagination
:limit.sync="listQuery.pageSize"
:page.sync="listQuery.pageNo"
:total="listQuery.total"
@pagination="getDataList" />
<base-dialog
:dialogTitle="addOrEditTitle"
:dialogVisible="addOrUpdateVisible"
@cancel="handleCancel"
@confirm="handleConfirm"
:before-close="handleCancel"
width="50%">
<add-or-update
ref="addOrUpdate"
@refreshDataList="successSubmit"></add-or-update>
</base-dialog>
</div>
</template>
<script>
import AddOrUpdate from './add-or-updata';
import basicPage from '@/mixins/basic-page';
import { parseTime } from '@/mixins/code-filter';
import {
deleteFactory,
getFactoryPage
} from '@/api/core/base/factory';
const tableProps = [
{
prop: 'createTime',
label: '添加时间',
filter: parseTime
},
{
prop: 'name',
label: '工厂名称'
},
{
prop: 'code',
label: '工厂编码'
},
{
prop: 'address',
label: '地址'
},
{
prop: 'remark',
label: '备注'
}
];
export default {
mixins: [basicPage],
data() {
return {
urlOptions: {
getDataListURL: getFactoryPage,
deleteURL: deleteFactory,
// exportURL: exportFactoryExcel,
},
tableProps,
tableBtn: [
this.$auth.hasPermi(`base:core-factory:update`)
? {
type: 'edit',
btnName: '编辑',
}
: undefined,
this.$auth.hasPermi(`base:core-factory:delete`)
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v)=>v),
tableData: [],
formConfig: [
{
type: 'input',
label: '工厂名称',
placeholder: '工厂名称',
param: 'name',
},
{
type: 'input',
label: '工厂编码',
placeholder: '工厂编码',
param: 'code',
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
// {
// type: 'separate',
// },
// {
// type: 'button',
// btnName: '',
// name: 'reset',
// },
{
type: 'separate',
},
{
type: this.$auth.hasPermi('base:core-factory:create') ? 'button' : '',
btnName: '新增',
name: 'add',
color: 'success',
plain: true,
},
// {
// type: this.$auth.hasPermi('base:factory:create') ? 'separate' : '',
// },
// {
// type: this.$auth.hasPermi('base:factory:export') ? 'button' : '',
// btnName: '',
// name: 'export',
// color: 'warning',
// },
],
};
},
components: {
AddOrUpdate,
},
created() {},
methods: {
buttonClick(val) {
switch (val.btnName) {
case 'search':
this.listQuery.pageNo = 1;
this.listQuery.pageSize = 10;
this.listQuery.name = val.name;
this.listQuery.code = val.code;
this.getDataList();
break;
case 'reset':
this.$refs.searchBarForm.resetForm();
this.listQuery = {
pageSize: 10,
pageNo: 1,
total: 1,
};
this.getDataList();
break;
case 'add':
this.addOrEditTitle = '新增';
this.addOrUpdateVisible = true;
this.addOrUpdateHandle();
break;
case 'export':
this.handleExport();
break;
default:
console.log(val);
}
},
},
};
</script>

View File

@ -241,7 +241,9 @@ export default {
}, },
/** 删除按钮操作 */ /** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
this.$modal.confirm('是否确认删除监控对象为"' + row.objName + '"的数据项?').then(function() { this.$modal
.delConfirm(row.objName)
.then(function() {
return deleteEnergyLimit(row.id); return deleteEnergyLimit(row.id);
}).then(() => { }).then(() => {
this.queryParams.pageNo = 1; this.queryParams.pageNo = 1;

View File

@ -63,7 +63,7 @@ const tableProps = [
label: '对象编码' label: '对象编码'
}, },
{ {
prop: 'plcTableName', prop: 'plcTableName',
label: '关联表名' label: '关联表名'
}, },
{ {
@ -230,7 +230,9 @@ export default {
}, },
/** 删除按钮操作 */ /** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
this.$modal.confirm('是否确认删除对象为"' + row.objName + '"的数据项?').then(function() { this.$modal
.delConfirm(row.objName)
.then(function() {
return deleteEnergyPlcConnect(row.id); return deleteEnergyPlcConnect(row.id);
}).then(() => { }).then(() => {
this.queryParams.pageNo = 1; this.queryParams.pageNo = 1;

View File

@ -63,7 +63,7 @@ const tableProps = [
showOverflowtooltip: true showOverflowtooltip: true
}, },
{ {
prop: 'type', prop: 'type',
label: '统计类型', label: '统计类型',
filter: publicFormatter('statistic_type') filter: publicFormatter('statistic_type')
}, },
@ -224,7 +224,9 @@ export default {
}, },
/** 删除按钮操作 */ /** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
this.$modal.confirm('是否确认删除方案名称为"' + row.name + '"的数据项?').then(function() { this.$modal
.delConfirm(row.name)
.then(function() {
return deleteEnergyStatistics(row.id); return deleteEnergyStatistics(row.id);
}).then(() => { }).then(() => {
this.queryParams.pageNo = 1; this.queryParams.pageNo = 1;

View File

@ -205,7 +205,9 @@ export default {
}, },
/** 删除按钮操作 */ /** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
this.$modal.confirm('是否确认删除能源类型为"' + row.name + '"的数据项?').then(function() { this.$modal
.delConfirm(row.name)
.then(function() {
return deleteEnergyType(row.id); return deleteEnergyType(row.id);
}).then(() => { }).then(() => {
this.queryParams.pageNo = 1; this.queryParams.pageNo = 1;

View File

@ -2,14 +2,17 @@
<div class="app-container contrastAnalysisBox" id="contrastAnalysisBox"> <div class="app-container contrastAnalysisBox" id="contrastAnalysisBox">
<!-- 搜索工作栏 --> <!-- 搜索工作栏 -->
<search-area :isFold="isFold" @submit="getList"/> <search-area :isFold="isFold" @submit="getList"/>
<el-tabs v-model="activeName" @tab-click="switchChart" v-show='chartData.length'> <div v-show="chartData.length">
<el-tab-pane label="柱状图" name="bar"> <bar-chart
<bar-chart ref="analysisBarChart" :chartData="chartData" :timeDim="timeDim" /> ref="analysisBarChart"
</el-tab-pane> :chartData="chartData"
<el-tab-pane label="折线图" name="line"> :timeDim="timeDim" />
<line-chart ref="analysisLineChart" :chartData="chartData" :timeDim="timeDim"/> <base-table
</el-tab-pane> :table-props="tableProps"
</el-tabs> :table-data="list"
:max-height="tableH"
class="contrast-out-table" />
</div>
<!-- 没有数据 --> <!-- 没有数据 -->
<div class="no-data-bg" v-show='!chartData.length'></div> <div class="no-data-bg" v-show='!chartData.length'></div>
</div> </div>
@ -18,50 +21,96 @@
import { getCompare } from "@/api/analysis/energyAnalysis" import { getCompare } from "@/api/analysis/energyAnalysis"
import SearchArea from "./components/searchArea" import SearchArea from "./components/searchArea"
import BarChart from "./components/barChart" import BarChart from "./components/barChart"
import LineChart from "./components/lineChart" import tableHeightMixin from '@/mixins/tableHeightMixin';
import FileSaver from 'file-saver';
import * as XLSX from 'xlsx/xlsx.mjs';
// import moment from 'moment' // import moment from 'moment'
export default { export default {
name: 'ContrastAnalysis', name: 'ContrastAnalysis',
components: { SearchArea, BarChart, LineChart }, components: { SearchArea, BarChart },
mixins: [tableHeightMixin],
data() { data() {
return { return {
isFold: false, isFold: false,
activeName: 'bar', chartData: [],
chartData: [], timeDim: '',
timeDim: '' tableProps: [],
list: [],
tableH: this.tableHeight(250) / 2,
} }
}, },
mounted() { mounted() {
window.addEventListener('resize', () => { window.addEventListener('resize', () => {
this.tableH = this.tableHeight(260) this.tableH = this.tableHeight(260)
this.isFold = this.searchBarWidth('contrastAnalysisBox', 1437) this.isFold = this.searchBarWidth('contrastAnalysisBox', 1310)
// console.log(document.getElementById("contrastAnalysisBox").offsetWidth) // console.log(document.getElementById("contrastAnalysisBox").offsetWidth)
}) })
this.isFold = this.searchBarWidth('contrastAnalysisBox', 1437) this.isFold = this.searchBarWidth('contrastAnalysisBox', 1310)
}, },
methods: { methods: {
_setTableHeight() {
this.tableH = this.tableHeight(250) / 2;
},
getList(params) { getList(params) {
this.timeDim = params.timeDim this.timeDim = params.timeDim
getCompare({ ...params }).then((res) => { getCompare({ ...params }).then((res) => {
console.log(res) if (res.code === 0) {
if (res.code === 0) { this.getTableList(res.data || []);
this.chartData = res.data || [] this.chartData = res.data || [];
} else { } else {
this.chartData = [] this.chartData = []
} }
}) })
}, },
switchChart() { getTableList(arr) {
if (this.activeName === 'bar') { this.tableProps = [];
this.$nextTick((res) => { this.list = [];
this.$refs.analysisBarChart.getChart() let tempX = [];
}) let timeArr = arr[0].trendRespVOList || [];
} else { this.list = timeArr.map((item) => {
this.$nextTick((res) => { return { time: item.time };
this.$refs.analysisLineChart.getChart() });
}) for (let i = 0; i < arr.length; i++) {
} let obj = {};
} obj.prop = arr[i].objId;
obj.label = arr[i].objName;
obj.minWidth = 100;
tempX.push(obj);
let tiemList = arr[i].trendRespVOList;
for (let j = 0; j < tiemList.length; j++) {
this.list[j][arr[i].objId] = tiemList[j].useNum
? tiemList[j].useNum.toFixed(2)
: null;
}
}
this.tableProps = [{ prop: 'time', label: '时间' }].concat(tempX);
},
//
exportExl() {
if (this.list.length > 0) {
var wb = XLSX.utils.table_to_book(
document.querySelector('.contrast-out-table')
);
let fileName = '对比分析.xlsx';
var wbout = XLSX.write(wb, {
bookType: 'xlsx',
bookSST: true,
type: 'array',
});
try {
FileSaver.saveAs(
new Blob([wbout], { type: 'application/octet-stream' }),
fileName
);
this.$message.success('导出成功');
} catch (e) {
if (typeof console !== 'undefined') console.log(e, wbout);
}
return wbout;
} else {
this.$modal.msgWarning('暂无数据导出');
}
},
} }
} }
</script> </script>
@ -93,4 +142,4 @@ export default {
color: rgba(0, 0, 0, 0.45); color: rgba(0, 0, 0, 0.45);
} }
} }
</style> </style>

View File

@ -0,0 +1,74 @@
<!--
* @Author: zwq
* @Date: 2024-09-23 14:35:30
* @LastEditors: zwq
* @LastEditTime: 2024-09-23 14:48:08
* @Description:
-->
<template>
<div>
<div style="background: #f2f4f9; height: 40px; width: 100%">
<ButtonNav
:menus="['走势分析', '对比分析', '同比分析', '环比分析']"
@change="currentMenu">
<template v-slot:tab1>
<div>走势分析</div>
</template>
<template v-slot:tab2>
<div>对比分析</div>
</template>
<template v-slot:tab3>
<div>同比分析</div>
</template>
<template v-slot:tab4>
<div>环比分析</div>
</template>
</ButtonNav>
</div>
<div class="app-container">
<div v-if="activeName === '走势分析'">
<trendAnalysis />
</div>
<div v-else-if="activeName === '对比分析'">
<contrastAnalysis />
</div>
<div v-else-if="activeName === '同比分析'">
<yoyAnalysis />
</div>
<div v-else-if="activeName === '环比分析'">
<qoqAnalysis />
</div>
</div>
</div>
</template>
<script>
import ButtonNav from '@/components/ButtonNav';
import trendAnalysis from './trendAnalysis';
import contrastAnalysis from './contrastAnalysis';
import yoyAnalysis from './yoyAnalysis';
import qoqAnalysis from './qoqAnalysis';
export default {
name: '',
data() {
return {
activeName: '走势分析',
};
},
components: {
ButtonNav,
trendAnalysis,
contrastAnalysis,
yoyAnalysis,
qoqAnalysis,
},
created() {},
methods: {
currentMenu(val) {
this.activeName = val;
},
},
};
</script>
<style lang="scss"></style>

View File

@ -1,456 +1,489 @@
<template> <template>
<div class="searchBarBox divHeight" ref="searchBarRef" :style="{ paddingRight: isFold ? '55px' : '0px' }"> <div
<el-form :inline="true" class="demo-form-inline"> class="searchBarBox divHeight"
<span class="blue-block"></span> ref="searchBarRef"
<el-form-item label="能源类型" required> :style="{ paddingRight: isFold ? '55px' : '0px' }">
<el-select v-model="queryParams.energyTypeId" placeholder="请选择" style="width: 100px;" size="small"> <el-form :inline="true" class="demo-form-inline">
<el-option <span class="blue-block"></span>
v-for="item in energyTypeList" <el-form-item label="能源类型" required>
:key="item.id" <el-select
:label="item.name" v-model="queryParams.energyTypeId"
:value="item.id"> placeholder="请选择"
</el-option> style="width: 100px"
</el-select> size="small">
</el-form-item> <el-option
<el-form-item label="对象选择" required> v-for="item in energyTypeList"
<el-cascader :key="item.id"
v-model="objArr" :label="item.name"
:options="objList" :value="item.id"></el-option>
:props="{ checkStrictly: true, value: 'id', label: 'name' }" </el-select>
popper-class="cascaderParent" </el-form-item>
size="small" <el-form-item label="对象选择" required>
clearable></el-cascader> <el-cascader
</el-form-item> v-model="objArr"
<el-form-item label="时间维度" required> :options="objList"
<el-select v-model="queryParams.timeDim" placeholder="请选择" style="width: 80px;" size="small"> :props="{ checkStrictly: true, value: 'id', label: 'name' }"
<el-option popper-class="cascaderParent"
v-for="item in getDictDatas(this.DICT_TYPE.TIME_DIM)" size="small"
:key="item.value" clearable></el-cascader>
:label="item.label" </el-form-item>
:value="item.value" <el-form-item label="时间维度" required>
size="small"> <el-select
</el-option> v-model="queryParams.timeDim"
</el-select> placeholder="请选择"
</el-form-item> style="width: 80px"
<el-form-item label="时间范围" required> size="small">
<div v-show="queryParams.timeDim === '1'"> <el-option
<el-date-picker v-for="item in getDictDatas(this.DICT_TYPE.TIME_DIM)"
v-model="timeValue" :key="item.value"
type="datetimerange" :label="item.label"
range-separator="至" :value="item.value"
start-placeholder="开始日期" size="small"></el-option>
end-placeholder="结束日期" </el-select>
format="yyyy-MM-dd HH:mm" </el-form-item>
value-format="timestamp" <el-form-item label="时间范围" required>
:picker-options="pickerOptions" <div v-show="queryParams.timeDim === '1'">
popper-class="noneMinute" <el-date-picker
@change="timeSelect" v-model="timeValue"
size="small" type="datetimerange"
style='width:350px;' range-separator="至"
> start-placeholder="开始日期"
</el-date-picker> end-placeholder="结束日期"
</div> format="yyyy-MM-dd HH:mm"
<div v-show="queryParams.timeDim === '2'"> value-format="timestamp"
<el-date-picker :picker-options="pickerOptions"
v-model="dateValue" popper-class="noneMinute"
type="daterange" @change="timeSelect"
range-separator="至" size="small"
start-placeholder="开始日期" style="width: 350px"></el-date-picker>
end-placeholder="结束日期" </div>
value-format="timestamp" <div v-show="queryParams.timeDim === '2'">
:picker-options="pickerOptions" <el-date-picker
@change="timeSelect" v-model="dateValue"
size="small" type="daterange"
style='width:350px;' range-separator="至"
> start-placeholder="开始日期"
</el-date-picker> end-placeholder="结束日期"
</div> value-format="timestamp"
<div v-show="queryParams.timeDim === '3'"> :picker-options="pickerOptions"
<el-date-picker @change="timeSelect"
v-model="weekValue1" size="small"
type="week" style="width: 350px"></el-date-picker>
format="yyyy 第 WW 周" </div>
style='width:170px;' <div v-show="queryParams.timeDim === '3'">
:picker-options="pickerOptionsWeek" <el-date-picker
@change="startWeek" v-model="weekValue1"
size="small" type="week"
placeholder="选择周"> format="yyyy 第 WW 周"
</el-date-picker>- style="width: 170px"
<el-date-picker :picker-options="pickerOptionsWeek"
v-model="weekValue2" @change="startWeek"
type="week" size="small"
format="yyyy 第 WW 周" placeholder="选择周"></el-date-picker>
:picker-options="pickerOptionsWeek" -
style='width:170px;' <el-date-picker
@change="endWeek" v-model="weekValue2"
size="small" type="week"
placeholder="选择周"> format="yyyy 第 WW 周"
</el-date-picker> :picker-options="pickerOptionsWeek"
</div> style="width: 170px"
<div v-show="queryParams.timeDim === '4'"> @change="endWeek"
<el-date-picker size="small"
v-model="monthValue" placeholder="选择周"></el-date-picker>
type="monthrange" </div>
range-separator="至" <div v-show="queryParams.timeDim === '4'">
start-placeholder="开始日期" <el-date-picker
end-placeholder="结束日期" v-model="monthValue"
value-format="timestamp" type="monthrange"
:picker-options="pickerOptions" range-separator="至"
size="small" start-placeholder="开始日期"
style='width:350px;' end-placeholder="结束日期"
@change="timeSelect" value-format="timestamp"
> :picker-options="pickerOptions"
</el-date-picker> size="small"
</div> style="width: 350px"
<div v-show="queryParams.timeDim === '5'"> @change="timeSelect"></el-date-picker>
<el-date-picker </div>
style='width:170px;' <div v-show="queryParams.timeDim === '5'">
v-model="yearValue1" <el-date-picker
type="year" style="width: 170px"
:picker-options="pickerOptions" v-model="yearValue1"
value-format="timestamp" type="year"
placeholder="选择年" :picker-options="pickerOptions"
size="small" value-format="timestamp"
@change="startYear" placeholder="选择年"
> size="small"
</el-date-picker>- @change="startYear"></el-date-picker>
<el-date-picker -
style='width:170px;' <el-date-picker
v-model="yearValue2" style="width: 170px"
type="year" v-model="yearValue2"
:picker-options="pickerOptions" type="year"
value-format="timestamp" :picker-options="pickerOptions"
placeholder="选择年" value-format="timestamp"
size="small" placeholder="选择年"
@change="endYear" size="small"
> @change="endYear"></el-date-picker>
</el-date-picker> </div>
</div> </el-form-item>
</el-form-item> <el-form-item>
<el-form-item> <el-button type="primary" size="small" @click="search">查询</el-button>
<el-button type="primary" size="small" @click="search">查询</el-button> <span class="separateStyle"></span>
<span class="separateStyle"></span> <el-button size="small" @click="resetBtn">重置</el-button>
<el-button size="small" @click="resetBtn">重置</el-button> <span class="separateStyle"></span>
</el-form-item> <el-button type="primary" size="small" @click="exportData" plain>
</el-form> 导出
<span v-if="isFold" class="foldClass" @click='switchMode'> </el-button>
{{ isExpand ? '收起' : '展开' }} </el-form-item>
<svg-icon :icon-class="isExpand ? 'upward' : 'downward'" /> </el-form>
</span> <span v-if="isFold" class="foldClass" @click="switchMode">
</div> {{ isExpand ? '收起' : '展开' }}
<svg-icon :icon-class="isExpand ? 'upward' : 'downward'" />
</span>
</div>
</template> </template>
<script> <script>
import { getEnergyTypeListAll } from "@/api/base/energyType" import { getEnergyTypeListAll } from '@/api/base/energyType';
import { getTree } from '@/api/base/factory' import { getTree } from '@/api/base/factory';
import moment from 'moment' import moment from 'moment';
export default { export default {
name: 'searchArea', name: 'searchArea',
props: { props: {
isFold: {// isFold: {
type: Boolean, //
default: false type: Boolean,
} default: false,
}, },
data() { },
return { data() {
isExpand: false, // return {
// isExpand: false, //
queryParams: { //
energyTypeId: null, queryParams: {
objId: null, energyTypeId: null,
timeDim: null, objId: null,
startTime: null, timeDim: null,
endTime: null startTime: null,
}, endTime: null,
objArr: [], },
timeValue: [],// 7 objArr: [],
dateValue: [],// 30 timeValue: [], // 7
weekValue1: null,//24 dateValue: [], // 30
weekValue2: null, weekValue1: null, //24
monthValue: [],//24 weekValue2: null,
yearValue1: null,//10 monthValue: [], //24
yearValue2: null, yearValue1: null, //10
energyTypeList: [], yearValue2: null,
objList: [], energyTypeList: [],
pickerOptions: { objList: [],
disabledDate(date) { pickerOptions: {
return date.getTime() > Date.now() disabledDate(date) {
} return date.getTime() > Date.now();
}, },
pickerOptionsWeek: { },
disabledDate(time) { pickerOptionsWeek: {
let day = Date.now() disabledDate(time) {
let limitTime = moment(day).day(-1) let day = Date.now();
return time.getTime() > new Date(limitTime).getTime() let limitTime = moment(day).day(-1);
} return time.getTime() > new Date(limitTime).getTime();
} },
} },
}, };
mounted() { },
this.getTypeList() mounted() {
this.getObjTree() this.getTypeList();
this.queryParams.timeDim = this.getDictDatas(this.DICT_TYPE.TIME_DIM)[0].value // this.getObjTree();
this.timeValue = [moment().startOf('day'), moment().endOf('day')-59*61*1000] this.queryParams.timeDim = this.getDictDatas(
}, this.DICT_TYPE.TIME_DIM
methods: { )[0].value; //
getTypeList() { this.timeValue = [
getEnergyTypeListAll().then((res) => { moment().startOf('day'),
this.energyTypeList = res.data || [] moment().endOf('day') - 59 * 61 * 1000,
}) ];
}, },
getObjTree() { methods: {
getTree().then(res => { getTypeList() {
this.objList = res.data || [] getEnergyTypeListAll().then((res) => {
}) this.energyTypeList = res.data || [];
}, });
// },
timeSelect() { getObjTree() {
switch (this.queryParams.timeDim) { getTree().then((res) => {
case '1': this.objList = res.data || [];
if (this.timeValue[1] - this.timeValue[0] > 7*24*3600000) { });
this.$modal.msgError('最大时间范围为7天请重新选择') },
this.timeValue = [] //
} timeSelect() {
break switch (this.queryParams.timeDim) {
case '2': case '1':
if (this.dateValue[1] - this.dateValue[0] > 29*24*3600000) { if (this.timeValue[1] - this.timeValue[0] > 7 * 24 * 3600000) {
this.$modal.msgError('最大时间范围为30天请重新选择') // 0:00:0023:59:59 this.$modal.msgError('最大时间范围为7天请重新选择');
this.dateValue = [] this.timeValue = [];
} }
break break;
case '4': case '2':
if (this.monthValue[1] - this.monthValue[0] > 729*24*3600000) { if (this.dateValue[1] - this.dateValue[0] > 29 * 24 * 3600000) {
this.$modal.msgError('最大时间范围为24个月请重新选择')// this.$modal.msgError('最大时间范围为30天请重新选择'); // 0:00:0023:59:59
this.monthValue = [] this.dateValue = [];
} }
break break;
default: case '4':
} if (this.monthValue[1] - this.monthValue[0] > 729 * 24 * 3600000) {
}, this.$modal.msgError('最大时间范围为24个月请重新选择'); //
// this.monthValue = [];
startYear() { }
if (this.yearValue2 && this.yearValue2 < this.yearValue1) { break;
this.$modal.msgError('开始时间不能晚于结束时间,请重新选择') default:
this.yearValue1 = null }
return false },
} //
if (this.yearValue1 && this.yearValue2) { startYear() {
if (this.yearValue2 - this.yearValue1 > 10*365*24*3600000) { if (this.yearValue2 && this.yearValue2 < this.yearValue1) {
this.$modal.msgError('最大时间范围为10年请重新选择') this.$modal.msgError('开始时间不能晚于结束时间,请重新选择');
this.yearValue1 = null this.yearValue1 = null;
return false return false;
} }
} if (this.yearValue1 && this.yearValue2) {
}, if (this.yearValue2 - this.yearValue1 > 10 * 365 * 24 * 3600000) {
endYear() { this.$modal.msgError('最大时间范围为10年请重新选择');
if (this.yearValue2 && this.yearValue2 < this.yearValue1) { this.yearValue1 = null;
this.$modal.msgError('结束时间不能早于开始时间,请重新选择') return false;
this.yearValue2 = null }
return false }
} },
if (this.yearValue1 && this.yearValue2) { endYear() {
if (this.yearValue2 - this.yearValue1 > 10*365*24*3600000) { if (this.yearValue2 && this.yearValue2 < this.yearValue1) {
this.$modal.msgError('最大时间范围为10年请重新选择') this.$modal.msgError('结束时间不能早于开始时间,请重新选择');
this.yearValue2 = null this.yearValue2 = null;
return false return false;
} }
} if (this.yearValue1 && this.yearValue2) {
}, if (this.yearValue2 - this.yearValue1 > 10 * 365 * 24 * 3600000) {
// this.$modal.msgError('最大时间范围为10年请重新选择');
startWeek() { this.yearValue2 = null;
if (this.weekValue1 && this.weekValue2) { return false;
let a = new Date(this.weekValue1).getTime() }
let b = new Date(this.weekValue2).getTime() }
if (a > b) { },
this.$modal.msgError('开始时间不能晚于结束时间,请重新选择') //
this.weekValue1 = null startWeek() {
return false if (this.weekValue1 && this.weekValue2) {
} let a = new Date(this.weekValue1).getTime();
if (b - a > 167*24*3600000) { let b = new Date(this.weekValue2).getTime();
this.$modal.msgError('最大时间范围为24周请重新选择') if (a > b) {
this.weekValue1 = null this.$modal.msgError('开始时间不能晚于结束时间,请重新选择');
return false this.weekValue1 = null;
} return false;
} }
}, if (b - a > 167 * 24 * 3600000) {
endWeek() { this.$modal.msgError('最大时间范围为24周请重新选择');
if (this.weekValue1 && this.weekValue2) { this.weekValue1 = null;
let a = new Date(this.weekValue1).getTime() return false;
let b = new Date(this.weekValue2).getTime() }
if (a > b) { }
this.$modal.msgError('结束时间不能早于开始时间,请重新选择') },
this.weekValue2 = null endWeek() {
return false if (this.weekValue1 && this.weekValue2) {
} let a = new Date(this.weekValue1).getTime();
if (b - a > 167*24*3600000) { let b = new Date(this.weekValue2).getTime();
this.$modal.msgError('最大时间范围为24周请重新选择') if (a > b) {
this.weekValue2 = null this.$modal.msgError('结束时间不能早于开始时间,请重新选择');
return false this.weekValue2 = null;
} return false;
} }
}, if (b - a > 167 * 24 * 3600000) {
// this.$modal.msgError('最大时间范围为24周请重新选择');
search() { this.weekValue2 = null;
if (!this.queryParams.energyTypeId) { return false;
this.$modal.msgError('请选择能源类型') }
return false }
} },
if (this.objArr.length === 0) { //
this.$modal.msgError('请选择对象') validateData() {
return false if (!this.queryParams.energyTypeId) {
} else { this.$modal.msgError('请选择能源类型');
this.queryParams.objId = this.objArr[this.objArr.length-1] return false;
} }
if (!this.queryParams.timeDim) { if (this.objArr.length === 0) {
this.$modal.msgError('请选择时间维度') this.$modal.msgError('请选择对象');
return false return false;
} } else {
switch (this.queryParams.timeDim) { this.queryParams.objId = this.objArr[this.objArr.length - 1];
case '1': }
if (this.timeValue.length > 0) { if (!this.queryParams.timeDim) {
this.queryParams.startTime = this.timeValue[0] this.$modal.msgError('请选择时间维度');
this.queryParams.endTime = this.timeValue[1] // return false;
} else { }
this.$modal.msgError('时间范围不能为空') switch (this.queryParams.timeDim) {
return false case '1':
} if (this.timeValue.length > 0) {
break this.queryParams.startTime = this.timeValue[0];
case '2': this.queryParams.endTime = this.timeValue[1]; //
if (this.dateValue.length > 0) { } else {
this.queryParams.startTime = this.dateValue[0] this.$modal.msgError('时间范围不能为空');
this.queryParams.endTime = this.dateValue[1] + 86399000 // 23:59:59 return false;
} else { }
this.$modal.msgError('日范围不能为空') break;
return false case '2':
} if (this.dateValue.length > 0) {
break this.queryParams.startTime = this.dateValue[0];
case '3': this.queryParams.endTime = this.dateValue[1] + 86399000; // 23:59:59
if (this.weekValue1 && this.weekValue2) { } else {
let a = moment(this.weekValue1).day(0).format('YYYY-MM-DD') + ' 00:00:00' this.$modal.msgError('日范围不能为空');
let b = moment(this.weekValue2).day(6).format('YYYY-MM-DD') + ' 23:59:59' return false;
this.queryParams.startTime = new Date(a).getTime() }
this.queryParams.endTime = new Date(b).getTime() break;
} else { case '3':
this.$modal.msgError('周范围不能为空') if (this.weekValue1 && this.weekValue2) {
return false let a =
} moment(this.weekValue1).day(0).format('YYYY-MM-DD') + ' 00:00:00';
break let b =
case '4':// moment(this.weekValue2).day(6).format('YYYY-MM-DD') + ' 23:59:59';
if (this.monthValue.length > 0) { this.queryParams.startTime = new Date(a).getTime();
this.queryParams.startTime = this.monthValue[0] this.queryParams.endTime = new Date(b).getTime();
this.queryParams.endTime = this.transformTime(this.monthValue[1]) } else {
} else { this.$modal.msgError('周范围不能为空');
this.$modal.msgError('月范围不能为空') return false;
return false }
} break;
break case '4': //
default:// if (this.monthValue.length > 0) {
if (this.yearValue1 && this.yearValue2) { this.queryParams.startTime = this.monthValue[0];
if (this.yearValue2 < this.yearValue1) { this.queryParams.endTime = this.transformTime(this.monthValue[1]);
this.$modal.msgError('结束时间不能早于开始时间') } else {
return false this.$modal.msgError('月范围不能为空');
} else { return false;
this.queryParams.startTime = this.yearValue1 }
this.queryParams.endTime = this.transformYear(this.yearValue2) break;
} default: //
} else { if (this.yearValue1 && this.yearValue2) {
this.$modal.msgError('年范围不能为空') if (this.yearValue2 < this.yearValue1) {
return false this.$modal.msgError('结束时间不能早于开始时间');
} return false;
} } else {
this.queryParams.startTime = this.queryParams.startTime + '' this.queryParams.startTime = this.yearValue1;
this.queryParams.endTime = this.queryParams.endTime + '' this.queryParams.endTime = this.transformYear(this.yearValue2);
this.$emit('submit', this.queryParams) }
}, } else {
// this.$modal.msgError('年范围不能为空');
resetBtn() { return false;
this.queryParams.energyTypeId = null }
this.queryParams.objId = null }
this.objArr = [] return true;
this.queryParams.timeDim = this.getDictDatas(this.DICT_TYPE.TIME_DIM)[0].value // },
this.timeValue = [moment().startOf('day'), moment().endOf('day')-59*61*1000] //
}, search() {
transformTime(timeStamp) {// if (this.validateData()) {
let year = moment(timeStamp).format('YYYY') this.queryParams.startTime = this.queryParams.startTime + '';
let month = moment(timeStamp).format('MM') this.queryParams.endTime = this.queryParams.endTime + '';
let newData = moment(new Date(year,month,0)).format('YYYY-MM-DD') + ' 23:59:59' this.$emit('submit', this.queryParams);
let value = new Date(newData).getTime() }
return value },
}, //
transformYear(timeStamp) {// resetBtn() {
let year = moment(timeStamp).format('YYYY') this.queryParams.energyTypeId = null;
let newData = year+'-12-31 23:59:59' this.queryParams.objId = null;
let value = new Date(newData).getTime() this.objArr = [];
return value this.queryParams.timeDim = this.getDictDatas(
}, this.DICT_TYPE.TIME_DIM
switchMode() {// )[0].value; //
this.isExpand = !this.isExpand this.timeValue = [
const element = this.$refs.searchBarRef moment().startOf('day'),
if (this.isExpand) { moment().endOf('day') - 59 * 61 * 1000,
element.classList.remove('divHeight') ];
} else { },
element.classList.add('divHeight') transformTime(timeStamp) {
} //
} let year = moment(timeStamp).format('YYYY');
} let month = moment(timeStamp).format('MM');
} let newData =
moment(new Date(year, month, 0)).format('YYYY-MM-DD') + ' 23:59:59';
let value = new Date(newData).getTime();
return value;
},
transformYear(timeStamp) {
//
let year = moment(timeStamp).format('YYYY');
let newData = year + '-12-31 23:59:59';
let value = new Date(newData).getTime();
return value;
},
switchMode() {
//
this.isExpand = !this.isExpand;
const element = this.$refs.searchBarRef;
if (this.isExpand) {
element.classList.remove('divHeight');
} else {
element.classList.add('divHeight');
}
},
exportData() {
if (this.validateData()) {
this.queryParams.startTime = this.queryParams.startTime + '';
this.queryParams.endTime = this.queryParams.endTime + '';
this.$emit('exportD', this.queryParams);
}
},
},
};
</script> </script>
<style lang='scss'> <style lang="scss">
/* 级联选择器 */ /* 级联选择器 */
.cascaderParent .el-cascader-panel .el-scrollbar:first-child .el-radio { .cascaderParent .el-cascader-panel .el-scrollbar:first-child .el-radio {
display: none; display: none;
} }
/* 时间整点 */ /* 时间整点 */
.noneMinute .el-time-spinner__wrapper { .noneMinute .el-time-spinner__wrapper {
width: 100%; width: 100%;
} }
.noneMinute .el-scrollbar:nth-of-type(2) { .noneMinute .el-scrollbar:nth-of-type(2) {
display: none; display: none;
} }
.demo-form-inline { .demo-form-inline {
.el-date-editor .el-range__icon { .el-date-editor .el-range__icon {
font-size: 16px; font-size: 16px;
color: #0B58FF; color: #0b58ff;
} }
.el-input__prefix .el-icon-date { .el-input__prefix .el-icon-date {
font-size: 16px; font-size: 16px;
color: #0B58FF; color: #0b58ff;
} }
} }
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
.demo-form-inline { .demo-form-inline {
.blue-block { .blue-block {
display: inline-block; display: inline-block;
width: 4px; width: 4px;
height: 16px; height: 16px;
background-color: #0B58FF; background-color: #0b58ff;
border-radius: 1px; border-radius: 1px;
margin-right: 8px; margin-right: 8px;
margin-top: 12px; margin-top: 12px;
} }
} }
.searchBarBox .foldClass { .searchBarBox .foldClass {
position: absolute; position: absolute;
top: 14px; top: 14px;
right: 0; right: 0;
cursor: pointer; cursor: pointer;
font-size: 12px; font-size: 12px;
color:#0B58FF; color: #0b58ff;
} }
.searchBarBox .foldClass .iconfont { .searchBarBox .foldClass .iconfont {
font-size: 14px; font-size: 14px;
} }
.divHeight { .divHeight {
height: 45px; height: 45px;
overflow: hidden; overflow: hidden;
} }
.separateStyle { .separateStyle {
display: inline-block; display: inline-block;
width: 1px; width: 1px;
height: 24px; height: 24px;
background: #E8E8E8; background: #e8e8e8;
vertical-align: middle; vertical-align: middle;
margin: 0 10px; margin: 0 10px;
} }
</style> </style>

View File

@ -1,94 +1,104 @@
<!--
* @Author: zwq
* @Date: 2024-07-01 14:53:55
* @LastEditors: zwq
* @LastEditTime: 2024-09-26 10:47:36
* @Description:
-->
<template> <template>
<div class="app-container trendAnalysisBox" id="trendAnalysisBox"> <div class="app-container trendAnalysisBox" id="trendAnalysisBox">
<!-- 搜索工作栏 --> <!-- 搜索工作栏 -->
<search-area :isFold="isFold" @submit="getList"/> <search-area :isFold="isFold" @submit="getList" @exportD="exportData"/>
<el-tabs v-model="activeName" @tab-click="switchChart" v-show='chartData.length'> <div v-show="chartData.length">
<el-tab-pane label="柱状图" name="bar"> <base-table
<bar-chart ref="analysisBarChart" :chartData="chartData" :timeDim="timeDim"/> :table-props="tableProps"
</el-tab-pane> :table-data="list"
<el-tab-pane label="折线图" name="line"> class="trend-out-table" />
<line-chart ref="analysisLineChart" :chartData="chartData" :timeDim="timeDim"/> <line-chart
</el-tab-pane> ref="analysisLineChart"
</el-tabs> :chartData="chartData"
:timeDim="timeDim" />
</div>
<!-- 没有数据 --> <!-- 没有数据 -->
<div class="no-data-bg" v-show='!chartData.length'></div> <div class="no-data-bg" v-show='!chartData.length'></div>
</div> </div>
</template> </template>
<script> <script>
import { getEnergyTrend } from "@/api/analysis/energyAnalysis" import { getEnergyTrend, exportTrend } from "@/api/analysis/energyAnalysis"
import SearchArea from "./components/searchArea" import SearchArea from "./components/searchArea"
import BarChart from "./components/barChart"
import LineChart from "./components/lineChart" import LineChart from "./components/lineChart"
// import moment from 'moment' // import moment from 'moment'
export default { export default {
name: 'TrendAnalysis', name: 'TrendAnalysis',
components: { SearchArea, BarChart, LineChart }, components: { SearchArea, LineChart },
data() { data() {
return { return {
isFold: false, isFold: false,
activeName: 'bar',
chartData: [], chartData: [],
timeDim: '' timeDim: '',
tableProps: [],
list: [],
} }
}, },
mounted() { mounted() {
window.addEventListener('resize', () => { window.addEventListener('resize', () => {
this.tableH = this.tableHeight(260) this.tableH = this.tableHeight(260)
this.isFold = this.searchBarWidth('trendAnalysisBox', 1263) this.isFold = this.searchBarWidth('trendAnalysisBox', 1146)
}) })
this.isFold = this.searchBarWidth('trendAnalysisBox', 1263) this.isFold = this.searchBarWidth('trendAnalysisBox', 1146)
}, },
methods: { methods: {
getList(params) { getList(params) {
this.timeDim = params.timeDim this.timeDim = params.timeDim
getEnergyTrend({ ...params }).then((res) => { getEnergyTrend({ ...params }).then((res) => {
if (res.code === 0) { if (res.code === 0) {
this.chartData = res.data this.getTableList(res.data || []);
this.chartData = res.data || [];
} else { } else {
this.chartData = [] this.chartData = []
} }
}) })
}, },
switchChart() { getTableList(arr) {
if (this.activeName === 'bar') { this.tableProps = [];
this.$nextTick((res) => { this.list = [];
this.$refs.analysisBarChart.getChart() let tempX = [];
}) let listObj = { useNum: '消耗量' }; //
} else { for (let i = 0; i < arr.length; i++) {
this.$nextTick((res) => { let obj = {};
this.$refs.analysisLineChart.getChart() if (this.timeDim === '3') {
}) let fName = arr[i].time.slice(0, 4);
} let lName = arr[i].time.slice(4, 6);
obj.label = fName + ' 第 ' + lName + ' 周';
} else {
obj.label = arr[i].time;
}
obj.prop = arr[i].time;
obj.minWidth = 100;
tempX.push(obj);
listObj[arr[i].time] = arr[i].useNum || null;
}
this.tableProps = [{ prop: 'useNum', label: '时间' }].concat(tempX);
this.list.push(listObj);
},
/** 导出按钮操作 */
exportData(val) {
//
this.$modal.confirm('是否确认导出走势分析数据?').then(() => {
this.exportLoading = true;
return exportTrend(val);
}).then(response => {
this.$download.excel(response, '走势分析数据.xlsx');
this.exportLoading = false;
}).catch(() => {});
} }
} }
} }
</script> </script>
<style lang='scss'> <style lang='scss'>
.trendAnalysisBox { .trendAnalysisBox {
.el-tabs__nav::after { .trend-out-table {
content: ""; margin-bottom: 15px;
position: absolute; }
left: 0;
bottom: 0;
width: 100%;
height: 2px;
background-color: #e4e7ed;
/* z-index: 1; */
}
.el-tabs__nav-wrap::after {
width: 0;
}
.el-tabs__item {
padding: 0 10px;
}
.el-tabs__item:hover {
color: rgba(0, 0, 0, 0.85);
}
.el-tabs__item.is-active {
color: rgba(0, 0, 0, 0.85);
}
.el-tabs__item {
color: rgba(0, 0, 0, 0.45);
}
} }
</style> </style>

View File

@ -6,7 +6,7 @@
style="font-size: 24px; cursor: pointer" style="font-size: 24px; cursor: pointer"
@click="toHome" /> --> @click="toHome" /> -->
<svg-icon <svg-icon
icon-class="home-alarm-white" :icon-class="isAlarm ? 'home-alarm-white-circle' : 'home-alarm-white'"
style="font-size: 24px; cursor: pointer" style="font-size: 24px; cursor: pointer"
@click="toAlarm" /> @click="toAlarm" />
</div> </div>
@ -46,16 +46,15 @@
import moment from 'moment'; import moment from 'moment';
import { getUser } from '@/api/system/user.js'; import { getUser } from '@/api/system/user.js';
import { getPath } from '@/utils/ruoyi'; import { getPath } from '@/utils/ruoyi';
import { getHomeGetAlarm } from '@/api/home';
export default { export default {
name: 'navRight', name: 'navRight',
data() { data() {
return { return {
// topDate: '',
// topTime: '',
// timeZone: '',
timer: '', timer: '',
dept: ' ', dept: ' ',
nickname: this.$store.getters.nickname, nickname: this.$store.getters.nickname,
isAlarm: false,
}; };
}, },
props: { props: {
@ -68,21 +67,18 @@ export default {
}, },
created() { created() {
this.getUserMsg(); this.getUserMsg();
// this.getTime(); this.getHomeGetAlarm();
this.timer = setInterval(this.getHomeGetAlarm(), 3600000);
},
beforeDestroy() {
clearInterval(this.timer);
}, },
// beforeDestroy() {
// clearInterval(this.timer);
// },
methods: { methods: {
// getTime() { getHomeGetAlarm() {
// let _this = this; getHomeGetAlarm().then((response) => {
// this.timer = setInterval(function () { this.isAlarm = response.data || false;
// _this.topDate = moment().format('YYYY/MM/DD'); });
// let temp = moment().format('A-hh:mm').split('-'); },
// _this.timeZone = temp[0];
// _this.topTime = temp[1];
// }, 1000);
// },
getUserMsg() { getUserMsg() {
let id = this.$store.getters.userId; let id = this.$store.getters.userId;
getUser(id).then((res) => { getUser(id).then((res) => {

View File

@ -3,50 +3,47 @@
<div> <div>
<navbar /> <navbar />
</div> </div>
<div class="date-tabs">
<el-tabs v-model="activeName" :stretch="true">
<el-tab-pane
:label="'\u2002\u2002日\u2002\u2002'"
name="日"></el-tab-pane>
<el-tab-pane
:label="'\u2002\u2002周\u2002\u2002'"
name="周"></el-tab-pane>
<el-tab-pane
:label="'\u2002\u2002月\u2002\u2002'"
name="月"></el-tab-pane>
<el-tab-pane
:label="'\u2002\u2002年\u2002\u2002'"
name="年"></el-tab-pane>
</el-tabs>
<div class="current-date">(6.13-6.20)</div>
<div class="current-time">
<span style="display: inline-block; margin-right: 16px">
{{ topTime + timeZone }}
</span>
<span>{{ topDate }}</span>
</div>
</div>
<el-row class="main-top" :gutter="16"> <el-row class="main-top" :gutter="16">
<el-col :span="12" style="position: relative"> <el-col :span="12" style="position: relative">
<div class="title"> <div class="title">
<svg-icon icon-class="home-produce" /> <svg-icon icon-class="home-produce" />
<span class="title-inner">生产总览</span> <span class="title-inner">生产总览</span>
<div class="date-tabs">
<el-tabs
v-model="activeName"
@tab-click="handleClick"
:stretch="true">
<el-tab-pane
:label="'\u2002\u2002日\u2002\u2002'"
name="日"></el-tab-pane>
<el-tab-pane
:label="'\u2002\u2002周\u2002\u2002'"
name="周"></el-tab-pane>
<el-tab-pane
:label="'\u2002\u2002月\u2002\u2002'"
name="月"></el-tab-pane>
<el-tab-pane
:label="'\u2002\u2002年\u2002\u2002'"
name="年"></el-tab-pane>
</el-tabs>
</div>
<div class="current-date">( {{ showTime }} )</div>
</div> </div>
<el-row class="box"> <el-row class="box">
<el-col :span="6" class="num-box shadow"> <el-col :span="6" class="num-box shadow">
<div class="num-style">9,301.01</div> <div class="num-style">{{ homeProduce.quantity }}</div>
<div class="unit-style">产量/千片</div> <div class="unit-style">产量/千片</div>
</el-col> </el-col>
<el-col :span="4" class="num-box shadow"> <el-col :span="4" class="num-box shadow">
<div class="num-style">94.34</div> <div class="num-style">{{ homeProduce.yieldRate }}</div>
<div class="unit-style">良品率/%</div> <div class="unit-style">良品率/%</div>
</el-col> </el-col>
<el-col :span="8" class="num-box shadow"> <el-col :span="8" class="num-box shadow">
<div class="num-style">29,301.01</div> <div class="num-style">{{ homeProduce.endWorkOrderQuantity }}</div>
<div class="unit-style">完成工单数量/千片</div> <div class="unit-style">完成工单数量/千片</div>
</el-col> </el-col>
<el-col :span="6" class="num-box"> <el-col :span="6" class="num-box">
<div class="num-style">1,340</div> <div class="num-style">{{ homeProduce.endOrderQuantity }}</div>
<div class="unit-style">完成订单数量/</div> <div class="unit-style">完成订单数量/</div>
</el-col> </el-col>
</el-row> </el-row>
@ -55,22 +52,29 @@
<div class="title"> <div class="title">
<svg-icon icon-class="home-device" /> <svg-icon icon-class="home-device" />
<span class="title-inner">设备总览</span> <span class="title-inner">设备总览</span>
<!-- <div class="date-tabs">
<div class="current-time">
<span>
{{ topTime + timeZone + ' '+ topDate }}
</span>
</div>
</div> -->
</div> </div>
<el-row class="box"> <el-row class="box">
<el-col :span="6" class="num-box shadow"> <el-col :span="6" class="num-box shadow">
<div class="num-style">2,931</div> <div class="num-style">{{ homeDevice.allEquipment }}</div>
<div class="unit-style">设备总数/</div> <div class="unit-style">设备总数/</div>
</el-col> </el-col>
<el-col :span="6" class="num-box shadow"> <el-col :span="6" class="num-box shadow">
<div class="num-style">931</div> <div class="num-style">{{ homeDevice.onlineEquipment }}</div>
<div class="unit-style">在线设备总数/</div> <div class="unit-style">在线设备总数/</div>
</el-col> </el-col>
<el-col :span="6" class="num-box shadow"> <el-col :span="6" class="num-box shadow">
<div class="num-style">7</div> <div class="num-style">{{ homeDevice.errorEquipment }}</div>
<div class="unit-style">故障设备总数/</div> <div class="unit-style">故障设备总数/</div>
</el-col> </el-col>
<el-col :span="6" class="num-box"> <el-col :span="6" class="num-box">
<div class="num-style">0</div> <div class="num-style">{{ homeDevice.stopEquipment }}</div>
<div class="unit-style">停机设备总数/</div> <div class="unit-style">停机设备总数/</div>
</el-col> </el-col>
</el-row> </el-row>
@ -81,6 +85,7 @@
class="item" class="item"
:class="{ shadow: index !== middleMenu.length - 1 }" :class="{ shadow: index !== middleMenu.length - 1 }"
v-for="(item, index) in middleMenu" v-for="(item, index) in middleMenu"
@click="goPage(item)"
:key="index"> :key="index">
<div style="width: 160px; margin: 0 auto; padding-top: 20px"> <div style="width: 160px; margin: 0 auto; padding-top: 20px">
<svg-icon :icon-class="item.icon" style="font-size: 56px" /> <svg-icon :icon-class="item.icon" style="font-size: 56px" />
@ -105,14 +110,14 @@
<div class="order-box"> <div class="order-box">
<div <div
class="order-item" class="order-item"
v-for="(item, index) in orderList" v-for="(item, index) in homeProduce.orderList"
:key="index"> :key="index">
<div> <div>
<span class="order-name">{{ item.name }}</span> <span class="order-name">{{ item.orderName }}</span>
<span class="order-value">{{ item.value }}%</span> <span class="order-value">{{ item.completeRate * 100 }}%</span>
</div> </div>
<el-progress <el-progress
:percentage="item.value" :percentage="item.completeRate * 100"
:text-inside="false" :text-inside="false"
:stroke-width="15" :stroke-width="15"
:show-text="false"></el-progress> :show-text="false"></el-progress>
@ -130,7 +135,7 @@
:page="1" :page="1"
:limit="100000" :limit="100000"
:table-props="tableProps" :table-props="tableProps"
:table-data="list" :table-data="homeDevice.list"
:max-height="tableH" /> :max-height="tableH" />
</div> </div>
</el-col> </el-col>
@ -155,6 +160,13 @@
import Navbar from './components/Navbar'; import Navbar from './components/Navbar';
import moment from 'moment'; import moment from 'moment';
import tableHeightMixin from '@/mixins/tableHeightMixin'; import tableHeightMixin from '@/mixins/tableHeightMixin';
import {
getHomeOrder,
getHomeOrderNum,
getHomeEquipment,
getHomeEquipmentAlarmList,
} from '@/api/home';
export default { export default {
name: 'Home', name: 'Home',
mixins: [tableHeightMixin], mixins: [tableHeightMixin],
@ -175,69 +187,107 @@ export default {
topTime: '', topTime: '',
timeZone: '', timeZone: '',
middleMenu: [ middleMenu: [
{ name: '工单管理', url: '', icon: 'home-work-menu' }, { name: '生产管理', url: 'productLine24h', icon: 'home-work-menu' },
{ name: '订单管理', url: '', icon: 'home-order-menu' }, {
{ name: '设备管理', url: '', icon: 'home-device-menu' }, name: '能源管理',
{ name: '质量管理', url: '', icon: 'home-quality-menu' }, url: 'EnergyQuantityRealtime',
{ name: '仓库管理', url: '', icon: 'home-store-menu' }, icon: 'home-order-menu',
], },
orderList: [ { name: '设备管理', url: 'PlanConfig', icon: 'home-device-menu' },
{ name: '工单1', value: 50 }, { name: '质量管理', url: 'qualityScrapLog', icon: 'home-quality-menu' },
{ name: '工单2', value: 60 }, { name: '仓库管理', url: 'warehouse-info', icon: 'home-store-menu' },
{ name: '工单3', value: 30 },
{ name: '工单4', value: 60 },
{ name: '工单5', value: 10 },
{ name: '工单6', value: 60 },
{ name: '工单7', value: 40 },
{ name: '工单8', value: 70 },
{ name: '工单9', value: 90 },
], ],
heightNum: 640, heightNum: 640,
tableProps: [ tableProps: [
{ {
prop: 'productionLineName', prop: 'equipmentName',
label: '设备名称', label: '设备名称',
showOverflowtooltip: true, showOverflowtooltip: true,
}, },
{ {
prop: 'sectionName', prop: 'alarmContent',
label: '告警内容', label: '告警内容',
showOverflowtooltip: true, showOverflowtooltip: true,
}, },
{ {
prop: 'createTime', prop: 'updateTime',
label: '告警时间', label: '告警时间',
width: 180, width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'), filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
}, },
], ],
list: [ homeProduce: {
{ productionLineName: 1 }, quantity: undefined,
{ productionLineName: 1 }, yieldRate: undefined,
{ productionLineName: 1 }, endWorkOrderQuantity: undefined,
{ productionLineName: 1 }, endOrderQuantity: undefined,
{ productionLineName: 1 }, orderList: [],
{ productionLineName: 1 }, },
{ productionLineName: 1 }, homeDevice: {
{ productionLineName: 1 }, allEquipment: undefined,
{ productionLineName: 1 }, onlineEquipment: undefined,
{ productionLineName: 1 }, errorEquipment: undefined,
{ productionLineName: 1 }, stopEquipment: undefined,
{ productionLineName: 1 }, list: [],
{ productionLineName: 1 }, },
{ productionLineName: 1 }, times: [],
{ productionLineName: 1 }, showTime: '',
{ productionLineName: 1 },
],
}; };
}, },
created() { created() {
this.getTime(); this.getTime();
this.handleClick();
this.getHomeEquipment();
this.showTime = moment(new Date()).subtract(0, 'days').format('YYYY-MM-DD');
}, },
beforeDestroy() { beforeDestroy() {
clearInterval(this.timer); clearInterval(this.timer);
}, },
methods: { methods: {
handleClick() {
let start =
Date.parse(new Date())
let end =
Date.parse(new Date())
switch (this.activeName) {
case '日':
this.showTime = moment(new Date())
.subtract(0, 'days')
.format('YYYY-MM-DD');
this.times = [start, end];
break;
case '周':
start =
moment(new Date()).subtract(6, 'days').format('x')
this.showTime =
moment(new Date()).subtract(6, 'days').format('MM-DD') +
' ~ ' +
moment(new Date()).subtract(0, 'days').format('MM-DD');
this.times = [start, end];
break;
case '月':
start =
moment(new Date()).subtract(1, 'month').format('x')
this.showTime =
moment(new Date()).subtract(1, 'month').format('MM-DD') +
' ~ ' +
moment(new Date()).subtract(0, 'days').format('MM-DD');
this.times = [start, end];
break;
case '年':
start =
moment(new Date()).subtract(1, 'year').format('x')
this.showTime =
moment(new Date()).subtract(1, 'year').format('YYYY') +
' ~ ' +
moment(new Date()).subtract(0, 'days').format('YYYY');
this.times = [start, end];
break;
default:
console.log(val);
}
this.getHomeOrder();
},
getTime() { getTime() {
let _this = this; let _this = this;
this.timer = setInterval(function () { this.timer = setInterval(function () {
@ -247,6 +297,59 @@ export default {
_this.topTime = temp[1]; _this.topTime = temp[1];
}, 1000); }, 1000);
}, },
getHomeOrder() {
getHomeOrder(this.times).then((response) => {
if (response.hasOwnProperty('data')) {
this.homeProduce.quantity = response.data.quantity;
this.homeProduce.yieldRate = response.data.yieldRate * 100;
this.homeProduce.endWorkOrderQuantity =
response.data.endWorkOrderQuantity;
this.homeProduce.orderList = response.data.orderMonitorVO;
} else {
this.homeProduce = {
quantity: undefined,
yieldRate: undefined,
endWorkOrderQuantity: undefined,
endOrderQuantity: undefined,
orderList: [],
};
}
});
getHomeOrderNum(this.times).then((response) => {
if (response.hasOwnProperty('data')) {
this.homeProduce.endOrderQuantity = response.data.endOrderQuantity;
} else {
this.homeProduce.endOrderQuantity = '-';
}
});
},
getHomeEquipment() {
getHomeEquipment().then((response) => {
if (response.hasOwnProperty('data')) {
this.homeDevice.allEquipment = response.data.allEquipment;
this.homeDevice.onlineEquipment = response.data.onlineEquipment;
this.homeDevice.errorEquipment = response.data.errorEquipment;
this.homeDevice.stopEquipment = response.data.stopEquipment;
} else {
this.homeDevice = {
allEquipment: undefined,
onlineEquipment: undefined,
errorEquipment: undefined,
stopEquipment: undefined,
};
}
});
getHomeEquipmentAlarmList().then((response) => {
if (response.hasOwnProperty('data')) {
this.homeDevice.list = response.data;
} else {
this.homeDevice.list = [];
}
});
},
goPage(val) {
this.$router.push({ name: val.url });
},
}, },
}; };
</script> </script>
@ -260,56 +363,14 @@ export default {
height: 300px; height: 300px;
width: 100%; width: 100%;
} }
.date-tabs {
padding-left: 40px;
padding-top: 20px;
position: relative;
}
:deep(.date-tabs) {
.el-tabs__header {
margin-bottom: 8px;
display: inline-block;
transform: translateY(-12px);
}
.el-tabs__content {
overflow: visible;
}
.el-tabs__item {
font-size: 18px;
color: #fff;
padding-left: 0 !important;
padding-right: 0 !important;
line-height: 36px !important;
height: 36px;
}
.el-tabs__item.is-active {
color: #0b58ff;
}
}
.current-date {
color: #fff;
font-size: 18px;
position: absolute;
left: 260px;
top: 14px;
}
.current-time {
color: #fff;
font-size: 18px;
position: absolute;
right: 38px;
top: 14px;
}
.main-top { .main-top {
width: 100%; width: 100%;
padding: 0 20px 0 40px; padding: 10px 20px 0 40px;
.title { .title {
position: absolute; position: absolute;
left: 34px; left: 34px;
top: 20px; top: 20px;
width: 180px; width: 90%;
font-size: 32px; font-size: 32px;
z-index: 10; z-index: 10;
.title-inner { .title-inner {
@ -318,12 +379,53 @@ export default {
top: 5px; top: 5px;
font-size: 24px; font-size: 24px;
} }
.date-tabs {
position: absolute;
right: 100px;
top: 5px;
font-size: 18px;
}
:deep(.date-tabs) {
.el-tabs__header {
margin-bottom: 8px;
display: inline-block;
}
.el-tabs__content {
overflow: visible;
}
.el-tabs__item {
font-size: 18px;
padding-left: 0 !important;
padding-right: 0 !important;
line-height: 20px !important;
height: 24px;
}
.el-tabs__item.is-active {
color: #0b58ff;
}
}
.current-date {
font-size: 10px;
font-weight: 500;
position: absolute;
right: 0px;
top: 5px;
}
// .current-time {
// width: 160px;
// font-size: 18px;
// position: absolute;
// right: -20px;
// top: 5px;
// }
} }
.box { .box {
background-color: #fff; background-color: #fff;
border-radius: 24px; border-radius: 24px;
height: 192px; height: 232px;
padding: 40px 24px 32px 24px; padding: 60px 24px 32px 24px;
.num-box { .num-box {
height: 120px; height: 120px;
padding-top: 26px; padding-top: 26px;

View File

@ -1,66 +1,17 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form <search-bar
:model="queryParams" :formConfigs="formConfig"
ref="queryForm" ref="searchBarForm"
size="small" @headBtnClick="buttonClick" />
:inline="true"
v-show="showSearch">
<el-form-item label="部门名称" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入部门名称"
clearable
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="菜单状态"
clearable>
<el-option
v-for="dict in statusDictDatas"
:key="parseInt(dict.value)"
:label="dict.label"
:value="parseInt(dict.value)" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">
搜索
</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:dept:create']">
新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="el-icon-sort"
size="mini"
@click="toggleExpandAll">
展开/折叠
</el-button>
</el-col>
<right-toolbar
:showSearch.sync="showSearch"
@queryTable="getList"></right-toolbar>
</el-row>
<el-table <el-table
:header-cell-style="{
background: '#F2F4F9',
color: '#606266',
}"
border
style="width: 100%"
v-if="refreshTable" v-if="refreshTable"
v-loading="loading" v-loading="loading"
:data="deptList" :data="deptList"
@ -125,8 +76,14 @@
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- 添加或修改部门对话框 --> <!-- 添加或修改菜单对话框 -->
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body> <el-dialog :visible.sync="open" width="800px" append-to-body class="dialog">
<template #title>
<slot name="title">
<div class="titleStyle">{{ title }}</div>
</slot>
</template>
<slot />
<el-form ref="form" :model="form" :rules="rules" label-width="80px"> <el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-row> <el-row>
<el-col :span="24"> <el-col :span="24">
@ -197,8 +154,8 @@
</el-row> </el-row>
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button> <el-button class="btnTextStyle" @click="cancel"> </el-button>
<el-button @click="cancel"> </el-button> <el-button type="primary" class="btnTextStyle" @click="submitForm"> </el-button>
</div> </div>
</el-dialog> </el-dialog>
</div> </div>
@ -276,6 +233,40 @@ export default {
], ],
status: [{ required: true, message: '状态不能为空', trigger: 'blur' }], status: [{ required: true, message: '状态不能为空', trigger: 'blur' }],
}, },
formConfig: [
{
type: 'input',
label: '部门名称',
placeholder: '部门名称',
param: 'name',
},
{
type: 'select',
label: '状态',
selectOptions: getDictDatas(DICT_TYPE.COMMON_STATUS),
param: 'status',
defaultSelect: '',
valueField: 'value',
labelField: 'label',
filterable: true,
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: this.$auth.hasPermi('system:dept:create') ? 'separate' : '',
},
{
type: this.$auth.hasPermi('system:dept:create') ? 'button' : '',
btnName: '新增',
name: 'add',
color: 'success',
plain: true,
},
],
// //
CommonStatusEnum: CommonStatusEnum, CommonStatusEnum: CommonStatusEnum,
@ -291,6 +282,15 @@ export default {
}); });
}, },
methods: { methods: {
buttonClick(val) {
if (val.btnName === 'search') {
this.queryParams.name = val.name;
this.queryParams.status = val.status;
this.getList();
} else {
this.handleAdd();
}
},
/** 查询部门列表 */ /** 查询部门列表 */
getList() { getList() {
this.loading = true; this.loading = true;
@ -422,3 +422,36 @@ export default {
}, },
}; };
</script> </script>
<style scoped>
.app-container >>> .el-table .el-table__cell {
padding: 0;
height: 35px;
}
.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;
}
.dialog >>> .btnTextStyle {
letter-spacing: 6px;
padding: 9px 10px 9px 16px;
font-size: 14px;
}
</style>

View File

@ -1,38 +1,18 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> <search-bar
<el-form-item label="字典名称" prop="dictType"> :formConfigs="formConfig"
<el-select v-model="queryParams.dictType"> ref="searchBarForm"
<el-option v-for="item in typeOptions" :key="item.id" :label="item.name" :value="item.type"/> @headBtnClick="buttonClick" />
</el-select>
</el-form-item>
<el-form-item label="字典标签" prop="label">
<el-input v-model="queryParams.label" placeholder="请输入字典标签" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="数据状态" clearable>
<el-option v-for="dict in statusDictDatas" :key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8"> <el-table
<el-col :span="1.5"> :header-cell-style="{
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" background: '#F2F4F9',
v-hasPermi="['system:dict:create']">新增</el-button> color: '#606266',
</el-col> }"
<el-col :span="1.5"> border
<el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport" :loading="exportLoading" style="width: 100%"
v-hasPermi="['system:dict:export']">导出</el-button> v-loading="loading" :data="dataList" >
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="dataList" >
<el-table-column label="字典编码" align="center" prop="id" /> <el-table-column label="字典编码" align="center" prop="id" />
<el-table-column label="字典标签" align="center" prop="label" /> <el-table-column label="字典标签" align="center" prop="label" />
<el-table-column label="字典键值" align="center" prop="value" /> <el-table-column label="字典键值" align="center" prop="value" />
@ -64,7 +44,13 @@
@pagination="getList"/> @pagination="getList"/>
<!-- 添加或修改参数配置对话框 --> <!-- 添加或修改参数配置对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body> <el-dialog :visible.sync="open" width="800px" append-to-body class="dialog">
<template #title>
<slot name="title">
<div class="titleStyle">{{ title }}</div>
</slot>
</template>
<slot />
<el-form ref="form" :model="form" :rules="rules" label-width="90px"> <el-form ref="form" :model="form" :rules="rules" label-width="90px">
<el-form-item label="字典类型"> <el-form-item label="字典类型">
<el-input v-model="form.dictType" :disabled="true" /> <el-input v-model="form.dictType" :disabled="true" />
@ -96,8 +82,8 @@
</el-form-item> </el-form-item>
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button> <el-button class="btnTextStyle" @click="cancel"> </el-button>
<el-button @click="cancel"> </el-button> <el-button type="primary" class="btnTextStyle" @click="submitForm"> </el-button>
</div> </div>
</el-dialog> </el-dialog>
</div> </div>
@ -130,8 +116,6 @@ export default {
title: "", title: "",
// //
open: false, open: false,
//
typeOptions: [],
// //
queryParams: { queryParams: {
pageNo: 1, pageNo: 1,
@ -176,6 +160,60 @@ export default {
} }
], ],
formConfig: [
{
type: 'select',
label: '字典名称',
selectOptions: [],
param: 'dictType',
defaultSelect: '',
valueField: 'type',
labelField: 'name',
filterable: true,
},
{
type: 'input',
label: '字典标签',
placeholder: '字典标签',
param: 'label',
},
{
type: 'select',
label: '状态',
selectOptions: getDictDatas(DICT_TYPE.COMMON_STATUS),
param: 'status',
defaultSelect: '',
valueField: 'value',
labelField: 'label',
filterable: true,
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: this.$auth.hasPermi('system:dict:create') ? 'separate' : '',
},
{
type: this.$auth.hasPermi('system:dict:create') ? 'button' : '',
btnName: '新增',
name: 'add',
color: 'success',
plain: true,
},
{
type: this.$auth.hasPermi('system:dict:export') ? 'separate' : '',
},
{
type: this.$auth.hasPermi('system:dict:export') ? 'button' : '',
btnName: '导出',
name: 'export',
color: 'primary',
plain: true,
},
],
// //
CommonStatusEnum: CommonStatusEnum, CommonStatusEnum: CommonStatusEnum,
// //
@ -188,6 +226,19 @@ export default {
this.getTypeList(); this.getTypeList();
}, },
methods: { methods: {
buttonClick(val) {
if (val.btnName === 'search') {
this.queryParams.dictType = val.dictType;
this.queryParams.label = val.label;
this.queryParams.status = val.status;
this.getList();
} else if (val.btnName === 'export'){
this.handleExport()
}
else {
this.handleAdd();
}
},
/** 查询字典类型详细 */ /** 查询字典类型详细 */
getType(dictId) { getType(dictId) {
getType(dictId).then(response => { getType(dictId).then(response => {
@ -199,7 +250,7 @@ export default {
/** 查询字典类型列表 */ /** 查询字典类型列表 */
getTypeList() { getTypeList() {
listAllSimple().then(response => { listAllSimple().then(response => {
this.typeOptions = response.data; this.formConfig[0].selectOptions = response.data;
}); });
}, },
/** 查询字典数据列表 */ /** 查询字典数据列表 */
@ -281,7 +332,8 @@ export default {
/** 删除按钮操作 */ /** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
const ids = row.id; const ids = row.id;
this.$modal.confirm('是否确认删除字典编码为"' + ids + '"的数据项?').then(function() { this.$modal
.delConfirm(row.label).then(function() {
return delData(ids); return delData(ids);
}).then(() => { }).then(() => {
this.getList(); this.getList();
@ -302,3 +354,36 @@ export default {
} }
}; };
</script> </script>
<style scoped>
.app-container >>> .el-table .el-table__cell {
padding: 0;
height: 35px;
}
.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;
}
.dialog >>> .btnTextStyle {
letter-spacing: 6px;
padding: 9px 10px 9px 16px;
font-size: 14px;
}
</style>

View File

@ -1,40 +1,18 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> <search-bar
<el-form-item label="字典名称" prop="name"> :formConfigs="formConfig"
<el-input v-model="queryParams.name" placeholder="请输入字典名称" clearable style="width: 240px" @keyup.enter.native="handleQuery"/> ref="searchBarForm"
</el-form-item> @headBtnClick="buttonClick" />
<el-form-item label="字典类型" prop="type">
<el-input v-model="queryParams.type" placeholder="请输入字典类型" clearable style="width: 240px" @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="字典状态" clearable style="width: 240px">
<el-option v-for="dict in statusDictDatas" :key="parseInt(dict.value)" :label="dict.label" :value="parseInt(dict.value)"/>
</el-select>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8"> <el-table
<el-col :span="1.5"> :header-cell-style="{
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" background: '#F2F4F9',
v-hasPermi="['system:dict:create']">新增</el-button> color: '#606266',
</el-col> }"
<el-col :span="1.5"> border
<el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport" :loading="exportLoading" style="width: 100%"
v-hasPermi="['system:dict:export']">导出</el-button> v-loading="loading" :data="typeList">
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="typeList">
<el-table-column label="字典编号" align="center" prop="id" /> <el-table-column label="字典编号" align="center" prop="id" />
<el-table-column label="字典名称" align="center" prop="name" :show-overflow-tooltip="true" /> <el-table-column label="字典名称" align="center" prop="name" :show-overflow-tooltip="true" />
<el-table-column label="字典类型" align="center" :show-overflow-tooltip="true"> <el-table-column label="字典类型" align="center" :show-overflow-tooltip="true">
@ -69,7 +47,13 @@
@pagination="getList"/> @pagination="getList"/>
<!-- 添加或修改参数配置对话框 --> <!-- 添加或修改参数配置对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body> <el-dialog :visible.sync="open" width="800px" append-to-body class="dialog">
<template #title>
<slot name="title">
<div class="titleStyle">{{ title }}</div>
</slot>
</template>
<slot />
<el-form ref="form" :model="form" :rules="rules" label-width="80px"> <el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="字典名称" prop="name"> <el-form-item label="字典名称" prop="name">
<el-input v-model="form.name" placeholder="请输入字典名称" /> <el-input v-model="form.name" placeholder="请输入字典名称" />
@ -87,8 +71,8 @@
</el-form-item> </el-form-item>
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button> <el-button class="btnTextStyle" @click="cancel"> </el-button>
<el-button @click="cancel"> </el-button> <el-button type="primary" class="btnTextStyle" @click="submitForm"> </el-button>
</div> </div>
</el-dialog> </el-dialog>
</div> </div>
@ -139,6 +123,70 @@ export default {
] ]
}, },
formConfig: [
{
type: 'input',
label: '字典名称',
placeholder: '字典名称',
param: 'name',
},
{
type: 'input',
label: '字典类型',
placeholder: '字典类型',
param: 'type',
},
{
type: 'select',
label: '状态',
selectOptions: getDictDatas(DICT_TYPE.COMMON_STATUS),
param: 'status',
defaultSelect: '',
valueField: 'value',
labelField: 'label',
filterable: true,
},
{
type: 'datePicker',
label: '创建时间',
dateType: 'daterange',
format: 'yyyy-MM-dd',
valueFormat: 'yyyy-MM-dd HH:mm:ss',
rangeSeparator: '-',
startPlaceholder: '开始日期',
endPlaceholder: '结束日期',
param: 'createTime',
defaultSelect: [],
defaultTime: ['00:00:00', '23:59:59'],
width: 250,
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: this.$auth.hasPermi('system:dict:create') ? 'separate' : '',
},
{
type: this.$auth.hasPermi('system:dict:create') ? 'button' : '',
btnName: '新增',
name: 'add',
color: 'success',
plain: true,
},
{
type: this.$auth.hasPermi('system:dict:export') ? 'separate' : '',
},
{
type: this.$auth.hasPermi('system:dict:export') ? 'button' : '',
btnName: '导出',
name: 'export',
color: 'primary',
plain: true,
},
],
// //
CommonStatusEnum: CommonStatusEnum, CommonStatusEnum: CommonStatusEnum,
// //
@ -149,6 +197,20 @@ export default {
this.getList(); this.getList();
}, },
methods: { methods: {
buttonClick(val) {
if (val.btnName === 'search') {
this.queryParams.name = val.name;
this.queryParams.type = val.type;
this.queryParams.createTime = val.createTime;
this.queryParams.status = val.status;
this.getList();
} else if (val.btnName === 'export'){
this.handleExport()
}
else {
this.handleAdd();
}
},
/** 查询字典类型列表 */ /** 查询字典类型列表 */
getList() { getList() {
this.loading = true; this.loading = true;
@ -224,7 +286,8 @@ export default {
/** 删除按钮操作 */ /** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
const ids = row.id || this.ids; const ids = row.id || this.ids;
this.$modal.confirm('是否确认删除字典编号为"' + ids + '"的数据项?').then(function() { this.$modal
.delConfirm(row.name).then(function() {
return delType(ids); return delType(ids);
}).then(() => { }).then(() => {
this.getList(); this.getList();
@ -249,3 +312,36 @@ export default {
} }
}; };
</script> </script>
<style scoped>
.app-container >>> .el-table .el-table__cell {
padding: 0;
height: 35px;
}
.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;
}
.dialog >>> .btnTextStyle {
letter-spacing: 6px;
padding: 9px 10px 9px 16px;
font-size: 14px;
}
</style>

View File

@ -1,406 +1,572 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<!-- <doc-alert title="功能权限" url="https://doc.iocoder.cn/resource-permission" /> <!-- <doc-alert title="功能权限" url="https://doc.iocoder.cn/resource-permission" />
<doc-alert title="菜单路由" url="https://doc.iocoder.cn/vue2/route/" /> --> <doc-alert title="菜单路由" url="https://doc.iocoder.cn/vue2/route/" /> -->
<!-- 搜索工作栏 --> <!-- 搜索工作栏 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch"> <search-bar
<el-form-item label="菜单名称" prop="name"> :formConfigs="formConfig"
<el-input v-model="queryParams.name" placeholder="请输入菜单名称" clearable @keyup.enter.native="handleQuery"/> ref="searchBarForm"
</el-form-item> @headBtnClick="buttonClick" />
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="菜单状态" clearable>
<el-option v-for="dict in statusDictDatas" :key="parseInt(dict.value)" :label="dict.label" :value="parseInt(dict.value)"/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8"> <el-table
<el-col :span="1.5"> :header-cell-style="{
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" background: '#F2F4F9',
v-hasPermi="['system:menu:create']">新增</el-button> color: '#606266',
</el-col> }"
<el-col :span="1.5"> border
<el-button type="info" plain icon="el-icon-sort" size="mini" @click="toggleExpandAll">展开/折叠</el-button> style="width: 100%"
</el-col> v-if="refreshTable"
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> v-loading="loading"
</el-row> :data="menuList"
row-key="id"
:default-expand-all="isExpandAll"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }">
<el-table-column
prop="name"
label="菜单名称"
:show-overflow-tooltip="true"
width="250"></el-table-column>
<el-table-column prop="icon" label="图标" align="center" width="100">
<template v-slot="scope">
<svg-icon :icon-class="scope.row.icon" />
</template>
</el-table-column>
<el-table-column prop="sort" label="排序" width="60"></el-table-column>
<el-table-column
prop="permission"
label="权限标识"
:show-overflow-tooltip="true" />
<el-table-column
prop="component"
label="组件路径"
:show-overflow-tooltip="true" />
<el-table-column
prop="componentName"
label="组件名称"
:show-overflow-tooltip="true" />
<el-table-column prop="status" label="状态" width="80">
<template v-slot="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column
label="操作"
align="center"
class-name="small-padding fixed-width">
<template v-slot="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:menu:update']">
修改
</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-plus"
@click="handleAdd(scope.row)"
v-hasPermi="['system:menu:create']">
新增
</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['system:menu:delete']">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<el-table v-if="refreshTable" v-loading="loading" :data="menuList" row-key="id" :default-expand-all="isExpandAll" <!-- 添加或修改菜单对话框 -->
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"> <el-dialog :visible.sync="open" width="800px" append-to-body class="dialog">
<el-table-column prop="name" label="菜单名称" :show-overflow-tooltip="true" width="250"></el-table-column> <template #title>
<el-table-column prop="icon" label="图标" align="center" width="100"> <slot name="title">
<template v-slot="scope"> <div class="titleStyle">{{ title }}</div>
<svg-icon :icon-class="scope.row.icon" /> </slot>
</template> </template>
</el-table-column> <slot />
<el-table-column prop="sort" label="排序" width="60"></el-table-column> <el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-table-column prop="permission" label="权限标识" :show-overflow-tooltip="true" /> <el-row>
<el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true" /> <el-col :span="24">
<el-table-column prop="componentName" label="组件名称" :show-overflow-tooltip="true" /> <el-form-item label="上级菜单">
<el-table-column prop="status" label="状态" width="80"> <treeselect
<template v-slot="scope"> v-model="form.parentId"
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/> :options="menuOptions"
</template> :normalizer="normalizer"
</el-table-column> :show-count="true"
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> placeholder="选择上级菜单" />
<template v-slot="scope"> </el-form-item>
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" </el-col>
v-hasPermi="['system:menu:update']">修改</el-button> <el-col :span="24">
<el-button size="mini" type="text" icon="el-icon-plus" @click="handleAdd(scope.row)" <el-form-item label="菜单类型" prop="type">
v-hasPermi="['system:menu:create']">新增</el-button> <el-radio-group v-model="form.type">
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" <el-radio
v-hasPermi="['system:menu:delete']">删除</el-button> v-for="dict in menuTypeDictDatas"
</template> :key="parseInt(dict.value)"
</el-table-column> :label="parseInt(dict.value)">
</el-table> {{ dict.label }}
</el-radio>
<!-- 添加或修改菜单对话框 --> </el-radio-group>
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body> </el-form-item>
<el-form ref="form" :model="form" :rules="rules" label-width="100px"> </el-col>
<el-row> <el-col :span="24">
<el-col :span="24"> <el-form-item v-if="form.type !== 3" label="菜单图标">
<el-form-item label="上级菜单"> <el-popover
<treeselect v-model="form.parentId" :options="menuOptions" :normalizer="normalizer" :show-count="true" placement="bottom-start"
placeholder="选择上级菜单"/> width="460"
</el-form-item> trigger="click"
</el-col> @show="$refs['iconSelect'].reset()">
<el-col :span="24"> <IconSelect ref="iconSelect" @selected="selected" />
<el-form-item label="菜单类型" prop="type"> <el-input
<el-radio-group v-model="form.type"> slot="reference"
<el-radio v-for="dict in menuTypeDictDatas" :key="parseInt(dict.value)" :label="parseInt(dict.value)"> clearable
{{dict.label}}</el-radio> v-model="form.icon"
</el-radio-group> placeholder="点击选择图标">
</el-form-item> <svg-icon
</el-col> v-if="form.icon"
<el-col :span="24"> slot="prefix"
<el-form-item v-if="form.type !== 3" label="菜单图标"> :icon-class="form.icon"
<el-popover placement="bottom-start" width="460" trigger="click" @show="$refs['iconSelect'].reset()"> class="el-input__icon"
<IconSelect ref="iconSelect" @selected="selected" /> style="height: 32px; width: 16px" />
<el-input slot="reference" clearable v-model="form.icon" placeholder="点击选择图标"> <i
<svg-icon v-if="form.icon" slot="prefix" :icon-class="form.icon" class="el-input__icon" v-else
style="height: 32px;width: 16px;"/> slot="prefix"
<i v-else slot="prefix" class="el-icon-search el-input__icon" /> class="el-icon-search el-input__icon" />
</el-input> </el-input>
</el-popover> </el-popover>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="菜单名称" prop="name"> <el-form-item label="菜单名称" prop="name">
<el-input v-model="form.name" placeholder="请输入菜单名称" /> <el-input v-model="form.name" placeholder="请输入菜单名称" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="显示排序" prop="sort"> <el-form-item label="显示排序" prop="sort">
<el-input-number v-model="form.sort" controls-position="right" :min="0" /> <el-input-number
</el-form-item> v-model="form.sort"
</el-col> controls-position="right"
<el-col :span="12"> :min="0" />
<el-form-item v-if="form.type !== 3" label="路由地址" prop="path"> </el-form-item>
<span slot="label"> </el-col>
<el-tooltip content="访问的路由地址,如:`user`。如需外网地址时,则以 `http(s)://` 开头" placement="top"> <el-col :span="12">
<i class="el-icon-question" /> <el-form-item v-if="form.type !== 3" label="路由地址" prop="path">
</el-tooltip> <span slot="label">
路由地址 <el-tooltip
</span> content="访问的路由地址,如:`user`。如需外网地址时,则以 `http(s)://` 开头"
<el-input v-model="form.path" placeholder="请输入路由地址" /> placement="top">
</el-form-item> <i class="el-icon-question" />
</el-col> </el-tooltip>
路由地址
</span>
<el-input v-model="form.path" placeholder="请输入路由地址" />
</el-form-item>
</el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item v-if="form.type !== 1" label="权限标识"> <el-form-item v-if="form.type !== 1" label="权限标识">
<span slot="label"> <span slot="label">
<el-tooltip content="Controller 方法上的权限字符,如:@PreAuthorize(`@ss.hasPermission('system:user:list')`)" placement="top"> <el-tooltip
<i class="el-icon-question" /> content="Controller 方法上的权限字符,如:@PreAuthorize(`@ss.hasPermission('system:user:list')`)"
</el-tooltip> placement="top">
权限字符 <i class="el-icon-question" />
</span> </el-tooltip>
<el-input v-model="form.permission" placeholder="请权限标识" maxlength="50" /> 权限字符
</span>
<el-input
v-model="form.permission"
placeholder="请权限标识"
maxlength="50" />
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.type === 2">
<el-form-item label="组件路径" prop="component">
<el-input
v-model="form.component"
placeholder="例如说system/user/index" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12" v-if="form.type === 2">
<el-form-item label="组件路径" prop="component">
<el-input v-model="form.component" placeholder="例如说system/user/index" />
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.type === 2"> <el-col :span="12" v-if="form.type === 2">
<el-form-item label="组件名称" prop="componentName"> <el-form-item label="组件名称" prop="componentName">
<el-input v-model="form.componentName" placeholder="例如说SystemUser" /> <el-input
v-model="form.componentName"
placeholder="例如说SystemUser" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="菜单状态" prop="status">
<span slot="label">
<el-tooltip
content="选择停用时,路由将不会出现在侧边栏,也不能被访问"
placement="top">
<i class="el-icon-question" />
</el-tooltip>
菜单状态
</span>
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)"
:key="dict.value"
:label="parseInt(dict.value)">
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="form.type !== 3" label="显示状态">
<span slot="label">
<el-tooltip
content="选择隐藏时,路由将不会出现在侧边栏,但仍然可以访问"
placement="top">
<i class="el-icon-question" />
</el-tooltip>
是否显示
</span>
<el-radio-group v-model="form.visible">
<el-radio :key="true" :label="true">显示</el-radio>
<el-radio :key="false" :label="false">隐藏</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="form.type !== 3" label="总是显示">
<span slot="label">
<el-tooltip
content="选择不是时,当该菜单只有一个子菜单时,不展示自己,直接展示子菜单"
placement="top">
<i class="el-icon-question" />
</el-tooltip>
总是显示
</span>
<el-radio-group v-model="form.alwaysShow">
<el-radio :key="true" :label="true">总是</el-radio>
<el-radio :key="false" :label="false">不是</el-radio>
</el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12">
<el-form-item label="菜单状态" prop="status">
<span slot="label">
<el-tooltip content="选择停用时,路由将不会出现在侧边栏,也不能被访问" placement="top">
<i class="el-icon-question" />
</el-tooltip>
菜单状态
</span>
<el-radio-group v-model="form.status">
<el-radio v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)"
:key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="form.type !== 3" label="显示状态">
<span slot="label">
<el-tooltip content="选择隐藏时,路由将不会出现在侧边栏,但仍然可以访问" placement="top">
<i class="el-icon-question" />
</el-tooltip>
是否显示
</span>
<el-radio-group v-model="form.visible">
<el-radio :key="true" :label="true">显示</el-radio>
<el-radio :key="false" :label="false">隐藏</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="form.type !== 3" label="总是显示">
<span slot="label">
<el-tooltip content="选择不是时,当该菜单只有一个子菜单时,不展示自己,直接展示子菜单" placement="top">
<i class="el-icon-question" />
</el-tooltip>
总是显示
</span>
<el-radio-group v-model="form.alwaysShow">
<el-radio :key="true" :label="true">总是</el-radio>
<el-radio :key="false" :label="false">不是</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item v-if="form.type === 2" label="是否缓存"> <el-form-item v-if="form.type === 2" label="是否缓存">
<span slot="label"> <span slot="label">
<el-tooltip content="选择缓存时,则会被 `keep-alive` 缓存,必须填写「组件名称」字段" placement="top"> <el-tooltip
<i class="el-icon-question" /> content="选择缓存时,则会被 `keep-alive` 缓存,必须填写「组件名称」字段"
</el-tooltip> placement="top">
是否缓存 <i class="el-icon-question" />
</span> </el-tooltip>
是否缓存
</span>
<el-radio-group v-model="form.keepAlive"> <el-radio-group v-model="form.keepAlive">
<el-radio :key="true" :label="true">缓存</el-radio> <el-radio :key="true" :label="true">缓存</el-radio>
<el-radio :key="false" :label="false">不缓存</el-radio> <el-radio :key="false" :label="false">不缓存</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button> <el-button class="btnTextStyle" @click="cancel"> </el-button>
<el-button @click="cancel"> </el-button> <el-button type="primary" class="btnTextStyle" @click="submitForm"> </el-button>
</div> </div>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<script> <script>
import { listMenu, getMenu, delMenu, addMenu, updateMenu } from "@/api/system/menu"; import {
import Treeselect from "@riophae/vue-treeselect"; listMenu,
import "@riophae/vue-treeselect/dist/vue-treeselect.css"; getMenu,
import IconSelect from "@/components/IconSelect"; delMenu,
addMenu,
updateMenu,
} from '@/api/system/menu';
import Treeselect from '@riophae/vue-treeselect';
import '@riophae/vue-treeselect/dist/vue-treeselect.css';
import IconSelect from '@/components/IconSelect';
import { SystemMenuTypeEnum, CommonStatusEnum } from '@/utils/constants' import { SystemMenuTypeEnum, CommonStatusEnum } from '@/utils/constants';
import { getDictDatas, DICT_TYPE } from '@/utils/dict' import { getDictDatas, DICT_TYPE } from '@/utils/dict';
import {isExternal} from "@/utils/validate"; import { isExternal } from '@/utils/validate';
export default { export default {
name: "SystemMenu", name: 'SystemMenu',
components: { Treeselect, IconSelect }, components: { Treeselect, IconSelect },
data() { data() {
return { return {
// //
loading: true, loading: true,
// //
showSearch: true, showSearch: true,
// //
menuList: [], menuList: [],
// //
menuOptions: [], menuOptions: [],
// //
title: "", title: '',
// //
open: false, open: false,
// //
isExpandAll: false, isExpandAll: false,
// //
refreshTable: true, refreshTable: true,
// //
queryParams: { queryParams: {
name: undefined, name: undefined,
visible: undefined visible: undefined,
}, },
// //
form: {}, form: {},
// //
rules: { rules: {
name: [ name: [
{ required: true, message: "菜单名称不能为空", trigger: "blur" } { required: true, message: '菜单名称不能为空', trigger: 'blur' },
], ],
sort: [ sort: [
{ required: true, message: "菜单顺序不能为空", trigger: "blur" } { required: true, message: '菜单顺序不能为空', trigger: 'blur' },
], ],
path: [ path: [
{ required: true, message: "路由地址不能为空", trigger: "blur" } { required: true, message: '路由地址不能为空', trigger: 'blur' },
], ],
status: [ status: [{ required: true, message: '状态不能为空', trigger: 'blur' }],
{ required: true, message: "状态不能为空", trigger: "blur" } },
]
},
// formConfig: [
MenuTypeEnum: SystemMenuTypeEnum, {
CommonStatusEnum: CommonStatusEnum, type: 'input',
// label: '菜单名称',
menuTypeDictDatas: getDictDatas(DICT_TYPE.SYSTEM_MENU_TYPE), placeholder: '菜单名称',
statusDictDatas: getDictDatas(DICT_TYPE.COMMON_STATUS) param: 'name',
}; },
}, {
created() { type: 'select',
this.getList(); label: '状态',
}, selectOptions: getDictDatas(DICT_TYPE.COMMON_STATUS),
methods: { param: 'status',
// defaultSelect: '',
selected(name) { valueField: 'value',
this.form.icon = name; labelField: 'label',
}, filterable: true,
/** 查询菜单列表 */ },
getList() { {
this.loading = true; type: 'button',
listMenu(this.queryParams).then(response => { btnName: '查询',
this.menuList = this.handleTree(response.data, "id"); name: 'search',
this.loading = false; color: 'primary',
}); },
}, {
/** 转换菜单数据结构 */ type: this.$auth.hasPermi('system:menu:create') ? 'separate' : '',
normalizer(node) { },
if (node.children && !node.children.length) { {
delete node.children; type: this.$auth.hasPermi('system:menu:create') ? 'button' : '',
} btnName: '新增',
return { name: 'add',
id: node.id, color: 'success',
label: node.name, plain: true,
children: node.children },
}; ],
},
/** 查询菜单下拉树结构 */
getTreeselect() {
listMenu().then(response => {
this.menuOptions = [];
const menu = { id: 0, name: '主类目', children: [] };
menu.children = this.handleTree(response.data, "id");
this.menuOptions.push(menu);
});
},
//
cancel() {
this.open = false;
this.reset();
},
//
reset() {
this.form = {
id: undefined,
parentId: 0,
name: undefined,
icon: undefined,
type: SystemMenuTypeEnum.DIR,
sort: undefined,
status: CommonStatusEnum.ENABLE,
visible: true,
keepAlive: true,
alwaysShow: true,
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
/** 展开/折叠操作 */
toggleExpandAll() {
this.refreshTable = false;
this.isExpandAll = !this.isExpandAll;
this.$nextTick(() => {
this.refreshTable = true;
});
},
/** 新增按钮操作 */
handleAdd(row) {
this.reset();
this.getTreeselect();
if (row != null && row.id) {
this.form.parentId = row.id;
} else {
this.form.parentId = 0;
}
this.open = true;
this.title = "添加菜单";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
this.getTreeselect();
getMenu(row.id).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改菜单";
});
},
/** 提交按钮 */
submitForm: function() {
this.$refs["form"].validate(valid => {
if (valid) {
// path
if (this.form.type === SystemMenuTypeEnum.DIR
|| this.form.type === SystemMenuTypeEnum.MENU) {
//
const path = this.form.path
if (!isExternal(path)) {
// path /
if (this.form.parentId === 0 && path.charAt(0) !== '/') {
this.$modal.msgSuccess('前端必须以 / 开头')
return
} else if (this.form.parentId !== 0 && path.charAt(0) === '/') {
this.$modal.msgSuccess('前端不能以 / 开头')
return
}
}
}
// //
if (this.form.id !== undefined) { MenuTypeEnum: SystemMenuTypeEnum,
updateMenu(this.form).then(response => { CommonStatusEnum: CommonStatusEnum,
this.$modal.msgSuccess("修改成功"); //
this.open = false; menuTypeDictDatas: getDictDatas(DICT_TYPE.SYSTEM_MENU_TYPE),
this.getList(); statusDictDatas: getDictDatas(DICT_TYPE.COMMON_STATUS),
}); };
} else { },
addMenu(this.form).then(response => { created() {
this.$modal.msgSuccess("新增成功"); this.getList();
this.open = false; },
this.getList(); methods: {
}); buttonClick(val) {
} if (val.btnName === 'search') {
} this.queryParams.name = val.name;
}); this.queryParams.status = val.status;
}, this.getList();
/** 删除按钮操作 */ } else {
handleDelete(row) { this.handleAdd();
this.$modal.confirm('是否确认删除名称为"' + row.name + '"的数据项?').then(function() { }
return delMenu(row.id); },
}).then(() => { //
this.getList(); selected(name) {
this.$modal.msgSuccess("删除成功"); this.form.icon = name;
}).catch(() => {}); },
} /** 查询菜单列表 */
} getList() {
this.loading = true;
listMenu(this.queryParams).then((response) => {
this.menuList = this.handleTree(response.data, 'id');
this.loading = false;
});
},
/** 转换菜单数据结构 */
normalizer(node) {
if (node.children && !node.children.length) {
delete node.children;
}
return {
id: node.id,
label: node.name,
children: node.children,
};
},
/** 查询菜单下拉树结构 */
getTreeselect() {
listMenu().then((response) => {
this.menuOptions = [];
const menu = { id: 0, name: '主类目', children: [] };
menu.children = this.handleTree(response.data, 'id');
this.menuOptions.push(menu);
});
},
//
cancel() {
this.open = false;
this.reset();
},
//
reset() {
this.form = {
id: undefined,
parentId: 0,
name: undefined,
icon: undefined,
type: SystemMenuTypeEnum.DIR,
sort: undefined,
status: CommonStatusEnum.ENABLE,
visible: true,
keepAlive: true,
alwaysShow: true,
};
this.resetForm('form');
},
/** 搜索按钮操作 */
handleQuery() {
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm');
this.handleQuery();
},
/** 展开/折叠操作 */
toggleExpandAll() {
this.refreshTable = false;
this.isExpandAll = !this.isExpandAll;
this.$nextTick(() => {
this.refreshTable = true;
});
},
/** 新增按钮操作 */
handleAdd(row) {
this.reset();
this.getTreeselect();
if (row != null && row.id) {
this.form.parentId = row.id;
} else {
this.form.parentId = 0;
}
this.open = true;
this.title = '添加菜单';
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
this.getTreeselect();
getMenu(row.id).then((response) => {
this.form = response.data;
this.open = true;
this.title = '修改菜单';
});
},
/** 提交按钮 */
submitForm: function () {
this.$refs['form'].validate((valid) => {
if (valid) {
// path
if (
this.form.type === SystemMenuTypeEnum.DIR ||
this.form.type === SystemMenuTypeEnum.MENU
) {
//
const path = this.form.path;
if (!isExternal(path)) {
// path /
if (this.form.parentId === 0 && path.charAt(0) !== '/') {
this.$modal.msgSuccess('前端必须以 / 开头');
return;
} else if (this.form.parentId !== 0 && path.charAt(0) === '/') {
this.$modal.msgSuccess('前端不能以 / 开头');
return;
}
}
}
//
if (this.form.id !== undefined) {
updateMenu(this.form).then((response) => {
this.$modal.msgSuccess('修改成功');
this.open = false;
this.getList();
});
} else {
addMenu(this.form).then((response) => {
this.$modal.msgSuccess('新增成功');
this.open = false;
this.getList();
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
this.$modal
.delConfirm(row.name)
.then(function () {
return delMenu(row.id);
})
.then(() => {
this.getList();
this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
},
},
}; };
</script> </script>
<style scoped>
.app-container >>> .el-table .el-table__cell {
padding: 0;
height: 35px;
}
.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;
}
.dialog >>> .btnTextStyle {
letter-spacing: 6px;
padding: 9px 10px 9px 16px;
font-size: 14px;
}
</style>

View File

@ -1,36 +1,18 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> <search-bar
<el-form-item label="岗位编码" prop="code"> :formConfigs="formConfig"
<el-input v-model="queryParams.code" placeholder="请输入岗位编码" clearable @keyup.enter.native="handleQuery"/> ref="searchBarForm"
</el-form-item> @headBtnClick="buttonClick" />
<el-form-item label="岗位名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入岗位名称" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="岗位状态" clearable>
<el-option v-for="dict in statusDictDatas" :key="parseInt(dict.value)" :label="dict.label" :value="parseInt(dict.value)"/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8"> <el-table
<el-col :span="1.5"> :header-cell-style="{
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" background: '#F2F4F9',
v-hasPermi="['system:post:create']">新增</el-button> color: '#606266',
</el-col> }"
<el-col :span="1.5"> border
<el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport" :loading="exportLoading" style="width: 100%"
v-hasPermi="['system:post:export']">导出</el-button> v-loading="loading" :data="postList">
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="postList">
<el-table-column label="岗位编号" align="center" prop="id" /> <el-table-column label="岗位编号" align="center" prop="id" />
<el-table-column label="岗位编码" align="center" prop="code" /> <el-table-column label="岗位编码" align="center" prop="code" />
<el-table-column label="岗位名称" align="center" prop="name" /> <el-table-column label="岗位名称" align="center" prop="name" />
@ -59,7 +41,13 @@
@pagination="getList"/> @pagination="getList"/>
<!-- 添加或修改岗位对话框 --> <!-- 添加或修改岗位对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body> <el-dialog :visible.sync="open" width="800px" append-to-body class="dialog">
<template #title>
<slot name="title">
<div class="titleStyle">{{ title }}</div>
</slot>
</template>
<slot />
<el-form ref="form" :model="form" :rules="rules" label-width="80px"> <el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="岗位名称" prop="name"> <el-form-item label="岗位名称" prop="name">
<el-input v-model="form.name" placeholder="请输入岗位名称" /> <el-input v-model="form.name" placeholder="请输入岗位名称" />
@ -81,8 +69,8 @@
</el-form-item> </el-form-item>
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button> <el-button class="btnTextStyle" @click="cancel"> </el-button>
<el-button @click="cancel"> </el-button> <el-button type="primary" class="btnTextStyle" @click="submitForm"> </el-button>
</div> </div>
</el-dialog> </el-dialog>
</div> </div>
@ -135,6 +123,56 @@ export default {
] ]
}, },
formConfig: [
{
type: 'input',
label: '岗位编码',
placeholder: '岗位编码',
param: 'code',
},
{
type: 'input',
label: '岗位名称',
placeholder: '岗位名称',
param: 'name',
},
{
type: 'select',
label: '状态',
selectOptions: getDictDatas(DICT_TYPE.COMMON_STATUS),
param: 'status',
defaultSelect: '',
valueField: 'value',
labelField: 'label',
filterable: true,
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: this.$auth.hasPermi('system:post:create') ? 'separate' : '',
},
{
type: this.$auth.hasPermi('system:post:create') ? 'button' : '',
btnName: '新增',
name: 'add',
color: 'success',
plain: true,
},
{
type: this.$auth.hasPermi('system:post:export') ? 'separate' : '',
},
{
type: this.$auth.hasPermi('system:post:export') ? 'button' : '',
btnName: '导出',
name: 'export',
color: 'primary',
plain: true,
},
],
// //
CommonStatusEnum: CommonStatusEnum, CommonStatusEnum: CommonStatusEnum,
// //
@ -145,6 +183,19 @@ export default {
this.getList(); this.getList();
}, },
methods: { methods: {
buttonClick(val) {
if (val.btnName === 'search') {
this.queryParams.name = val.name;
this.queryParams.code = val.code;
this.queryParams.status = val.status;
this.getList();
} else if (val.btnName === 'export'){
this.handleExport()
}
else {
this.handleAdd();
}
},
/** 查询岗位列表 */ /** 查询岗位列表 */
getList() { getList() {
this.loading = true; this.loading = true;
@ -220,7 +271,8 @@ export default {
/** 删除按钮操作 */ /** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
const ids = row.id; const ids = row.id;
this.$modal.confirm('是否确认删除岗位编号为"' + ids + '"的数据项?').then(function() { this.$modal
.delConfirm(row.name).then(function() {
return delPost(ids); return delPost(ids);
}).then(() => { }).then(() => {
this.getList(); this.getList();
@ -241,3 +293,36 @@ export default {
} }
}; };
</script> </script>
<style scoped>
.app-container >>> .el-table .el-table__cell {
padding: 0;
height: 35px;
}
.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;
}
.dialog >>> .btnTextStyle {
letter-spacing: 6px;
padding: 9px 10px 9px 16px;
font-size: 14px;
}
</style>

View File

@ -144,21 +144,24 @@ export default {
this.chart.getZr().off('click'); this.chart.getZr().off('click');
this.chart.getZr().on('click', function () { this.chart.getZr().on('click', function () {
if (_this.targetId !== '') { if (_this.targetId !== '') {
switch (_this.targetId) { _this.$router.push({
case 1: path: `warehouse-manage${_this.targetId}/InventoryOverview/` + _this.targetId,
_this.$router.push({ });
path: 'warehouse-manage1/InventoryOverview/' + _this.targetId, // switch (_this.targetId) {
}); // case 1:
break; // _this.$router.push({
case '1818175999715164161': // path: 'warehouse-manage1/InventoryOverview/' + _this.targetId,
_this.$router.push({ // });
path: 'warehouse-manage2/InventoryOverview/' + _this.targetId, // break;
}); // case '1818175999715164161':
break; // _this.$router.push({
default: // path: 'warehouse-manage2/InventoryOverview/' + _this.targetId,
console.log(_this.targetId); // });
break; // break;
} // default:
// console.log(_this.targetId);
// break;
// }
} }
}); });
}, },

View File

@ -2,7 +2,7 @@
* @Author: zwq * @Author: zwq
* @Date: 2024-07-02 15:56:48 * @Date: 2024-07-02 15:56:48
* @LastEditors: zwq * @LastEditors: zwq
* @LastEditTime: 2024-08-02 14:57:52 * @LastEditTime: 2024-09-23 09:15:30
* @Description: * @Description:
--> -->
<template> <template>
@ -59,21 +59,24 @@ export default {
}, },
methods: { methods: {
toPage(i) { toPage(i) {
switch (i.id) { this.$router.push({
case 1: path: `warehouse-manage${i.id}/InventoryOverview/` + i.id,
this.$router.push({
path: 'warehouse-manage1/InventoryOverview/' + i.id,
}); });
break; // switch (i.id) {
case '1818175999715164161': // case 1:
this.$router.push({ // this.$router.push({
path: 'warehouse-manage2/InventoryOverview/' + i.id, // path: 'warehouse-manage1/InventoryOverview/' + i.id,
}); // });
break; // break;
default: // case '1818175999715164161':
console.log(i.id); // this.$router.push({
break; // path: 'warehouse-manage2/InventoryOverview/' + i.id,
} // });
// break;
// default:
// console.log(i.id);
// break;
// }
}, },
}, },
}; };