feat: 初始化星元智灵人脸识别回收箱项目
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
import { env } from "cloudflare:workers";
|
||||
|
||||
const schemaStatements = [
|
||||
`CREATE TABLE IF NOT EXISTS people (
|
||||
id TEXT PRIMARY KEY, name TEXT NOT NULL, workshop TEXT NOT NULL, role TEXT NOT NULL,
|
||||
face_status TEXT NOT NULL, face_version INTEGER NOT NULL DEFAULT 1,
|
||||
sync_status TEXT NOT NULL, active INTEGER NOT NULL DEFAULT 1, updated_at INTEGER NOT NULL
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS workshops (
|
||||
code TEXT PRIMARY KEY, name TEXT NOT NULL UNIQUE, location TEXT NOT NULL, note TEXT NOT NULL
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS devices (
|
||||
id TEXT PRIMARY KEY, type TEXT NOT NULL, ip TEXT NOT NULL, status TEXT NOT NULL,
|
||||
last_seen INTEGER NOT NULL, heartbeat_seconds INTEGER NOT NULL,
|
||||
fill_percent INTEGER NOT NULL DEFAULT 0, category TEXT NOT NULL DEFAULT ''
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS weighings (
|
||||
id TEXT PRIMARY KEY, created_at INTEGER NOT NULL, operator TEXT NOT NULL,
|
||||
machine TEXT NOT NULL, category TEXT NOT NULL, source TEXT NOT NULL,
|
||||
weight REAL NOT NULL, event_id TEXT NOT NULL, status TEXT NOT NULL
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS events (
|
||||
id TEXT PRIMARY KEY, operator TEXT NOT NULL, entered_at INTEGER NOT NULL,
|
||||
left_at INTEGER NOT NULL, atomic_count INTEGER NOT NULL,
|
||||
scale_total REAL NOT NULL, verdict TEXT NOT NULL
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS reconciliations (
|
||||
id TEXT PRIMARY KEY, event_id TEXT NOT NULL, category TEXT NOT NULL,
|
||||
small_scale REAL NOT NULL, floor_scale REAL NOT NULL, difference REAL NOT NULL,
|
||||
difference_rate REAL NOT NULL, verdict TEXT NOT NULL, storage_status TEXT NOT NULL
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS traces (
|
||||
id TEXT PRIMARY KEY, created_at INTEGER NOT NULL, workshop TEXT NOT NULL,
|
||||
task_id TEXT NOT NULL, rfid TEXT NOT NULL, batch TEXT NOT NULL,
|
||||
tare REAL NOT NULL, gross REAL NOT NULL, net REAL NOT NULL,
|
||||
machine TEXT NOT NULL, operator TEXT NOT NULL, mes_status TEXT NOT NULL
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS rfid_tags (
|
||||
id TEXT PRIMARY KEY, status TEXT NOT NULL, name TEXT NOT NULL, last_checked INTEGER
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS alerts (
|
||||
id TEXT PRIMARY KEY, created_at INTEGER NOT NULL, type TEXT NOT NULL,
|
||||
severity TEXT NOT NULL, source TEXT NOT NULL, reference TEXT NOT NULL,
|
||||
description TEXT NOT NULL, status TEXT NOT NULL
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS settings (
|
||||
key TEXT PRIMARY KEY, value TEXT NOT NULL, updated_at INTEGER NOT NULL
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS audit_logs (
|
||||
id TEXT PRIMARY KEY, created_at INTEGER NOT NULL, actor TEXT NOT NULL,
|
||||
action TEXT NOT NULL, details TEXT NOT NULL, level TEXT NOT NULL
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS deliveries (
|
||||
record_id TEXT PRIMARY KEY, device_id TEXT NOT NULL, created_at INTEGER NOT NULL,
|
||||
employee_name TEXT NOT NULL, employee_no TEXT NOT NULL, machine_no TEXT NOT NULL,
|
||||
production_batch TEXT NOT NULL, garbage_type INTEGER NOT NULL, weight REAL NOT NULL,
|
||||
payload TEXT NOT NULL, status TEXT NOT NULL
|
||||
)`,
|
||||
`CREATE INDEX IF NOT EXISTS weighings_created_at_idx ON weighings(created_at)`,
|
||||
`CREATE INDEX IF NOT EXISTS alerts_status_idx ON alerts(status)`,
|
||||
`CREATE INDEX IF NOT EXISTS people_updated_at_idx ON people(updated_at)`,
|
||||
];
|
||||
|
||||
const now = Date.now();
|
||||
const minute = 60_000;
|
||||
|
||||
const seedStatements: Array<[string, unknown[]]> = [
|
||||
["INSERT OR IGNORE INTO workshops(code,name,location,note) VALUES(?,?,?,?)", ["WS-01", "一楼新能源车间", "1F · 东侧", "废料回收主区域"]],
|
||||
["INSERT OR IGNORE INTO workshops(code,name,location,note) VALUES(?,?,?,?)", ["WS-02", "二楼导体车间", "2F · 南侧", "导体称重与追溯"]],
|
||||
["INSERT OR IGNORE INTO workshops(code,name,location,note) VALUES(?,?,?,?)", ["WS-03", "仓储中心", "1F · 西侧", "地磅与成品暂存"]],
|
||||
["INSERT OR IGNORE INTO people(id,name,workshop,role,face_status,face_version,sync_status,active,updated_at) VALUES(?,?,?,?,?,?,?,?,?)", ["P1001", "张三", "一楼新能源车间", "仓管员", "已录入", 3, "已同步", 1, now - 3 * minute]],
|
||||
["INSERT OR IGNORE INTO people(id,name,workshop,role,face_status,face_version,sync_status,active,updated_at) VALUES(?,?,?,?,?,?,?,?,?)", ["P1002", "李四", "二楼导体车间", "产线工人", "已录入", 2, "已同步", 1, now - 8 * minute]],
|
||||
["INSERT OR IGNORE INTO people(id,name,workshop,role,face_status,face_version,sync_status,active,updated_at) VALUES(?,?,?,?,?,?,?,?,?)", ["P1003", "赵六", "一楼新能源车间", "仓管员", "需更新", 4, "同步失败", 1, now - 12 * minute]],
|
||||
["INSERT OR IGNORE INTO people(id,name,workshop,role,face_status,face_version,sync_status,active,updated_at) VALUES(?,?,?,?,?,?,?,?,?)", ["P1004", "王工", "仓储中心", "管理员", "已录入", 1, "已同步", 1, now - 20 * minute]],
|
||||
["INSERT OR IGNORE INTO devices(id,type,ip,status,last_seen,heartbeat_seconds,fill_percent,category) VALUES(?,?,?,?,?,?,?,?)", ["WKS-01", "入库触摸屏", "192.168.10.11", "在线", now - 2_000, 30, 0, "终端"]],
|
||||
["INSERT OR IGNORE INTO devices(id,type,ip,status,last_seen,heartbeat_seconds,fill_percent,category) VALUES(?,?,?,?,?,?,?,?)", ["SB-01", "小秤台", "192.168.10.12", "在线", now - 3_000, 30, 0, "称重"]],
|
||||
["INSERT OR IGNORE INTO devices(id,type,ip,status,last_seen,heartbeat_seconds,fill_percent,category) VALUES(?,?,?,?,?,?,?,?)", ["IB-01", "智能回收箱 A", "192.168.10.13", "在线", now - 5_000, 30, 72, "废铜"]],
|
||||
["INSERT OR IGNORE INTO devices(id,type,ip,status,last_seen,heartbeat_seconds,fill_percent,category) VALUES(?,?,?,?,?,?,?,?)", ["IB-02", "智能回收箱 B", "192.168.10.14", "在线", now - 4_000, 30, 46, "废电线"]],
|
||||
["INSERT OR IGNORE INTO devices(id,type,ip,status,last_seen,heartbeat_seconds,fill_percent,category) VALUES(?,?,?,?,?,?,?,?)", ["FS-01", "3 吨地磅", "192.168.10.15", "在线", now - 1_000, 30, 0, "称重"]],
|
||||
["INSERT OR IGNORE INTO devices(id,type,ip,status,last_seen,heartbeat_seconds,fill_percent,category) VALUES(?,?,?,?,?,?,?,?)", ["RFID-01", "RFID 读写器", "192.168.10.16", "在线", now - 6_000, 30, 0, "追溯"]],
|
||||
["INSERT OR IGNORE INTO weighings(id,created_at,operator,machine,category,source,weight,event_id,status) VALUES(?,?,?,?,?,?,?,?,?)", ["W-0001", now - 26 * minute, "张三", "MC-101", "废铜", "SB-01", 12.48, "EV-0728-001", "已确认"]],
|
||||
["INSERT OR IGNORE INTO weighings(id,created_at,operator,machine,category,source,weight,event_id,status) VALUES(?,?,?,?,?,?,?,?,?)", ["W-0002", now - 24 * minute, "张三", "MC-101", "废铜", "SB-01", 9.82, "EV-0728-001", "已确认"]],
|
||||
["INSERT OR IGNORE INTO weighings(id,created_at,operator,machine,category,source,weight,event_id,status) VALUES(?,?,?,?,?,?,?,?,?)", ["W-0003", now - 18 * minute, "赵六", "MC-108", "废电线", "IB-02", 14.50, "EV-0728-002", "偏差超阈"]],
|
||||
["INSERT OR IGNORE INTO weighings(id,created_at,operator,machine,category,source,weight,event_id,status) VALUES(?,?,?,?,?,?,?,?,?)", ["W-0004", now - 9 * minute, "李四", "MC-105", "废锡", "IB-01", 19.50, "EV-0728-003", "已确认"]],
|
||||
["INSERT OR IGNORE INTO events(id,operator,entered_at,left_at,atomic_count,scale_total,verdict) VALUES(?,?,?,?,?,?,?)", ["EV-0728-001", "张三", now - 30 * minute, now - 22 * minute, 2, 22.30, "正常"]],
|
||||
["INSERT OR IGNORE INTO events(id,operator,entered_at,left_at,atomic_count,scale_total,verdict) VALUES(?,?,?,?,?,?,?)", ["EV-0728-002", "赵六", now - 21 * minute, now - 14 * minute, 1, 14.50, "超标"]],
|
||||
["INSERT OR IGNORE INTO events(id,operator,entered_at,left_at,atomic_count,scale_total,verdict) VALUES(?,?,?,?,?,?,?)", ["EV-0728-003", "李四", now - 12 * minute, now - 6 * minute, 1, 19.50, "警告"]],
|
||||
["INSERT OR IGNORE INTO reconciliations(id,event_id,category,small_scale,floor_scale,difference,difference_rate,verdict,storage_status) VALUES(?,?,?,?,?,?,?,?,?)", ["RC-001", "EV-0728-001", "废铜", 22.30, 22.60, 0.30, 1.35, "正常", "已自动入库"]],
|
||||
["INSERT OR IGNORE INTO reconciliations(id,event_id,category,small_scale,floor_scale,difference,difference_rate,verdict,storage_status) VALUES(?,?,?,?,?,?,?,?,?)", ["RC-002", "EV-0728-002", "废电线", 14.50, 15.40, 0.90, 6.21, "超标", "已入库 · 异常"]],
|
||||
["INSERT OR IGNORE INTO reconciliations(id,event_id,category,small_scale,floor_scale,difference,difference_rate,verdict,storage_status) VALUES(?,?,?,?,?,?,?,?,?)", ["RC-003", "EV-0728-003", "废锡", 19.50, 20.10, 0.60, 3.08, "警告", "已入库 · 预警"]],
|
||||
["INSERT OR IGNORE INTO traces(id,created_at,workshop,task_id,rfid,batch,tare,gross,net,machine,operator,mes_status) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)", ["TR-001", now - 48 * minute, "二楼导体车间", "WT-260728-03", "E280-6102-0345", "B2607-018", 152.30, 268.10, 115.80, "MC-201", "李四", "已推送"]],
|
||||
["INSERT OR IGNORE INTO traces(id,created_at,workshop,task_id,rfid,batch,tare,gross,net,machine,operator,mes_status) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)", ["TR-002", now - 90 * minute, "二楼导体车间", "WT-260728-02", "E280-6102-0288", "B2607-017", 148.20, 252.70, 104.50, "MC-203", "周七", "待推送"]],
|
||||
["INSERT OR IGNORE INTO rfid_tags(id,status,name,last_checked) VALUES(?,?,?,?)", ["E280-6102-0345", "在用", "8# 导体轴标签", now - 48 * minute]],
|
||||
["INSERT OR IGNORE INTO rfid_tags(id,status,name,last_checked) VALUES(?,?,?,?)", ["E280-6102-0288", "在用", "7# 导体轴标签", now - 90 * minute]],
|
||||
["INSERT OR IGNORE INTO rfid_tags(id,status,name,last_checked) VALUES(?,?,?,?)", ["E280-6102-0411", "未用", "备用标签", null]],
|
||||
["INSERT OR IGNORE INTO alerts(id,created_at,type,severity,source,reference,description,status) VALUES(?,?,?,?,?,?,?,?)", ["AL-001", now - 16 * minute, "满溢预警", "警告", "废料库", "IB-01", "满溢率达到 72%,建议安排清运", "待处理"]],
|
||||
["INSERT OR IGNORE INTO alerts(id,created_at,type,severity,source,reference,description,status) VALUES(?,?,?,?,?,?,?,?)", ["AL-002", now - 42 * minute, "双秤偏差", "严重", "地磅核对", "EV-0728-002", "地磅增量与台秤汇总偏差 6.21%", "处理中"]],
|
||||
["INSERT OR IGNORE INTO settings(key,value,updated_at) VALUES(?,?,?)", ["mes_url", "http://mes.local/api/v2", now]],
|
||||
["INSERT OR IGNORE INTO settings(key,value,updated_at) VALUES(?,?,?)", ["mes_timeout", "10", now]],
|
||||
["INSERT OR IGNORE INTO settings(key,value,updated_at) VALUES(?,?,?)", ["deviation_warn", "2", now]],
|
||||
["INSERT OR IGNORE INTO settings(key,value,updated_at) VALUES(?,?,?)", ["deviation_critical", "5", now]],
|
||||
["INSERT OR IGNORE INTO settings(key,value,updated_at) VALUES(?,?,?)", ["fill_warn", "70", now]],
|
||||
["INSERT OR IGNORE INTO settings(key,value,updated_at) VALUES(?,?,?)", ["fill_critical", "90", now]],
|
||||
["INSERT OR IGNORE INTO audit_logs(id,created_at,actor,action,details,level) VALUES(?,?,?,?,?,?)", ["LOG-001", now - 15 * minute, "系统", "设备心跳", "WKS-01 状态恢复为在线", "信息"]],
|
||||
["INSERT OR IGNORE INTO audit_logs(id,created_at,actor,action,details,level) VALUES(?,?,?,?,?,?)", ["LOG-002", now - 38 * minute, "王工", "处理告警", "AL-002 标记为处理中", "重要"]],
|
||||
];
|
||||
|
||||
export function getD1(): D1Database {
|
||||
if (!env.DB) {
|
||||
throw new Error("D1 数据库未绑定,请将 .openai/hosting.json 的 d1 设置为 DB。");
|
||||
}
|
||||
return env.DB;
|
||||
}
|
||||
|
||||
export async function ensureDatabase() {
|
||||
const db = getD1();
|
||||
await db.batch(schemaStatements.map((statement) => db.prepare(statement)));
|
||||
await db.batch(
|
||||
seedStatements.map(([statement, bindings]) =>
|
||||
db.prepare(statement).bind(...bindings),
|
||||
),
|
||||
);
|
||||
return db;
|
||||
}
|
||||
|
||||
export async function addAudit(
|
||||
actor: string,
|
||||
action: string,
|
||||
details: string,
|
||||
level = "信息",
|
||||
) {
|
||||
const db = getD1();
|
||||
await db
|
||||
.prepare(
|
||||
"INSERT INTO audit_logs(id,created_at,actor,action,details,level) VALUES(?,?,?,?,?,?)",
|
||||
)
|
||||
.bind(crypto.randomUUID(), Date.now(), actor, action, details, level)
|
||||
.run();
|
||||
}
|
||||
|
||||
export async function loadConsoleData() {
|
||||
const db = await ensureDatabase();
|
||||
const [
|
||||
peopleResult,
|
||||
workshopResult,
|
||||
deviceResult,
|
||||
weighingResult,
|
||||
eventResult,
|
||||
reconciliationResult,
|
||||
traceResult,
|
||||
tagResult,
|
||||
alertResult,
|
||||
settingResult,
|
||||
logResult,
|
||||
] = await Promise.all([
|
||||
db.prepare("SELECT * FROM people ORDER BY active DESC, name").all(),
|
||||
db.prepare("SELECT * FROM workshops ORDER BY code").all(),
|
||||
db.prepare("SELECT * FROM devices ORDER BY id").all(),
|
||||
db.prepare("SELECT * FROM weighings ORDER BY created_at DESC LIMIT 200").all(),
|
||||
db.prepare("SELECT * FROM events ORDER BY entered_at DESC LIMIT 100").all(),
|
||||
db.prepare("SELECT * FROM reconciliations ORDER BY event_id DESC LIMIT 100").all(),
|
||||
db.prepare("SELECT * FROM traces ORDER BY created_at DESC LIMIT 200").all(),
|
||||
db.prepare("SELECT * FROM rfid_tags ORDER BY status, id").all(),
|
||||
db.prepare("SELECT * FROM alerts ORDER BY created_at DESC LIMIT 200").all(),
|
||||
db.prepare("SELECT * FROM settings ORDER BY key").all(),
|
||||
db.prepare("SELECT * FROM audit_logs ORDER BY created_at DESC LIMIT 200").all(),
|
||||
]);
|
||||
return {
|
||||
people: peopleResult.results,
|
||||
workshops: workshopResult.results,
|
||||
devices: deviceResult.results,
|
||||
weighings: weighingResult.results,
|
||||
events: eventResult.results,
|
||||
reconciliations: reconciliationResult.results,
|
||||
traces: traceResult.results,
|
||||
tags: tagResult.results,
|
||||
alerts: alertResult.results,
|
||||
settings: Object.fromEntries(
|
||||
settingResult.results.map((row) => [String(row.key), String(row.value)]),
|
||||
),
|
||||
logs: logResult.results,
|
||||
serverTime: Date.now(),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user