This commit is contained in:
ywb
2026-06-16 14:17:05 +08:00
parent 62292edc70
commit 916b44bc3c
10 changed files with 725 additions and 133 deletions
+35 -2
View File
@@ -20,7 +20,9 @@ createApp({
agvCameraError: false,
hasAgvCamera: false, // AGV 车体是否有可用相机
armCameraError: false,
reconnectingDevice: null
reconnectingDevice: null,
// 环境切换
testMode: true,
}
},
computed: {
@@ -38,6 +40,7 @@ createApp({
mounted() {
this.refresh()
this.refreshCameraCapabilities()
this.loadEnvMode()
setInterval(this.refreshStatus, 3000)
this.refreshCams()
setInterval(() => this.refreshCams(), 2000)
@@ -133,6 +136,36 @@ createApp({
} else {
window.location.href = '/running'
}
}
},
async loadEnvMode() {
try {
const res = await fetch(API + '/api/config/mode')
const data = await res.json()
if (data.ok) {
this.testMode = data.test_mode
}
} catch (e) {
console.error('加载环境配置失败:', e)
}
},
async toggleEnvMode() {
const newMode = !this.testMode
try {
const res = await fetch(API + '/api/config/mode', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({test_mode: newMode})
})
const data = await res.json()
if (data.ok) {
this.testMode = data.test_mode
alert('已切换至: ' + data.label)
} else {
alert('切换失败: ' + (data.error || '未知错误'))
}
} catch (e) {
alert('切换请求失败: ' + e.message)
}
},
}
}).mount('#app')
+30
View File
@@ -28,6 +28,7 @@ createApp({
errorMsg: '',
waitingStep: false,
stepLabel: '',
qrMessage: '所有姿态均未识别到二维码,请手动输入:',
// 任务步骤控制开关(机械臂初始化并入AGV移动)
agvMoveEnabled: true,
qrScanEnabled: true,
@@ -36,6 +37,8 @@ createApp({
// 速度控制
agvSpeed: 1.0,
armSpeed: 1000,
// 查验
inspection: null,
}
},
computed: {
@@ -51,6 +54,14 @@ createApp({
}
return map[this.missionState] || '未知'
},
inspectionTotal() {
if (!this.inspection || !this.inspection.items) return 0
return this.inspection.items.reduce((s, i) => s + (i.inspected || 0), 0)
},
inspectionTarget() {
if (!this.inspection || !this.inspection.items) return 0
return this.inspection.items.reduce((s, i) => s + (i.quantify || 0), 0)
},
},
mounted() {
this.poll()
@@ -101,6 +112,7 @@ createApp({
if (data.grid) this.missionGrid = data.grid
if (data.point_status) this.pointStatus = data.point_status
if (data.machine_status) this.machineStatus = data.machine_status
if (data.inspection) this.inspection = data.inspection
this.armCameraOpened = data.arm_camera_opened
if (this.armCameraOpened && !this.armPreviewUrl) {
this.armPreviewUrl = API + '/api/camera/arm_preview'
@@ -122,6 +134,11 @@ createApp({
this.waitingStep = false
}
// QR 弹窗消息
if (data.qr_message) {
this.qrMessage = data.qr_message
}
// QR 弹窗(防止提交后重复弹出)
if (this.missionState !== 'waiting_qr') {
this.qrSubmitting = false
@@ -129,6 +146,9 @@ createApp({
if (this.missionState === 'waiting_qr' && !this.showQrModal && !this.qrSubmitting) {
this.showQrModal = true
this.qrValue = ''
if (!this.qrMessage) {
this.qrMessage = '所有姿态均未识别到二维码,请手动输入:'
}
}
// 完成后获取报告
@@ -156,6 +176,11 @@ createApp({
},
async startMission() {
if (this.missionState !== 'idle') return
// 没有设置报关单时阻止启动(后端也会校验,这里提前友好提示)
if (!this.inspection) {
alert('⚠️ 请先在「设置→报关单」中选择报关单并点击「开始查验」')
return
}
this.logs = []
this.progress = 0
this.report = null
@@ -186,6 +211,11 @@ createApp({
},
async startSingleStep() {
if (this.missionState !== 'idle') return
// 没有设置报关单时阻止启动(后端会校验,这里提前友好提示)
if (!this.inspection) {
alert('⚠️ 请先在「设置→报关单」中选择报关单并点击「开始查验」')
return
}
this.logs = []
this.progress = 0
this.report = null
+113 -55
View File
@@ -82,8 +82,9 @@ createApp({
this.refreshAngles()
this.loadQrConfigs()
this.nav2Timer = setInterval(this.refreshNavStatus, 3000)
this.armCameraUrl = API + '/api/camera/arm_preview?t=' + Date.now()
},
this.armSnapshotUrl = ""; this.armCameraUrl = API + '/api/camera/arm_preview?t=' + Date.now()
this.armSnapshotUrl = ""; this.armCameraUrl = API + "/api/camera/arm_preview?t=" + Date.now()
},
computed: {
customsTotalPages() {
return Math.max(1, Math.ceil(this.customsTotal / this.customsPageSize))
@@ -1203,64 +1204,121 @@ createApp({
alert('❌ 复位请求失败: ' + e.message)
}
},
},
// ===== 报关单方法 =====
async loadCustomsList() {
this.customsLoading = true
try {
const url = API + '/api/customs/list?pageNum=' + this.customsPage + '&pageSize=' + this.customsPageSize
const res = await fetch(url)
const d = await res.json()
if (d.ok && d.data) {
const raw = d.data
let list = []
let total = 0
if (raw.rows) { list = raw.rows; total = raw.total || list.length }
else if (raw.records) { list = raw.records; total = raw.total || list.length }
else if (Array.isArray(raw)) { list = raw; total = list.length }
else if (raw.data && raw.data.rows) { list = raw.data.rows; total = raw.data.total || list.length }
else if (raw.data && raw.data.records) { list = raw.data.records; total = raw.data.total || list.length }
else if (raw.data && Array.isArray(raw.data)) { list = raw.data; total = list.length }
this.customsList = list
this.customsTotal = total || list.length
} else {
// ===== 报关单方法 =====
async loadCustomsList() {
this.customsLoading = true
try {
const url = API + '/api/customs/list?pageNum=' + this.customsPage + '&pageSize=' + this.customsPageSize + '&customsName=' + encodeURIComponent(this.customsName) + '&customsNo=' + encodeURIComponent(this.customsNo)
const res = await fetch(url)
const d = await res.json()
if (d.ok && d.data) {
const raw = d.data
let list = []
let total = 0
if (raw.rows) { list = raw.rows; total = raw.total || list.length }
else if (raw.records) { list = raw.records; total = raw.total || list.length }
else if (Array.isArray(raw)) { list = raw; total = list.length }
else if (raw.data && raw.data.rows) { list = raw.data.rows; total = raw.data.total || list.length }
else if (raw.data && raw.data.records) { list = raw.data.records; total = raw.data.total || list.length }
else if (raw.data && Array.isArray(raw.data)) { list = raw.data; total = list.length }
this.customsList = list
this.customsTotal = total || list.length
} else {
this.customsList = []
this.customsTotal = 0
}
} catch (e) {
console.error('加载报关单列表失败', e)
this.customsList = []
this.customsTotal = 0
} finally {
this.customsLoading = false
}
} catch (e) {
console.error('加载报关单列表失败', e)
this.customsList = []
this.customsTotal = 0
} finally {
this.customsLoading = false
}
},
async selectCustomsRow(item) {
const id = item.id || item.customsId || item.customs_id || ''
if (!id) return
this.selectedCustomsId = id
this.selectedCustomsName = item.customsNo || item.customs_no || item.name || item.customsName || item.customs_name || id
this.customsMachines = []
try {
const res = await fetch(API + '/api/customs/machines?customsId=' + encodeURIComponent(id))
const d = await res.json()
if (d.ok && d.data) {
const raw = d.data
let machines = []
if (raw.rows) { machines = raw.rows }
else if (raw.records) { machines = raw.records }
else if (raw.data && Array.isArray(raw.data)) { machines = raw.data }
else if (Array.isArray(raw)) { machines = raw }
else if (Array.isArray(raw.data)) { machines = raw.data }
this.customsMachines = machines
} else {
},
async selectCustomsRow(item) {
// 新数据结构: { customs:{id,orderId,..}, orderCode, drawCode }
const id = (item.customs && item.customs.id) || item.id || item.customsId || item.customs_id || ''
if (!id) return
this.selectedCustomsId = id
this.selectedCustomsName = (item.customs && item.customs.customsCode) || item.orderCode || item.drawCode || id
this.customsMachines = []
try {
const url = API + '/api/customs/machines?customsId=' + encodeURIComponent(id)
const res = await fetch(url)
const d = await res.json()
if (d.ok && d.data) {
const raw = d.data
let machines = []
// customsMachines 返回格式: {"code":"0","data":[{serialNumber,inventoryName,...}]}
if (raw.rows) { machines = raw.rows }
else if (raw.records) { machines = raw.records }
else if (raw.data && Array.isArray(raw.data)) { machines = raw.data }
else if (Array.isArray(raw)) { machines = raw }
else if (Array.isArray(raw.data)) { machines = raw.data }
this.customsMachines = machines
} else {
this.customsMachines = []
}
} catch (e) {
console.error('加载机器列表失败', e)
this.customsMachines = []
}
} catch (e) {
console.error('加载机器列表失败', e)
this.customsMachines = []
},
async startInspection(item) {
const id = (item.customs && item.customs.id) || item.id || item.customsId || item.customs_id || ''
const name = (item.customs && item.customs.customsCode) || item.orderCode || item.drawCode || id
if (!id) return
if (!confirm(`确定要对报关单「${name}」开始查验吗?\n点击确定后,运行页将以该报关单的机器进行查验。`)) return
try {
const res = await fetch(API + '/api/customs/inspection/start', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ customsId: id, customsName: name })
})
const d = await res.json()
if (d.ok) {
alert(`✅ 查验已开始!\n报关单: ${name}\n机型: ${d.inspection.items.length}\n总数: ${d.inspection.items.reduce((s,i)=>s+i.quantify,0)}\n\n请前往「运行」页执行任务。`)
// 同时选中该报关单,显示机器列表
this.selectedCustomsId = id
this.selectedCustomsName = name
// 用 inspection items 填充 customsMachines 显示(聚合后)
this.customsMachines = d.inspection.items.map(it => ({
inventoryCode: it.inventoryCode,
inventoryName: it.inventoryName,
inventorySpecification: it.spec,
serialNumber: '',
quantify: it.quantify,
inspectionCount: it.inspected,
}))
} else {
alert('❌ 开始查验失败: ' + (d.error || '未知错误'))
}
} catch (e) {
alert('❌ 请求失败: ' + e.message)
}
},
async loadInspectionCounts() {
// 轮询查验计数,更新 customsMachines 的 inspectionCount
try {
const res = await fetch(API + '/api/customs/inspection')
const d = await res.json()
if (d.ok && d.inspection && this.customsMachines.length) {
for (const item of d.inspection.items) {
const match = this.customsMachines.find(m => m.inventoryCode === item.inventoryCode)
if (match) {
match.inspectionCount = item.inspected
}
}
}
} catch (e) {}
},
},
watch: {
tab(newVal) {
if (newVal === 'customs' && this.customsMachines.length > 0) {
// 切换到报关单 tab 时刷新查验计数
this.loadInspectionCounts()
}
}
},
}
}).mount('#app')