Merge branch 'develop' of http://120.46.212.6:3000/joylink/rts-sim-testing-client into develop
This commit is contained in:
commit
548930fd3c
@ -184,51 +184,18 @@ export async function ibpKeyOperation(params: IbpKeyOperationParams) {
|
|||||||
return await api.post(`${UriBase}/ibp/key/operation`, params);
|
return await api.post(`${UriBase}/ibp/key/operation`, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TccButtonOperationParams {
|
export interface TccOperationParams {
|
||||||
buttonId: number;
|
|
||||||
down: boolean;
|
|
||||||
mapId: number;
|
|
||||||
simulationId: string;
|
simulationId: string;
|
||||||
tccId: number;
|
trainId: string;
|
||||||
|
deviceId: number;
|
||||||
|
controlType: request.TrainControl.TrainControlType;
|
||||||
|
button?: object;
|
||||||
|
driverKey?: object;
|
||||||
|
dirKey?: object;
|
||||||
|
handler?: object;
|
||||||
}
|
}
|
||||||
export async function tccButtonOperation(params: TccButtonOperationParams) {
|
export async function tccOperation(params: TccOperationParams) {
|
||||||
return await api.post(`${UriBase}/tcc/btn/operation`, params);
|
return await api.post(`${UriBase}/train/control`, params);
|
||||||
}
|
|
||||||
|
|
||||||
export interface TccKeyOperationParams {
|
|
||||||
simulationId: string;
|
|
||||||
mapId: number;
|
|
||||||
tccId: number;
|
|
||||||
val: boolean;
|
|
||||||
keyId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function tccKeyOperation(params: TccKeyOperationParams) {
|
|
||||||
return await api.post(`${UriBase}/tcc/key/operation`, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TccKeyDirOperationParams {
|
|
||||||
simulationId: string;
|
|
||||||
mapId: number;
|
|
||||||
tccId: number;
|
|
||||||
val: number;
|
|
||||||
keyId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function tccKeyDirOperation(params: TccKeyDirOperationParams) {
|
|
||||||
return await api.post(`${UriBase}/tcc/key/operation`, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TccHandleOperationParams {
|
|
||||||
simulationId: string;
|
|
||||||
mapId: number;
|
|
||||||
tccId: number;
|
|
||||||
val: number;
|
|
||||||
handleId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function tccHandleOperation(params: TccHandleOperationParams) {
|
|
||||||
return await api.post(`${UriBase}/tcc/handle/operation`, params);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkMapData(data: { mapProto: string }) {
|
export function checkMapData(data: { mapProto: string }) {
|
||||||
|
@ -11,8 +11,9 @@ import {
|
|||||||
ITccButtonState,
|
ITccButtonState,
|
||||||
TccButton,
|
TccButton,
|
||||||
} from 'src/graphics/tccButton/TccButton';
|
} from 'src/graphics/tccButton/TccButton';
|
||||||
import { tccButtonOperation } from 'src/api/Simulation';
|
import { tccOperation } from 'src/api/Simulation';
|
||||||
import { errorNotify } from 'src/utils/CommonNotify';
|
import { errorNotify } from 'src/utils/CommonNotify';
|
||||||
|
import { request } from 'src/protos/request';
|
||||||
|
|
||||||
export class TccButtonData extends GraphicDataBase implements ITccButtonData {
|
export class TccButtonData extends GraphicDataBase implements ITccButtonData {
|
||||||
constructor(data?: tccGraphicData.TccButton) {
|
constructor(data?: tccGraphicData.TccButton) {
|
||||||
@ -115,21 +116,20 @@ export class TccButtonOperateInteraction extends GraphicInteractionPlugin<TccBut
|
|||||||
|
|
||||||
onClick(e: FederatedMouseEvent): void {
|
onClick(e: FederatedMouseEvent): void {
|
||||||
const simulationId = useLineStore().simulationId;
|
const simulationId = useLineStore().simulationId;
|
||||||
const mapId = useLineStore().mapId;
|
|
||||||
const tccId = useTccStore().tccId;
|
const tccId = useTccStore().tccId;
|
||||||
const target = e.target as DisplayObject;
|
const target = e.target as DisplayObject;
|
||||||
const tccButton = target.getGraphic<TccButton>();
|
const tccButton = target.getGraphic<TccButton>();
|
||||||
if (!tccButton || !simulationId || !mapId) return;
|
if (!tccButton || !simulationId) return;
|
||||||
tccButton.states.down = !tccButton.states.down;
|
tccOperation({
|
||||||
tccButton.doRepaint();
|
|
||||||
/* tccButtonOperation({
|
|
||||||
simulationId,
|
simulationId,
|
||||||
mapId,
|
trainId: tccId + '',
|
||||||
buttonId: tccButton.id,
|
deviceId: tccButton.id,
|
||||||
tccId,
|
controlType: request.TrainControl.TrainControlType.EMERGENT_BUTTON,
|
||||||
down: !tccButton.states.down,
|
button: {
|
||||||
|
active: !tccButton.states.down,
|
||||||
|
},
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
errorNotify('操作失败', { message: err.origin.response.data.title });
|
errorNotify('操作失败', { message: err.origin.response.data.title });
|
||||||
}); */
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,9 @@ import { GraphicInteractionPlugin, IGraphicScene, JlGraphic } from 'jl-graphic';
|
|||||||
import { type FederatedMouseEvent, DisplayObject } from 'pixi.js';
|
import { type FederatedMouseEvent, DisplayObject } from 'pixi.js';
|
||||||
import { useTccStore } from 'src/stores/tcc-store';
|
import { useTccStore } from 'src/stores/tcc-store';
|
||||||
import { useLineStore } from 'src/stores/line-store';
|
import { useLineStore } from 'src/stores/line-store';
|
||||||
import { tccHandleOperation } from 'src/api/Simulation';
|
import { tccOperation } from 'src/api/Simulation';
|
||||||
import { errorNotify } from 'src/utils/CommonNotify';
|
import { errorNotify } from 'src/utils/CommonNotify';
|
||||||
|
import { request } from 'src/protos/request';
|
||||||
|
|
||||||
export class TccHandleData extends GraphicDataBase implements ITccHandleData {
|
export class TccHandleData extends GraphicDataBase implements ITccHandleData {
|
||||||
constructor(data?: tccGraphicData.TccHandle) {
|
constructor(data?: tccGraphicData.TccHandle) {
|
||||||
@ -156,15 +157,17 @@ export class TccHandleInteraction extends GraphicInteractionPlugin<TccHandle> {
|
|||||||
const target = e.target as DisplayObject;
|
const target = e.target as DisplayObject;
|
||||||
const tccHandle = target.getGraphic<TccHandle>();
|
const tccHandle = target.getGraphic<TccHandle>();
|
||||||
if (!tccHandle || !simulationId || !mapId) return;
|
if (!tccHandle || !simulationId || !mapId) return;
|
||||||
tccHandle.doRepaint();
|
const handleVal = Math.floor(-(tccHandle._tccHandle.y / 144) * 100);
|
||||||
/* tccHandleOperation({
|
tccOperation({
|
||||||
simulationId,
|
simulationId,
|
||||||
mapId,
|
trainId: tccId + '',
|
||||||
handleId: tccHandle.id,
|
deviceId: tccHandle.id,
|
||||||
tccId,
|
controlType: request.TrainControl.TrainControlType.HANDLER,
|
||||||
val: tccHandle._tccHandle.y,
|
handler: {
|
||||||
|
val: handleVal,
|
||||||
|
},
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
errorNotify('操作失败', { message: err.origin.response.data.title });
|
errorNotify('操作失败', { message: err.origin.response.data.title });
|
||||||
}); */
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,10 @@ import {
|
|||||||
Sprite,
|
Sprite,
|
||||||
} from 'pixi.js';
|
} from 'pixi.js';
|
||||||
import { useTccStore } from 'src/stores/tcc-store';
|
import { useTccStore } from 'src/stores/tcc-store';
|
||||||
import { threadId } from 'worker_threads';
|
|
||||||
import { useLineStore } from 'src/stores/line-store';
|
import { useLineStore } from 'src/stores/line-store';
|
||||||
import { tccKeyDirOperation, tccKeyOperation } from 'src/api/Simulation';
|
import { tccOperation } from 'src/api/Simulation';
|
||||||
import { errorNotify } from 'src/utils/CommonNotify';
|
import { errorNotify } from 'src/utils/CommonNotify';
|
||||||
|
import { request } from 'src/protos/request';
|
||||||
|
|
||||||
export class TccKeyData extends GraphicDataBase implements ITccKeyData {
|
export class TccKeyData extends GraphicDataBase implements ITccKeyData {
|
||||||
constructor(data?: tccGraphicData.TccKey) {
|
constructor(data?: tccGraphicData.TccKey) {
|
||||||
@ -97,7 +97,6 @@ export interface IKeyInteractionConfig {
|
|||||||
gearPositionAmount?: number;
|
gearPositionAmount?: number;
|
||||||
keyRotationMethod: KeyRotationMethod;
|
keyRotationMethod: KeyRotationMethod;
|
||||||
doAfterChangeRotation: (g: JlGraphic, rotation: number) => void;
|
doAfterChangeRotation: (g: JlGraphic, rotation: number) => void;
|
||||||
doFinish: () => void;
|
|
||||||
}
|
}
|
||||||
export abstract class KeyInteraction<
|
export abstract class KeyInteraction<
|
||||||
G extends JlGraphic
|
G extends JlGraphic
|
||||||
@ -107,6 +106,7 @@ export abstract class KeyInteraction<
|
|||||||
mouseDownBeginPos = new Point();
|
mouseDownBeginPos = new Point();
|
||||||
mouseDownBeginRotation = 0;
|
mouseDownBeginRotation = 0;
|
||||||
keyInteractionConfig: IKeyInteractionConfig;
|
keyInteractionConfig: IKeyInteractionConfig;
|
||||||
|
lastTimenRotation = 0;
|
||||||
constructor(
|
constructor(
|
||||||
name: string,
|
name: string,
|
||||||
app: IGraphicScene,
|
app: IGraphicScene,
|
||||||
@ -122,7 +122,6 @@ export abstract class KeyInteraction<
|
|||||||
g.onmouseup = (e) => {
|
g.onmouseup = (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
this.isMouseDown = false;
|
this.isMouseDown = false;
|
||||||
this.keyInteractionConfig.doFinish();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
totalUnbind(g: G): void {
|
totalUnbind(g: G): void {
|
||||||
@ -148,6 +147,7 @@ export abstract class KeyInteraction<
|
|||||||
this.isMouseDown = true;
|
this.isMouseDown = true;
|
||||||
this.mouseDownBeginPos = this.app.toCanvasCoordinates(e.global);
|
this.mouseDownBeginPos = this.app.toCanvasCoordinates(e.global);
|
||||||
this.mouseDownBeginRotation = this.ratatingSprite.rotation;
|
this.mouseDownBeginRotation = this.ratatingSprite.rotation;
|
||||||
|
this.lastTimenRotation = this.ratatingSprite.rotation;
|
||||||
}
|
}
|
||||||
onMousemove(e: FederatedMouseEvent) {
|
onMousemove(e: FederatedMouseEvent) {
|
||||||
const target = e.target as DisplayObject;
|
const target = e.target as DisplayObject;
|
||||||
@ -160,46 +160,44 @@ export abstract class KeyInteraction<
|
|||||||
g.position,
|
g.position,
|
||||||
mouseEndPos
|
mouseEndPos
|
||||||
);
|
);
|
||||||
|
let changeRotation = 0;
|
||||||
if (
|
if (
|
||||||
this.keyInteractionConfig.keyRotationMethod ==
|
this.keyInteractionConfig.keyRotationMethod ==
|
||||||
KeyRotationMethod.jumpChange
|
KeyRotationMethod.jumpChange
|
||||||
) {
|
) {
|
||||||
if (direction == 'ssz') {
|
if (direction == 'ssz') {
|
||||||
if (angle < 45) {
|
if (angle < 45) {
|
||||||
this.ratatingSprite.rotation = this.mouseDownBeginRotation;
|
changeRotation = this.mouseDownBeginRotation;
|
||||||
}
|
}
|
||||||
if (angle >= 45 && angle < 90) {
|
if (
|
||||||
this.ratatingSprite.rotation =
|
angle >= 45 &&
|
||||||
this.mouseDownBeginRotation + Math.PI / 4;
|
angle < 90 &&
|
||||||
|
this.mouseDownBeginRotation !== Math.PI / 4
|
||||||
|
) {
|
||||||
|
changeRotation = this.mouseDownBeginRotation + Math.PI / 4;
|
||||||
} else if (
|
} else if (
|
||||||
angle >= 90 &&
|
angle >= 90 &&
|
||||||
this.mouseDownBeginRotation == -Math.PI / 4
|
this.mouseDownBeginRotation == -Math.PI / 4
|
||||||
) {
|
) {
|
||||||
this.ratatingSprite.rotation =
|
changeRotation = this.mouseDownBeginRotation + Math.PI / 2;
|
||||||
this.mouseDownBeginRotation + Math.PI / 2;
|
}
|
||||||
|
if (this.lastTimenRotation !== changeRotation) {
|
||||||
|
this.lastTimenRotation = changeRotation;
|
||||||
|
this.keyInteractionConfig.doAfterChangeRotation(g, changeRotation);
|
||||||
}
|
}
|
||||||
this.keyInteractionConfig.doAfterChangeRotation(
|
|
||||||
g,
|
|
||||||
this.ratatingSprite.rotation
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (direction == 'nsz') {
|
if (direction == 'nsz') {
|
||||||
if (angle < 45) {
|
if (angle < 45) {
|
||||||
this.ratatingSprite.rotation = this.mouseDownBeginRotation;
|
changeRotation = this.mouseDownBeginRotation;
|
||||||
} else if (angle >= 45 && angle < 90) {
|
} else if (angle >= 45 && angle < 90) {
|
||||||
this.ratatingSprite.rotation =
|
changeRotation = this.mouseDownBeginRotation - Math.PI / 4;
|
||||||
this.mouseDownBeginRotation - Math.PI / 4;
|
} else if (angle >= 90 && changeRotation == Math.PI / 4) {
|
||||||
} else if (
|
changeRotation = this.mouseDownBeginRotation - Math.PI / 2;
|
||||||
angle >= 90 &&
|
}
|
||||||
this.mouseDownBeginRotation == Math.PI / 4
|
if (this.lastTimenRotation !== changeRotation) {
|
||||||
) {
|
this.lastTimenRotation = changeRotation;
|
||||||
this.ratatingSprite.rotation =
|
this.keyInteractionConfig.doAfterChangeRotation(g, changeRotation);
|
||||||
this.mouseDownBeginRotation - Math.PI / 2;
|
|
||||||
}
|
}
|
||||||
this.keyInteractionConfig.doAfterChangeRotation(
|
|
||||||
g,
|
|
||||||
this.ratatingSprite.rotation
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (direction == 'ssz') {
|
if (direction == 'ssz') {
|
||||||
@ -223,9 +221,6 @@ export class TccKeyInteraction extends KeyInteraction<TccKey> {
|
|||||||
doAfterChangeRotation: (g: JlGraphic, rotation: number) => {
|
doAfterChangeRotation: (g: JlGraphic, rotation: number) => {
|
||||||
this.changeState(g, rotation);
|
this.changeState(g, rotation);
|
||||||
},
|
},
|
||||||
doFinish: () => {
|
|
||||||
this.onFinish();
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
static init(app: IGraphicScene) {
|
static init(app: IGraphicScene) {
|
||||||
@ -266,17 +261,20 @@ export class TccKeyInteraction extends KeyInteraction<TccKey> {
|
|||||||
const target = e.target as DisplayObject;
|
const target = e.target as DisplayObject;
|
||||||
const tccKey = target.getGraphic<TccKey>();
|
const tccKey = target.getGraphic<TccKey>();
|
||||||
if (!tccKey || !simulationId || !mapId) return;
|
if (!tccKey || !simulationId || !mapId) return;
|
||||||
tccKey.state.position = tccKey?.state.position == 0 ? 1 : 0;
|
const state = tccKey?.state.position == 0 ? true : false;
|
||||||
tccKey.doRepaint();
|
const driverKeyType = tccKey?.datas.code == '司控器钥匙1' ? 0 : 1;
|
||||||
/* tccKeyOperation({
|
tccOperation({
|
||||||
simulationId,
|
simulationId,
|
||||||
mapId,
|
trainId: tccId + '',
|
||||||
keyId: tccKey.id,
|
deviceId: tccKey.id,
|
||||||
tccId,
|
controlType: request.TrainControl.TrainControlType.DRIVER_KEY_SWITCH,
|
||||||
val: !tccKey.state.position,
|
driverKey: {
|
||||||
|
val: state,
|
||||||
|
dt: driverKeyType,
|
||||||
|
},
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
errorNotify('操作失败', { message: err.origin.response.data.title });
|
errorNotify('操作失败', { message: err.origin.response.data.title });
|
||||||
}); */
|
});
|
||||||
}
|
}
|
||||||
changeState(g: JlGraphic, rotation: number) {
|
changeState(g: JlGraphic, rotation: number) {
|
||||||
let position = 0;
|
let position = 0;
|
||||||
@ -292,22 +290,20 @@ export class TccKeyInteraction extends KeyInteraction<TccKey> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
(g as TccKey).state.position = position;
|
(g as TccKey).state.position = position;
|
||||||
g.doRepaint();
|
|
||||||
}
|
|
||||||
onFinish() {
|
|
||||||
const simulationId = useLineStore().simulationId;
|
const simulationId = useLineStore().simulationId;
|
||||||
const mapId = useLineStore().mapId;
|
|
||||||
const tccId = useTccStore().tccId;
|
const tccId = useTccStore().tccId;
|
||||||
if (!simulationId || !mapId) return;
|
if (!simulationId) return;
|
||||||
/* tccKeyDirOperation({
|
tccOperation({
|
||||||
simulationId,
|
simulationId,
|
||||||
mapId,
|
trainId: tccId + '',
|
||||||
keyId: g.id,
|
deviceId: g.id,
|
||||||
tccId,
|
controlType: request.TrainControl.TrainControlType.DIRECTION_KEY_SWITCH,
|
||||||
val: (g as TccKey).state.position,
|
dirKey: {
|
||||||
|
val: position,
|
||||||
|
},
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
errorNotify('操作失败', { message: err.origin.response.data.title });
|
errorNotify('操作失败', { message: err.origin.response.data.title });
|
||||||
}); */
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ export class TccHandle extends JlGraphic {
|
|||||||
return this.getStates<ITccHandleState>();
|
return this.getStates<ITccHandleState>();
|
||||||
}
|
}
|
||||||
doRepaint(): void {
|
doRepaint(): void {
|
||||||
this._tccHandle.rotation = (-Math.PI / 2) * this.state.gear;
|
this._tccHandle.y = -Math.floor((this.state.gear * 144) / 100);
|
||||||
this._tccHandle.texture = this.tccHandleTextures.tccHandle;
|
this._tccHandle.texture = this.tccHandleTextures.tccHandle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1422,7 +1422,7 @@ export namespace request {
|
|||||||
#one_of_decls: number[][] = [];
|
#one_of_decls: number[][] = [];
|
||||||
constructor(data?: any[] | {
|
constructor(data?: any[] | {
|
||||||
simulationId?: string;
|
simulationId?: string;
|
||||||
trainId?: number;
|
trainId?: string;
|
||||||
deviceId?: number;
|
deviceId?: number;
|
||||||
controlType?: TrainControl.TrainControlType;
|
controlType?: TrainControl.TrainControlType;
|
||||||
button?: TrainControl.EmergentButton;
|
button?: TrainControl.EmergentButton;
|
||||||
@ -1466,9 +1466,9 @@ export namespace request {
|
|||||||
pb_1.Message.setField(this, 1, value);
|
pb_1.Message.setField(this, 1, value);
|
||||||
}
|
}
|
||||||
get trainId() {
|
get trainId() {
|
||||||
return pb_1.Message.getFieldWithDefault(this, 2, 0) as number;
|
return pb_1.Message.getFieldWithDefault(this, 2, "") as string;
|
||||||
}
|
}
|
||||||
set trainId(value: number) {
|
set trainId(value: string) {
|
||||||
pb_1.Message.setField(this, 2, value);
|
pb_1.Message.setField(this, 2, value);
|
||||||
}
|
}
|
||||||
get deviceId() {
|
get deviceId() {
|
||||||
@ -1521,7 +1521,7 @@ export namespace request {
|
|||||||
}
|
}
|
||||||
static fromObject(data: {
|
static fromObject(data: {
|
||||||
simulationId?: string;
|
simulationId?: string;
|
||||||
trainId?: number;
|
trainId?: string;
|
||||||
deviceId?: number;
|
deviceId?: number;
|
||||||
controlType?: TrainControl.TrainControlType;
|
controlType?: TrainControl.TrainControlType;
|
||||||
button?: ReturnType<typeof TrainControl.EmergentButton.prototype.toObject>;
|
button?: ReturnType<typeof TrainControl.EmergentButton.prototype.toObject>;
|
||||||
@ -1559,7 +1559,7 @@ export namespace request {
|
|||||||
toObject() {
|
toObject() {
|
||||||
const data: {
|
const data: {
|
||||||
simulationId?: string;
|
simulationId?: string;
|
||||||
trainId?: number;
|
trainId?: string;
|
||||||
deviceId?: number;
|
deviceId?: number;
|
||||||
controlType?: TrainControl.TrainControlType;
|
controlType?: TrainControl.TrainControlType;
|
||||||
button?: ReturnType<typeof TrainControl.EmergentButton.prototype.toObject>;
|
button?: ReturnType<typeof TrainControl.EmergentButton.prototype.toObject>;
|
||||||
@ -1599,8 +1599,8 @@ export namespace request {
|
|||||||
const writer = w || new pb_1.BinaryWriter();
|
const writer = w || new pb_1.BinaryWriter();
|
||||||
if (this.simulationId.length)
|
if (this.simulationId.length)
|
||||||
writer.writeString(1, this.simulationId);
|
writer.writeString(1, this.simulationId);
|
||||||
if (this.trainId != 0)
|
if (this.trainId.length)
|
||||||
writer.writeUint32(2, this.trainId);
|
writer.writeString(2, this.trainId);
|
||||||
if (this.deviceId != 0)
|
if (this.deviceId != 0)
|
||||||
writer.writeUint32(3, this.deviceId);
|
writer.writeUint32(3, this.deviceId);
|
||||||
if (this.controlType != TrainControl.TrainControlType.EMERGENT_BUTTON)
|
if (this.controlType != TrainControl.TrainControlType.EMERGENT_BUTTON)
|
||||||
@ -1626,7 +1626,7 @@ export namespace request {
|
|||||||
message.simulationId = reader.readString();
|
message.simulationId = reader.readString();
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
message.trainId = reader.readUint32();
|
message.trainId = reader.readString();
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
message.deviceId = reader.readUint32();
|
message.deviceId = reader.readUint32();
|
||||||
|
Loading…
Reference in New Issue
Block a user