修复生产监控分页和设备监控筛选
This commit is contained in:
21
docs/生产监控三级模块表单UX验证.md
Normal file
21
docs/生产监控三级模块表单UX验证.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# 生产监控三级模块表单 UX 验证
|
||||||
|
|
||||||
|
## Findings
|
||||||
|
|
||||||
|
- **High** `src/views/planning-production/production-monitoring/equipment-monitoring/index.vue`: 已修复设备监控表格无数据问题。新版请求封装会直接返回业务 `data`,原页面仍按旧版 `res.data` 取值,导致 `status_num` 和设备列表读取为空。
|
||||||
|
- **Medium** `src/views/planning-production/production-monitoring/equipment-monitoring/index.vue`: 已新增设备类别下拉筛选。筛选项放在状态卡片上方,属于查询上下文,不会遮挡状态统计,也会随 5 秒自动刷新一起传参。
|
||||||
|
- **Medium** `src/components/page-table/index.vue`: 已兼容分页对象的 `current/size` 与旧式 `currentPage/pageSize` 字段。这样三级模块或迁移页面使用旧分页字段时,分页跳转和页大小切换能回传两套字段,降低迁移兼容风险。
|
||||||
|
- **Low** `src/views/planning-production/production-monitoring/tray-registration/index.vue`: 托盘登录页面自身没有分页控件,装载电池表、批次弹窗和格式弹窗都显式使用 `pagination=null`。本次未改动托盘登录业务逻辑,分页兼容修复落在共享 `page-table`。
|
||||||
|
|
||||||
|
## Evidence
|
||||||
|
|
||||||
|
- Browser: source-only。当前环境未使用真实登录态打开页面做浏览器操作。
|
||||||
|
- Source checks: 已对照旧版设备监控 `/home/mes/WEBMAN-VUE-APP-develop/webman-vue-app/src/views/planning_production/produce/monitor/device` 的接口与响应结构;旧版使用 `res.data.status_num`,新版请求封装已解包,需要直接读取返回对象。
|
||||||
|
- Build checks: 已通过目标文件 `eslint`、locale JSON 解析和生产构建验证。
|
||||||
|
- Confidence limits: 设备类别筛选参数使用 `device_category_id`,需后端 `production_configuration/device_model/device_management/all` 接口支持该筛选字段;如果后端字段名不同,需要后端或接口层统一。
|
||||||
|
|
||||||
|
## Suggested Shape
|
||||||
|
|
||||||
|
- 设备监控查询区保持一行筛选控件,状态卡片作为快速状态过滤入口。
|
||||||
|
- 状态卡片与设备类别筛选可以叠加过滤,重置只清空设备类别,状态卡片保持当前选择,便于运维人员持续看某类设备在某状态下的情况。
|
||||||
|
- 托盘登录当前是扫码型操作页,批次选择和格式选择比分页更关键;分页兼容应放在共享表格层处理,避免在扫码页引入无关控件。
|
||||||
@@ -169,9 +169,9 @@
|
|||||||
-->
|
-->
|
||||||
<div ref="footer" class="page-table__footer" v-if="pagination">
|
<div ref="footer" class="page-table__footer" v-if="pagination">
|
||||||
<el-pagination
|
<el-pagination
|
||||||
:current-page="pagination.current"
|
:current-page="paginationCurrent"
|
||||||
:page-size="pagination.size || 10"
|
:page-size="paginationSize"
|
||||||
:total="pagination.total"
|
:total="paginationTotal"
|
||||||
:page-sizes="[10, 25, 50, 100, 250, 500]"
|
:page-sizes="[10, 25, 50, 100, 250, 500]"
|
||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
layout="total, sizes, prev, pager, next, jumper"
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
@@ -361,6 +361,21 @@ export default {
|
|||||||
return this.tableSelected.length
|
return this.tableSelected.length
|
||||||
},
|
},
|
||||||
|
|
||||||
|
paginationCurrent () {
|
||||||
|
if (!this.pagination) return 1
|
||||||
|
return Number(this.pagination.current || this.pagination.currentPage || 1)
|
||||||
|
},
|
||||||
|
|
||||||
|
paginationSize () {
|
||||||
|
if (!this.pagination) return 10
|
||||||
|
return Number(this.pagination.size || this.pagination.pageSize || 10)
|
||||||
|
},
|
||||||
|
|
||||||
|
paginationTotal () {
|
||||||
|
if (!this.pagination) return 0
|
||||||
|
return Number(this.pagination.total || 0)
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表头样式:浅灰背景 + 黑色加粗文字
|
* 表头样式:浅灰背景 + 黑色加粗文字
|
||||||
*/
|
*/
|
||||||
@@ -424,16 +439,20 @@ export default {
|
|||||||
onSizeChange (size) {
|
onSizeChange (size) {
|
||||||
this.$emit('page-change', {
|
this.$emit('page-change', {
|
||||||
current: 1,
|
current: 1,
|
||||||
|
currentPage: 1,
|
||||||
size,
|
size,
|
||||||
total: this.pagination.total
|
pageSize: size,
|
||||||
|
total: this.paginationTotal
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
onCurrentChange (current) {
|
onCurrentChange (current) {
|
||||||
this.$emit('page-change', {
|
this.$emit('page-change', {
|
||||||
current,
|
current,
|
||||||
size: this.pagination.size,
|
currentPage: current,
|
||||||
total: this.pagination.total
|
size: this.paginationSize,
|
||||||
|
pageSize: this.paginationSize,
|
||||||
|
total: this.paginationTotal
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -2896,7 +2896,11 @@
|
|||||||
"current_process": "Current Process"
|
"current_process": "Current Process"
|
||||||
},
|
},
|
||||||
"equipment_monitoring": {
|
"equipment_monitoring": {
|
||||||
|
"query": "Search",
|
||||||
|
"reset": "Reset",
|
||||||
"device_total": "Total Devices",
|
"device_total": "Total Devices",
|
||||||
|
"device_category": "Device Category",
|
||||||
|
"select_device_category": "Please select device category",
|
||||||
"device_code": "Device Code",
|
"device_code": "Device Code",
|
||||||
"device_name": "Device Name",
|
"device_name": "Device Name",
|
||||||
"area": "Plant Area",
|
"area": "Plant Area",
|
||||||
|
|||||||
@@ -2896,7 +2896,11 @@
|
|||||||
"current_process": "当前工序"
|
"current_process": "当前工序"
|
||||||
},
|
},
|
||||||
"equipment_monitoring": {
|
"equipment_monitoring": {
|
||||||
|
"query": "查询",
|
||||||
|
"reset": "重置",
|
||||||
"device_total": "设备总数",
|
"device_total": "设备总数",
|
||||||
|
"device_category": "设备类别",
|
||||||
|
"select_device_category": "请选择设备类别",
|
||||||
"device_code": "设备编码",
|
"device_code": "设备编码",
|
||||||
"device_name": "设备名称",
|
"device_name": "设备名称",
|
||||||
"area": "厂区",
|
"area": "厂区",
|
||||||
|
|||||||
@@ -1,6 +1,35 @@
|
|||||||
<template>
|
<template>
|
||||||
<d2-container>
|
<d2-container>
|
||||||
<template #header>
|
<template #header>
|
||||||
|
<div class="search-bar">
|
||||||
|
<el-form :inline="true" size="mini">
|
||||||
|
<el-form-item :label="$t(key('device_category'))">
|
||||||
|
<el-select
|
||||||
|
v-model="search.device_category_id"
|
||||||
|
:placeholder="$t(key('select_device_category'))"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
style="width:220px"
|
||||||
|
@change="onSearch"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in deviceCategoryOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="el-icon-search" :disabled="loading" @click="onSearch">
|
||||||
|
{{ $t(key('query')) }}
|
||||||
|
</el-button>
|
||||||
|
<el-button icon="el-icon-refresh" :disabled="loading" @click="onReset">
|
||||||
|
{{ $t(key('reset')) }}
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
<div class="status-board">
|
<div class="status-board">
|
||||||
<el-card
|
<el-card
|
||||||
:class="['status-card', 'status-card--all', { 'is-active': activeStatus === '' }]"
|
:class="['status-card', 'status-card--all', { 'is-active': activeStatus === '' }]"
|
||||||
@@ -53,6 +82,7 @@ import { useTableColumns } from '@/composables/useTableColumns'
|
|||||||
import { i18nMixin } from '@/composables/useI18n'
|
import { i18nMixin } from '@/composables/useI18n'
|
||||||
import PageTable from '@/components/page-table'
|
import PageTable from '@/components/page-table'
|
||||||
import { getDeviceAll } from '@/api/planning-production/equipment-monitoring'
|
import { getDeviceAll } from '@/api/planning-production/equipment-monitoring'
|
||||||
|
import { getDeviceCategoryAll } from '@/api/production-master-data/device-category'
|
||||||
|
|
||||||
const STATUS_META = {
|
const STATUS_META = {
|
||||||
FINISH: { label: 'finished', color: '#409EFF', className: 'finish' },
|
FINISH: { label: 'finished', color: '#409EFF', className: 'finish' },
|
||||||
@@ -73,6 +103,10 @@ export default {
|
|||||||
activeStatus: '',
|
activeStatus: '',
|
||||||
tableData: [],
|
tableData: [],
|
||||||
statusNum: [],
|
statusNum: [],
|
||||||
|
deviceCategoryOptions: [],
|
||||||
|
search: {
|
||||||
|
device_category_id: ''
|
||||||
|
},
|
||||||
refreshTimer: null
|
refreshTimer: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -112,6 +146,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
this.loadDeviceCategoryOptions()
|
||||||
this.fetchData()
|
this.fetchData()
|
||||||
this.refreshTimer = setInterval(() => {
|
this.refreshTimer = setInterval(() => {
|
||||||
this.fetchData(false)
|
this.fetchData(false)
|
||||||
@@ -128,11 +163,47 @@ export default {
|
|||||||
this.activeStatus = status === 'all' ? '' : status
|
this.activeStatus = status === 'all' ? '' : status
|
||||||
this.fetchData()
|
this.fetchData()
|
||||||
},
|
},
|
||||||
|
normalizePayload (res) {
|
||||||
|
const payload = res && res.data !== undefined ? res.data : (res || {})
|
||||||
|
if (Array.isArray(payload)) {
|
||||||
|
return { data: payload, status_num: [] }
|
||||||
|
}
|
||||||
|
if (payload && payload.data && !Array.isArray(payload.data) && (payload.data.data || payload.data.status_num)) {
|
||||||
|
return payload.data
|
||||||
|
}
|
||||||
|
return payload || {}
|
||||||
|
},
|
||||||
|
normalizeList (res) {
|
||||||
|
const payload = this.normalizePayload(res)
|
||||||
|
if (Array.isArray(payload)) return payload
|
||||||
|
if (Array.isArray(payload.data)) return payload.data
|
||||||
|
if (Array.isArray(payload.list)) return payload.list
|
||||||
|
return []
|
||||||
|
},
|
||||||
|
async loadDeviceCategoryOptions () {
|
||||||
|
try {
|
||||||
|
const res = await getDeviceCategoryAll()
|
||||||
|
this.deviceCategoryOptions = this.normalizeList(res).map(item => ({
|
||||||
|
value: item.id || item.device_category_id,
|
||||||
|
label: item.name || item.device_category_name || item.code
|
||||||
|
})).filter(item => item.value !== undefined && item.label)
|
||||||
|
} catch { /* 类别加载失败不影响监控列表 */ }
|
||||||
|
},
|
||||||
|
onReset () {
|
||||||
|
this.search.device_category_id = ''
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
onSearch () {
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
async fetchData (showLoading = true) {
|
async fetchData (showLoading = true) {
|
||||||
if (showLoading) this.loading = true
|
if (showLoading) this.loading = true
|
||||||
try {
|
try {
|
||||||
const res = await getDeviceAll({ status: this.activeStatus })
|
const res = await getDeviceAll({
|
||||||
const payload = res && res.data ? res.data : (res || {})
|
status: this.activeStatus,
|
||||||
|
device_category_id: this.search.device_category_id
|
||||||
|
})
|
||||||
|
const payload = this.normalizePayload(res)
|
||||||
this.statusNum = Array.isArray(payload.status_num) ? payload.status_num : []
|
this.statusNum = Array.isArray(payload.status_num) ? payload.status_num : []
|
||||||
this.tableData = Array.isArray(payload.data) ? payload.data : []
|
this.tableData = Array.isArray(payload.data) ? payload.data : []
|
||||||
} finally {
|
} finally {
|
||||||
@@ -152,6 +223,10 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.search-bar {
|
||||||
|
padding: 0 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.status-board {
|
.status-board {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
|
||||||
|
|||||||
Reference in New Issue
Block a user