Browse Source

login/logout

master
zhangjiming 5 months ago
parent
commit
b253712415
  1. 12
      public/index.html
  2. 37
      public/main.js
  3. 25
      src/index.ts
  4. 60
      src/routes/auth.ts
  5. 18
      src/routes/cmd.ts
  6. 59
      src/routes/debug.ts
  7. 142
      src/types/cmdTypes.ts
  8. 275
      src/types/wsTypes.ts
  9. 1503
      src/utils/measure.json
  10. 1
      tsconfig.json

12
public/index.html

@ -9,13 +9,11 @@
<body>
<div class="main">
<div>
<span>x</span>
<input type="number" id="armX" />
<span>y</span>
<input type="number" id="armY" />
<span>z</span>
<input type="number" id="armZ" />
<button id="moveArm">移动机械臂</button>
<button id="startRecord">开始测量</button>
<button id="upload">连续上报</button>
<button id="endRecord">结束测量</button>
</div>
</div>
<script src="lib/zepto.min.js"></script>

37
public/main.js

@ -13,14 +13,39 @@ ws.onclose = () => {
console.log("Disconnected from server");
};
$("#moveArm").on("click", () => {
const x = $("#armX").val();
const y = $("#armY").val();
const z = $("#armZ").val();
$("#startRecord").on("click", () => {
$.ajax({
type: "POST",
url: "/api/debug/railArm",
data: JSON.stringify({ x: +x, y: +y, z: +z }),
url: "/api/debug/record-sig/start",
data: JSON.stringify({}),
contentType: "application/json",
success: res => {
console.log("Success", res);
},
error: err => {
console.error("Error", err);
},
});
});
$("#endRecord").on("click", () => {
$.ajax({
type: "POST",
url: "/api/debug/record-sig/stop",
data: JSON.stringify({}),
contentType: "application/json",
success: res => {
console.log("Success", res);
},
error: err => {
console.error("Error", err);
},
});
});
$("#upload").on("click", () => {
$.ajax({
type: "POST",
url: "/api/debug/record-sig/upload",
data: JSON.stringify({}),
contentType: "application/json",
success: res => {
console.log("Success", res);

25
src/index.ts

@ -5,9 +5,11 @@ import bodyParser from "body-parser";
import cmdRouter from "./routes/cmd";
import debugRouter from "./routes/debug";
import authRouter from "./routes/auth";
import { defaultStatus, StatusDatagram } from "./types/wsTypes";
// import { defaultStatus, StatusDatagram } from "./types/wsTypes";
import { wsSend } from "./utils/wss";
import { ContextMessage, defaultContext } from "./types/wsTypes";
const app = express();
app.use(express.static("public"));
@ -30,23 +32,32 @@ wss.on("connection", ws => {
// }
// });
// });
// 当连接关闭时触发
ws.send(JSON.stringify(getCurrStatus()));
// DeviceContext
ws.send(
JSON.stringify({
messageType: "DeviceContext",
data: app.locals["context"],
path: "/deviceContext",
})
);
ws.on("close", () => {
console.log("Client disconnected");
});
});
function getCurrStatus() {
return app.locals["status"] as StatusDatagram["data"];
function getCurrContext() {
return app.locals["context"] as ContextMessage["data"];
}
app.locals["wss"] = wss;
app.locals["status"] = defaultStatus;
app.locals["context"] = defaultContext;
// app.get("/", (req, res) => {
// res.send("Hello World!");
// });
app.use("/api/debug", debugRouter);
app.use("/api/cmd", cmdRouter);
app.use("/auth", authRouter);
//@ts-ignore
app.use((err, req, res, next) => {
@ -55,7 +66,7 @@ app.use((err, req, res, next) => {
});
// 监听端口
const PORT = process.env.PORT || 3003;
const PORT = process.env.PORT || 3005;
server.listen(PORT, () => {
console.log(`Server is listening on port ${PORT}`);
});

60
src/routes/auth.ts

@ -0,0 +1,60 @@
import express from "express";
const router = express.Router();
import { wsSend } from "../utils/wss";
import { delay } from "../utils/helper";
router.post("/login", async (req, res) => {
console.log("/login:", req.body);
req.app.locals["context"] = {
loginFlag: true,
loginUser: {
id: 0,
account: "Demo",
nickname: "Demo",
password: "Demo",
userRole: "Admin",
isBuiltInUser: false,
},
};
wsSend(req.app.locals["wss"], {
messageType: "DeviceContext",
data: req.app.locals["context"],
path: "/deviceContext",
});
await delay(200);
res.json({
status: 0,
data: {
id: 3, //数据主键id
createTime: "2025-03-03 17:51:13", //数据创建时间
updateTime: "2025-03-03 19:22:35", //数据更新时间
account: "test001", //用户账户
nickname: "测试账户001", //用户昵称
password: null,
usrRole: "Admin", //用户角色,可用值:User,Admin,Dev
isBuiltInUser: false, //是否内置用户(内置用户不可删除)
},
timestamp: 1741001321389,
});
});
router.post("/logout", (req, res) => {
req.app.locals["context"] = {
loginFlag: false,
loginUser: {},
};
wsSend(req.app.locals["wss"], {
messageType: "DeviceContext",
data: req.app.locals["context"],
path: "/deviceContext",
});
res.json({
status: 0,
timestamp: 1741005358167,
});
});
export default router;

18
src/routes/cmd.ts

@ -5,15 +5,15 @@ const router = express.Router();
router.post("/", async (req, res) => {
await delay(200);
setTimeout(() => {
wsSend(req.app.locals["wss"], {
type: "cmd",
data: {
commandId: req.body.commandId,
status: "D0000",
},
});
}, 2000);
// setTimeout(() => {
// wsSend(req.app.locals["wss"], {
// type: "cmd",
// data: {
// commandId: req.body.commandId,
// status: "D0000",
// },
// });
// }, 2000);
res.json({ code: "00000", msg: "执行成功" });
});

59
src/routes/debug.ts

@ -1,21 +1,56 @@
import express from "express";
import { delay } from "../utils/helper";
import { wsSend } from "../utils/wss";
import { StatusDatagram } from "../types/wsTypes";
import { TrackRecordSig } from "../types/wsTypes";
const router = express.Router();
import points from "../utils/measure.json";
let ptIndex = 0;
let intervalId: ReturnType<typeof setInterval>;
router.post("/railArm", async (req, res) => {
// console.log(points)
router.post("/record-sig/:action", async (req, res) => {
// await delay(200);
const curr: StatusDatagram["data"] = req.app.locals["status"];
setTimeout(() => {
curr.railArm.x = req.body.x;
curr.railArm.y = req.body.y;
curr.railArm.z = req.body.z;
wsSend(req.app.locals["wss"], {
type: "status",
data: curr,
});
}, 1000);
if (req.params["action"] === "start") {
ptIndex = 0;
setTimeout(() => {
wsSend(req.app.locals["wss"], {
messageType: "EVENT",
data: {
event: "START_RECORD_SIG",
},
path: "/measurement-task/get-task-state",
});
}, 1000);
} else if (req.params["action"] === "stop") {
ptIndex = 0;
setTimeout(() => {
wsSend(req.app.locals["wss"], {
messageType: "EVENT",
data: {
event: "END_RECORD_SIG",
},
path: "/measurement-task/get-task-state",
});
}, 1000);
} else if (req.params["action"] === "upload") {
intervalId = setInterval(() => {
if (ptIndex >= points.length) {
clearInterval(intervalId);
// ptIndex = 0;
return;
}
wsSend(req.app.locals["wss"], {
messageType: "EVENT",
data: {
x: points[ptIndex].x,
y: points[ptIndex].y,
},
path: "/measurement-task/profile-record-ctrl-sig",
});
ptIndex = ptIndex + 2;
}, 10);
}
// const curr: StatusDatagram["data"] = req.app.locals["status"];
res.json({ code: "00000", msg: "执行成功" });
});

142
src/types/cmdTypes.ts

@ -1,142 +0,0 @@
type UpTrayStepStruct = {
method: "upTray";
// params: {
// heaterId: number;
// };
};
type DownTrayStepStruct = {
method: "downTray";
// params: {
// heaterId: number;
// };
};
export type TubeSolStruct = {
tubeNum: number;
addLiquidList: Array<{
solId: number;
volume: number;
}>;
};
type AddLiquidStepStruct = {
method: "addLiquid";
params: {
solId: number;
volume: number;
tubeSolList?: TubeSolStruct[];
};
};
type MoveToSolStepStruct = {
method: "moveToSol";
// params: {
// heaterId: number;
// };
};
type MoveToHeaterStepStruct = {
method: "moveToHeat";
// params: {
// heaterId: number;
// };
};
type ShakingStepStruct = {
method: "shaking";
params: {
second: number;
};
};
type StartHeatingStepStruct = {
method: "startHeating";
params: {
// heaterId: number;
temperature: number;
};
};
type StopHeatingStepStruct = {
method: "stopHeating";
// params: {
// heaterId: number;
// };
};
type TakePhotoStepStruct = {
method: "takePhoto";
};
type DelayStepStruct = {
method: "delay";
params: {
second: number;
};
};
export type StepStruct =
| UpTrayStepStruct
| DownTrayStepStruct
| AddLiquidStepStruct
| MoveToSolStepStruct
| MoveToHeaterStepStruct
| ShakingStepStruct
| StartHeatingStepStruct
| StopHeatingStepStruct
| TakePhotoStepStruct
| DelayStepStruct;
export type StepCmd = StepStruct["method"];
export const StepCmdDescMap: { [k in StepCmd]: string } = {
upTray: "抬起托盘",
downTray: "降下托盘",
addLiquid: "添加溶液",
moveToSol: "移至加液",
moveToHeat: "移至加热",
shaking: "摇匀",
startHeating: "开始加热",
stopHeating: "停止加热",
takePhoto: "拍照",
delay: "等待",
};
export const CmdDescMap: { [k in OperationCmd]: string } = {
upTray: "抬起托盘",
downTray: "降下托盘",
injectFluid: "注入溶液",
moveToActionArea: "移至操作区",
startShakeUp: "开始摇匀",
stopShakeUp: "结束摇匀",
startHeat: "开始加热",
stopHeat: "停止加热",
// keepHeat: "恒温",
takePhoto: "拍照",
// moveToUnusual: "移至异常区",
moveToHeatArea: "移至加热区",
takeOffCap: "取下拍子",
putBackCap: "装回拍子",
openClaw: "张开夹爪",
closeClaw: "收合夹爪",
moveMachineArm: "移动机械臂",
moveTube: "移动试管",
openDoor: "开门",
closeDoor: "关门",
};
export type OperationCmd =
| "upTray" // 抬起托盘
| "downTray" // 降下托盘
| "injectFluid" // 注入溶液
| "moveToActionArea" // 移至操作区
| "startShakeUp" // 开始摇匀
| "stopShakeUp" // 结束摇匀
| "startHeat" // 开始加热
| "stopHeat" // 停止加热
// | "keepHeat" // 恒温
| "takePhoto" // 拍照
// | "moveToUnusual" // 移至异常区
| "moveToHeatArea" // 移至加热区
| "takeOffCap" // 取下拍子
| "putBackCap" // 装回拍子
| "openClaw" // 张开夹爪
| "closeClaw" // 收合夹爪
| "moveMachineArm" // 移动机械臂
| "moveTube" // 移动试管
| "openDoor" //开门
| "closeDoor"; //关门

275
src/types/wsTypes.ts

@ -1,266 +1,41 @@
import type { StepCmd } from "./cmdTypes";
export type CmdDatagram = {
type: "cmd"; // 指令
data: {
commandId: string;
// commandName: DebugCmd;
status: "D0000" | "D1111";
message?: string;
// success: boolean;
};
};
export type CraftDatagram = {
type: "crafts";
data: {
// 当前工艺执行状态,0 表示未执行,1 表示正在执行,2 表示暂停执行,3 表示停止执行 4:Error, 6: 完成。
status: 0 | 1 | 2 | 3 | 4 | 6;
// 当前正在执行的具体工艺方法
method: StepCmd;
// 当前正在执行的工艺步骤索引
methodIndex: number;
// 加热区 ID
heatId: number;
};
};
export type WarnDatagram = {
type: "warn"; // 报警
// 开始、停止绘制
export type TaskState = {
messageType: "EVENT";
data: {
code: string;
msg: string;
module: string;
event: "START_RECORD_SIG" | "END_RECORD_SIG";
};
path: "/measurement-task/get-task-state";
};
export type StatusDatagram = {
type: "status"; // 状态
// 连接上报坐标点
export type TrackRecordSig = {
messageType: "EVENT";
data: {
emergencyStop: boolean; // 硬件急停信号,true 为急停触发,false 为正常运行
doorStatus: boolean; // 门的状态,false 表示关闭,true 表示开启
railArm: {
x: number;
y: number;
z: number;
joint1: number;
joint2: number;
distance: number; // 当前机械臂(轴 3)上下移动的距离
railDistance: number;
clawDistance: number;
clawStatus: boolean; // 夹爪状态,true 为张开,false 为闭合
isZeroPos: boolean; // 导轨是否在原点
isLimitPos: boolean; // 导轨是否在限位点
};
// 操作区(加液、摇匀、拍照)状态
liquidArea: {
liquidArm: {
x: number;
y: number;
z: number;
joint1: number;
joint2: number;
pump: Array<{
pumpId: number;
isPumping: boolean; // 是否正在加液,true正在加液
}>;
};
isShaking: boolean; // 是否正在摇匀
liquidTray: boolean; // 是否存在托盘
// 溶液容器状态
solutionBucket: Array<{
isEmpty: boolean; // 容器是否为空
isFull: boolean; // 容器是否已满
}>;
};
// 加热区列表
heatArea: Array<{
// heaterId: string;
hardwareId: string;
trayStatus: 0 | 1 | 2; // 0为无托盘,1为有托盘,2为托盘抬起
isHeating: boolean; // 是否正在加热
capStatus: boolean; // 是否存在拍子
isSealed: boolean; // 拍子密封状态,true为已密封,false为未密封
temperature: number; // 当前温度
}>;
// 碱容器状态(废液桶)
alkaliBucket: {
isEmpty: boolean; // 容器是否为空
isFull: boolean; // 容器是否已满
};
x: number;
y: number;
};
path: "/measurement-task/profile-record-ctrl-sig";
};
export type CraftState = {
type: "crafts";
data: {
heatId: string | number;
methodIndex: string | number;
status: string | number;
};
export const defaultContext: ContextMessage["data"] = {
loginFlag: false,
loginUser: {},
};
export type ContainerDatagram = {
type: "container";
export type ContextMessage = {
messageType: "DeviceContext";
data: {
containerList: Array<{
loginFlag: Boolean;
loginUser: Partial<{
id: number;
type: 0 | 1; // 0:酸液 1:废液
solutionId: number;
pumpId: number;
capacityTotal: number;
capacityUsed: number;
account: string;
nickname: string;
password: string;
userRole: "Admin" | "User" | "Dev";
isBuiltInUser: boolean;
}>;
};
path: "/deviceContext";
};
export type Datagram = CmdDatagram | WarnDatagram | StatusDatagram | CraftDatagram | ContainerDatagram;
export const defaultStatus: StatusDatagram["data"] = {
emergencyStop: false, // 硬件急停信号,true 为急停触发,false 为正常运行
doorStatus: false, // 门的状态,false 表示关闭,true 表示开启
railArm: {
x: 0,
y: 0,
z: 0,
joint1: 0,
joint2: 0,
distance: 0, // 当前机械臂(轴 3)上下移动的距离
railDistance: 0,
clawDistance: 0,
clawStatus: false, // 夹爪状态,true 为张开,false 为闭合
isZeroPos: true, // 导轨是否在原点
isLimitPos: false, // 导轨是否在限位点
},
// 操作区(加液、摇匀、拍照)状态
liquidArea: {
liquidArm: {
x: 0,
y: 0,
z: 0,
joint1: 0,
joint2: 0,
pump: [
{
pumpId: 1,
isPumping: false, // 是否正在加液,true正在加液
},
{
pumpId: 2,
isPumping: false, // 是否正在加液,true正在加液
},
{
pumpId: 3,
isPumping: false, // 是否正在加液,true正在加液
},
{
pumpId: 4,
isPumping: false, // 是否正在加液,true正在加液
},
{
pumpId: 5,
isPumping: false, // 是否正在加液,true正在加液
},
{
pumpId: 6,
isPumping: false, // 是否正在加液,true正在加液
},
],
},
isShaking: false, // 是否正在摇匀
liquidTray: false, // 是否存在托盘
// 溶液容器状态
solutionBucket: [
{
isEmpty: false, // 容器是否为空
isFull: false, // 容器是否已满
},
{
isEmpty: false, // 容器是否为空
isFull: false, // 容器是否已满
},
{
isEmpty: false, // 容器是否为空
isFull: false, // 容器是否已满
},
{
isEmpty: false, // 容器是否为空
isFull: false, // 容器是否已满
},
{
isEmpty: false, // 容器是否为空
isFull: false, // 容器是否已满
},
{
isEmpty: false, // 容器是否为空
isFull: false, // 容器是否已满
},
{
isEmpty: false, // 容器是否为空
isFull: false, // 容器是否已满
},
{
isEmpty: false, // 容器是否为空
isFull: false, // 容器是否已满
},
],
},
// 加热区列表
heatArea: [
{
hardwareId: "hardware_1",
trayStatus: 0, // 0为无托盘,1为有托盘,2为托盘抬起
isHeating: false, // 是否正在加热
capStatus: false, // 是否存在拍子
isSealed: false, // 拍子密封状态,true为已密封,false为未密封
temperature: 0, // 当前温度
},
{
hardwareId: "hardware_2",
trayStatus: 0, // 0为无托盘,1为有托盘,2为托盘抬起
isHeating: false, // 是否正在加热
capStatus: false, // 是否存在拍子
isSealed: false, // 拍子密封状态,true为已密封,false为未密封
temperature: 0, // 当前温度
},
{
hardwareId: "hardware_3",
trayStatus: 0, // 0为无托盘,1为有托盘,2为托盘抬起
isHeating: false, // 是否正在加热
capStatus: false, // 是否存在拍子
isSealed: false, // 拍子密封状态,true为已密封,false为未密封
temperature: 0, // 当前温度
},
{
hardwareId: "hardware_4",
trayStatus: 0, // 0为无托盘,1为有托盘,2为托盘抬起
isHeating: false, // 是否正在加热
capStatus: false, // 是否存在拍子
isSealed: false, // 拍子密封状态,true为已密封,false为未密封
temperature: 0, // 当前温度
},
{
hardwareId: "hardware_5",
trayStatus: 0, // 0为无托盘,1为有托盘,2为托盘抬起
isHeating: false, // 是否正在加热
capStatus: false, // 是否存在拍子
isSealed: false, // 拍子密封状态,true为已密封,false为未密封
temperature: 0, // 当前温度
},
{
hardwareId: "hardware_6",
trayStatus: 0, // 0为无托盘,1为有托盘,2为托盘抬起
isHeating: false, // 是否正在加热
capStatus: false, // 是否存在拍子
isSealed: false, // 拍子密封状态,true为已密封,false为未密封
temperature: 0, // 当前温度
},
],
// 碱容器状态(废液桶)
alkaliBucket: {
isEmpty: false, // 容器是否为空
isFull: false, // 容器是否已满
},
};
export type Datagram = TrackRecordSig | TaskState | ContextMessage;

1503
src/utils/measure.json
File diff suppressed because it is too large
View File

1
tsconfig.json

@ -3,6 +3,7 @@
"target": "ES6",
"module": "commonjs",
"strict": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,

Loading…
Cancel
Save