修复生产监控分页和设备监控筛选
Some checks failed
Release pipeline / publish (push) Has been cancelled
Release pipeline / Always run job (push) Has been cancelled

This commit is contained in:
sheng
2026-06-25 00:49:52 +08:00
parent 22ccc9c219
commit c2db61dad9
5 changed files with 131 additions and 8 deletions

View 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
- 设备监控查询区保持一行筛选控件,状态卡片作为快速状态过滤入口。
- 状态卡片与设备类别筛选可以叠加过滤,重置只清空设备类别,状态卡片保持当前选择,便于运维人员持续看某类设备在某状态下的情况。
- 托盘登录当前是扫码型操作页,批次选择和格式选择比分页更关键;分页兼容应放在共享表格层处理,避免在扫码页引入无关控件。

View File

@@ -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
}) })
}, },

View File

@@ -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",

View File

@@ -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": "厂区",

View File

@@ -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));