Commit 87eb6d2c authored by jingnan's avatar jingnan 👀

首页站位统计及问题项管理开发

parent 8d03dd62
/** /** * @Description:问题项管理 * @author gjn * @date 2024/7/11 */
* @Description:物料缺件分析
* @author gjn
* @date 2023/12/04
*/
<template> <template>
<div ref="pieDom" style="height: 200px; width:200px" /> <el-card id="rightCenterPaneBottom" class="rightCenterPaneBottom">
<el-row slot="header" class="clearfix">
<el-col :span="3" class="link" @click.native="handleClick">问题项管理</el-col>
<el-col :span="21">
<el-form :model="form" label-width="90px" :inline="true">
<el-form-item label="机型:" prop="planeType">
<el-select v-model="form.planeType" size="small" style="width: 100px;">
<el-option
v-for="item in dataModel"
:key="item.id"
:label="item.resName"
:value="item.resCode"
/>
</el-select>
</el-form-item>
<el-form-item label="架次:" prop="sorties">
<el-select v-model="form.sorties" style="width: 100px;" size="small" filterable>
<el-option
v-for="item in dataSorties"
:key="item.id"
:label="item.defCode"
:value="item.defCode"
/>
</el-select>
</el-form-item>
<el-form-item label="责任部门:" prop="sorties">
<el-input
v-model="form.department"
class="input-with-select el-input--small"
placeholder="请输入"
clearable
style="width: 100px;"
@change="departmentChange"
/>
</el-form-item>
</el-form>
</el-col>
</el-row>
<div id="bottomBarChart" style="height: 40vh; width: 100%;margin-top: 20px;" />
</el-card>
</template> </template>
<script> <script>
import { post } from '@/utils/http'
export default { export default {
props: { name: 'RightCenterPaneBottom',
item: { components: { },
type: Object, props: {},
default: () => {}
}
},
data() { data() {
return { return {
pieEcharts: '', form: {
pieOption: {}, planeType: '',
datas: [], sorties: ''
hideColor: '#E2E7EB' },
dataModel: [],
dataSorties: [],
xAxisData: ['安全', '工艺', '设计', '质量', '物料', '设备', '工装', '工具', '其他'],
seriesData: []
} }
}, },
mounted() { computed: {},
this.datas = [ watch: {
{ 'form.planeType': {
value: this.item.present, immediate: true,
name: this.item.present + '%' handler(val) {
}, if (!val) {
{ return
value: 100 - this.item.present, }
name: (100 - this.item.present) + '%' this.$set(this.form, 'sorties', '')
this.getAircraftSorties()
} }
] },
'form.sorties': {
this.pieEcharts = this.$echarts.init(this.$refs.pieDom) immediate: true,
this.setPieOption() handler(val) {
this.setPieEvents() if (!val) {
return
}
this.getExtPositionView()
}
},
// 授权部门下拉列表
authOrgOptions: []
},
created() {},
mounted() {
this.getModelData()
},
beforeDestroy() {
if (this.chart) {
this.chart.dispose() // 清理ECharts实例,避免内存泄漏
}
window.removeEventListener('resize', this.chart.resize)
}, },
methods: { methods: {
setPieOption() { /**
this.pieOption = { * 获取机型
color: [this.item.color, this.hideColor], // 环形的分段色值设置 */
title: { getModelData() {
text: this.item.name, this.modelData = []
color: '#3F3F3F', const params = {
bottom: -4, searchItems: { items: [] },
right: 'center', sortItem: [{ fieldName: 'modifyTime', sortOrder: 'asc' }]
textStyle: { }
fontSize: 15 this.$api
.searchApi('AircraftType', params)
.then((res) => {
if (res.items && res.items.content && res.items.content.length) {
this.dataModel = res.items.content.map((p) => {
return {
id: p.id,
resCode: p.defCode,
resName: p.defName
}
})
if (this.dataModel.length) { this.form.planeType = this.dataModel[0].resCode }
} }
})
.catch((err) => console.log(err))
.finally(() => {})
},
/**
* 获取架次数据
*/
getAircraftSorties() {
const params = {
searchItems: {
items: [
{
fieldName: 'aircraftType.defName',
operator: 'EQ',
value: this.form.planeType
}
]
}, },
tooltip: { sortItem: [{ fieldName: 'defCode', sortOrder: 'asc' }]
trigger: 'item', }
position: (point, params, dom, rect, size) => { this.dataSorties = []
return [point[0], point[1]] this.$api
.searchApi('AircraftSorties', params)
.then((res) => {
if (res.items && res.items.content && res.items.content.length) {
this.dataSorties = res.items.content.map((p) => {
return {
id: p.id,
defCode: p.defCode
}
})
if (this.dataSorties.length) { this.form.sorties = this.dataSorties[0].defCode }
} }
}, })
series: [{ .catch((err) => console.log(err))
type: 'pie', .finally(() => {})
radius: ['50%', '70%'], // 内存 、外层 },
avoidLabelOverlap: false, getExtPositionView() {
hoverAnimation: true, this.seriesData = []
hoverOffset: 2, let queryStr = ''
label: { if (this.form.department) {
normal: { queryStr = `&department=${this.form.department}`
show: false, // 中间的标签 }
position: 'center', post(
textStyle: { `/SpotProblem/board/spotProblemWithSortie?aircraftType=${this.form.planeType}&sorties=${this.form.sorties}${queryStr}`
fontSize: '18', )
fontWeight: 'bold' .then((res) => {
if (res && res.items) {
this.xAxisData.map(key => {
if (res.items[key]) {
this.seriesData.push(res.items[key])
} else {
this.seriesData.push(0)
} }
}, })
emphasis: { this.$nextTick(function() {
this.initChart()
})
}
})
.catch((err) => {
console.log(err)
})
},
initChart() {
const that = this
that.chart = this.$echarts.init(document.getElementById('bottomBarChart'))
const option = {
toolbox: {
feature: {
dataView: { show: false, readOnly: false },
magicType: { show: true, type: ['line', 'bar'] },
restore: { show: true },
saveAsImage: { show: true }
}
},
legend: {
data: ['问题数量'],
top: 10
},
xAxis: {
type: 'category',
data: that.xAxisData,
axisPointer: {
type: 'shadow'
}
},
yAxis: {
type: 'value'
},
series: [
{
name: '问题数量',
data: that.seriesData,
type: 'bar',
// 在柱子内顶端显示数量
label: {
show: true, show: true,
textStyle: { position: 'insideTop',
fontSize: '18', color: '#fff', // 根据背景色调整
fontWeight: 'bold' formatter: '{c}'
},
itemStyle: {
normal: {
shadowBlur: 20, // 阴影的模糊大小
shadowColor: 'rgba(0, 0, 0, 0.5)', // 阴影颜色
shadowOffsetY: -6, // 阴影Y轴方向上的偏移
shadowOffsetX: 8, //
color: '#6dc5f5', // 正常状态下的颜色
barBorderRadius: 0 // 圆角大小,如果需要的话
},
emphasis: {
color: '#6bc2f6' // 高亮状态下的颜色
} }
} }
}, }
labelLine: { ]
normal: {
show: false
}
},
selectedOffset: 0,
itemStyle: {
emphasis: {
}
},
data: this.datas
}]
} }
// 渲染图表
this.pieEcharts.setOption(this.pieOption) that.chart.setOption(option)
window.addEventListener('resize', function() { that.chart.resize() })
this.setupResizeObserver()
}, },
/** departmentChange() {
* 设置图表的事件 this.getExtPositionView()
*/ },
setPieEvents() { handleClick() {
/** this.$router.push({
* 刷新时默认显示第一条 path: '/page/48d01892-3cb9-4ad9-908a-19887f0a6abe',
*/ query: {
this.pieEcharts.dispatchAction( title: '现场问题',
{ menuRootAppId: 1626782774926
type: 'highlight',
seriesIndex: 0,
dataIndex: 0
}
)
/**
* 鼠标移入图表时,不为第一条时就取消第一条的高亮效果
*/
this.pieEcharts.on('mouseover', (v) => {
if (v.dataIndex !== 0) {
this.pieEcharts.dispatchAction({
type: 'downplay',
seriesIndex: 0,
dataIndex: 0
})
} }
}) })
/** },
* 鼠标图表时默认显示第一条 setupResizeObserver() {
*/ const resizeObserver = new ResizeObserver(entries => {
this.pieEcharts.on('mouseout', (v) => { for (const entry of entries) {
this.pieEcharts.dispatchAction( if (entry.target === document.getElementById('rightCenterPaneBottom')) {
{ // 调用 ECharts 的 resize 方法
type: 'highlight', if (this.chart) {
seriesIndex: 0, this.chart.resize()
dataIndex: 0 }
} }
) }
})
// 确保 $refs.rightCenterPaneBottom 是一个 DOM 元素
if (document.getElementById('rightCenterPaneBottom') instanceof Element) {
resizeObserver.observe(document.getElementById('rightCenterPaneBottom'))
} else {
console.error('rightCenterPaneBottom is not a DOM element')
}
// 组件销毁时断开 ResizeObserver
this.$once('hook:beforeDestroy', () => {
resizeObserver.disconnect()
}) })
// 监听窗口变化 - 只刷新最后一个图表
// window.onresize = () => {
// this.pieEcharts.resize()
// }
// 监听窗口变化 - 多个图表同时刷新
// window.addEventListener('resize', () => {
// this.pieEcharts.resize()
// })
} }
} }
} }
</script> </script>
<style lang="scss">
<style scoped> .rightCenterPaneBottom {
width: 100%;
height: 100%;
.el-card__header {
overflow: auto;
height: 60px;
padding: 8px 10px;
font-size: 14px;
font-weight: 600;
.el-form-item{
margin-bottom: 6px!important;
margin-right: 0px!important;
}
}
.clearfix {
height: 40px;
line-height: 40px;
}
}
</style> </style>
/** /** * @Description:站位完工统计 * @author gjn * @date 2024/7/14 */
* @Description:站位完工统计
* @author gjn
* @date 2023/12/04
*/
<template> <template>
<el-card class="rightCenterPaneTop"> <el-card id="rightCenterPaneTop" class="rightCenterPaneTop">
<div slot="header" class="clearfix"> <el-row slot="header" class="clearfix">
<span>站位完工统计</span> <el-col :span="4" class="link" @click.native="handleClick">站位完工统计</el-col>
<el-col :span="20">
<el-form :model="form" label-width="70px" :inline="true">
<el-form-item label="机型:" prop="planeType">
<el-select v-model="form.planeType" size="small">
<el-option
v-for="item in dataModel"
:key="item.id"
:label="item.resName"
:value="item.resCode"
/>
</el-select>
</el-form-item>
<el-form-item label="架次:" prop="sorties">
<el-select v-model="form.sorties" size="small" filterable>
<el-option
v-for="item in dataSorties"
:key="item.id"
:label="item.defCode"
:value="item.defCode"
/>
</el-select>
</el-form-item>
</el-form>
</el-col>
</el-row>
<div style="width: 100%">
<div v-if="showPieChatBox" class="pieChatBox">
<StationPie
v-for="(item, index) in materialLists"
:key="index"
:item="item"
/>
</div>
<div v-else class="pieChatBox" />
<div id="barChart" style="height: 30vh; width: 100%" />
</div> </div>
<div id="topChart" style="height:400px;width: 100%" />
</el-card> </el-card>
</template> </template>
<script> <script>
import { get } from '@/utils/http'
import StationPie from './stationPie.vue'
export default { export default {
name: '', name: '',
components: {}, components: { StationPie },
props: {}, props: {},
data() { data() {
return {} return {
form: {
planeType: '',
sorties: ''
},
dataModel: [],
dataSorties: [],
xAxisData: [],
seriesData: [],
maxValueOfCountAO: 100,
materialLists: [],
showPieChatBox: false
}
}, },
computed: {}, computed: {},
watch: {}, watch: {
'form.planeType': {
immediate: true,
handler(val) {
if (!val) {
return
}
this.$set(this.form, 'sorties', '')
this.getAircraftSorties()
}
},
'form.sorties': {
immediate: true,
handler(val) {
if (!val) {
return
}
this.getExtPositionView()
}
}
},
created() {}, created() {},
mounted() { mounted() {
this.$nextTick(function() { this.getModelData()
this.initChart() },
beforeDestroy() {
if (this.chart) {
this.chart.dispose() // 清理ECharts实例,避免内存泄漏
}
window.removeEventListener('resize', this.chart.resize)
this.$once('beforeUnmount', () => {
this.disconnect()
}) })
}, },
methods: { methods: {
/**
* 获取机型
*/
getModelData() {
this.modelData = []
const params = {
searchItems: { items: [] },
sortItem: [{ fieldName: 'modifyTime', sortOrder: 'asc' }]
}
this.$api
.searchApi('AircraftType', params)
.then((res) => {
if (res.items && res.items.content && res.items.content.length) {
this.dataModel = res.items.content.map((p) => {
return {
id: p.id,
resCode: p.defCode,
resName: p.defName
}
})
if (this.dataModel.length) { this.form.planeType = this.dataModel[0].resCode }
}
})
.catch((err) => console.log(err))
.finally(() => {})
},
/**
* 获取架次数据
*/
getAircraftSorties() {
const params = {
searchItems: {
items: [
{
fieldName: 'aircraftType.defName',
operator: 'EQ',
value: this.form.planeType
}
]
},
sortItem: [{ fieldName: 'defCode', sortOrder: 'asc' }]
}
this.dataSorties = []
this.$api
.searchApi('AircraftSorties', params)
.then((res) => {
if (res.items && res.items.content && res.items.content.length) {
this.dataSorties = res.items.content.map((p) => {
return {
id: p.id,
defCode: p.defCode
}
})
if (this.dataSorties.length) { this.form.sorties = this.dataSorties[0].defCode }
}
})
.catch((err) => console.log(err))
.finally(() => {})
},
getExtPositionView() {
this.showPieChatBox = false
get(
`/ExtProcessPlan/homeAoCondition?planeType=${this.form.planeType}&sorties=${this.form.sorties}`
)
.then((res) => {
if (res && res.items) {
this.xAxisData = Object.keys(res.items)
this.materialLists = Object.keys(res.items).map((key) => ({
name: key,
...res.items[key],
countUndone: res.items[key].countAO - res.items[key].countNotOk - res.items[key].countCarry
}))
this.seriesData = [
{
name: '未开始',
type: 'bar',
tooltip: {
valueFormatter: function(value) {
return value
}
},
itemStyle: {
normal: {
shadowBlur: 10, // 阴影的模糊大小
shadowColor: 'rgba(0, 0, 0, 0.5)', // 阴影颜色
shadowOffsetY: 5, // 阴影Y轴方向上的偏移
color: 'blue'
}
},
data: this.xAxisData.map(
(category) =>
res.items[category].countAO -
res.items[category].countNotOk -
res.items[category].countCarry
)
},
{
name: '执行中',
type: 'bar',
tooltip: {
valueFormatter: function(value) {
return value
}
},
itemStyle: {
normal: {
shadowBlur: 10, // 阴影的模糊大小
shadowColor: 'rgba(0, 0, 0, 0.5)', // 阴影颜色
shadowOffsetY: 5, // 阴影Y轴方向上的偏移
color: '#f2743a'
}
},
data: this.xAxisData.map(
(category) => res.items[category].countNotOk
)
},
{
name: '已完成',
type: 'bar',
itemStyle: {
normal: {
shadowBlur: 10, // 阴影的模糊大小
shadowColor: 'rgba(0, 0, 0, 0.5)', // 阴影颜色
shadowOffsetY: 5, // 阴影Y轴方向上的偏移
color: '#13b346'
}
},
data: this.xAxisData.map(
(category) => res.items[category].countCarry
)
},
{
name: '完工率',
type: 'line',
yAxisIndex: 1,
tooltip: {
valueFormatter: function(value) {
return value + '%'
}
},
data: this.xAxisData.map((category) => {
const resData =
(res.items[category].countCarry /
res.items[category].countAO) *
100
if (resData > 100) {
return 100
} else if (resData < 0) {
return 0
} else {
return resData.toFixed(2)
}
}),
itemStyle: {
normal: {
shadowBlur: 10, // 阴影的模糊大小
shadowColor: 'rgba(0, 0, 0, 0.5)', // 阴影颜色
shadowOffsetY: 5, // 阴影Y轴方向上的偏移
color: 'red'
}
}
}
]
// 找到 countAO 系列的最大值
const targetData = this.xAxisData.map(
(category) => res.items[category].countAO
)
this.maxValueOfCountAO = Math.max(...targetData)
this.$nextTick(function() {
this.initChart()
})
this.showPieChatBox = true
}
})
.catch((err) => {
console.log(err)
})
},
initChart() { initChart() {
const that = this const that = this
that.chart = this.$echarts.init(document.getElementById('topChart')) that.chart = this.$echarts.init(document.getElementById('barChart'))
const option = { const option = {
color: ['#4DADF6', '#3FD1C2'],
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
axisPointer: { axisPointer: {
type: 'cross', type: 'cross',
crossStyle: { crossStyle: {
color: '#345678' color: '#999'
} }
} }
}, },
// toolbox: { toolbox: {
// feature: { feature: {
// dataView: { show: true, readOnly: false }, dataView: { show: false, readOnly: false },
// magicType: { show: true, type: ['line', 'bar'] }, magicType: { show: true, type: ['line', 'bar'] },
// restore: { show: true }, restore: { show: true },
// saveAsImage: { show: true } saveAsImage: { show: true }
// } }
// }, },
legend: { legend: {
data: ['到账金额', '合同金额'], data: ['未开始', '执行中', '已完成', '完工率'],
right: 100 bottom: 14
}, },
xAxis: [ xAxis: [
{ {
type: 'category', type: 'category',
data: ['51站位', '52站位', '53站位', '54站位', '55站位', '56站位', '57站位'], data: that.xAxisData || [],
axisPointer: { axisPointer: {
type: 'shadow' type: 'shadow'
} }
...@@ -67,49 +314,95 @@ export default { ...@@ -67,49 +314,95 @@ export default {
yAxis: [ yAxis: [
{ {
type: 'value', type: 'value',
name: '', // name: '',
min: 0, min: 0,
max: 250, max: that.maxValueOfCountAO,
interval: 50, interval: that.maxValueOfCountAO / 5,
axisLabel: { axisLabel: {
formatter: '{value}' formatter: '{value}'
} }
}
],
series: [
{
name: '到账金额',
type: 'bar',
tooltip: {
valueFormatter: function(value) {
return value
}
},
data: [
2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3
]
}, },
{ {
name: '合同金额', type: 'value',
type: 'bar', // name: '完工率',
tooltip: { min: 0,
valueFormatter: function(value) { max: 100,
return value axisLabel: {
} formatter: '{value} %'
}, }
data: [
2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3
]
} }
] ],
series: that.seriesData || []
} }
that.chart.setOption(option) that.chart.setOption(option)
window.addEventListener('resize', function() { that.chart.resize() })
this.setupResizeObserver()
},
handleClick() {
this.$router.push({
path: '/page/9c1ec552-9513-4011-8a63-a40016b3a811',
query: {
title: '作业计划执行查询',
menuRootAppId: 1626782774926
}
})
},
setupResizeObserver() {
const resizeObserver = new ResizeObserver(entries => {
for (const entry of entries) {
if (entry.target === document.getElementById('rightCenterPaneTop')) {
// 调用 ECharts 的 resize 方法
if (this.chart) {
this.chart.resize()
}
}
}
})
// 确保 $refs.rightCenterPaneTop 是一个 DOM 元素
if (document.getElementById('rightCenterPaneTop') instanceof Element) {
resizeObserver.observe(document.getElementById('rightCenterPaneTop'))
} else {
console.error('rightCenterPaneTop is not a DOM element')
}
// 组件销毁时断开 ResizeObserver
this.$once('hook:beforeDestroy', () => {
resizeObserver.disconnect()
})
} }
} }
} }
</script> </script>
<style lang="scss"> <style lang="scss">
.rightCenterPaneTop{ .rightCenterPaneTop {
height: 100%; width: 100%;
height: 100%;
.el-card__body{
padding: 10px;
}
.el-card__header {
overflow: auto;
height: 60px;
padding: 8px 10px;
font-size: 14px;
font-weight: 600;
.el-form-item{
margin-bottom: 6px!important;
}
} }
</style> .clearfix {
height: 40px;
line-height: 40px;
}
.pieChatBox {
width: 100%;
height: 10vh;
display: flex;
justify-content: space-evenly;
}
.pieChatBox > div {
flex: 1;
}
}
</style>
/** * @Description:物料缺件分析 * @author gjn * @date 2023/12/04 */
<template>
<div ref="pieDom" style="width: 100%; height: 10vh" />
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => {}
}
},
data() {
return {
pieEcharts: '',
pieOption: {},
datas: []
}
},
watch: {
item: {
deep: true,
immediate: true,
handler(val) {
this.datas = [
{
value: this.item.countUndone,
name: '未开始' // 未完成
},
{
value: this.item.countNotOk,
name: '执行中' // 执行中
},
{
value: this.item.countCarry,
name: '已完成' // 已完成
}
]
this.$nextTick(() => {
this.pieEcharts = this.$echarts.init(this.$refs.pieDom)
this.setPieOption()
this.setPieEvents()
})
}
}
},
mounted() {},
beforeDestroy() {
if (this.pieEcharts) {
this.pieEcharts.dispose() // 清理ECharts实例,避免内存泄漏
}
window.removeEventListener('resize', this.pieEcharts.resize)
},
methods: {
setPieOption() {
this.pieOption = {
color: ['blue', '#f2743a', '#13b346'], // 环形的分段色值设置
title: {
text: this.item.name,
color: '#3F3F3F',
bottom: 0,
right: 'center',
textStyle: {
fontSize: 14
}
},
tooltip: {
trigger: 'item'
},
series: [
{
type: 'pie',
radius: ['50%', '70%'], // 内存 、外层
avoidLabelOverlap: false,
hoverAnimation: true,
hoverOffset: 2,
top: -18,
label: {
normal: {
show: false, // 中间的标签
position: 'center'
},
emphasis: {
show: true,
textStyle: {
fontSize: '12'
}
}
},
labelLine: {
normal: {
show: false
}
},
selectedOffset: 0,
itemStyle: {
emphasis: {}
},
data: this.datas
}
]
}
// 渲染图表
this.pieEcharts.setOption(this.pieOption)
window.addEventListener('resize', function() {
this.pieEcharts.resize()
})
},
/**
* 设置图表的事件
*/
setPieEvents() {
/**
* 刷新时默认显示第一条
*/
this.pieEcharts.dispatchAction({
type: 'highlight',
seriesIndex: 0,
dataIndex: 0
})
/**
* 鼠标移入图表时,不为第一条时就取消第一条的高亮效果
*/
this.pieEcharts.on('mouseover', (v) => {
if (v.dataIndex !== 0) {
this.pieEcharts.dispatchAction({
type: 'downplay',
seriesIndex: 0,
dataIndex: 0
})
}
})
/**
* 鼠标图表时默认显示第一条
*/
this.pieEcharts.on('mouseout', (v) => {
this.pieEcharts.dispatchAction({
type: 'highlight',
seriesIndex: 0,
dataIndex: 0
})
})
// 监听窗口变化 - 只刷新最后一个图表
// window.onresize = () => {
// this.pieEcharts.resize()
// }
// 监听窗口变化 - 多个图表同时刷新
// window.addEventListener('resize', () => {
// this.pieEcharts.resize()
// })
}
}
}
</script>
<style scoped></style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment