feat: frontend add virtual matrix key
This commit is contained in:
parent
b68d8eaf11
commit
bea1c7e5ae
|
@ -21,6 +21,7 @@
|
||||||
"ts-results-es": "^5.0.1",
|
"ts-results-es": "^5.0.1",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-router": "4",
|
"vue-router": "4",
|
||||||
|
"yocto-queue": "^1.2.1",
|
||||||
"zod": "^3.24.2"
|
"zod": "^3.24.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -4065,6 +4066,18 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/yocto-queue": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.20"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/yoctocolors": {
|
"node_modules/yoctocolors": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.1.tgz",
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
"ts-results-es": "^5.0.1",
|
"ts-results-es": "^5.0.1",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-router": "4",
|
"vue-router": "4",
|
||||||
|
"yocto-queue": "^1.2.1",
|
||||||
"zod": "^3.24.2"
|
"zod": "^3.24.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
@ -0,0 +1,298 @@
|
||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"author": "template",
|
||||||
|
"editor": "system",
|
||||||
|
"parts": [
|
||||||
|
{
|
||||||
|
"id": "board",
|
||||||
|
"type": "BaseBoard",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"attrs": {
|
||||||
|
"size": 1.2,
|
||||||
|
"width": 400,
|
||||||
|
"height": 400,
|
||||||
|
"roundCorner": 20
|
||||||
|
},
|
||||||
|
"rotate": 0,
|
||||||
|
"group": "MatrixKeypad",
|
||||||
|
"positionlock": false,
|
||||||
|
"hidepins": false,
|
||||||
|
"isOn": true,
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "key_0_0",
|
||||||
|
"type": "MechanicalButton",
|
||||||
|
"x": 50,
|
||||||
|
"y": 50,
|
||||||
|
"attrs": {
|
||||||
|
"size": 0.5,
|
||||||
|
"bindKey": "1",
|
||||||
|
"pins": []
|
||||||
|
},
|
||||||
|
"rotate": 0,
|
||||||
|
"group": "MatrixKeypad",
|
||||||
|
"positionlock": false,
|
||||||
|
"hidepins": true,
|
||||||
|
"isOn": false,
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "key_0_1",
|
||||||
|
"type": "MechanicalButton",
|
||||||
|
"x": 150,
|
||||||
|
"y": 50,
|
||||||
|
"attrs": {
|
||||||
|
"size": 0.5,
|
||||||
|
"bindKey": "2",
|
||||||
|
"pins": []
|
||||||
|
},
|
||||||
|
"rotate": 0,
|
||||||
|
"group": "MatrixKeypad",
|
||||||
|
"positionlock": false,
|
||||||
|
"hidepins": true,
|
||||||
|
"isOn": false,
|
||||||
|
"index": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "key_0_2",
|
||||||
|
"type": "MechanicalButton",
|
||||||
|
"x": 250,
|
||||||
|
"y": 50,
|
||||||
|
"attrs": {
|
||||||
|
"size": 0.5,
|
||||||
|
"bindKey": "3",
|
||||||
|
"pins": []
|
||||||
|
},
|
||||||
|
"rotate": 0,
|
||||||
|
"group": "MatrixKeypad",
|
||||||
|
"positionlock": false,
|
||||||
|
"hidepins": true,
|
||||||
|
"isOn": false,
|
||||||
|
"index": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "key_0_3",
|
||||||
|
"type": "MechanicalButton",
|
||||||
|
"x": 350,
|
||||||
|
"y": 50,
|
||||||
|
"attrs": {
|
||||||
|
"size": 0.5,
|
||||||
|
"bindKey": "A",
|
||||||
|
"pins": []
|
||||||
|
},
|
||||||
|
"rotate": 0,
|
||||||
|
"group": "MatrixKeypad",
|
||||||
|
"positionlock": false,
|
||||||
|
"hidepins": true,
|
||||||
|
"isOn": false,
|
||||||
|
"index": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "key_1_0",
|
||||||
|
"type": "MechanicalButton",
|
||||||
|
"x": 50,
|
||||||
|
"y": 150,
|
||||||
|
"attrs": {
|
||||||
|
"size": 0.5,
|
||||||
|
"bindKey": "4",
|
||||||
|
"pins": []
|
||||||
|
},
|
||||||
|
"rotate": 0,
|
||||||
|
"group": "MatrixKeypad",
|
||||||
|
"positionlock": false,
|
||||||
|
"hidepins": true,
|
||||||
|
"isOn": false,
|
||||||
|
"index": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "key_1_1",
|
||||||
|
"type": "MechanicalButton",
|
||||||
|
"x": 150,
|
||||||
|
"y": 150,
|
||||||
|
"attrs": {
|
||||||
|
"size": 0.5,
|
||||||
|
"bindKey": "5",
|
||||||
|
"pins": []
|
||||||
|
},
|
||||||
|
"rotate": 0,
|
||||||
|
"group": "MatrixKeypad",
|
||||||
|
"positionlock": false,
|
||||||
|
"hidepins": true,
|
||||||
|
"isOn": false,
|
||||||
|
"index": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "key_1_2",
|
||||||
|
"type": "MechanicalButton",
|
||||||
|
"x": 250,
|
||||||
|
"y": 150,
|
||||||
|
"attrs": {
|
||||||
|
"size": 0.5,
|
||||||
|
"bindKey": "6",
|
||||||
|
"pins": []
|
||||||
|
},
|
||||||
|
"rotate": 0,
|
||||||
|
"group": "MatrixKeypad",
|
||||||
|
"positionlock": false,
|
||||||
|
"hidepins": true,
|
||||||
|
"isOn": false,
|
||||||
|
"index": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "key_1_3",
|
||||||
|
"type": "MechanicalButton",
|
||||||
|
"x": 350,
|
||||||
|
"y": 150,
|
||||||
|
"attrs": {
|
||||||
|
"size": 0.5,
|
||||||
|
"bindKey": "B",
|
||||||
|
"pins": []
|
||||||
|
},
|
||||||
|
"rotate": 0,
|
||||||
|
"group": "MatrixKeypad",
|
||||||
|
"positionlock": false,
|
||||||
|
"hidepins": true,
|
||||||
|
"isOn": false,
|
||||||
|
"index": 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "key_2_0",
|
||||||
|
"type": "MechanicalButton",
|
||||||
|
"x": 50,
|
||||||
|
"y": 250,
|
||||||
|
"attrs": {
|
||||||
|
"size": 0.5,
|
||||||
|
"bindKey": "7",
|
||||||
|
"pins": []
|
||||||
|
},
|
||||||
|
"rotate": 0,
|
||||||
|
"group": "MatrixKeypad",
|
||||||
|
"positionlock": false,
|
||||||
|
"hidepins": true,
|
||||||
|
"isOn": false,
|
||||||
|
"index": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "key_2_1",
|
||||||
|
"type": "MechanicalButton",
|
||||||
|
"x": 150,
|
||||||
|
"y": 250,
|
||||||
|
"attrs": {
|
||||||
|
"size": 0.5,
|
||||||
|
"bindKey": "8",
|
||||||
|
"pins": []
|
||||||
|
},
|
||||||
|
"rotate": 0,
|
||||||
|
"group": "MatrixKeypad",
|
||||||
|
"positionlock": false,
|
||||||
|
"hidepins": true,
|
||||||
|
"isOn": false,
|
||||||
|
"index": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "key_2_2",
|
||||||
|
"type": "MechanicalButton",
|
||||||
|
"x": 250,
|
||||||
|
"y": 250,
|
||||||
|
"attrs": {
|
||||||
|
"size": 0.5,
|
||||||
|
"bindKey": "9",
|
||||||
|
"pins": []
|
||||||
|
},
|
||||||
|
"rotate": 0,
|
||||||
|
"group": "MatrixKeypad",
|
||||||
|
"positionlock": false,
|
||||||
|
"hidepins": true,
|
||||||
|
"isOn": false,
|
||||||
|
"index": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "key_2_3",
|
||||||
|
"type": "MechanicalButton",
|
||||||
|
"x": 350,
|
||||||
|
"y": 250,
|
||||||
|
"attrs": {
|
||||||
|
"size": 0.5,
|
||||||
|
"bindKey": "C",
|
||||||
|
"pins": []
|
||||||
|
},
|
||||||
|
"rotate": 0,
|
||||||
|
"group": "MatrixKeypad",
|
||||||
|
"positionlock": false,
|
||||||
|
"hidepins": true,
|
||||||
|
"isOn": false,
|
||||||
|
"index": 11
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "key_3_0",
|
||||||
|
"type": "MechanicalButton",
|
||||||
|
"x": 50,
|
||||||
|
"y": 350,
|
||||||
|
"attrs": {
|
||||||
|
"size": 0.5,
|
||||||
|
"bindKey": "*",
|
||||||
|
"pins": []
|
||||||
|
},
|
||||||
|
"rotate": 0,
|
||||||
|
"group": "MatrixKeypad",
|
||||||
|
"positionlock": false,
|
||||||
|
"hidepins": true,
|
||||||
|
"isOn": false,
|
||||||
|
"index": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "key_3_1",
|
||||||
|
"type": "MechanicalButton",
|
||||||
|
"x": 150,
|
||||||
|
"y": 350,
|
||||||
|
"attrs": {
|
||||||
|
"size": 0.5,
|
||||||
|
"bindKey": "0",
|
||||||
|
"pins": []
|
||||||
|
},
|
||||||
|
"rotate": 0,
|
||||||
|
"group": "MatrixKeypad",
|
||||||
|
"positionlock": false,
|
||||||
|
"hidepins": true,
|
||||||
|
"isOn": false,
|
||||||
|
"index": 13
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "key_3_2",
|
||||||
|
"type": "MechanicalButton",
|
||||||
|
"x": 250,
|
||||||
|
"y": 350,
|
||||||
|
"attrs": {
|
||||||
|
"size": 0.5,
|
||||||
|
"bindKey": "#",
|
||||||
|
"pins": []
|
||||||
|
},
|
||||||
|
"rotate": 0,
|
||||||
|
"group": "MatrixKeypad",
|
||||||
|
"positionlock": false,
|
||||||
|
"hidepins": true,
|
||||||
|
"isOn": false,
|
||||||
|
"index": 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "key_3_3",
|
||||||
|
"type": "MechanicalButton",
|
||||||
|
"x": 350,
|
||||||
|
"y": 350,
|
||||||
|
"attrs": {
|
||||||
|
"size": 0.5,
|
||||||
|
"bindKey": "D",
|
||||||
|
"pins": []
|
||||||
|
},
|
||||||
|
"rotate": 0,
|
||||||
|
"group": "MatrixKeypad",
|
||||||
|
"positionlock": false,
|
||||||
|
"hidepins": true,
|
||||||
|
"isOn": false,
|
||||||
|
"index": 15
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"connections": []
|
||||||
|
}
|
|
@ -52,6 +52,7 @@ try
|
||||||
{
|
{
|
||||||
options.AddPolicy("Users", policy => policy
|
options.AddPolicy("Users", policy => policy
|
||||||
.AllowAnyOrigin()
|
.AllowAnyOrigin()
|
||||||
|
.AllowAnyHeader()
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ public class BoundaryScanRegs
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonProperty("cell_name")]
|
[JsonProperty("cell_name")]
|
||||||
[JsonRequired]
|
[JsonRequired]
|
||||||
public string CellName { get; set; }
|
public string CellName { get; set; } = "UnknownCellName";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// [TODO:description]
|
/// [TODO:description]
|
||||||
|
@ -146,7 +146,8 @@ public class Parser
|
||||||
/// <returns>[TODO:return]</returns>
|
/// <returns>[TODO:return]</returns>
|
||||||
public Optional<List<BoundaryScanRegs.CellEntry>> GetBoundaryLogicalPorts()
|
public Optional<List<BoundaryScanRegs.CellEntry>> GetBoundaryLogicalPorts()
|
||||||
{
|
{
|
||||||
var registers = this.BoundaryRegsDesp["registers"]?.ToList().Where((item)=>{
|
var registers = this.BoundaryRegsDesp["registers"]?.ToList().Where((item) =>
|
||||||
|
{
|
||||||
return item["port_id"] is not null;
|
return item["port_id"] is not null;
|
||||||
});
|
});
|
||||||
if (registers is null) return new();
|
if (registers is null) return new();
|
||||||
|
|
|
@ -21,7 +21,7 @@ public class MatrixKeyController : ControllerBase
|
||||||
/// <returns>返回操作结果的状态码</returns>
|
/// <returns>返回操作结果的状态码</returns>
|
||||||
[HttpPost("EnabelMatrixKey")]
|
[HttpPost("EnabelMatrixKey")]
|
||||||
[EnableCors("Users")]
|
[EnableCors("Users")]
|
||||||
[ProducesResponseType(typeof(uint), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
|
[ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
|
||||||
public async ValueTask<IResult> EnabelMatrixKey(string address, int port)
|
public async ValueTask<IResult> EnabelMatrixKey(string address, int port)
|
||||||
{
|
{
|
||||||
|
@ -48,7 +48,7 @@ public class MatrixKeyController : ControllerBase
|
||||||
/// <returns>返回操作结果的状态码</returns>
|
/// <returns>返回操作结果的状态码</returns>
|
||||||
[HttpPost("DisableMatrixKey")]
|
[HttpPost("DisableMatrixKey")]
|
||||||
[EnableCors("Users")]
|
[EnableCors("Users")]
|
||||||
[ProducesResponseType(typeof(uint), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
|
[ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
|
||||||
public async ValueTask<IResult> DisableMatrixKey(string address, int port)
|
public async ValueTask<IResult> DisableMatrixKey(string address, int port)
|
||||||
{
|
{
|
||||||
|
@ -76,7 +76,7 @@ public class MatrixKeyController : ControllerBase
|
||||||
/// <returns>返回操作结果的状态码</returns>
|
/// <returns>返回操作结果的状态码</returns>
|
||||||
[HttpPost("SetMatrixKeyStatus")]
|
[HttpPost("SetMatrixKeyStatus")]
|
||||||
[EnableCors("Users")]
|
[EnableCors("Users")]
|
||||||
[ProducesResponseType(typeof(uint), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
|
[ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
|
||||||
public async ValueTask<IResult> SetMatrixKeyStatus(string address, int port, [FromBody] bool[] keyStates)
|
public async ValueTask<IResult> SetMatrixKeyStatus(string address, int port, [FromBody] bool[] keyStates)
|
||||||
{
|
{
|
||||||
|
|
|
@ -955,7 +955,13 @@ export class MatrixKeyClient {
|
||||||
this.baseUrl = baseUrl ?? "http://localhost:5000";
|
this.baseUrl = baseUrl ?? "http://localhost:5000";
|
||||||
}
|
}
|
||||||
|
|
||||||
enabelMatrixKey(address: string | undefined, port: number | undefined): Promise<number> {
|
/**
|
||||||
|
* 启用矩阵键控制。
|
||||||
|
* @param address (optional) 设备的IP地址
|
||||||
|
* @param port (optional) 设备的端口号
|
||||||
|
* @return 返回操作结果的状态码
|
||||||
|
*/
|
||||||
|
enabelMatrixKey(address: string | undefined, port: number | undefined): Promise<boolean> {
|
||||||
let url_ = this.baseUrl + "/api/MatrixKey/EnabelMatrixKey?";
|
let url_ = this.baseUrl + "/api/MatrixKey/EnabelMatrixKey?";
|
||||||
if (address === null)
|
if (address === null)
|
||||||
throw new Error("The parameter 'address' cannot be null.");
|
throw new Error("The parameter 'address' cannot be null.");
|
||||||
|
@ -968,7 +974,7 @@ export class MatrixKeyClient {
|
||||||
url_ = url_.replace(/[?&]$/, "");
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
let options_: RequestInit = {
|
let options_: RequestInit = {
|
||||||
method: "GET",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Accept": "application/json"
|
"Accept": "application/json"
|
||||||
}
|
}
|
||||||
|
@ -979,7 +985,7 @@ export class MatrixKeyClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected processEnabelMatrixKey(response: Response): Promise<number> {
|
protected processEnabelMatrixKey(response: Response): Promise<boolean> {
|
||||||
const status = response.status;
|
const status = response.status;
|
||||||
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
if (status === 200) {
|
if (status === 200) {
|
||||||
|
@ -1002,10 +1008,16 @@ export class MatrixKeyClient {
|
||||||
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Promise.resolve<number>(null as any);
|
return Promise.resolve<boolean>(null as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
disableMatrixKey(address: string | undefined, port: number | undefined): Promise<number> {
|
/**
|
||||||
|
* 禁用矩阵键控制。
|
||||||
|
* @param address (optional) 设备的IP地址
|
||||||
|
* @param port (optional) 设备的端口号
|
||||||
|
* @return 返回操作结果的状态码
|
||||||
|
*/
|
||||||
|
disableMatrixKey(address: string | undefined, port: number | undefined): Promise<boolean> {
|
||||||
let url_ = this.baseUrl + "/api/MatrixKey/DisableMatrixKey?";
|
let url_ = this.baseUrl + "/api/MatrixKey/DisableMatrixKey?";
|
||||||
if (address === null)
|
if (address === null)
|
||||||
throw new Error("The parameter 'address' cannot be null.");
|
throw new Error("The parameter 'address' cannot be null.");
|
||||||
|
@ -1018,7 +1030,7 @@ export class MatrixKeyClient {
|
||||||
url_ = url_.replace(/[?&]$/, "");
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
let options_: RequestInit = {
|
let options_: RequestInit = {
|
||||||
method: "GET",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Accept": "application/json"
|
"Accept": "application/json"
|
||||||
}
|
}
|
||||||
|
@ -1029,7 +1041,7 @@ export class MatrixKeyClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected processDisableMatrixKey(response: Response): Promise<number> {
|
protected processDisableMatrixKey(response: Response): Promise<boolean> {
|
||||||
const status = response.status;
|
const status = response.status;
|
||||||
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
if (status === 200) {
|
if (status === 200) {
|
||||||
|
@ -1052,10 +1064,17 @@ export class MatrixKeyClient {
|
||||||
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Promise.resolve<number>(null as any);
|
return Promise.resolve<boolean>(null as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
setMatrixKeyStatus(address: string | undefined, port: number | undefined, keyStates: boolean[]): Promise<number> {
|
/**
|
||||||
|
* 设置矩阵键的状态。
|
||||||
|
* @param address (optional) 设备的IP地址
|
||||||
|
* @param port (optional) 设备的端口号
|
||||||
|
* @param keyStates 矩阵键的状态数组,长度应为16
|
||||||
|
* @return 返回操作结果的状态码
|
||||||
|
*/
|
||||||
|
setMatrixKeyStatus(address: string | undefined, port: number | undefined, keyStates: boolean[]): Promise<boolean> {
|
||||||
let url_ = this.baseUrl + "/api/MatrixKey/SetMatrixKeyStatus?";
|
let url_ = this.baseUrl + "/api/MatrixKey/SetMatrixKeyStatus?";
|
||||||
if (address === null)
|
if (address === null)
|
||||||
throw new Error("The parameter 'address' cannot be null.");
|
throw new Error("The parameter 'address' cannot be null.");
|
||||||
|
@ -1071,7 +1090,7 @@ export class MatrixKeyClient {
|
||||||
|
|
||||||
let options_: RequestInit = {
|
let options_: RequestInit = {
|
||||||
body: content_,
|
body: content_,
|
||||||
method: "GET",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"Accept": "application/json"
|
"Accept": "application/json"
|
||||||
|
@ -1083,7 +1102,7 @@ export class MatrixKeyClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected processSetMatrixKeyStatus(response: Response): Promise<number> {
|
protected processSetMatrixKeyStatus(response: Response): Promise<boolean> {
|
||||||
const status = response.status;
|
const status = response.status;
|
||||||
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
if (status === 200) {
|
if (status === 200) {
|
||||||
|
@ -1106,7 +1125,7 @@ export class MatrixKeyClient {
|
||||||
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Promise.resolve<number>(null as any);
|
return Promise.resolve<boolean>(null as any);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -182,6 +182,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, shallowRef, onMounted } from "vue";
|
import { ref, computed, shallowRef, onMounted } from "vue";
|
||||||
import motherboardSvg from "../components/equipments/svg/motherboard.svg";
|
import motherboardSvg from "../components/equipments/svg/motherboard.svg";
|
||||||
|
import buttonSvg from "../components//equipments/svg/button.svg";
|
||||||
|
|
||||||
// Props 定义
|
// Props 定义
|
||||||
interface Props {
|
interface Props {
|
||||||
|
@ -219,6 +220,7 @@ const availableComponents = [
|
||||||
{ type: "SMA", name: "SMA连接器" },
|
{ type: "SMA", name: "SMA连接器" },
|
||||||
{ type: "MotherBoard", name: "主板" },
|
{ type: "MotherBoard", name: "主板" },
|
||||||
{ type: "PG2L100H_FBG676", name: "PG2L100H FBG676芯片" },
|
{ type: "PG2L100H_FBG676", name: "PG2L100H FBG676芯片" },
|
||||||
|
{ type: "BaseBoard", name: "通用底板" },
|
||||||
];
|
];
|
||||||
|
|
||||||
// --- 可用虚拟外设列表 ---
|
// --- 可用虚拟外设列表 ---
|
||||||
|
@ -233,6 +235,13 @@ const availableTemplates = ref([
|
||||||
path: "/EquipmentTemplates/PG2L100H_Pango100pro.json",
|
path: "/EquipmentTemplates/PG2L100H_Pango100pro.json",
|
||||||
thumbnailUrl: motherboardSvg,
|
thumbnailUrl: motherboardSvg,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "矩阵键盘",
|
||||||
|
id: "MatrixKey",
|
||||||
|
description: "包含4x4,共16个按键的矩阵键盘",
|
||||||
|
path: "/EquipmentTemplates/MatrixKey.json",
|
||||||
|
thumbnailUrl: buttonSvg,
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 显示/隐藏组件菜单
|
// 显示/隐藏组件菜单
|
||||||
|
@ -372,6 +381,7 @@ async function addTemplate(template: any) {
|
||||||
id: template.id,
|
id: template.id,
|
||||||
name: template.name,
|
name: template.name,
|
||||||
template: templateData,
|
template: templateData,
|
||||||
|
capsPage: template.capsPage
|
||||||
});
|
});
|
||||||
|
|
||||||
// 关闭菜单
|
// 关闭菜单
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useDialogStore } from "@/stores/dialog";
|
import { useDialogStore } from "@/stores/dialog";
|
||||||
const dialog = useDialogStore();
|
const dialog = useDialogStore();
|
||||||
|
dialog.enableDialog = true;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="postcss">
|
<style scoped lang="postcss">
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
<template>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" :width="width" :height="height" :class="$attrs">
|
||||||
|
<rect :width="width" :height="height" :rx="props.roundCorner" fill="#222222" />
|
||||||
|
</svg>
|
||||||
|
<Teleport to="#ComponentCapabilities" v-if="selectecComponentID === props.componentId && !!slot.default">
|
||||||
|
<slot></slot>
|
||||||
|
</Teleport>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, computed, inject } from "vue";
|
||||||
|
import { CanvasCurrentSelectedComponentID } from "../InjectKeys";
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
size?: number;
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
roundCorner?: number;
|
||||||
|
componentId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const slot = defineSlots();
|
||||||
|
const props = withDefaults(defineProps<Props>(), getDefaultProps());
|
||||||
|
const selectecComponentID = inject(CanvasCurrentSelectedComponentID, ref(null));
|
||||||
|
|
||||||
|
// 计算实际宽高
|
||||||
|
const width = computed(() => props.width * props.size);
|
||||||
|
const height = computed(() => props.height * props.size);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export function getDefaultProps(): Props {
|
||||||
|
return {
|
||||||
|
size: 1,
|
||||||
|
width: 200,
|
||||||
|
height: 200,
|
||||||
|
roundCorner: 20,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="postcss"></style>
|
|
@ -1,16 +1,28 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="button-container" :style="{
|
<div
|
||||||
|
class="button-container"
|
||||||
|
:style="{
|
||||||
width: width + 'px',
|
width: width + 'px',
|
||||||
height: height + 'px',
|
height: height + 'px',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
}">
|
}"
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" :width="width" :height="height" viewBox="400 400 800 800"
|
>
|
||||||
class="mechanical-button">
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
:width="width"
|
||||||
|
:height="height"
|
||||||
|
viewBox="400 400 800 800"
|
||||||
|
class="mechanical-button"
|
||||||
|
>
|
||||||
<!-- defs 和按钮底座保持不变 -->
|
<!-- defs 和按钮底座保持不变 -->
|
||||||
<defs>
|
<defs>
|
||||||
<filter id="btn-shadow">
|
<filter id="btn-shadow">
|
||||||
<feGaussianBlur in="SourceAlpha" stdDeviation="20" result="blur" />
|
<feGaussianBlur in="SourceAlpha" stdDeviation="20" result="blur" />
|
||||||
<feColorMatrix result="bluralpha" type="matrix" :values="colorMatrix" />
|
<feColorMatrix
|
||||||
|
result="bluralpha"
|
||||||
|
type="matrix"
|
||||||
|
:values="colorMatrix"
|
||||||
|
/>
|
||||||
<feOffset in="bluralpha" dx="20" dy="20" result="offsetBlur" />
|
<feOffset in="bluralpha" dx="20" dy="20" result="offsetBlur" />
|
||||||
<feMerge>
|
<feMerge>
|
||||||
<feMergeNode in="offsetBlur" />
|
<feMergeNode in="offsetBlur" />
|
||||||
|
@ -37,42 +49,81 @@
|
||||||
<circle r="20" cx="525" cy="1075" fill="#171717" />
|
<circle r="20" cx="525" cy="1075" fill="#171717" />
|
||||||
|
|
||||||
<!-- 按钮主体 -->
|
<!-- 按钮主体 -->
|
||||||
<circle r="220" cx="800" cy="800" fill="black" filter="url(#btn-shadow)" />
|
<circle
|
||||||
<circle :r="btnHeight" cx="800" cy="800" :fill="isKeyPressed ? 'url(#pressed)' : 'url(#normal)'"
|
r="220"
|
||||||
fill-opacity="0.9" @mousedown="toggleButtonState(true)" @mouseup="toggleButtonState(false)"
|
cx="800"
|
||||||
@mouseleave="toggleButtonState(false)" style="
|
cy="800"
|
||||||
|
fill="black"
|
||||||
|
filter="url(#btn-shadow)"
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
:r="btnHeight"
|
||||||
|
cx="800"
|
||||||
|
cy="800"
|
||||||
|
:fill="isKeyPressed ? 'url(#pressed)' : 'url(#normal)'"
|
||||||
|
fill-opacity="0.9"
|
||||||
|
@mousedown="toggleButtonState(true)"
|
||||||
|
@mouseup="toggleButtonState(false)"
|
||||||
|
@mouseleave="toggleButtonState(false)"
|
||||||
|
style="
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
transition: all 20ms ease-in-out;
|
transition: all 20ms ease-in-out;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
" />
|
"
|
||||||
|
/>
|
||||||
<!-- 按键文字 - 仅显示绑定的按键 -->
|
<!-- 按键文字 - 仅显示绑定的按键 -->
|
||||||
<text v-if="bindKeyDisplay" x="800" y="800" font-size="310" text-anchor="middle" dominant-baseline="central"
|
<text
|
||||||
fill="#ccc" style="
|
v-if="bindKeyDisplay"
|
||||||
|
x="800"
|
||||||
|
y="800"
|
||||||
|
font-size="310"
|
||||||
|
text-anchor="middle"
|
||||||
|
dominant-baseline="central"
|
||||||
|
fill="#ccc"
|
||||||
|
style="
|
||||||
font-family: Arial;
|
font-family: Arial;
|
||||||
filter: url(#btn-shadow);
|
filter: url(#btn-shadow);
|
||||||
user-select: none;
|
user-select: none;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
mix-blend-mode: overlay;
|
mix-blend-mode: overlay;
|
||||||
">
|
"
|
||||||
|
>
|
||||||
{{ bindKeyDisplay }}
|
{{ bindKeyDisplay }}
|
||||||
</text>
|
</text>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<!-- 渲染自定义引脚数组 -->
|
<!-- 渲染自定义引脚数组 -->
|
||||||
<div v-for="pin in props.pins" :key="pin.pinId" :style="{
|
<div
|
||||||
|
v-for="pin in props.pins"
|
||||||
|
:key="pin.pinId"
|
||||||
|
:style="{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: `${pin.x * props.size}px`,
|
left: `${pin.x * props.size}px`,
|
||||||
top: `${pin.y * props.size}px`,
|
top: `${pin.y * props.size}px`,
|
||||||
transform: 'translate(-50%, -50%)',
|
transform: 'translate(-50%, -50%)',
|
||||||
zIndex: 3,
|
zIndex: 3,
|
||||||
pointerEvents: 'auto',
|
pointerEvents: 'auto',
|
||||||
}" :data-pin-wrapper="`${pin.pinId}`" :data-pin-x="`${pin.x * props.size}`"
|
}"
|
||||||
:data-pin-y="`${pin.y * props.size}`">
|
:data-pin-wrapper="`${pin.pinId}`"
|
||||||
<Pin :ref="(el) => {
|
:data-pin-x="`${pin.x * props.size}`"
|
||||||
|
:data-pin-y="`${pin.y * props.size}`"
|
||||||
|
>
|
||||||
|
<Pin
|
||||||
|
:ref="
|
||||||
|
(el) => {
|
||||||
if (el) pinRefs[pin.pinId] = el;
|
if (el) pinRefs[pin.pinId] = el;
|
||||||
}
|
}
|
||||||
" direction="output" type="digital" :label="pin.pinId" :constraint="pin.constraint" :pinId="pin.pinId"
|
"
|
||||||
:size="0.8" :componentId="props.componentId" @value-change="handlePinValueChange" @pin-click="handlePinClick" />
|
direction="output"
|
||||||
|
type="digital"
|
||||||
|
:label="pin.pinId"
|
||||||
|
:constraint="pin.constraint"
|
||||||
|
:pinId="pin.pinId"
|
||||||
|
:size="0.8"
|
||||||
|
:componentId="props.componentId"
|
||||||
|
@value-change="handlePinValueChange"
|
||||||
|
@pin-click="handlePinClick"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -80,16 +131,16 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, onUnmounted, computed } from "vue";
|
import { ref, onMounted, onUnmounted, computed } from "vue";
|
||||||
import Pin from "./Pin.vue";
|
import Pin from "./Pin.vue";
|
||||||
|
import { useEquipments } from "@/stores/equipments";
|
||||||
|
import { useDialogStore } from "@/stores/dialog";
|
||||||
import { useConstraintsStore } from "../../stores/constraints";
|
import { useConstraintsStore } from "../../stores/constraints";
|
||||||
const { notifyConstraintChange } = useConstraintsStore();
|
import { isNull, isUndefined } from "mathjs";
|
||||||
|
import z from "zod";
|
||||||
// 存储多个Pin引用
|
import { toNumber } from "lodash";
|
||||||
const pinRefs = ref<Record<string, any>>({});
|
|
||||||
|
|
||||||
// 按钮特有属性
|
// 按钮特有属性
|
||||||
interface ButtonProps {
|
export interface ButtonProps {
|
||||||
size?: number;
|
size: number;
|
||||||
bindKey?: string;
|
|
||||||
componentId?: string;
|
componentId?: string;
|
||||||
pins?: {
|
pins?: {
|
||||||
pinId: string;
|
pinId: string;
|
||||||
|
@ -97,21 +148,20 @@ interface ButtonProps {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
|
bindKey?: string;
|
||||||
|
bindMatrixKey?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<ButtonProps>(), {
|
const props = defineProps<ButtonProps>();
|
||||||
size: 1,
|
|
||||||
bindKey: "",
|
// Global Stores
|
||||||
componentId: "button-default",
|
const constrainsts = useConstraintsStore();
|
||||||
pins: () => [
|
const dialog = useDialogStore();
|
||||||
{
|
const eqps = useEquipments();
|
||||||
pinId: "BTN",
|
|
||||||
constraint: "",
|
// 存储多个Pin引用
|
||||||
x: 80,
|
const pinRefs = ref<Record<string, any>>({});
|
||||||
y: 140,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
// 计算实际宽高
|
// 计算实际宽高
|
||||||
const width = computed(() => 160 * props.size);
|
const width = computed(() => 160 * props.size);
|
||||||
|
@ -153,15 +203,25 @@ function toggleButtonState(isPressed: boolean) {
|
||||||
isKeyPressed.value = isPressed;
|
isKeyPressed.value = isPressed;
|
||||||
btnHeight.value = isPressed ? 180 : 200;
|
btnHeight.value = isPressed ? 180 : 200;
|
||||||
|
|
||||||
|
// 矩阵键盘
|
||||||
|
if (eqps.enableMatrixKey) {
|
||||||
|
const ret = eqps.setMatrixKey(props.bindMatrixKey, isPressed);
|
||||||
|
if (!ret)
|
||||||
|
dialog.error(
|
||||||
|
`绑定的矩阵键盘值只能是0 ~ 15,而不是: ${props.bindMatrixKey}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// 发出事件通知父组件
|
// 发出事件通知父组件
|
||||||
if (isPressed) {
|
if (isPressed) {
|
||||||
emit("press");
|
emit("press");
|
||||||
|
|
||||||
|
if (props.pins) {
|
||||||
// 如果有约束,通知约束状态变化为高电平
|
// 如果有约束,通知约束状态变化为高电平
|
||||||
// 对所有引脚应用相同的状态
|
// 对所有引脚应用相同的状态
|
||||||
if (props.pins) {
|
|
||||||
props.pins.forEach((pin) => {
|
props.pins.forEach((pin) => {
|
||||||
if (pin.constraint) {
|
if (pin.constraint) {
|
||||||
notifyConstraintChange(pin.constraint, "high");
|
constrainsts.notifyConstraintChange(pin.constraint, "high");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -172,7 +232,7 @@ function toggleButtonState(isPressed: boolean) {
|
||||||
if (props.pins) {
|
if (props.pins) {
|
||||||
props.pins.forEach((pin) => {
|
props.pins.forEach((pin) => {
|
||||||
if (pin.constraint) {
|
if (pin.constraint) {
|
||||||
notifyConstraintChange(pin.constraint, "low");
|
constrainsts.notifyConstraintChange(pin.constraint, "low");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -200,35 +260,37 @@ onUnmounted(() => {
|
||||||
defineExpose({
|
defineExpose({
|
||||||
toggleButtonState,
|
toggleButtonState,
|
||||||
getInfo: () => ({
|
getInfo: () => ({
|
||||||
// 按钮特有属性
|
|
||||||
bindKey: props.bindKey,
|
bindKey: props.bindKey,
|
||||||
componentId: props.componentId,
|
componentId: props.componentId,
|
||||||
pins: props.pins,
|
pins: props.pins,
|
||||||
}),
|
}),
|
||||||
// 获取引脚位置
|
// 获取引脚位置
|
||||||
getPinPosition: (pinId: string) => {
|
getPinPosition: (pinId: string) => {
|
||||||
console.log(`[MechanicalButton] 调用getPinPosition,寻找pinId: ${pinId}`);
|
console.debug(`[MechanicalButton] 调用getPinPosition,寻找pinId: ${pinId}`);
|
||||||
console.log(
|
console.debug(
|
||||||
`[MechanicalButton] 组件ID: ${props.componentId}, 当前尺寸: ${props.size}, 组件宽高: ${width.value}x${height.value}`,
|
`[MechanicalButton] 组件ID: ${props.componentId}, 当前尺寸: ${props.size}, 组件宽高: ${width.value}x${height.value}`,
|
||||||
);
|
);
|
||||||
console.log(`[MechanicalButton] 当前存在的pins:`, props.pins);
|
console.debug(`[MechanicalButton] 当前存在的pins:`, props.pins);
|
||||||
|
|
||||||
// 如果是自定义的引脚ID
|
// 如果是自定义的引脚ID
|
||||||
if (props.pins && props.pins.length > 0) {
|
if (props.pins && props.pins.length > 0) {
|
||||||
const customPin = props.pins.find((p) => p.pinId === pinId);
|
const customPin = props.pins.find((p) => p.pinId === pinId);
|
||||||
|
|
||||||
if (customPin) {
|
if (customPin) {
|
||||||
console.log(`[MechanicalButton] 找到自定义引脚: ${pinId},配置位置:`, {
|
console.debug(
|
||||||
|
`[MechanicalButton] 找到自定义引脚: ${pinId},配置位置:`,
|
||||||
|
{
|
||||||
x: customPin.x,
|
x: customPin.x,
|
||||||
y: customPin.y,
|
y: customPin.y,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// 考虑组件尺寸的缩放
|
// 考虑组件尺寸的缩放
|
||||||
// 这里的x和y是针对标准尺寸(size=1)的坐标,需要根据实际size调整
|
// 这里的x和y是针对标准尺寸(size=1)的坐标,需要根据实际size调整
|
||||||
const scaledX = customPin.x * props.size;
|
const scaledX = customPin.x * props.size;
|
||||||
const scaledY = customPin.y * props.size;
|
const scaledY = customPin.y * props.size;
|
||||||
|
|
||||||
console.log(`[MechanicalButton] 返回缩放后的坐标:`, {
|
console.debug(`[MechanicalButton] 返回缩放后的坐标:`, {
|
||||||
x: scaledX,
|
x: scaledX,
|
||||||
y: scaledY,
|
y: scaledY,
|
||||||
});
|
});
|
||||||
|
@ -237,12 +299,12 @@ defineExpose({
|
||||||
y: scaledY,
|
y: scaledY,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
console.log(`[MechanicalButton] 未找到pinId: ${pinId}的引脚配置`);
|
console.debug(`[MechanicalButton] 未找到pinId: ${pinId}的引脚配置`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log(`[MechanicalButton] 没有配置任何引脚`);
|
console.debug(`[MechanicalButton] 没有配置任何引脚`);
|
||||||
}
|
}
|
||||||
console.log(`[MechanicalButton] 返回null,未找到引脚`);
|
console.debug(`[MechanicalButton] 返回null,未找到引脚`);
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -253,7 +315,6 @@ defineExpose({
|
||||||
export function getDefaultProps() {
|
export function getDefaultProps() {
|
||||||
return {
|
return {
|
||||||
size: 1,
|
size: 1,
|
||||||
bindKey: "",
|
|
||||||
pins: [
|
pins: [
|
||||||
{
|
{
|
||||||
pinId: "BTN",
|
pinId: "BTN",
|
||||||
|
@ -262,6 +323,8 @@ export function getDefaultProps() {
|
||||||
y: 140,
|
y: 140,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
bindKey: "",
|
||||||
|
bindMatrixKey: "",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -23,7 +23,7 @@ import { toNumber } from "lodash";
|
||||||
|
|
||||||
// 主板特有属性
|
// 主板特有属性
|
||||||
export interface MotherBoardProps {
|
export interface MotherBoardProps {
|
||||||
size?: number;
|
size: number;
|
||||||
boardAddr?: string;
|
boardAddr?: string;
|
||||||
boardPort?: string;
|
boardPort?: string;
|
||||||
componentId?: string;
|
componentId?: string;
|
||||||
|
@ -63,7 +63,6 @@ export function getDefaultProps(): MotherBoardProps {
|
||||||
size: 1,
|
size: 1,
|
||||||
boardAddr: "127.0.0.1",
|
boardAddr: "127.0.0.1",
|
||||||
boardPort: "1234",
|
boardPort: "1234",
|
||||||
componentId: "DefaultMotherBoardID",
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -44,6 +44,12 @@
|
||||||
{{ eqps.enableJtagBoundaryScan ? "关闭边界扫描" : "启动边界扫描" }}
|
{{ eqps.enableJtagBoundaryScan ? "关闭边界扫描" : "启动边界扫描" }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="divider"></div>
|
||||||
|
<h1 class="font-bold text-center text-2xl">外设</h1>
|
||||||
|
<div class="flex flex-row">
|
||||||
|
<input type="checkbox" class="checkbox" :checked="eqps.enableMatrixKey" @change="handleMatrixkeyCheckboxChange" />
|
||||||
|
<p class="mx-2">启用矩阵键盘</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -52,7 +58,7 @@ import z from "zod";
|
||||||
import UploadCard from "@/components/UploadCard.vue";
|
import UploadCard from "@/components/UploadCard.vue";
|
||||||
import { useDialogStore } from "@/stores/dialog";
|
import { useDialogStore } from "@/stores/dialog";
|
||||||
import { useEquipments } from "@/stores/equipments";
|
import { useEquipments } from "@/stores/equipments";
|
||||||
import { computed, ref, watchEffect } from "vue";
|
import { computed, ref, watchEffect, watchPostEffect } from "vue";
|
||||||
|
|
||||||
interface CapsProps {
|
interface CapsProps {
|
||||||
jtagAddr?: string;
|
jtagAddr?: string;
|
||||||
|
@ -100,6 +106,19 @@ function handleSelectJtagSpeed(event: Event) {
|
||||||
emits("changeJtagFreq", target.value);
|
emits("changeJtagFreq", target.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleMatrixkeyCheckboxChange(event: Event) {
|
||||||
|
const target = event.target as HTMLInputElement;
|
||||||
|
if (target.checked) {
|
||||||
|
const ret = await eqps.matrixKeypadEnable(true);
|
||||||
|
if (!ret) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const ret = await eqps.matrixKeypadEnable(false);
|
||||||
|
if (!ret) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function toggleJtagBoundaryScan() {
|
async function toggleJtagBoundaryScan() {
|
||||||
if (eqps.jtagClientMutex.isLocked()) {
|
if (eqps.jtagClientMutex.isLocked()) {
|
||||||
dialog.warn("Jtag正在被占用");
|
dialog.warn("Jtag正在被占用");
|
||||||
|
|
|
@ -1,40 +1,61 @@
|
||||||
import { ref, computed } from 'vue'
|
import { ref, reactive, watchPostEffect, computed } from 'vue'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { isUndefined } from 'lodash';
|
import { isUndefined } from 'lodash';
|
||||||
|
import Queue from 'yocto-queue';
|
||||||
|
|
||||||
export const useDialogStore = defineStore('dialog', () => {
|
export const useDialogStore = defineStore('dialog', () => {
|
||||||
type Title = "Error" | "Info" | "Warn";
|
type Title = "Error" | "Info" | "Warn";
|
||||||
|
const enableDialog = ref(false);
|
||||||
const isDialogOpen = ref(false);
|
const isDialogOpen = ref(false);
|
||||||
const dialogTitle = ref<Title>("Error");
|
const dialogTitle = ref<Title>("Error");
|
||||||
const dialogContent = ref("这是一个错误");
|
const dialogContent = ref("这是一个错误");
|
||||||
|
const contentQueue = new Queue<{ type: Title; content: string }>()
|
||||||
|
|
||||||
function openDialog(title: Title, content?: string) {
|
function openDialog(title?: Title, content?: string) {
|
||||||
|
if (isUndefined(title)) {
|
||||||
|
if (contentQueue.size != 0) {
|
||||||
|
const dialog = contentQueue.dequeue();
|
||||||
|
if (isUndefined(dialog)) return;
|
||||||
|
openDialog(dialog.type, dialog.content);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (!isUndefined(content) && content.length != 0)
|
if (!isUndefined(content) && content.length != 0)
|
||||||
dialogContent.value = content;
|
dialogContent.value = content;
|
||||||
dialogTitle.value = title;
|
dialogTitle.value = title;
|
||||||
isDialogOpen.value = true;
|
isDialogOpen.value = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function closeDialog() {
|
function closeDialog() {
|
||||||
isDialogOpen.value = false;
|
isDialogOpen.value = false;
|
||||||
|
|
||||||
|
openDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
function info(content?: string) {
|
function info(content: string) {
|
||||||
openDialog("Info", content);
|
contentQueue.enqueue({ type: "Info", content: content });
|
||||||
|
openDialog();
|
||||||
|
// openDialog("Info", content);
|
||||||
}
|
}
|
||||||
|
|
||||||
function error(content?: string) {
|
function error(content: string) {
|
||||||
openDialog("Error", content);
|
contentQueue.enqueue({ type: "Error", content: content });
|
||||||
|
openDialog();
|
||||||
|
// openDialog("Error", content);
|
||||||
}
|
}
|
||||||
|
|
||||||
function warn(content?: string) {
|
function warn(content: string) {
|
||||||
openDialog("Warn", content);
|
contentQueue.enqueue({ type: "Warn", content: content });
|
||||||
|
openDialog();
|
||||||
|
// openDialog("Warn", content);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
enableDialog,
|
||||||
isDialogOpen,
|
isDialogOpen,
|
||||||
dialogTitle,
|
dialogTitle,
|
||||||
dialogContent,
|
dialogContent,
|
||||||
|
dialogQueue: contentQueue,
|
||||||
openDialog,
|
openDialog,
|
||||||
closeDialog,
|
closeDialog,
|
||||||
info,
|
info,
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { ref, watchEffect } from 'vue'
|
import { ref, watchEffect, watchPostEffect } from 'vue'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { isString, toNumber, isUndefined } from 'lodash';
|
import { isString, toNumber, isUndefined } from 'lodash';
|
||||||
import { Common } from '@/Common';
|
import { Common } from '@/Common';
|
||||||
import z from "zod"
|
import z from "zod"
|
||||||
import { isNumber } from 'mathjs';
|
import { isNumber } from 'mathjs';
|
||||||
import { JtagClient } from "@/APIClient";
|
import { JtagClient, MatrixKeyClient } from "@/APIClient";
|
||||||
import { Mutex, withTimeout } from 'async-mutex';
|
import { Mutex, withTimeout } from 'async-mutex';
|
||||||
import { useConstraintsStore } from "@/stores/constraints";
|
import { useConstraintsStore } from "@/stores/constraints";
|
||||||
import { useDialogStore } from './dialog';
|
import { useDialogStore } from './dialog';
|
||||||
|
@ -14,15 +14,41 @@ export const useEquipments = defineStore('equipments', () => {
|
||||||
const constrainsts = useConstraintsStore();
|
const constrainsts = useConstraintsStore();
|
||||||
const dialog = useDialogStore();
|
const dialog = useDialogStore();
|
||||||
|
|
||||||
|
// Basic Info
|
||||||
const boardAddr = ref("127.0.0.1");
|
const boardAddr = ref("127.0.0.1");
|
||||||
const boardPort = ref(1234);
|
const boardPort = ref(1234);
|
||||||
|
|
||||||
|
// Jtag
|
||||||
const jtagBitstream = ref<File>();
|
const jtagBitstream = ref<File>();
|
||||||
const jtagBoundaryScanFreq = ref(100);
|
const jtagBoundaryScanFreq = ref(100);
|
||||||
const jtagClientMutex = withTimeout(new Mutex(), 1000, new Error("JtagClient Mutex Timeout!"))
|
const jtagClientMutex = withTimeout(new Mutex(), 1000, new Error("JtagClient Mutex Timeout!"))
|
||||||
const jtagClient = new JtagClient();
|
const jtagClient = new JtagClient();
|
||||||
|
|
||||||
const enableJtagBoundaryScan = ref(false);
|
// Matrix Key
|
||||||
|
const matrixKeyStates = ref(new Array<boolean>(16).fill(false))
|
||||||
|
const matrixKeypadClientMutex = withTimeout(new Mutex(), 1000, new Error("Matrixkeyclient Mutex Timeout!"));
|
||||||
|
const matrixKeypadClient = new MatrixKeyClient();
|
||||||
|
|
||||||
|
// Enable Setting
|
||||||
|
const enableJtagBoundaryScan = ref(false);
|
||||||
|
const enableMatrixKey = ref(false);
|
||||||
|
|
||||||
|
// Watch
|
||||||
|
watchPostEffect(async () => {
|
||||||
|
if (true === enableJtagBoundaryScan.value) jtagBoundaryScan();
|
||||||
|
});
|
||||||
|
|
||||||
|
watchPostEffect(async () => {
|
||||||
|
if (true === enableMatrixKey.value) {
|
||||||
|
const ret = await matrixKeypadSetKeyStates(matrixKeyStates.value)
|
||||||
|
if (!ret) {
|
||||||
|
dialog.error("设置矩阵键盘失败")
|
||||||
|
enableMatrixKey.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Parse and Set
|
||||||
function setAddr(address: string | undefined): boolean {
|
function setAddr(address: string | undefined): boolean {
|
||||||
if (isString(address) && z.string().ip("4").safeParse(address).success) {
|
if (isString(address) && z.string().ip("4").safeParse(address).success) {
|
||||||
boardAddr.value = address;
|
boardAddr.value = address;
|
||||||
|
@ -49,9 +75,23 @@ export const useEquipments = defineStore('equipments', () => {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
watchEffect(() => {
|
function setMatrixKey(keyNum: number | string | undefined, keyValue: boolean): boolean {
|
||||||
if (enableJtagBoundaryScan.value) jtagBoundaryScan();
|
|
||||||
});
|
let _keyNum: number;
|
||||||
|
if (isString(keyNum)) {
|
||||||
|
_keyNum = toNumber(keyNum);
|
||||||
|
} else if (isNumber(keyNum)) {
|
||||||
|
_keyNum = keyNum;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (z.number().nonnegative().max(16).safeParse(_keyNum).success) {
|
||||||
|
matrixKeyStates.value[_keyNum] = keyValue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
async function jtagBoundaryScan() {
|
async function jtagBoundaryScan() {
|
||||||
const release = await jtagClientMutex.acquire();
|
const release = await jtagClientMutex.acquire();
|
||||||
|
@ -138,11 +178,59 @@ export const useEquipments = defineStore('equipments', () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function matrixKeypadSetKeyStates(keyStates: boolean[]) {
|
||||||
|
const release = await matrixKeypadClientMutex.acquire();
|
||||||
|
try {
|
||||||
|
const resp = await matrixKeypadClient.setMatrixKeyStatus(
|
||||||
|
boardAddr.value,
|
||||||
|
boardPort.value,
|
||||||
|
matrixKeyStates.value
|
||||||
|
);
|
||||||
|
return resp;
|
||||||
|
} catch (e) {
|
||||||
|
dialog.error("设置矩阵键盘时,服务器发生错误");
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function matrixKeypadEnable(enable: boolean) {
|
||||||
|
const release = await matrixKeypadClientMutex.acquire();
|
||||||
|
try {
|
||||||
|
if (enable) {
|
||||||
|
const resp = await matrixKeypadClient.enabelMatrixKey(
|
||||||
|
boardAddr.value,
|
||||||
|
boardPort.value,
|
||||||
|
);
|
||||||
|
enableMatrixKey.value = resp;
|
||||||
|
return resp;
|
||||||
|
} else {
|
||||||
|
const resp = await matrixKeypadClient.disableMatrixKey(
|
||||||
|
boardAddr.value,
|
||||||
|
boardPort.value,
|
||||||
|
);
|
||||||
|
enableMatrixKey.value = !resp;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
enableMatrixKey.value = false;
|
||||||
|
dialog.error("设置矩阵键盘是否启用时,服务器发生错误");
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
boardAddr,
|
boardAddr,
|
||||||
boardPort,
|
boardPort,
|
||||||
setAddr,
|
setAddr,
|
||||||
setPort,
|
setPort,
|
||||||
|
setMatrixKey,
|
||||||
|
|
||||||
|
// Jtag
|
||||||
|
enableJtagBoundaryScan,
|
||||||
jtagBitstream,
|
jtagBitstream,
|
||||||
jtagBoundaryScanFreq,
|
jtagBoundaryScanFreq,
|
||||||
jtagClientMutex,
|
jtagClientMutex,
|
||||||
|
@ -151,7 +239,14 @@ export const useEquipments = defineStore('equipments', () => {
|
||||||
jtagDownloadBitstream,
|
jtagDownloadBitstream,
|
||||||
jtagGetIDCode,
|
jtagGetIDCode,
|
||||||
jtagSetSpeed,
|
jtagSetSpeed,
|
||||||
enableJtagBoundaryScan,
|
|
||||||
|
// Matrix Key
|
||||||
|
enableMatrixKey,
|
||||||
|
matrixKeyStates,
|
||||||
|
matrixKeypadClientMutex,
|
||||||
|
matrixKeypadClient,
|
||||||
|
matrixKeypadEnable,
|
||||||
|
matrixKeypadSetKeyStates,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue