This commit is contained in:
hzz 2025-04-16 17:02:48 +08:00
parent bd8271dea7
commit 2ce62d244e
24 changed files with 1231 additions and 279 deletions

View File

@ -1,7 +1,7 @@
<template>
<ScaleScreen :width="1366" :height="768">
<!-- <ScaleScreen :width="1366" :height="768"> -->
<RouterView />
</ScaleScreen>
<!-- </ScaleScreen> -->
</template>
<script setup>

View File

@ -1,13 +1,7 @@
import request from '@/utils/request'
import useUserStore from '@/store/modules/user'
const userStore = useUserStore()
let devCode = getDevCode()
let userCode = userStore.userCode
let checkQuery = {
devCode,
userCode
}
function getDevCode() {
return localStorage.getItem('devStorage')?JSON.parse(localStorage.getItem('devStorage')).devCode:""
@ -35,29 +29,41 @@ export function getdeviceInfo() {
}
// 查询设备列表
export function getrepairInfoa(query) {
// 查询设备维修单列表
// 设备保养提醒
export function deviceCheck(devCode) {
return request({
url: '/pms/statement/getrepairInfoa',
url: '/mf/deviceCheck',
method: 'get',
params: Object.assign({}, checkQuery, query)
params: { devCode:devCode }
})
}
// 查询保养
export function getmaintenInfoa(query) {
//设备报警记录
export function deviceRepair(devCode) {
return request({
url: '/pms/statement/getmaintenInfoa',
url: '/mf/deviceRepair',
method: 'get',
params: Object.assign({}, checkQuery, query)
params: { devCode }
})
}
// 查询点检
export function getcheckInfoa(query) {
//查询单设产量统计
export function productionChartByDevice(obj) {
return request({
url: '/pms/statement/getcheckInfoa',
url: '/mf/productionChartByDevice',
method: 'get',
params: Object.assign({}, checkQuery, query)
params: obj
})
}
//查询单设备状态统计
export function deviceStatusChartByDevice(obj) {
return request({
url: '/mf/deviceStatusChartByDevice',
method: 'get',
params: obj
})
}

View File

@ -1,41 +0,0 @@
import request from '@/utils/request'
import useUserStore from '@/store/modules/user'
const userStore = useUserStore()
let devCode = JSON.parse(localStorage.getItem('devStorage')).devCode
let userCode = userStore.userCode
let query = {
devCode,
userCode
}
//
export function getWorkStationBaseDeviceInfo() {
return request({
url: '/pms/output/getWorkStationBaseDeviceInfo',
method: 'get',
params:query
})
}
//
export function getCurrentOutputInfo() {
return request({
url: '/pms/output/getCurrentOutputInfo',
method: 'get',
params:query
})
}
//
export function halfHourOutputTotal() {
return request({
url: '/pms/output/halfHourOutputTotal',
method: 'get',
params:query
})
}
//
export function getCurrentAcceptInfo() {
return request({
url: '/pms/output/getCurrentAcceptInfo',
method: 'get',
params:query
})
}

View File

@ -1,46 +0,0 @@
import request from '@/utils/request'
import useUserStore from '@/store/modules/user'
const userStore = useUserStore()
let devCode = JSON.parse(localStorage.getItem('devStorage')).devCode
let userCode = userStore.userCode
let checkQuery = {
devCode,
userCode
}
//
export function getTotalAcceptInfo(query) {
return request({
url: '/pms/output/getTotalAcceptInfo',
method: 'get',
params: Object.assign({}, checkQuery, query)
})
}
export function list(query) {
return request({
url: '/pms/output/ordersList',
method: 'get',
params: Object.assign({}, checkQuery, query)
})
}
//接单
export function acceptOrder(query) {
return request({
url: '/pms/output/acceptOrder',
method: 'get',
params: Object.assign({}, checkQuery, query)
})
}
//开始工作
export function startWork(query) {
return request({
url: '/pms/output/startWork',
method: 'get',
params: Object.assign({}, checkQuery, query)
})
}

View File

@ -1,53 +0,0 @@
import request from '@/utils/request'
// 查询设备维修单列表
export function listRepair(query) {
return request({
url: '/pms/repair/list',
method: 'get',
params: query
})
}
// 查询设备维修单详细
export function getRepair(repairId) {
return request({
url: '/pms/repair/' + repairId,
method: 'get'
})
}
// 新增设备维修单
export function addRepair(data) {
return request({
url: '/pms/repair',
method: 'post',
data: data
})
}
// 修改设备维修单
export function updateRepair(data) {
return request({
url: '/pms/repair',
method: 'put',
data: data
})
}
// 删除设备维修单
export function delRepair(repairId) {
return request({
url: '/pms/repair/' + repairId,
method: 'delete'
})
}
// 设备维修单操作记录
export function selectRepairFLow(query) {
return request({
url: '/pms/repair/selectRepairFLow',
method: 'get',
params: query
})
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

View File

@ -0,0 +1,59 @@
interface ElType extends HTMLElement {
timer: number | null
isScroll: boolean
curTableTopValue: number
}
export default {
created(el: ElType) {
el.timer = null
el.isScroll = true
el.curTableTopValue = 0
},
mounted(el: ElType, binding: { value?: { delay?: number } }) {
const { delay = 15 } = binding.value || {}
const tableDom = el.getElementsByClassName(
'el-scrollbar__wrap'
)[0] as HTMLElement
const viewDom = el.getElementsByClassName(
'el-scrollbar__view'
)[0] as HTMLElement
const onMouseOver = () => (el.isScroll = false)
const onMouseOut = () => {
el.curTableTopValue = tableDom.scrollTop
el.isScroll = true
}
tableDom.addEventListener('mouseover', onMouseOver)
tableDom.addEventListener('mouseout', onMouseOut)
el.timer = window.setInterval(() => {
const viewDomClientHeight = viewDom.scrollHeight
const tableDomClientHeight = el.clientHeight
if (el.isScroll && viewDomClientHeight > tableDomClientHeight*1.5) {
const curScrollPosition = tableDom.clientHeight + el.curTableTopValue
el.curTableTopValue =
curScrollPosition === tableDom.scrollHeight
? 0
: el.curTableTopValue + 1
tableDom.scrollTop = el.curTableTopValue
}
}, delay)
},
unmounted(el: ElType) {
if (el.timer !== null) {
clearInterval(el.timer)
}
el.timer = null
const tableDom = el.getElementsByClassName(
'el-scrollbar__wrap'
)[0] as HTMLElement
tableDom.removeEventListener('mouseover', () => (el.isScroll = false))
tableDom.removeEventListener('mouseout', () => {
el.curTableTopValue = tableDom.scrollTop
el.isScroll = true
})
},
}

View File

@ -52,7 +52,8 @@ let router = useRouter()
let route = useRoute()
let { timeHtml } = useNowTime();
let userStore = useUserStore()
let timeFrame = ref(route.query.timeFrame||'d')
let timeFrame = ref(route.params.timeFrame||'d')
let gridData = ref([
{ text: proxy.tLang('common', '退出登录'), option: logout },
])
@ -62,7 +63,7 @@ function timeFrameChange(val) {
if (val == 'd') {
router.push({ path: '/index' })
} else{
router.push({ path: '/history',query: { timeFrame: val} })
router.push({ path: '/history_'+val })
}
}

View File

@ -1,6 +1,7 @@
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import tableAutoScroll from './directive/tableScroll/tableAutoScroll.ts'
import Cookies from 'js-cookie'
import ElementPlus from 'element-plus'
@ -86,7 +87,7 @@ app.component('v-chart', VECharts)
app.component('DictTag', DictTag)
app.directive('tableAutoScroll', tableAutoScroll)
// app.use(createPinia())
app.use(router)

View File

@ -20,7 +20,7 @@ export const constantRoutes = [
meta: { title: '首页', icon: 'home', affix: true }
},
{
path: '/history',
path: '/history_:timeFrame',
name: 'history',
component: () => import('@/views/history/index.vue'),
meta: { title: '首页', icon: 'home', affix: true }

View File

@ -0,0 +1,98 @@
<template>
<el-table v-bind="$attrs" :data="tableData" header-row-class-name="table_header" :border="border" :stripe="stripe"
style="width: 100%;height: 100%;" @selection-change="handleSelectionChange">
<template v-for="item in columns" :key="item.prop">
<!-- 选择列 -->
<el-table-column v-if="item.type === 'selection'" type="selection" width="55" />
<!-- 序号列 -->
<el-table-column v-else-if="item.type === 'index'" type="index" :width="item.width || '80'"
:label="item.label || tLang('common', '序号')" />
<!-- 普通列 -->
<el-table-column v-else :prop="item.prop" :label="item.label" :width="item.width" :min-width="item.minWidth"
:align="item.align || 'center'">
<!-- 自定义列内容 -->
<template #default="scope" v-if="item.slot">
<slot :name="item.slot" :row="scope.row"></slot>
</template>
</el-table-column>
</template>
</el-table>
</template>
<script setup>
const props = defineProps({
title: {
type: String,
default: ''
},
columns: {
type: Array,
required: true
},
tableData: {
type: Array,
required: true
},
border: {
type: Boolean,
default: false
},
stripe: {
type: Boolean,
default: false
}
})
const emit = defineEmits(['selection-change'])
const handleSelectionChange = (val) => {
emit('selection-change', val)
}
</script>
<style lang="scss" scoped>
.el-table {
--el-table-border-color: transparent;
--el-table-border: none;
--el-table-text-color: #bdbdbe;
--el-table-header-text-color: #bdbdbe;
--el-table-row-hover-bg-color: transparent;
--el-table-current-row-bg-color: transparent;
--el-table-header-bg-color: transparent;
--el-table-bg-color: transparent;
--el-table-tr-bg-color: transparent;
--el-table-expanded-cell-bg-color: transparent;
font-size: 12px;
}
::v-deep(.table_header th) {
background-color: transparent !important;
color: #fff;
text-align: center;
}
.title {
width: 100%;
height: 20px;
line-height: 20px;
font-size: 14px;
color: #cfcfcf;
}
.content {
width: 100%;
height: calc(100% - 20px);
display: flex;
justify-content: center;
align-items: center;
}
.table-container {
width: 100%;
height: 100%;
}
</style>

View File

@ -0,0 +1,221 @@
<template>
<div class="lc-container">
<div class="title">
{{ tLang('common', '耗电量') }}
</div>
<div class="content">
<div class="left">
<v-chart autoresize :option="left_option" theme="dark" style="width: 100%;height: 100%;" />
</div>
<div class="right">
<v-chart :option="line_option" theme="dark" style="width: 100%;height: 100%;" />
</div>
</div>
</div>
</template>
<script setup>
import { computed } from 'vue';
const prop = defineProps({
lineData: {
type: Object,
default: () => {
return {
xAxis: [],
series: []
};
}
}
})
let left_option = computed(() => {
return {
backgroundColor: 'transparent',
series: [
{
type: 'gauge',
axisLine: {
lineStyle: {
width: 10,
color: [
[0.3, '#67e0e3'],
[0.7, '#37a2da'],
[1, '#fd666d']
]
}
},
pointer: {
itemStyle: {
color: 'auto'
}
},
axisTick: {
distance: -10,
length: 8,
lineStyle: {
color: '#fff',
width: 2
}
},
splitLine: {
distance: -10,
length: 3,
lineStyle: {
color: '#fff',
width: 2
}
},
axisLabel: {
color: 'inherit',
distance: 25,
fontSize: 10
},
detail: {
valueAnimation: true,
formatter: '{value} kw·h',
color: 'inherit',
fontSize: 12
},
title: {
color: 'inherit',
offsetCenter: [0, '100%'],
fontSize: 16,
color: '#fff'
},
data: [
{
value: 700,
name: '总耗电量'
}
]
}
]
}
})
let line_option = computed(() => {
return {
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(0, 0, 0, 0.8)',
borderColor: '#00c6ff',
borderWidth: 2,
textStyle: {
color: '#fff',
fontSize: 14
},
formatter: function (params) {
let tooltipText = '';
let xAxisValue = params[0].name;
params.forEach((item) => {
tooltipText += `<div style="padding: 2px 0;"><strong>${item.seriesName}:</strong> ${item.value}</div>`;
});
return `${xAxisValue}<br>${tooltipText}`;
},
padding: 10,
extraCssText: 'border-radius: 8px; box-shadow: 0 0 15px rgba(0, 0, 0, 0.5);'
},
backgroundColor: 'transparent',
// legend: {
// data: ['', ''],
// right: 'left',
// textStyle: {
// color: '#ffff'
// }
// },
grid: {
left: '10%',
bottom:'15%'
},
xAxis: {
type: 'category',
data: prop.lineData.xAxis,
axisLabel: {
color: "#ffffff",
},
},
yAxis: {
type: 'value',
name: '耗电量(kw·h)',
splitLine: {
show: true,
lineStyle: {
type: 'dashed',
color: '#3c3a4a85',
}
},
axisLabel: {
color: "#ffffff",
formatter: function (value) {
return `${value}`;
}
},
},
series: [{
name: '耗电量',
data: prop.lineData.series,
type: 'line',
smooth: true,
itemStyle: {
color: 'rgb(150 ,162 ,116)',
},
lineStyle: {
width: 2,
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0,
color: 'rgb(150 ,162 ,116 ,0.6)'
}, {
offset: 1,
color: 'rgb(150 ,162 ,116 ,0.2)'
}]
}
}
}]
}
})
</script>
<style lang="scss" scoped>
.title {
width: 100%;
height: 20px;
line-height: 20px;
font-size: 14px;
color: #cfcfcf;
}
.content {
width: 100%;
height: calc(100% - 20px);
}
.lc-container {
width: 100%;
height: 100%;
.content {
display: flex;
justify-content: space-between;
align-items: center;
.left {
width: 35%;
height: 100%;
}
.right {
width: 65%;
height: 100%;
}
}
}
</style>

View File

@ -0,0 +1,112 @@
<template>
<v-chart autoresize :option="line_option" theme="dark" style="width: 100%;height: 100%;" />
</template>
<script setup>
const prop = defineProps({
data: {
type: Object,
default: () => {
return {
xAxis: [],
series: []
};
}
}
});
let line_option = computed(() => {
return {
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(0, 0, 0, 0.8)',
borderColor: '#00c6ff',
borderWidth: 2,
textStyle: {
color: '#fff',
fontSize: 14
},
formatter: function (params) {
let tooltipText = '';
let xAxisValue = params[0].name;
params.forEach((item) => {
tooltipText += `<div style="padding: 2px 0;"><strong>${item.seriesName}:</strong> ${item.value}</div>`;
});
return `${xAxisValue}<br>${tooltipText}`;
},
padding: 10,
extraCssText: 'border-radius: 8px; box-shadow: 0 0 15px rgba(0, 0, 0, 0.5);'
},
backgroundColor: 'transparent',
// legend: {
// data: ['', ''],
// right: 'left',
// textStyle: {
// color: '#ffff'
// }
// },
grid: {
left: '10%',
bottom:'15%'
},
xAxis: {
type: 'category',
boundaryGap: false,
data: prop.data.xAxis,
axisLabel: {
color: "#ffffff",
},
},
yAxis: {
type: 'value',
name: '产量',
minInterval: 1,
splitLine: {
show: true,
lineStyle: {
type: 'dashed',
color: '#3c3a4a85',
}
},
axisLabel: {
color: "#ffffff",
formatter: function (value) {
return `${value}`;
}
},
},
series: [{
name: '耗电量',
data: prop.data.series,
type: 'line',
smooth: true,
itemStyle: {
color: 'rgb(150 ,162 ,116)',
},
lineStyle: {
width: 2,
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0,
color: 'rgb(150 ,162 ,116 ,0.6)'
}, {
offset: 1,
color: 'rgb(150 ,162 ,116 ,0.2)'
}]
}
}
}]
}
})
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,61 @@
<template>
<v-chart autoresize :option="options" theme="dark" style="width: 100%;height: 100%;" />
</template>
<script setup>
import { computed, ref } from 'vue';
const prop = defineProps({
data: {
type: Object,
default: () => {
return {
xAxis: [],
series: []
};
}
}
});
const options = computed(() => {
return {
tooltip: {
trigger: 'axis',
axisPointer: {
// Use axis to trigger tooltip
type: 'shadow' // 'shadow' as default; can also be 'line' or 'shadow'
}
},
legend: {},
backgroundColor: 'transparent',
grid: {
left: '3%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: prop.data.xAxis,
},
yAxis: {
name: 'min',
type: 'value',
},
series: prop.data.series.map((item, index) => {
return {
name: item.name,
type: 'line',
stack: 'Total',
areaStyle: {},
emphasis: {
focus: 'series'
},
data: item.data
};
})
}
});
</script>
<style lang="scss" scoped></style>

View File

@ -1,29 +1,226 @@
<template>
<div class="container">
asasdasda + {{ query }}
<div class="left">
<div class="lt box-bg-color">
<div class="title">
{{ proxy.tLang('common', '设备状态分析') }}
</div>
<div class="content">
<div class="status-list">
<div class="status-item" v-for="item of infoList">
<span class="status-name">{{ item.name }}:</span>
<span>{{ item.value }} min</span>
</div>
</div>
<div class="status-chart">
<StackBarChart :data="deviceStatusChartData"></StackBarChart>
</div>
</div>
</div>
<div class="lc box-bg-color">
<Lcenter :lineData="lineData"></Lcenter>
</div>
<div class="lb box-bg-color">
</div>
</div>
<div class="right">
<div class="rt box-bg-color">
<div class="title">{{ tLang('message', '报警维修记录') }}</div>
<div class="content">
<BottomTable v-tableAutoScroll="{ delay: 15 }" :columns="repair_column" :tableData="repair_data">
</BottomTable>
</div>
</div>
<div class="rc box-bg-color">
<div class="title">{{ tLang('message', '保养记录') }}</div>
<div class="content">
<BottomTable v-tableAutoScroll="{ delay: 15 }" :columns="remind_column" :tableData="remind_data">
</BottomTable>
</div>
</div>
<div class="rb box-bg-color">
<div class="title">{{ tLang('message', '产量统计') }}</div>
<div class="content">
<LineChart :data="productionChartData"></LineChart>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { watch } from 'vue';
import { getCurrentInstance, onMounted, watch } from 'vue';
import { useRoute } from 'vue-router';
import StackBarChart from './components/stackBarChart.vue';
import Lcenter from './components/lcenter.vue';
import BottomTable from './components/bottomTable.vue';
import LineChart from './components/lineChart.vue';
import { deviceCheck, deviceRepair, productionChartByDevice, deviceStatusChartByDevice } from '@/api/pms/device'
const { proxy } = getCurrentInstance()
const route = useRoute()
let query = ref(route.query.timeFrame)
watch(() => route.query.timeFrame, (newValue, oldValue) => {
query.value=newValue
let params = ref(route.params.timeFrame)
let deviceStatusChartData = reactive({
xAxis: [],
series: []
})
let devStorage = JSON.parse(localStorage.getItem('devStorage'))
let repair_column = [
{ prop: 'devCode', label: '编码', },
{ prop: 'name', label: '设备名称', },
{ prop: 'subject', label: '报警内容', },
{ prop: 'person', label: '负责人', },
{ prop: 'time', label: '报警时间', }
]
let remind_column = [
{ prop: 'devCode', label: '编码', },
{ prop: 'name', label: '设备名称', },
{ prop: 'subject', label: '保养内容', },
{ prop: 'person', label: '负责人', },
{ prop: 'time', label: '保养时间', }
]
let devTime = reactive({
workTime: 0,
waitTime: 0,
stopTime: 0,
faultTime: 0
})
let infoList = computed(() => {
return [
{ name: '总工作时长', value: devTime.workTime },
{ name: '总待机时长', value: devTime.waitTime },
{ name: '总停机时长', value: devTime.stopTime },
{ name: '总故障时长', value: devTime.faultTime },
]
})
let repair_data = ref()
let remind_data = ref()
let lineData = reactive({
xAxis: ['1', '2', '3', '4', '5'],
series: [0, 0, 0, 0, 0]
})
/**获取保养记录 */
function getDeviceCheck() {
deviceCheck(devStorage.devCode).then(res => {
remind_data.value = res.data
})
}
/**
* 获取维修报警记录
*/
function getDeviceRepair() {
deviceRepair(devStorage.devCode).then(res => {
repair_data.value = res.data
})
}
let productionChartData = reactive({
xAxis: [],
series: []
})
/**
* 设备产量
*/
function getproductionChart() {
productionChartByDevice({ type: params.value, devCode: devStorage.devCode }).then(res => {
productionChartData.xAxis = res.data.map(item => item.date);
productionChartData.series = res.data.map(item => item.num);
})
}
const getDeviceStatusChart = async () => {
const res = await deviceStatusChartByDevice({ type: params.value, devCode: devStorage.devCode });
let data = res.data
let xAxis = []
let series = {
work: [],
wait: [],
stop: [],
fault: []
}
data.forEach(item => {
xAxis.push(item.ts)
series.work.push(item.workTime)
series.wait.push(item.waitTime)
series.stop.push(item.stopTime)
series.fault.push(item.faultTime)
devTime.workTime += item.workTime
devTime.waitTime += item.waitTime
devTime.stopTime += item.stopTime
devTime.faultTime += item.faultTime
})
deviceStatusChartData.xAxis = xAxis;
deviceStatusChartData.series = []
deviceStatusChartData.series.push({
name: proxy.tLang('common', '工作'),
data: series.work
})
deviceStatusChartData.series.push({
name: proxy.tLang('common', '待机'),
data: series.wait
})
deviceStatusChartData.series.push({
name: proxy.tLang('common', '停机'),
data: series.stop
})
deviceStatusChartData.series.push({
name: proxy.tLang('common', '故障'),
data: series.fault
})
}
function init() {
getDeviceStatusChart()
getDeviceCheck()
getDeviceRepair()
getproductionChart()
}
onMounted(() => {
init()
})
</script>
<style lang="scss" scoped>
.title {
width: 100%;
height: 20px;
line-height: 20px;
font-size: 14px;
color: #cfcfcf;
}
.content {
width: 100%;
height: calc(100% - 20px);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.box-bg-color {
background-color: #192124;
border-radius: 5px;
padding: 5px;
box-sizing: border-box;
overflow: hidden;
}
.container {
width: 1366px;
height: 718px;
width: 100vw;
height: calc(100vh - 50px);
padding: 9px 8px;
box-sizing: border-box;
background: #131617;
@ -31,46 +228,94 @@ import { useRoute } from 'vue-router';
display: flex;
justify-content: space-between;
align-items: center;
.left {
width: 895px;
width: 60vw;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
.lt {
width: 100%;
height: 175px;
height: 31.7%;
.content {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
.status-list {
width: 30%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
.status-item {
width: 100%;
height: 26px;
box-sizing: border-box;
padding: 0 20px;
display: flex;
justify-content: space-between;
align-items: center;
.status-name {
font-size: 12px;
color: #999898;
}
span {
margin: 0 10px;
}
}
}
.status-chart {
width: 70%;
height: 100%;
}
}
}
.lc {
width: 100%;
height: 260px;
height: 31.7%;
}
.lb {
width: 100%;
height: 240px;
height: 31.7%;
}
}
.right {
width: 445px;
width: 37.7vw;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
.rt {
width: 100%;
height: 210px;
height: 31%;
}
.rc {
width: 100%;
height: 200px;
height: 31%;
}
.rb {
width: 100%;
height: 270px;
height: 34%;
}
}
}
</style>

View File

@ -8,13 +8,13 @@
<el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
<h3 class="form-title">{{ $t("login.用户登录") }}</h3>
<el-form-item prop="username">
<el-input v-model="loginForm.username" type="text" size="large" auto-complete="off"
<el-input v-model="loginForm.username" type="text" size="large" autocomplete="off"
:placeholder="$t('login.账号')">
<template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="loginForm.password" type="password" size="large" auto-complete="off"
<el-input v-model="loginForm.password" type="password" size="large" autocomplete="off"
:placeholder="$t('login.密码')" @keyup.enter="handleLogin">
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
</el-input>

View File

@ -0,0 +1,65 @@
<template>
<div class="info-container">
<div class="title">{{ tLang('device', '设备信息') }}</div>
<div class="content">
<div class="info-item" v-for="item of infoList">
<span class="info-name">{{ item.name }}:</span>
<span>{{ item.value }}</span>
</div>
</div>
</div>
</template>
<script setup>
let infoList = [
{name: '设备名称', value: '123456789'},
{name: '机架号', value: '123456789'},
{name: '最后保养', value: '123456789'},
]
</script>
<style lang="scss" scoped>
.title {
width: 100%;
height: 20px;
line-height: 20px;
font-size: 14px;
color: #cfcfcf;
}
.content {
width: 100%;
height: calc(100% - 20px);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.info-container {
width: 100%;
height: 100%;
.content {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.info-item {
width: 100%;
height: 26px;
margin: 10px;
display: flex;
justify-content: space-between;
align-items: center;
.info-name {
font-size: 12px;
color: #999898;
}
span {
margin: 0 10px;
}
}
}
}
</style>

View File

@ -0,0 +1,74 @@
<template>
<div class="imagecard-container">
<div class="title">{{ tLang('message', '设备视图') }}</div>
<div class="content">
<el-image style="width: 80%; height: 80%;max-width: 80%;max-height: 80%;" :src="bgimage" fit="contain">
</el-image>
<div class="data" v-if="data.length > 0">
<div class="data-item" v-for="(item, index) in data" :key="index">{{ item.name }}{{ item.value }}</div>
</div>
</div>
</div>
</template>
<script setup>
import bgimage from '@/assets/images/login-background.jpg'
const props = defineProps({
bgimage: {
type: String,
default: ''
},
data: {
type: Object,
default: () => {
return [
{ name: '当前花版名称', value: 'A' },
{ name: '冲孔进度', value: '90%' },
]
}
}
})
</script>
<style lang="scss" scoped>
.title {
width: 100%;
height: 20px;
line-height: 20px;
font-size: 14px;
color: #cfcfcf;
}
.content {
width: 100%;
height: calc(100% - 20px);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.imagecard-container {
width: 100%;
height: 100%;
.content {
.data {
width: 100%;
height: 50px;
display: flex;
justify-content: space-between;
align-items: center;
.data-item {
margin: 0 20px;
font-size: 14px;
color: #cfcfcf;
}
}
}
}
</style>

View File

@ -4,7 +4,7 @@
<div class="title">{{ tLang('message', 'OEE综合设备效率') }}</div>
<div class="content">
<div class="oee-chart">
<v-chart :option="oeeOption" theme="dark" style="width: 100%;height: 100%;" />
<v-chart autoresize :option="oeeOption" theme="dark" style="width: 100%;height: 100%;" />
</div>
<div class="progress">
<div class="progress-item">
@ -62,7 +62,7 @@
</div>
<div class="error-chart">
<v-chart :option="options" theme="dark" style="width: 100%;height: 100%;" />
<v-chart autoresize :option="options" theme="dark" style="width: 100%;height: 100%;" />
</div>
</div>
</div>

View File

@ -106,15 +106,16 @@ const { proxy } = getCurrentInstance();
align-items: center;
.top {
height: 100px;
height: 62%;
width: 100%;
box-sizing: border-box;
display: flex;
justify-content: space-between;
align-items: center;
.top-item {
width: 210px;
height: 100px;
width: 30%;
height: 100%;
padding: 10px;
box-sizing: border-box;
background: #1F2937;
@ -122,7 +123,7 @@ const { proxy } = getCurrentInstance();
}
.bottom {
height: 40px;
height: 23%;
width: 100%;
padding: 5px;
box-sizing: border-box;

View File

@ -11,11 +11,11 @@
<div class="right">
<div class="right-item" v-for="item of devData">
<div class="title">{{ item['label'] }}</div>
<div class="content" v-if="item['type'] == 'status'">
<div class="right-item-content" v-if="item['type'] == 'status'">
<div class="status-box" :style="{ background: statusList[item.value]['color'] }"></div>
<div class="status-title">{{ statusList[item.value]['label'] }}</div>
</div>
<div class="content" v-else>
<div class="right-item-content" v-else>
{{ item['value'] }}
</div>
</div>
@ -55,7 +55,7 @@ let statusList = {
width: 100%;
height: 20px;
line-height: 20px;
font-size: 14px;
font-size: 12px;
color: #cfcfcf;
}
@ -89,8 +89,8 @@ let statusList = {
align-items: center;
.speed-box {
width: 120px;
height: 120px;
width: 90px;
height: 90px;
background: url('./../image/u65.png') no-repeat;
background-size: 100%;
display: flex;
@ -111,23 +111,22 @@ let statusList = {
flex-wrap: wrap;
.right-item {
width: 155px;
height: 74px;
width: 23%;
height: 46%;
padding: 5px;
box-sizing: border-box;
background: #1F2937;
.content {
.right-item-content {
display: flex;
justify-content: space-around;
align-items: center;
flex-direction: column;
.status-box {
width: 20px;
height: 20px;
width: 1em;
height: 1em;
border-radius: 50%;
margin-bottom: 5px;
}
.status-title {

View File

@ -11,11 +11,11 @@
<div class="right">
<div class="right-item" v-for="item of devData">
<div class="title">{{ item['label'] }}</div>
<div class="content" v-if="item['type'] == 'status'">
<div class="right-item-content" v-if="item['type'] == 'status'">
<div class="status-box" :style="{ background: statusList[item.value]['color'] }"></div>
<div class="status-title">{{ statusList[item.value]['label'] }}</div>
</div>
<div class="content" v-else>
<div class="right-item-content" v-else>
{{ item['value'] }}
</div>
</div>
@ -50,7 +50,7 @@ let statusList = {
width: 100%;
height: 20px;
line-height: 20px;
font-size: 14px;
font-size: 12px;
color: #cfcfcf;
}
@ -84,8 +84,8 @@ let statusList = {
align-items: center;
.speed-box {
width: 120px;
height: 120px;
width: 90px;
height: 90px;
background: url('./../image/u65.png') no-repeat;
background-size: 100%;
display: flex;
@ -106,28 +106,30 @@ let statusList = {
flex-wrap: wrap;
.right-item {
width: 200px;
height: 120px;
padding: 15px;
width: 27%;
height: 55%;
padding: 5px;
border-radius: 5px;
box-sizing: border-box;
background: #1F2937;
.content {
.right-item-content {
width: 100%;
height: calc(100% - 20px);
display: flex;
justify-content: space-around;
align-items: center;
flex-direction: column;
.status-box {
width: 30px;
height: 30px;
width: 1em;
height: 1em;
border-radius: 50%;
margin-bottom: 5px;
}
.status-title {
font-size: 12px;
font-size: 10px;
color: #e7e7e7;
}

View File

@ -0,0 +1,138 @@
<template>
<div class="rbottom-container">
<div class="title">{{ tLang('device', '检测结果占比') }}</div>
<div class="content">
<div class="chart">
<v-chart autoresize :option="options" theme="dark" style="width: 100%;height: 100%;" />
</div>
<div class="rate-info">
<div class="ok flex-column">
<span>OK</span>
<span class="rate">{{ 50 }}%</span>
</div>
<div class="ng flex-column">
<span>NG</span>
<span class="rate">{{ 50 }}%</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
const props = defineProps({
})
const {proxy} = getCurrentInstance()
let options = computed(() => {
return {
tooltip: {
trigger: 'item'
},
// legend: {
// top: '5%',
// left: 'center'
// },
backgroundColor: 'transparent',
series: [
{
name: '',
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
padAngle: 5,
itemStyle: {
borderRadius: 10
},
label: {
show: false,
position: 'center'
},
// emphasis: {
// label: {
// show: true,
// fontSize: 40,
// fontWeight: 'bold'
// }
// },
labelLine: {
show: false
},
data: [
{ value: 1048, name: 'OK',itemStyle: {color: '#38D380'} },
{ value: 735, name: 'NG',itemStyle: {color: '#F05A5A'} },
]
}
]
}
})
</script>
<style lang="scss" scoped>
.title {
width: 100%;
height: 20px;
line-height: 20px;
font-size: 12px;
color: #cfcfcf;
}
.content {
width: 100%;
height: calc(100% - 20px);
display: flex;
justify-content: center;
align-items: center;
}
.rbottom-container {
width: 100%;
height: 100%;
.content {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
.chart {
width: 100%;
height: 70%;
display: flex;
justify-content: center;
align-items: center;
}
.rate-info {
width: 100%;
height: 30%;
display: flex;
justify-content: space-between;
align-items: center;
.ok {
width: 40%;
height: 80%;
background: #173027;
margin: 0 10px;
color: #38D380;
}
.ng {
width: 40%;
height: 80%;
background: #372022;
margin: 0 10px;
color: #F05A5A;
}
.flex-column {
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
color: 12px;
.rate {
color: #cfcfcf;
}
}
}
}
}
</style>

View File

@ -2,9 +2,9 @@
<div class="container">
<div class="left">
<div class="lt box-bg-color">
<!-- <Ltop1></Ltop1> -->
<Ltop1></Ltop1>
<!-- <Ltop2></Ltop2> -->
<Ltop3></Ltop3>
<!-- <Ltop3></Ltop3> -->
</div>
<div class="lc">
<!-- <Lcenter1></Lcenter1> -->
@ -15,9 +15,15 @@
</div>
</div>
<div class="right">
<div class="rt box-bg-color"></div>
<div class="rc box-bg-color"></div>
<div class="rb box-bg-color"></div>
<div class="rt box-bg-color">
<imageCard></imageCard>
</div>
<div class="rc box-bg-color">
<devInfo></devInfo>
</div>
<div class="rb box-bg-color">
<Rbottom1></Rbottom1>
</div>
</div>
</div>
</template>
@ -29,6 +35,9 @@ import Ltop3 from './components/ltop3.vue'
import Lcenter1 from './components/lcenter1.vue'
import Lcenter2 from './components/lcenter2.vue'
import bottomTable from './components/bottomTable.vue'
import imageCard from './components/imageCard.vue'
import devInfo from './components/devInfo.vue'
import Rbottom1 from './components/rbottom1.vue'
const columns = [
@ -56,8 +65,8 @@ let tableData = ref([
overflow: hidden;
}
.container {
width: 1366px;
height: 718px;
width: 100vw;
height: calc(100vh - 50px);
padding: 9px 8px;
box-sizing: border-box;
background: #131617;
@ -66,7 +75,7 @@ let tableData = ref([
justify-content: space-between;
align-items: center;
.left {
width: 895px;
width: 65.5vw;
height: 100%;
display: flex;
flex-direction: column;
@ -74,19 +83,19 @@ let tableData = ref([
align-items: center;
.lt {
width: 100%;
height: 175px;
height: 24.4%;
}
.lc {
width: 100%;
height: 260px;
height: 36.2%;
}
.lb {
width: 100%;
height: 240px;
height: 33.4%;
}
}
.right {
width: 445px;
width: 32.6vw;
height: 100%;
display: flex;
flex-direction: column;
@ -94,15 +103,15 @@ let tableData = ref([
align-items: center;
.rt {
width: 100%;
height: 210px;
height: 29.2%;
}
.rc {
width: 100%;
height: 200px;
height: 27.8%;
}
.rb {
width: 100%;
height: 270px;
height: 37.6%;
}
}
}