Commit 77f328ae authored by jingnan's avatar jingnan 👀

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

parent e6d57b43
/**
* @Description:物料缺件分析
* @author gjn
* @date 2023/12/04
*/
/** * @Description:问题项管理 * @author gjn * @date 2024/7/11 */
<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>
<script>
import { post } from '@/utils/http'
export default {
props: {
item: {
type: Object,
default: () => {}
}
},
name: 'RightCenterPaneBottom',
components: { },
props: {},
data() {
return {
pieEcharts: '',
pieOption: {},
datas: [],
hideColor: '#E2E7EB'
form: {
planeType: '',
sorties: ''
},
dataModel: [],
dataSorties: [],
xAxisData: ['安全', '工艺', '设计', '质量', '物料', '设备', '工装', '工具', '其他'],
seriesData: []
}
},
mounted() {
this.datas = [
{
value: this.item.present,
name: this.item.present + '%'
},
{
value: 100 - this.item.present,
name: (100 - this.item.present) + '%'
computed: {},
watch: {
'form.planeType': {
immediate: true,
handler(val) {
if (!val) {
return
}
this.$set(this.form, 'sorties', '')
this.getAircraftSorties()
}
]
this.pieEcharts = this.$echarts.init(this.$refs.pieDom)
this.setPieOption()
this.setPieEvents()
},
'form.sorties': {
immediate: true,
handler(val) {
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: {
setPieOption() {
this.pieOption = {
color: [this.item.color, this.hideColor], // 环形的分段色值设置
title: {
text: this.item.name,
color: '#3F3F3F',
bottom: -4,
right: 'center',
textStyle: {
fontSize: 15
/**
* 获取机型
*/
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
}
]
},
tooltip: {
trigger: 'item',
position: (point, params, dom, rect, size) => {
return [point[0], point[1]]
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 }
}
},
series: [{
type: 'pie',
radius: ['50%', '70%'], // 内存 、外层
avoidLabelOverlap: false,
hoverAnimation: true,
hoverOffset: 2,
label: {
normal: {
show: false, // 中间的标签
position: 'center',
textStyle: {
fontSize: '18',
fontWeight: 'bold'
})
.catch((err) => console.log(err))
.finally(() => {})
},
getExtPositionView() {
this.seriesData = []
let queryStr = ''
if (this.form.department) {
queryStr = `&department=${this.form.department}`
}
post(
`/SpotProblem/board/spotProblemWithSortie?aircraftType=${this.form.planeType}&sorties=${this.form.sorties}${queryStr}`
)
.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,
textStyle: {
fontSize: '18',
fontWeight: 'bold'
position: 'insideTop',
color: '#fff', // 根据背景色调整
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()
},
/**
* 设置图表的事件
*/
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
})
departmentChange() {
this.getExtPositionView()
},
handleClick() {
this.$router.push({
path: '/page/48d01892-3cb9-4ad9-908a-19887f0a6abe',
query: {
title: '现场问题',
menuRootAppId: 1626782774926
}
})
/**
* 鼠标图表时默认显示第一条
*/
this.pieEcharts.on('mouseout', (v) => {
this.pieEcharts.dispatchAction(
{
type: 'highlight',
seriesIndex: 0,
dataIndex: 0
},
setupResizeObserver() {
const resizeObserver = new ResizeObserver(entries => {
for (const entry of entries) {
if (entry.target === document.getElementById('rightCenterPaneBottom')) {
// 调用 ECharts 的 resize 方法
if (this.chart) {
this.chart.resize()
}
}
)
}
})
// 确保 $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>
<style scoped>
<style lang="scss">
.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>
/**
* @Description:站位完工统计
* @author gjn
* @date 2023/12/04
*/
/** * @Description:站位完工统计 * @author gjn * @date 2024/7/14 */
<template>
<el-card class="rightCenterPaneTop">
<div slot="header" class="clearfix">
<span>站位完工统计</span>
<el-card id="rightCenterPaneTop" class="rightCenterPaneTop">
<el-row slot="header" class="clearfix">
<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 id="topChart" style="height:400px;width: 100%" />
</el-card>
</template>
<script>
import { get } from '@/utils/http'
import StationPie from './stationPie.vue'
export default {
name: '',
components: {},
components: { StationPie },
props: {},
data() {
return {}
return {
form: {
planeType: '',
sorties: ''
},
dataModel: [],
dataSorties: [],
xAxisData: [],
seriesData: [],
maxValueOfCountAO: 100,
materialLists: [],
showPieChatBox: false
}
},
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() {},
mounted() {
this.$nextTick(function() {
this.initChart()
this.getModelData()
},
beforeDestroy() {
if (this.chart) {
this.chart.dispose() // 清理ECharts实例,避免内存泄漏
}
window.removeEventListener('resize', this.chart.resize)
this.$once('beforeUnmount', () => {
this.disconnect()
})
},
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() {
const that = this
that.chart = this.$echarts.init(document.getElementById('topChart'))
that.chart = this.$echarts.init(document.getElementById('barChart'))
const option = {
color: ['#4DADF6', '#3FD1C2'],
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
crossStyle: {
color: '#345678'
color: '#999'
}
}
},
// toolbox: {
// feature: {
// dataView: { show: true, readOnly: false },
// magicType: { show: true, type: ['line', 'bar'] },
// restore: { show: true },
// saveAsImage: { show: true }
// }
// },
toolbox: {
feature: {
dataView: { show: false, readOnly: false },
magicType: { show: true, type: ['line', 'bar'] },
restore: { show: true },
saveAsImage: { show: true }
}
},
legend: {
data: ['到账金额', '合同金额'],
right: 100
data: ['未开始', '执行中', '已完成', '完工率'],
bottom: 14
},
xAxis: [
{
type: 'category',
data: ['51站位', '52站位', '53站位', '54站位', '55站位', '56站位', '57站位'],
data: that.xAxisData || [],
axisPointer: {
type: 'shadow'
}
......@@ -67,49 +314,95 @@ export default {
yAxis: [
{
type: 'value',
name: '',
// name: '',
min: 0,
max: 250,
interval: 50,
max: that.maxValueOfCountAO,
interval: that.maxValueOfCountAO / 5,
axisLabel: {
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: 'bar',
tooltip: {
valueFormatter: function(value) {
return 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
]
type: 'value',
// name: '完工率',
min: 0,
max: 100,
axisLabel: {
formatter: '{value} %'
}
}
]
],
series: that.seriesData || []
}
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>
<style lang="scss">
.rightCenterPaneTop{
height: 100%;
<style lang="scss">
.rightCenterPaneTop {
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