feat: 装配线看板修正、统一密钥Hardman_2026、操作日志追溯、日志按天存储

Dashboard 移除 CNC/清洗机等不存在设备,改为纯装配线看板(扫码枪+拧紧枪+人工);JWT/内部token统一为 Hardman_2026 写入各 etc/*.yaml,MES 建表 DSN 改读 yaml;event_log 增加 workOrderNo/operator,BOM/备料/PLC下发/拧紧/扫码报工/半成品/AGV 全链路埋点,日志页支持工单号/操作人筛选;MES/WMS 日志按天存储(dailyWriter),WMS SetWriter 用 logx.NewWriter 适配
This commit is contained in:
SunYF
2026-08-28 09:22:19 +08:00
parent a2afd2f6dc
commit 450a094f0e
39 changed files with 516 additions and 2111 deletions
@@ -127,6 +127,8 @@ export interface EventLog {
jobId?: number
workOrderId?: number
workpieceNo?: string
workOrderNo?: string
operator?: string
equipmentId?: number
equipmentName?: string
tempSlotNo?: number
@@ -326,6 +328,8 @@ export function useWorkOrderApi() {
startTime?: string
endTime?: string
workpieceNo?: string
workOrderNo?: string
operator?: string
jobId?: number
}): Promise<PageResult<EventLog>> => {
return get({url: `/api/v1/event-logs`, params})
+17 -1
View File
@@ -8,4 +8,20 @@ export const EVENT_TYPE_LABELS: Record<string, string> = {
ORDER_CANCELLED: '取消', ORDER_COMPLETED: '工单完工',
ALARM_RAISED: '报警', ALARM_ACKED: '确认',
MANUAL_ACTION_CREATED: '人工处理', MANUAL_ACTION_RESOLVED: '已解决',
}
TEMP_SLOT_CHANGED: '暂存台',
EQUIPMENT_AVAILABILITY_CHANGED: '设备启停',
// 装配线操作日志
BOM_SAVED: 'BOM维护',
MATERIAL_REQUESTED: '备料',
PLC_PROCESS_SENT: 'PLC下发',
TORQUE_REPORTED: '拧紧',
SCAN_REPORTED: '扫码报工',
SEMI_FLOW: '半成品',
AGV_TASK_CREATED: 'AGV任务',
}
// 装配线操作日志事件(工序/备料/拧紧/扫码/流转/搬运)
export const ASSEMBLY_EVENT_TYPES = [
'BOM_SAVED', 'MATERIAL_REQUESTED', 'PLC_PROCESS_SENT',
'TORQUE_REPORTED', 'SCAN_REPORTED', 'SEMI_FLOW', 'AGV_TASK_CREATED',
]
@@ -8,7 +8,7 @@ import {TagColor} from '@douyinfe/semi-ui/lib/es/tag'
import {EVENT_TYPE_LABELS} from '@/constants/event'
// 事件类别分组
type EventCategory = 'material' | 'process' | 'lifecycle' | 'alarm' | 'manual'
type EventCategory = 'material' | 'process' | 'lifecycle' | 'alarm' | 'manual' | 'assembly'
const EVENT_CATEGORY: Record<string, EventCategory> = {
LOAD: 'material', UNLOAD: 'material', EXCHANGE: 'material', REPLENISH: 'material',
@@ -19,6 +19,9 @@ const EVENT_CATEGORY: Record<string, EventCategory> = {
ORDER_CANCELLED: 'lifecycle', ORDER_COMPLETED: 'lifecycle',
ALARM_RAISED: 'alarm', ALARM_ACKED: 'alarm',
MANUAL_ACTION_CREATED: 'manual', MANUAL_ACTION_RESOLVED: 'manual',
BOM_SAVED: 'assembly', MATERIAL_REQUESTED: 'assembly', PLC_PROCESS_SENT: 'assembly',
TORQUE_REPORTED: 'assembly', SCAN_REPORTED: 'assembly', SEMI_FLOW: 'assembly',
AGV_TASK_CREATED: 'assembly',
}
const CATEGORY_COLOR: Record<EventCategory, TagColor> = {
@@ -27,6 +30,7 @@ const CATEGORY_COLOR: Record<EventCategory, TagColor> = {
lifecycle: 'grey',
alarm: 'red',
manual: 'orange',
assembly: 'cyan',
}
const EVENT_TYPE_OPTIONS = [
@@ -35,6 +39,10 @@ const EVENT_TYPE_OPTIONS = [
{label: '加工', value: 'MACHINE_START'}, {label: '完工', value: 'MACHINE_DONE'},
{label: '完成', value: 'JOB_COMPLETED'}, {label: '报废', value: 'JOB_SCRAPPED'}, {label: '下线', value: 'JOB_DISCHARGED'},
{label: '报警', value: 'ALARM_RAISED'}, {label: '确认', value: 'ALARM_ACKED'},
{label: 'BOM维护', value: 'BOM_SAVED'}, {label: '备料', value: 'MATERIAL_REQUESTED'},
{label: 'PLC下发', value: 'PLC_PROCESS_SENT'}, {label: '拧紧上报', value: 'TORQUE_REPORTED'},
{label: '扫码报工', value: 'SCAN_REPORTED'}, {label: '半成品流转', value: 'SEMI_FLOW'},
{label: 'AGV任务', value: 'AGV_TASK_CREATED'},
]
const ENTITY_TYPE_OPTIONS = [
@@ -54,6 +62,8 @@ export default function WorkOrderLogPage() {
const [entityType, setEntityType] = useState<string>()
const [dateRange, setDateRange] = useState<[Date, Date]>()
const [workpieceNo, setWorkpieceNo] = useState<string>()
const [workOrderNo, setWorkOrderNo] = useState<string>()
const [operator, setOperator] = useState<string>()
const [panelVisible, setPanelVisible] = useState(false)
const [selectedOrderId, setSelectedOrderId] = useState<number>()
const [workpiecePanelVisible, setWorkpiecePanelVisible] = useState(false)
@@ -65,16 +75,18 @@ export default function WorkOrderLogPage() {
setPanelVisible(true)
}, [])
const fetchLogs = useCallback(async (page: number, filters?: {eventType?: string; entityType?: string; dateRange?: [Date, Date]; workpieceNo?: string}) => {
const fetchLogs = useCallback(async (page: number, filters?: {eventType?: string; entityType?: string; dateRange?: [Date, Date]; workpieceNo?: string; workOrderNo?: string; operator?: string}) => {
setLoading(true)
try {
const f = filters ?? {eventType, entityType, dateRange, workpieceNo}
const f = filters ?? {eventType, entityType, dateRange, workpieceNo, workOrderNo, operator}
const params: Record<string, unknown> = {page, limit: PAGE_SIZE}
if (f.eventType) params.eventType = f.eventType
if (f.entityType) params.entityType = f.entityType
if (f.dateRange?.[0]) params.startTime = moment(f.dateRange[0]).format('YYYY-MM-DD')
if (f.dateRange?.[1]) params.endTime = moment(f.dateRange[1]).format('YYYY-MM-DD')
if (f.workpieceNo) params.workpieceNo = f.workpieceNo
if (f.workOrderNo) params.workOrderNo = f.workOrderNo
if (f.operator) params.operator = f.operator
const result = await orderApi.queryEventLogs(params as Parameters<typeof orderApi.queryEventLogs>[0])
setLogs(result.data)
@@ -87,7 +99,7 @@ export default function WorkOrderLogPage() {
} finally {
setLoading(false)
}
}, [orderApi])
}, [orderApi, eventType, entityType, dateRange, workpieceNo, workOrderNo, operator])
useEffect(() => {
fetchLogs(1)
@@ -130,6 +142,18 @@ export default function WorkOrderLogPage() {
}
},
},
{
title: '工单号',
dataIndex: 'workOrderNo',
width: 130,
render: (text: string) => text || '-',
},
{
title: '操作人',
dataIndex: 'operator',
width: 100,
render: (text: string) => text || '-',
},
{
title: '设备',
dataIndex: 'equipmentName',
@@ -182,7 +206,23 @@ export default function WorkOrderLogPage() {
showClear
onClear={() => setWorkpieceNo(undefined)}
/>
<Button theme="solid" onClick={() => fetchLogs(1, {eventType, entityType, dateRange, workpieceNo})}></Button>
<Input
placeholder="工单号"
value={workOrderNo}
onChange={setWorkOrderNo}
style={{width: 160}}
showClear
onClear={() => setWorkOrderNo(undefined)}
/>
<Input
placeholder="操作人"
value={operator}
onChange={setOperator}
style={{width: 120}}
showClear
onClear={() => setOperator(undefined)}
/>
<Button theme="solid" onClick={() => fetchLogs(1, {eventType, entityType, dateRange, workpieceNo, workOrderNo, operator})}></Button>
</div>
<Table
dataSource={logs}
@@ -194,7 +234,7 @@ export default function WorkOrderLogPage() {
currentPage,
pageSize: PAGE_SIZE,
total,
onPageChange: (page: number) => fetchLogs(page, {eventType, entityType, dateRange, workpieceNo}),
onPageChange: (page: number) => fetchLogs(page, {eventType, entityType, dateRange, workpieceNo, workOrderNo, operator}),
}}
/>
</div>