From 74f28d54d94e2cc2f9729903e5b154a8533096fb Mon Sep 17 00:00:00 2001 From: joylink_zhaoerwei Date: Sat, 14 Sep 2024 12:02:41 +0800 Subject: [PATCH] =?UTF-8?q?CCTV=E7=BB=98=E5=88=B6app=E6=9A=82=E6=8F=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/drawIcon.svg | 99 +++++++ .../draw-app/CCTVDrawProperties.vue | 45 +++ .../properties/CCTV/CCTVButtonProperty.vue | 39 +++ .../properties/CCTV/CanvasCCTVProperty.vue | 80 ++++++ src/drawApp/cctvApp.ts | 129 +++++++++ .../graphics/CCTV/CCTVButtonInteraction.ts | 47 ++++ src/graphics/CCTV/cctvButton/CCTVButton.ts | 70 +++++ .../cctvButton/CCTVButtonDrawAssistant.ts | 122 +++++++++ .../CCTV/cctvButton/cctv-button-data.json | 29 ++ .../cctvButton/cctv-button-spritesheet.png | Bin 0 -> 2599 bytes src/layouts/CCTVDrawLayout.vue | 257 ++++++++++++++++++ src/protos/cctv_graphic_data.ts | 224 +++++++++++++++ src/protos/picture.ts | 18 ++ src/router/routes.ts | 5 + src/stores/cctv-draw-store.ts | 106 ++++++++ 15 files changed, 1270 insertions(+) create mode 100644 public/drawIcon.svg create mode 100644 src/components/draw-app/CCTVDrawProperties.vue create mode 100644 src/components/draw-app/properties/CCTV/CCTVButtonProperty.vue create mode 100644 src/components/draw-app/properties/CCTV/CanvasCCTVProperty.vue create mode 100644 src/drawApp/cctvApp.ts create mode 100644 src/drawApp/graphics/CCTV/CCTVButtonInteraction.ts create mode 100644 src/graphics/CCTV/cctvButton/CCTVButton.ts create mode 100644 src/graphics/CCTV/cctvButton/CCTVButtonDrawAssistant.ts create mode 100644 src/graphics/CCTV/cctvButton/cctv-button-data.json create mode 100644 src/graphics/CCTV/cctvButton/cctv-button-spritesheet.png create mode 100644 src/layouts/CCTVDrawLayout.vue create mode 100644 src/protos/cctv_graphic_data.ts create mode 100644 src/protos/picture.ts create mode 100644 src/stores/cctv-draw-store.ts diff --git a/public/drawIcon.svg b/public/drawIcon.svg new file mode 100644 index 0000000..0639126 --- /dev/null +++ b/public/drawIcon.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/draw-app/CCTVDrawProperties.vue b/src/components/draw-app/CCTVDrawProperties.vue new file mode 100644 index 0000000..9bf712f --- /dev/null +++ b/src/components/draw-app/CCTVDrawProperties.vue @@ -0,0 +1,45 @@ + + + diff --git a/src/components/draw-app/properties/CCTV/CCTVButtonProperty.vue b/src/components/draw-app/properties/CCTV/CCTVButtonProperty.vue new file mode 100644 index 0000000..faf6acc --- /dev/null +++ b/src/components/draw-app/properties/CCTV/CCTVButtonProperty.vue @@ -0,0 +1,39 @@ + + + diff --git a/src/components/draw-app/properties/CCTV/CanvasCCTVProperty.vue b/src/components/draw-app/properties/CCTV/CanvasCCTVProperty.vue new file mode 100644 index 0000000..08942a2 --- /dev/null +++ b/src/components/draw-app/properties/CCTV/CanvasCCTVProperty.vue @@ -0,0 +1,80 @@ + + + diff --git a/src/drawApp/cctvApp.ts b/src/drawApp/cctvApp.ts new file mode 100644 index 0000000..2aa9e80 --- /dev/null +++ b/src/drawApp/cctvApp.ts @@ -0,0 +1,129 @@ +import { + CombinationKey, + ContextMenu, + IDrawApp, + IGraphicStorage, + JlGraphic, + KeyListener, + MenuItemOptions, + newDrawApp, +} from 'jl-graphic'; +import { useCCTVDrawStore } from 'src/stores/cctv-draw-store'; +import { iscsGraphicData } from 'src/protos/iscs_graphic_data'; +import { toStorageTransform } from './graphics/GraphicDataBase'; +import { fromUint8Array } from 'js-base64'; +import { CCTVButtonDraw } from 'src/graphics/CCTV/cctvButton/CCTVButtonDrawAssistant'; +import { CCTVButtonTemplate } from 'src/graphics/CCTV/cctvButton/CCTVButton'; +import { CCTVButtonData } from './graphics/CCTV/CCTVButtonInteraction'; + +let drawApp: IDrawApp | null = null; + +const UndoOptions: MenuItemOptions = { + name: '撤销', +}; +const RedoOptions: MenuItemOptions = { + name: '重做', +}; +const SelectAllOptions: MenuItemOptions = { + name: '全选', +}; + +export const DefaultCanvasMenu = new ContextMenu({ + name: '绘制-画布菜单', + groups: [ + { + items: [UndoOptions, RedoOptions], + }, + { + items: [SelectAllOptions], + }, + ], +}); + +export function getDrawApp(): IDrawApp | null { + return drawApp; +} + +export function destroyDrawApp(): void { + if (drawApp) { + drawApp.destroy(); + drawApp = null; + } +} + +export function initDrawApp(): IDrawApp { + const isSupportDeletion = (g: JlGraphic) => { + console.log(g); + return true; + }; + drawApp = newDrawApp({ + dataLoader: loadDrawDatas, + isSupportDeletion: isSupportDeletion, + }); + + const app = drawApp; + new CCTVButtonDraw(drawApp, new CCTVButtonTemplate(new CCTVButtonData())); + app.canvas.on('_rightclick', (e) => { + if (app.drawing) return; + UndoOptions.disabled = !app.opRecord.hasUndo; + RedoOptions.disabled = !app.opRecord.hasRedo; + + UndoOptions.handler = () => { + app.opRecord.undo(); + }; + RedoOptions.handler = () => { + app.opRecord.redo(); + }; + SelectAllOptions.handler = () => { + app.selectAllGraphics(); + }; + DefaultCanvasMenu.open(e.global); + }); + app.on('destroy', async () => {}); + app.addKeyboardListener( + new KeyListener({ + value: 'KeyS', + global: true, + combinations: [CombinationKey.Ctrl], + onPress: () => { + saveDrawToServer(saveDrawDatas(app)); + }, + }) + ); + return drawApp; +} + +export async function loadDrawDatas(): Promise { + const drawStore = useCCTVDrawStore(); + const id = drawStore.draftId; + if (!id) { + throw new Error('获取数据异常:为获取到草稿地图ID'); + } + return Promise.resolve({ + datas: [], + }); +} + +export function saveDrawDatas(app: IDrawApp) { + const storage = new iscsGraphicData.IscsGraphicStorage(); + const canvasData = app.canvas.saveData(); + storage.canvas = new iscsGraphicData.Canvas({ + width: canvasData.width, + height: canvasData.height, + backgroundColor: canvasData.backgroundColor, + viewportTransform: toStorageTransform(canvasData.viewportTransform), + }); + const graphics = app.queryStore.getAllGraphics(); + console.log(storage, '保存数据', graphics); + const base64 = fromUint8Array(storage.serialize()); + return base64; +} + +export function saveDrawToServer(base64: string) { + const drawStore = useCCTVDrawStore(); + const id = drawStore.draftId; + if (!id) { + return; + } + console.log('save' + base64); +} diff --git a/src/drawApp/graphics/CCTV/CCTVButtonInteraction.ts b/src/drawApp/graphics/CCTV/CCTVButtonInteraction.ts new file mode 100644 index 0000000..c4b628f --- /dev/null +++ b/src/drawApp/graphics/CCTV/CCTVButtonInteraction.ts @@ -0,0 +1,47 @@ +import * as pb_1 from 'google-protobuf'; +import { CCTVGraphicData } from 'src/protos/cctv_graphic_data'; +import { GraphicDataBase } from '../GraphicDataBase'; +import { + CCTVButton, + ICCTVButtonData, +} from 'src/graphics/CCTV/cctvButton/CCTVButton'; + +export class CCTVButtonData extends GraphicDataBase implements ICCTVButtonData { + constructor(data?: CCTVGraphicData.CCTVButton) { + let cctvButton; + if (data) { + cctvButton = data; + } else { + cctvButton = new CCTVGraphicData.CCTVButton({ + common: GraphicDataBase.defaultCommonInfo(CCTVButton.Type), + }); + } + super(cctvButton); + } + + public get data(): CCTVGraphicData.CCTVButton { + return this.getData(); + } + + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + get buttonType(): CCTVGraphicData.CCTVButton.ButtonType { + return this.data.buttonType; + } + set buttonType(v: CCTVGraphicData.CCTVButton.ButtonType) { + this.data.buttonType = v; + } + clone(): CCTVButtonData { + return new CCTVButtonData(this.data.cloneMessage()); + } + copyFrom(data: CCTVButtonData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: CCTVButtonData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} diff --git a/src/graphics/CCTV/cctvButton/CCTVButton.ts b/src/graphics/CCTV/cctvButton/CCTVButton.ts new file mode 100644 index 0000000..7566bca --- /dev/null +++ b/src/graphics/CCTV/cctvButton/CCTVButton.ts @@ -0,0 +1,70 @@ +import { GraphicData, JlGraphic, JlGraphicTemplate } from 'jl-graphic'; +import CCTV_Button_Assets from './cctv-button-spritesheet.png'; +import CCTV_Button_JSON from './cctv-button-data.json'; +import { CCTVGraphicData } from 'src/protos/cctv_graphic_data'; +import { Assets, Sprite, Spritesheet, Texture } from 'pixi.js'; + +interface CCTVButtonTextures { + redBtn: Texture; + greenBtn: Texture; +} + +export interface ICCTVButtonData extends GraphicData { + get code(): string; + set code(v: string); + get buttonType(): CCTVGraphicData.CCTVButton.ButtonType; + set buttonType(v: CCTVGraphicData.CCTVButton.ButtonType); +} + +export class CCTVButton extends JlGraphic { + static Type = 'CCTVButton'; + _cctvButton: Sprite; + cctvButtonTextures: CCTVButtonTextures; + __state = 0; + + constructor(cctvButtonTextures: CCTVButtonTextures) { + super(CCTVButton.Type); + this.cctvButtonTextures = cctvButtonTextures; + this._cctvButton = new Sprite(); + this._cctvButton.texture = this.cctvButtonTextures.redBtn; + this._cctvButton.anchor.set(0.5); + this.addChild(this._cctvButton); + } + get code(): string { + return this.datas.code; + } + get datas(): ICCTVButtonData { + return this.getDatas(); + } + + doRepaint(): void { + this._cctvButton.rotation = 0; + this._cctvButton.texture = this.cctvButtonTextures.redBtn; + } +} + +export class CCTVButtonTemplate extends JlGraphicTemplate { + cctvButtonTextures?: CCTVButtonTextures; + constructor(dataTemplate: ICCTVButtonData) { + super(CCTVButton.Type, { dataTemplate }); + this.loadAssets(); + } + new(): CCTVButton { + if (this.cctvButtonTextures) { + const g = new CCTVButton(this.cctvButtonTextures); + g.loadData(this.datas); + return g; + } + throw new Error('资源未加载/加载失败'); + } + async loadAssets(): Promise { + const texture = await Assets.load(CCTV_Button_Assets); + const cctvButtonSheet = new Spritesheet(texture, CCTV_Button_JSON); + const result = await cctvButtonSheet.parse(); + this.cctvButtonTextures = { + redBtn: result['rect-press-btn.png'], + greenBtn: result['rect-btn.png'], + }; + return this.cctvButtonTextures as CCTVButtonTextures; + } +} diff --git a/src/graphics/CCTV/cctvButton/CCTVButtonDrawAssistant.ts b/src/graphics/CCTV/cctvButton/CCTVButtonDrawAssistant.ts new file mode 100644 index 0000000..b5ed24d --- /dev/null +++ b/src/graphics/CCTV/cctvButton/CCTVButtonDrawAssistant.ts @@ -0,0 +1,122 @@ +import { DisplayObject, FederatedMouseEvent, Point } from 'pixi.js'; +import { + AbsorbableLine, + AbsorbablePosition, + GraphicDrawAssistant, + GraphicInteractionPlugin, + GraphicTransformEvent, + IDrawApp, + JlGraphic, +} from 'jl-graphic'; +import { ICCTVButtonData, CCTVButton, CCTVButtonTemplate } from './CCTVButton'; + +export class CCTVButtonDraw extends GraphicDrawAssistant< + CCTVButtonTemplate, + ICCTVButtonData +> { + _cctvButton: CCTVButton | null = null; + constructor(app: IDrawApp, template: CCTVButtonTemplate) { + super( + app, + template, + 'svguse:../drawIcon.svg#icon-psl-button', + 'cctv按钮' + ); + CCTVButtonInteraction.init(app); + } + + bind(): void { + super.bind(); + if (!this._cctvButton) { + this._cctvButton = this.graphicTemplate.new(); + this.container.addChild(this._cctvButton); + } + } + + public get cctvButton(): CCTVButton { + if (!this._cctvButton) { + this._cctvButton = this.graphicTemplate.new(); + this.container.addChild(this._cctvButton); + } + return this._cctvButton; + } + + redraw(cp: Point): void { + this.cctvButton.position.copyFrom(cp); + } + onLeftUp(e: FederatedMouseEvent): void { + this.cctvButton.position.copyFrom(this.toCanvasCoordinates(e.global)); + this.createAndStore(true); + } + prepareData(data: ICCTVButtonData): boolean { + data.transform = this.cctvButton.saveTransform(); + return true; + } + onEsc(): void { + this.finish(); + } +} + +/** + * 构建吸附线 + * @param cctvButton + */ +function buildAbsorbablePositions(cctvButton: CCTVButton): AbsorbablePosition[] { + const aps: AbsorbablePosition[] = []; + const cctvButtons = cctvButton.queryStore.queryByType( + CCTVButton.Type + ); + const canvas = cctvButton.getCanvas(); + cctvButtons.forEach((item) => { + if (item.id === cctvButton.id) { + return; + } + const ala = new AbsorbableLine( + new Point(item.x, 0), + new Point(item.x, canvas.height) + ); + const alb = new AbsorbableLine( + new Point(0, item.y), + new Point(canvas.width, item.y) + ); + aps.push(ala); + aps.push(alb); + }); + + return aps; +} + +export class CCTVButtonInteraction extends GraphicInteractionPlugin { + static Name = 'cctv_button_transform'; + constructor(app: IDrawApp) { + super(CCTVButtonInteraction.Name, app); + } + static init(app: IDrawApp) { + return new CCTVButtonInteraction(app); + } + filter(...grahpics: JlGraphic[]): CCTVButton[] | undefined { + return grahpics + .filter((g) => g.type === CCTVButton.Type) + .map((g) => g as CCTVButton); + } + bind(g: CCTVButton): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.scalable = true; + g.rotatable = true; + g.on('transformstart', this.transformstart, this); + } + unbind(g: CCTVButton): void { + g.eventMode = 'none'; + g.scalable = false; + g.rotatable = false; + g.off('transformstart', this.transformstart, this); + } + transformstart(e: GraphicTransformEvent) { + const target = e.target as DisplayObject; + const cctvButton = target.getGraphic() as CCTVButton; + cctvButton.getGraphicApp().setOptions({ + absorbablePositions: buildAbsorbablePositions(cctvButton), + }); + } +} diff --git a/src/graphics/CCTV/cctvButton/cctv-button-data.json b/src/graphics/CCTV/cctvButton/cctv-button-data.json new file mode 100644 index 0000000..dd6250c --- /dev/null +++ b/src/graphics/CCTV/cctvButton/cctv-button-data.json @@ -0,0 +1,29 @@ +{ + "frames": { + "rect-press-btn.png": { + "frame": { "x": 0, "y": 0, "w": 74, "h": 66 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 74, "h": 66 }, + "sourceSize": { "w": 74, "h": 66 }, + "anchor": { "x": 0.5, "y": 0.5 } + }, + "rect-btn.png": { + "frame": { "x": 74, "y": 0, "w": 74, "h": 66 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 74, "h": 66 }, + "sourceSize": { "w": 74, "h": 66 }, + "anchor": { "x": 0.5, "y": 0.5 } + } + }, + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "1.1", + "image": "tcc-button.png", + "format": "RGBA8888", + "size": { "w": 148, "h": 66 }, + "scale": "1", + "smartupdate": "$TexturePacker:SmartUpdate:e7620bd2d73cc0b3e2deea9704e7eefc:f129a1d9e4b9ba57720b3861c22b155b:eb2d421f7759984b7713aa4aa5354134$" + } +} diff --git a/src/graphics/CCTV/cctvButton/cctv-button-spritesheet.png b/src/graphics/CCTV/cctvButton/cctv-button-spritesheet.png new file mode 100644 index 0000000000000000000000000000000000000000..769409dd1f5a4c61b988e00fb711c8acaa2b616b GIT binary patch literal 2599 zcmd5;dsGuw8V?(*#rkM{RK@KwL==_IGsEO@5>N;&X$@E&6|@B>^9U(PCYuQ);fPpw zrL9(Nv8+V|txBtIi%=i5@{qPZio#;og%#wn2Ms+|tSD)6-r%n!f>~Y;QkJ{q96SY_>WX&R)JffJuXd@NRS1- zE5KbIl_QZ%6wJw~&Q!w+H6vINniY&3;uUQmK3zA}|6&F$IcaFhQs>N*y7G{687+ z=3sesqV5^LFYu(5WjdX9HHx}iF2p5A1cwR5RVo#V5hy{x00E00o0E3KHgUligN_p! zhuQ8l3pU8dNE?N0r&b0c9hG3UkJH*jf0{tTP&aKyaRl>88Uq>(4~AN;<7m+tn*+S~ zuI!nDQxG$S zU(qo>J+8*Cj&X3bQ*a~;f@Q2wE5}$Mf(oXu} zzyfRLJr4sl7}R>3=%j57r`Ks^ASlFaX4MQvt9YCwVAe?TFvkE(Wh5hDPEJSQWQ2-R zP|QeNV7*RYvVDp6tsiZ0R$u_fcrMknLd7X?#t5@KMZyG5vapfijj&2?q*OdZM_`0; zj4i=o278RQ+|TNZiUo``&l4<%k+4$EQm~OHm9Wu>(J)723Klcs3Y;fp5X-1}!C|FA zN13g(i9_u+lMMP#G%MNu$;;Jyt4 z!T@sP%p&LpkAKT0aliLl7Be)`$7-7KZ6B?S@%0VI%KXFTUr6)A2^yt!WpaS@0bMc* z69wMsq8;3F6DZ05uwT(%lPS_U4;J}wz4U(}(qAejleU>SaK585pKR235{?!c{qG(a znY-`Q9D{?S*k_Kv1Hi-hTZFR#Y6o~nTzH~%heRSx*Xx!iyE|@{W@ODwoBP@x7qQ5? zW8VuQDFf3JKUDNK_sZPmv6r{h-8nzq8&;Vz;hyBDh$q9kkuA_)AB#m#biJ>y(SO~w z#oT-BQ2yjy*P4dQN}?0vA~yM9?y>4o$;>pWLSG(qQmRyvKfk|ed$Z%s zX^3aJ>oVerzOyL4d!5fOknchOh zP|Mp1-}Qh0#q6)szv)f#>dPLD>ps?dep+PStUZf7uhJEVlPu45ldo?pxvNiyK1<_G zn+=U6K^09?PTrYS0_>!Aec4-@#+ij-p$Tzi*8+VO2;h&v+Mx*m9ylQm58mth zV$H=aXR7p2?TVtUO=j=arVE1$Hg-O9{M`&q*ruSt(=BhC&b|2u`No~kmF0;CgVr?n zzgBHH?Uf*7cKne)zFsVfvo!8}q$C1gAA?q;=)Nil0~OKU_*Z z7Tyv+!w@#)4c?Y_E_~rP)K)l2x)^q#}Z(8JX)t`GRrxBrTNr}WdJTc56_q+NXnFESg* z?koKP$NR1i_q5rwS$Pk20{z`E;^R_pX5u&!wJ zr42Wm^ZQERGyFiP{^R=k_>dEQEw5CxzG7Y1xw++|&VY)}n&-WmO2zJ{+5;1QnpYgM zJinNu!d~!HyY0Pcvd;_)L_bI23jn`E~uif}> D5E{$e literal 0 HcmV?d00001 diff --git a/src/layouts/CCTVDrawLayout.vue b/src/layouts/CCTVDrawLayout.vue new file mode 100644 index 0000000..1bde02b --- /dev/null +++ b/src/layouts/CCTVDrawLayout.vue @@ -0,0 +1,257 @@ + + + diff --git a/src/protos/cctv_graphic_data.ts b/src/protos/cctv_graphic_data.ts new file mode 100644 index 0000000..700fb76 --- /dev/null +++ b/src/protos/cctv_graphic_data.ts @@ -0,0 +1,224 @@ +/** + * Generated by the protoc-gen-ts. DO NOT EDIT! + * compiler version: 5.27.4 + * source: cctv_graphic_data.proto + * git: https://github.com/thesayyn/protoc-gen-ts */ +import * as dependency_1 from "./iscs_graphic_data"; +import * as pb_1 from "google-protobuf"; +export namespace CCTVGraphicData { + export class CCTVGraphicStorage extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + canvas?: dependency_1.iscsGraphicData.Canvas; + cctvButtons?: CCTVButton[]; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [2], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("canvas" in data && data.canvas != undefined) { + this.canvas = data.canvas; + } + if ("cctvButtons" in data && data.cctvButtons != undefined) { + this.cctvButtons = data.cctvButtons; + } + } + } + get canvas() { + return pb_1.Message.getWrapperField(this, dependency_1.iscsGraphicData.Canvas, 1) as dependency_1.iscsGraphicData.Canvas; + } + set canvas(value: dependency_1.iscsGraphicData.Canvas) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_canvas() { + return pb_1.Message.getField(this, 1) != null; + } + get cctvButtons() { + return pb_1.Message.getRepeatedWrapperField(this, CCTVButton, 2) as CCTVButton[]; + } + set cctvButtons(value: CCTVButton[]) { + pb_1.Message.setRepeatedWrapperField(this, 2, value); + } + static fromObject(data: { + canvas?: ReturnType; + cctvButtons?: ReturnType[]; + }): CCTVGraphicStorage { + const message = new CCTVGraphicStorage({}); + if (data.canvas != null) { + message.canvas = dependency_1.iscsGraphicData.Canvas.fromObject(data.canvas); + } + if (data.cctvButtons != null) { + message.cctvButtons = data.cctvButtons.map(item => CCTVButton.fromObject(item)); + } + return message; + } + toObject() { + const data: { + canvas?: ReturnType; + cctvButtons?: ReturnType[]; + } = {}; + if (this.canvas != null) { + data.canvas = this.canvas.toObject(); + } + if (this.cctvButtons != null) { + data.cctvButtons = this.cctvButtons.map((item: CCTVButton) => item.toObject()); + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_canvas) + writer.writeMessage(1, this.canvas, () => this.canvas.serialize(writer)); + if (this.cctvButtons.length) + writer.writeRepeatedMessage(2, this.cctvButtons, (item: CCTVButton) => item.serialize(writer)); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): CCTVGraphicStorage { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new CCTVGraphicStorage(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.canvas, () => message.canvas = dependency_1.iscsGraphicData.Canvas.deserialize(reader)); + break; + case 2: + reader.readMessage(message.cctvButtons, () => pb_1.Message.addToRepeatedWrapperField(message, 2, CCTVButton.deserialize(reader), CCTVButton)); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): CCTVGraphicStorage { + return CCTVGraphicStorage.deserialize(bytes); + } + } + export class CCTVButton extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: dependency_1.iscsGraphicData.CommonInfo; + code?: string; + buttonType?: CCTVButton.ButtonType; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("common" in data && data.common != undefined) { + this.common = data.common; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + if ("buttonType" in data && data.buttonType != undefined) { + this.buttonType = data.buttonType; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, dependency_1.iscsGraphicData.CommonInfo, 1) as dependency_1.iscsGraphicData.CommonInfo; + } + set common(value: dependency_1.iscsGraphicData.CommonInfo) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_common() { + return pb_1.Message.getField(this, 1) != null; + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + get buttonType() { + return pb_1.Message.getFieldWithDefault(this, 3, CCTVButton.ButtonType.rect) as CCTVButton.ButtonType; + } + set buttonType(value: CCTVButton.ButtonType) { + pb_1.Message.setField(this, 3, value); + } + static fromObject(data: { + common?: ReturnType; + code?: string; + buttonType?: CCTVButton.ButtonType; + }): CCTVButton { + const message = new CCTVButton({}); + if (data.common != null) { + message.common = dependency_1.iscsGraphicData.CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + if (data.buttonType != null) { + message.buttonType = data.buttonType; + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + buttonType?: CCTVButton.ButtonType; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + if (this.buttonType != null) { + data.buttonType = this.buttonType; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_common) + writer.writeMessage(1, this.common, () => this.common.serialize(writer)); + if (this.code.length) + writer.writeString(2, this.code); + if (this.buttonType != CCTVButton.ButtonType.rect) + writer.writeEnum(3, this.buttonType); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): CCTVButton { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new CCTVButton(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = dependency_1.iscsGraphicData.CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + case 3: + message.buttonType = reader.readEnum(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): CCTVButton { + return CCTVButton.deserialize(bytes); + } + } + export namespace CCTVButton { + export enum ButtonType { + rect = 0, + monitor = 1 + } + } +} diff --git a/src/protos/picture.ts b/src/protos/picture.ts new file mode 100644 index 0000000..ba6f447 --- /dev/null +++ b/src/protos/picture.ts @@ -0,0 +1,18 @@ +/** + * Generated by the protoc-gen-ts. DO NOT EDIT! + * compiler version: 5.27.4 + * source: picture.proto + * git: https://github.com/thesayyn/protoc-gen-ts */ +import * as pb_1 from "google-protobuf"; +export enum PictureType { + FireAlarm = 0, + Electromechanical = 1, + Broadcast = 2, + PassengerInformation = 3, + CCTV = 4, + PSD = 5, + TicketSalesAndChecking = 6, + AccessControl = 7, + FloodGate = 8, + NetworkStatus = 9 +} diff --git a/src/router/routes.ts b/src/router/routes.ts index b2c4017..90a8188 100644 --- a/src/router/routes.ts +++ b/src/router/routes.ts @@ -13,6 +13,11 @@ const routes: RouteRecordRaw[] = [ path: '/:catchAll(.*)*', component: () => import('pages/ErrorNotFound.vue'), }, + { + path: '/cctvPainting', + name: 'cctvPainting', + component: () => import('layouts/CCTVDrawLayout.vue'), + }, ]; export default routes; diff --git a/src/stores/cctv-draw-store.ts b/src/stores/cctv-draw-store.ts new file mode 100644 index 0000000..f02c37e --- /dev/null +++ b/src/stores/cctv-draw-store.ts @@ -0,0 +1,106 @@ +import { defineStore } from 'pinia'; +import { initDrawApp, destroyDrawApp, getDrawApp } from 'src/drawApp/cctvApp'; +import { + DrawAssistant, + GraphicData, + IDrawApp, + IJlCanvas, + JlGraphic, +} from 'jl-graphic'; +import { markRaw } from 'vue'; + +export const useCCTVDrawStore = defineStore('cctvDraw', { + state: () => ({ + drawAssistant: null as DrawAssistant | null, + selectedGraphics: null as JlGraphic[] | null, + draftId: null as number | null, + }), + getters: { + drawMode: (state) => state.drawAssistant != null, + drawGraphicType: (state) => state.drawAssistant?.type, + drawGraphicName: (state) => state.drawAssistant?.description, + drawGraphicTemplate: (state) => state.drawAssistant?.graphicTemplate, + getApp: () => { + return getDrawApp(); + }, + selectedGraphicType: (state) => { + if (state.selectedGraphics) { + if (state.selectedGraphics.length === 1) { + return state.selectedGraphics[0].type; + } + } + }, + selectedObjName(state): string { + if (state.selectedGraphics) { + if (state.selectedGraphics.length == 0) { + return '画布'; + } else if (state.selectedGraphics.length == 1) { + const name = this.getApp?.getDrawAssistant( + state.selectedGraphics[0].type + ).description; + return name || ''; + } + return '批量设置'; + } + return ''; + }, + selectedGraphic: (state) => { + if (state.selectedGraphics) { + if (state.selectedGraphics.length === 1) { + return state.selectedGraphics[0]; + } + } + return null; + }, + }, + actions: { + getDrawApp(): IDrawApp { + const app = this.getApp; + if (app == null) { + throw new Error('未初始化app'); + } + return app; + }, + getJlCanvas(): IJlCanvas { + return this.getDrawApp().canvas; + }, + bindFormData(form: GraphicData): void { + const app = this.getDrawApp(); + app.bindFormData(form); + }, + unbindFormData(form: GraphicData): void { + const app = this.getDrawApp(); + app.unbindFormData(form); + }, + initDrawApp() { + let app: IDrawApp | null = null; + app = initDrawApp(); + if (app == null) { + throw new Error('未初始化app'); + } + app.on('interaction-plugin-resume', (plugin) => { + if (plugin.isAppPlugin()) { + if (Object.hasOwn(plugin, '__GraphicDrawAssistant')) { + this.drawAssistant = plugin as DrawAssistant; + } else { + this.drawAssistant = null; + } + } + }); + app.on('graphicselected', (graphics) => { + this.selectedGraphics = markRaw(graphics); + }); + this.selectedGraphics = []; + return app; + }, + destroy() { + // console.log('绘制状态清空,绘制应用销毁'); + this.drawAssistant = null; + this.selectedGraphics = null; + destroyDrawApp(); + }, + setDraftId(id: number | null) { + this.draftId = id; + }, + }, +});