CCTV绘制app暂提

This commit is contained in:
joylink_zhaoerwei 2024-09-14 12:02:41 +08:00
parent 9bb97141e1
commit 74f28d54d9
15 changed files with 1270 additions and 0 deletions

99
public/drawIcon.svg Normal file
View File

@ -0,0 +1,99 @@
<svg xmlns="http://www.w3.org/2000/svg">
<symbol id="icon-curve" viewBox="0 0 1280 1024">
<path
d="M1280 614.4c0-32-32-64-64-64-38.4 0-64 32-64 64 0 44.8-12.8 172.8-70.4 236.8-32 32-70.4 44.8-121.6 44.8-89.6 0-153.6-243.2-204.8-416-64-249.6-128-480-294.4-480C224 0 115.2 364.8 44.8 601.6c-12.8 51.2-25.6 96-38.4 121.6-12.8 32 6.4 70.4 38.4 83.2 32 12.8 70.4-6.4 83.2-38.4 12.8-32 25.6-76.8 44.8-134.4C217.6 460.8 320 128 460.8 128 531.2 128 595.2 358.4 640 512c70.4 249.6 140.8 512 326.4 512 83.2 0 153.6-25.6 204.8-83.2 115.2-121.6 108.8-320 108.8-326.4z"></path>
</symbol>
<symbol id="icon-fans" viewBox="0 0 1024 1024">
<path d="M947.303 517.937c-16.16-18.18-39.391-29.289-63.629-29.289h-240.377c-6.061-30.299-21.21-56.56-44.441-75.748l120.189-208.058c12.119-21.21 14.141-46.46 6.061-69.69s-25.249-40.398-47.47-49.49c-53.529-21.21-109.077-31.31-166.649-31.31s-113.118 10.1-166.649 31.31c-22.22 9.090-39.391 27.27-47.47 49.49-8.079 23.23-6.061 48.481 6.061 69.69l120.189 208.058c-22.22 19.188-38.379 46.46-44.441 75.748h-239.367c-24.238 0-47.47 11.109-63.629 29.289-16.16 18.18-22.22 42.42-19.188 66.659 9.090 56.56 27.27 110.087 56.56 159.578 28.278 49.49 65.65 92.917 110.087 128.269 15.149 12.119 33.329 18.18 51.51 18.18 5.050 0 10.1 0 15.149-1.009 24.238-4.041 44.441-19.188 56.56-40.398l120.189-208.058c6.061 2.020 12.119 4.041 19.188 5.050v289.867c0 14.141 11.109 25.249 25.249 25.249s25.249-11.109 25.249-25.249v-289.867c6.061-1.009 13.13-3.028 19.188-5.050l120.189 208.058c12.119 21.21 33.329 35.349 56.56 40.398 5.050 1.009 10.1 1.009 15.149 1.009 18.18 0 36.357-6.061 51.51-18.18 44.441-35.349 81.81-78.778 110.087-128.269 28.278-49.49 47.47-104.027 56.56-159.578 5.050-23.23-2.020-47.47-18.18-66.659zM303.942 823.961c-5.050 8.079-13.13 14.141-22.22 16.16s-18.18-1.009-26.259-6.061c-39.391-31.31-72.72-70.7-97.969-114.127-25.249-44.441-42.42-91.908-50.499-142.407-1.009-9.090 1.009-18.18 7.069-25.249s15.149-11.109 25.249-11.109h241.387c6.061 30.299 21.21 56.56 44.441 75.748l-121.197 207.047zM347.373 179.591c-5.050-8.079-6.061-18.18-3.028-27.27 3.028-9.090 10.1-16.16 18.18-19.188 47.47-18.18 96.958-28.278 148.468-28.278s100.998 9.090 148.468 28.278c9.090 3.028 15.149 10.1 18.18 19.188 3.028 9.090 2.020 19.188-3.028 27.27l-118.167 208.058c-14.141-5.050-28.278-7.069-44.441-7.069s-30.299 3.028-44.441 7.069l-120.189-208.058zM512 598.735c-46.46 0-83.829-37.37-83.829-83.829s37.37-83.829 83.829-83.829 83.829 37.37 83.829 83.829-37.37 83.829-83.829 83.829zM917.006 576.516c-8.079 50.499-24.238 97.969-50.499 142.407-25.249 44.441-58.579 82.818-97.969 114.127-7.069 6.061-16.16 8.079-26.259 6.061-9.090-2.020-18.18-8.079-22.22-16.16l-120.189-207.047c22.22-19.188 38.379-46.46 44.441-75.748h240.377c10.1 0 19.188 4.041 25.249 11.109 5.050 7.069 8.079 16.16 7.069 25.249z" p-id="12530"></path>
</symbol>
<symbol id="icon-platform" viewBox="0 0 1024 1024">
<path d="M199.68 564.906667L170.666667 721.92h250.88L392.533333 564.906667H199.68zM179.2 512h235.52c11.946667 0 23.893333 8.533333 25.6 22.186667l39.253333 209.92c1.706667 6.826667 0 15.36-5.12 22.186666s-11.946667 10.24-20.48 10.24H139.946667c-8.533333 0-15.36-3.413333-20.48-10.24-5.12-6.826667-6.826667-13.653333-5.12-22.186666L153.6 534.186667c1.706667-13.653333 11.946667-22.186667 25.6-22.186667z m411.306667 209.92h250.88l-29.013334-157.013333H619.52l-29.013333 157.013333zM597.333333 512h235.52c11.946667 0 23.893333 8.533333 25.6 22.186667l39.253334 209.92c1.706667 6.826667 0 15.36-5.12 22.186666s-11.946667 10.24-20.48 10.24H558.08c-8.533333 0-15.36-3.413333-20.48-10.24-5.12-6.826667-6.826667-13.653333-5.12-22.186666l39.253333-209.92c3.413333-13.653333 13.653333-22.186667 25.6-22.186667z m-216.746666-52.906667H631.466667l-29.013334-157.013333H409.6l-29.013333 157.013333z m6.826666-209.92h235.52c11.946667 0 23.893333 8.533333 25.6 22.186667l39.253334 209.92c1.706667 6.826667 0 15.36-5.12 22.186667s-11.946667 10.24-20.48 10.24H348.16c-8.533333 0-15.36-3.413333-20.48-10.24-5.12-6.826667-6.826667-13.653333-5.12-22.186667l39.253333-209.92c3.413333-11.946667 13.653333-22.186667 25.6-22.186667z m0 0" p-id="9166"></path>
</symbol>
<symbol id="icon-station" viewBox="0 0 1024 1024">
<path d="M890.3 390.6l-309.1-299c-38.3-37-100.5-37.1-138.9-0.3l-308.5 296c-9.2 8.9-14.4 20.9-14.4 33.4v456c0 52.2 43.9 84.4 98.1 84.4h147.2c54.2 0 98.1-32.3 98.1-84.4v-47.2c0-26.1 22-47.2 49.1-47.2s49.1 21.2 49.1 47.2v47.2c0 52.2 43.9 84.4 98.1 84.4h147.2c54.2 0 98.1-32.3 98.1-84.4V424c0.2-12.5-5-24.5-14.1-33.4z m-83.9 438.9c0 26.1-22 37.2-49.1 37.2h-49.1c-27.1 0-49.1-11.1-49.1-37.2v-47.2c0-52.2-43.9-104.5-98.1-104.5h-98.1c-54.2 0-98.1 52.3-98.1 104.5v47.2c0 26.1-22 37.2-49.1 37.2h-49.1c-27.1 0-49.1-11.1-49.1-37.2V448.7c0-6.3 2.6-12.3 7.2-16.7l252.1-242.6c19.2-18.5 50.3-18.5 69.4 0L799.3 433c4.6 4.4 7.2 10.4 7.2 16.7v379.8z" p-id="20574"></path>
</symbol>
<!-- <symbol id="icon-signal" viewBox="0 0 1024 1024">
<path d="M63.33 895.64V127.99h64v767.65z" fill="#fdfafa" p-id="24054"></path><path d="M750 365.57a146.25 146.25 0 1 1-103.36 42.83A145.29 145.29 0 0 1 750 365.57m0-64c-116.12 0-210.25 94.13-210.25 210.25S633.93 722.06 750 722.06s210.3-94.13 210.3-210.25S866.16 301.57 750 301.57z" fill="#fdfafa" p-id="24055"></path><path d="M336.94 365.57a146 146 0 1 1-103.27 42.78 145.09 145.09 0 0 1 103.27-42.78m0-64c-116 0-210 94-210 210s94 210 210 210 210-94 210-210-94-210-210-210z" fill="#fdfafa" p-id="24056"></path>
</symbol> -->
<symbol id="icon-signal" viewBox="0 0 1024 1024">
<path d="M63.33 895.64V127.99h64v767.65z" fill="#ffffff" p-id="1554"></path><path d="M750 365.57a146.25 146.25 0 1 1-103.36 42.83A145.29 145.29 0 0 1 750 365.57m0-64c-116.12 0-210.25 94.13-210.25 210.25S633.93 722.06 750 722.06s210.3-94.13 210.3-210.25S866.16 301.57 750 301.57z" fill="#ffffff" p-id="1555"></path><path d="M336.94 365.57a146 146 0 1 1-103.27 42.78 145.09 145.09 0 0 1 103.27-42.78m0-64c-116 0-210 94-210 210s94 210 210 210 210-94 210-210-94-210-210-210z" fill="#ffffff" p-id="1556"></path>
</symbol>
<symbol id="icon-stop-position" viewBox="0 0 38 30" fill="none">
<path d="M2.58909 29L19 1.92901L35.4109 29H2.58909Z" stroke="#FFFFFF" stroke-width="2"/>
<path d="M14.8153 22.9119V21.8977L19.2898 14.8182H20.0256V16.3892H19.5284L16.1477 21.7386V21.8182H22.1733V22.9119H14.8153ZM19.608 25V22.6037V22.1314V14.8182H20.7812V25H19.608Z" fill="#FFFFFF"/>
</symbol>
<symbol id="icon-spks-switch" viewBox="0 0 35 34" fill="none">
<rect x="1" y="1" width="33" height="32" stroke="white" stroke-width="2"/>
<path d="M20.7727 14.2727C20.7045 13.697 20.428 13.25 19.9432 12.9318C19.4583 12.6136 18.8636 12.4545 18.1591 12.4545C17.6439 12.4545 17.1932 12.5379 16.8068 12.7045C16.4242 12.8712 16.125 13.1004 15.9091 13.392C15.697 13.6837 15.5909 14.0152 15.5909 14.3864C15.5909 14.697 15.6648 14.964 15.8125 15.1875C15.964 15.4072 16.1572 15.5909 16.392 15.7386C16.6269 15.8826 16.8731 16.0019 17.1307 16.0966C17.3883 16.1875 17.625 16.2614 17.8409 16.3182L19.0227 16.6364C19.3258 16.7159 19.6629 16.8258 20.0341 16.9659C20.4091 17.1061 20.767 17.2973 21.108 17.5398C21.4527 17.7784 21.7367 18.0852 21.9602 18.4602C22.1837 18.8352 22.2955 19.2955 22.2955 19.8409C22.2955 20.4697 22.1307 21.0379 21.8011 21.5455C21.4754 22.053 20.9981 22.4564 20.3693 22.7557C19.7443 23.0549 18.9848 23.2045 18.0909 23.2045C17.2576 23.2045 16.536 23.0701 15.9261 22.8011C15.3201 22.5322 14.8428 22.1572 14.4943 21.6761C14.1496 21.1951 13.9545 20.6364 13.9091 20H15.3636C15.4015 20.4394 15.5492 20.803 15.8068 21.0909C16.0682 21.375 16.3977 21.5871 16.7955 21.7273C17.197 21.8636 17.6288 21.9318 18.0909 21.9318C18.6288 21.9318 19.1117 21.8447 19.5398 21.6705C19.9678 21.4924 20.3068 21.2462 20.5568 20.9318C20.8068 20.6136 20.9318 20.2424 20.9318 19.8182C20.9318 19.4318 20.8239 19.1174 20.608 18.875C20.392 18.6326 20.108 18.4356 19.7557 18.2841C19.4034 18.1326 19.0227 18 18.6136 17.8864L17.1818 17.4773C16.2727 17.2159 15.553 16.8428 15.0227 16.358C14.4924 15.8731 14.2273 15.2386 14.2273 14.4545C14.2273 13.803 14.4034 13.2348 14.7557 12.75C15.1117 12.2614 15.589 11.8826 16.1875 11.6136C16.7898 11.3409 17.4621 11.2045 18.2045 11.2045C18.9545 11.2045 19.6212 11.339 20.2045 11.608C20.7879 11.8731 21.25 12.2367 21.5909 12.6989C21.9356 13.161 22.1174 13.6856 22.1364 14.2727H20.7727Z" fill="white"/>
<line y1="32" x2="35" y2="32" stroke="white" stroke-width="4"/>
</symbol>
<symbol id="icon-ibp-box" viewBox="0 0 35 34" fill="none">
<rect x="1" y="1" width="33" height="32" stroke="white" stroke-width="2"/>
<path d="M16.4659 9.81818V20H15.233V9.81818H16.4659Z" fill="white"/>
<line y1="32" x2="35" y2="32" stroke="white" stroke-width="4"/>
</symbol>
<symbol id="icon-gated-box" viewBox="0 0 35 34" fill="none">
<rect x="1" y="1" width="33" height="32" stroke="white" stroke-width="2"/>
<path d="M14.4091 23V11.3636H18.3409C19.2538 11.3636 20 11.5284 20.5795 11.858C21.1629 12.1837 21.5947 12.625 21.875 13.1818C22.1553 13.7386 22.2955 14.3598 22.2955 15.0455C22.2955 15.7311 22.1553 16.3542 21.875 16.9148C21.5985 17.4754 21.1705 17.9223 20.5909 18.2557C20.0114 18.5852 19.2689 18.75 18.3636 18.75H15.5455V17.5H18.3182C18.9432 17.5 19.4451 17.392 19.8239 17.1761C20.2027 16.9602 20.4773 16.6686 20.6477 16.3011C20.822 15.9299 20.9091 15.5114 20.9091 15.0455C20.9091 14.5795 20.822 14.1629 20.6477 13.7955C20.4773 13.428 20.2008 13.1402 19.8182 12.9318C19.4356 12.7197 18.928 12.6136 18.2955 12.6136H15.8182V23H14.4091Z" fill="white"/>
<line y1="32" x2="35" y2="32" stroke="white" stroke-width="4"/>
</symbol>
<symbol id="icon-esb-button" viewBox="0 0 35 34" fill="none">
<rect x="1" y="1" width="31" height="30" stroke="white" stroke-width="2"/>
<line x1="0.0576497" y1="28.5011" x2="33.0333" y2="29.7694" stroke="white" stroke-width="3"/>
<path d="M13.233 20V9.81818H19.3778V10.9119H14.4659V14.3523H19.0597V15.446H14.4659V18.9062H19.4574V20H13.233Z" fill="white"/>
</symbol>
<symbol id="icon-hold-button" viewBox="0 0 35 34" fill="none">
<rect x="1" y="1" width="31" height="30" stroke="white" stroke-width="2"/>
<line x1="0.0576497" y1="28.5011" x2="33.0333" y2="29.7694" stroke="white" stroke-width="3"/>
<path d="M12.233 19V8.81818H13.4659V13.3523H18.8949V8.81818H20.1278V19H18.8949V14.446H13.4659V19H12.233Z" fill="white"/>
</symbol>
<symbol id="icon-unattenged-button" viewBox="0 0 35 34" fill="none">
<rect x="1" y="1" width="31" height="30" stroke="white" stroke-width="2"/>
<line x1="0.0576497" y1="28.5011" x2="33.0333" y2="29.7694" stroke="white" stroke-width="3"/>
<path d="M12.0824 21L9.2983 10.8182H10.5511L12.679 19.1108H12.7784L14.946 10.8182H16.3381L18.5057 19.1108H18.6051L20.733 10.8182H21.9858L19.2017 21H17.929L15.6818 12.8864H15.6023L13.3551 21H12.0824Z" fill="white"/>
</symbol>
<symbol id="icon-psl-light" viewBox="0 0 30 30" fill="none">
<circle cx="15" cy="15" r="14.5" stroke="white"/>
<circle cx="15" cy="15" r="10.5" stroke="white"/>
</symbol>
<symbol id="icon-psl-key" viewBox="0 0 27 31" fill="none">
<circle cx="19.5" cy="7.5" r="7" stroke="white"/>
<line x1="13.3536" y1="12.3536" x2="0.47714" y2="25.23" stroke="white"/>
<line x1="6.35355" y1="20.6464" x2="11.9397" y2="26.2326" stroke="white"/>
<line x1="1.35355" y1="25.6464" x2="6.35355" y2="30.6464" stroke="white"/>
</symbol>
<symbol id="icon-psl-button" viewBox="0 0 30 30" fill="none">
<circle cx="15" cy="15" r="14.5" stroke="white"/>
<circle cx="15" cy="15" r="6" fill="white"/>
</symbol>
<symbol id="icon-beacon" viewBox="-10 -10 60 60" fill="none">
<path d="M22.0055 37.9832L0.354889 0.483154L43.6562 0.483154L22.0055 37.9832Z" fill="white"/>
</symbol>
<symbol id="icon-zdwx-esb" viewBox="0 0 57 57" fill="none">
<rect x="1.5" y="8.5" width="47" height="47" stroke="#FFFFFF" fill="none" stroke-width="3"/>
<rect x="8.5" y="1.5" width="47" height="47" stroke="#FFFFFF" fill="none" stroke-width="3"/>
<path d="M20 26.9998C20 12 39 12 39 26.9998" stroke="#FFFFFF"/>
<path d="M20 27H39" stroke="#FFFFFF"/>
<path d="M29 27V43" stroke="#FFFFFF"/>
</symbol>
<symbol id="icon-departure-timer" viewBox="0 0 23 40" fill="none">
<rect x="0.5" y="0.5" width="22" height="39" stroke="white"/>
<rect x="4.5" y="8.5" width="14" height="8" stroke="white"/>
<rect x="4.5" y="24.5" width="14" height="8" stroke="white"/>
<path d="M11.5 9V16.5" stroke="white"/>
<path d="M11.5 25V32.5" stroke="white"/>
</symbol>
<symbol id="icon-autoreturn-box" viewBox="0 0 57 57" fill="none">
<rect x="5.0" y="5.0" width="47" height="47" stroke="#FFFFFF" fill="none" />
<circle cx="28.5" cy="28.5" r="22" stroke="white"/>
<path d="M20 26.9998C20 12 39 12 39 26.9998" stroke="#FFFFFF"/>
<path d="M20 27H39" stroke="#FFFFFF"/>
<path d="M29 27V43" stroke="#FFFFFF"/>
</symbol>
<symbol id="icon-car-washing" viewBox="0 0 150 150" fill="none">
<rect x="45" y="3" width="60" height="144" fill="#FFFFFF" stroke="#FFFFFF"/>
</symbol>
<symbol id="icon-flood-gate" viewBox="0 0 129 139" fill="none">
<path fill-rule="evenodd" stroke="rgba(255, 255, 255, 1)" stroke-width="5" d="M0 1.5L61.5 1.5M61.5 1.5L123 1.5M61.5 1.5L61.5 137.5L0 137.5L123 137.5"/>
</symbol>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,45 @@
<template>
<!-- 绘制图形模板属性 -->
<div v-if="drawStore.drawMode">
<q-card flat>
<q-card-section>
<div class="text-h6">{{ drawStore.drawGraphicName + ' 模板' }}</div>
</q-card-section>
<q-separator inset></q-separator>
<q-card-section> </q-card-section>
</q-card>
</div>
<!-- 画布或图形对象属性 -->
<div v-else-if="drawStore.selectedGraphics !== null">
<q-card flat>
<q-card-section>
<div class="text-h6">{{ drawStore.selectedObjName + ' 属性' }}</div>
</q-card-section>
<q-separator inset></q-separator>
<template v-if="drawStore.selectedGraphics.length === 0">
<q-card-section>
<canvas-property></canvas-property>
</q-card-section>
</template>
<template v-else-if="drawStore.selectedGraphics.length === 1">
<q-card-section>
<cctv-button-property
v-if="drawStore.selectedGraphicType === CCTVButton.Type"
/>
</q-card-section>
</template>
<template v-else-if="drawStore.selectedGraphics.length > 1">
<multiple-select-property></multiple-select-property>
</template>
</q-card>
</div>
</template>
<script setup lang="ts">
import { useCCTVDrawStore } from 'src/stores/cctv-draw-store';
import CanvasProperty from './properties/CCTV/CanvasCCTVProperty.vue';
import cctvButtonProperty from './properties/CCTV/CCTVButtonProperty.vue';
import { CCTVButton } from 'src/graphics/CCTV/cctvButton/CCTVButton';
const drawStore = useCCTVDrawStore();
</script>

View File

@ -0,0 +1,39 @@
<template>
<q-form class="q-gutter-sm">
<q-input outlined readonly v-model="cctvButtonModel.id" label="id" />
<q-input
outlined
v-model="cctvButtonModel.code"
@blur="onUpdate"
label="CCTV按钮"
lazy-rules
/>
<q-select
outlined
class="q-mt-sm"
v-model="cctvButtonModel.buttonType"
:options="optionsButtonType"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="按钮类型"
/>
</q-form>
</template>
<script setup lang="ts">
import { useFormData } from 'src/components/DrawAppFormUtils';
import { useCCTVDrawStore } from 'src/stores/cctv-draw-store';
import { CCTVGraphicData } from 'src/protos/cctv_graphic_data';
import { CCTVButtonData } from 'src/drawApp/graphics/CCTV/CCTVButtonInteraction';
const { data: cctvButtonModel, onUpdate } = useFormData(
new CCTVButtonData(),
useCCTVDrawStore().getDrawApp()
);
const optionsButtonType = [
{ label: '方形', value: CCTVGraphicData.CCTVButton.ButtonType.rect },
{ label: '监视器', value: CCTVGraphicData.CCTVButton.ButtonType.monitor },
];
</script>

View File

@ -0,0 +1,80 @@
<template>
<q-form>
<q-input
outlined
v-model.number="canvas.width"
@blur="onUpdate"
label="画布宽 *"
lazy-rules
:rules="[(val) => (val && val > 0) || '画布宽必须大于0']"
/>
<q-input
outlined
type="number"
v-model.number="canvas.height"
@blur="onUpdate"
label="画布高 *"
lazy-rules
:rules="[(val) => val > 0 || '画布高必须大于0']"
/>
<q-input
outlined
v-model="canvas.backgroundColor"
@blur="onUpdate"
label="画布背景色 *"
lazy-rules
:rules="[(val) => (val && val.length > 0) || '画布背景色必须设置']"
>
<template v-slot:append>
<q-icon name="colorize" class="cursor-pointer">
<q-popup-proxy cover transition-show="scale" transition-hide="scale">
<q-color
:model-value="canvas.backgroundColor"
@change="
(val) => {
canvas.backgroundColor = val;
onUpdate();
}
"
/>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
</q-form>
</template>
<script setup lang="ts">
import { useCCTVDrawStore } from 'src/stores/cctv-draw-store';
import { onMounted, onUnmounted, reactive } from 'vue';
const drawStore = useCCTVDrawStore();
const canvas = reactive({
width: 1920,
height: 1080,
backgroundColor: '#ffffff',
});
onMounted(() => {
// console.log('mounted');
const jc = drawStore.getJlCanvas();
canvas.width = jc.properties.width;
canvas.height = jc.properties.height;
canvas.backgroundColor = jc.properties.backgroundColor;
});
onUnmounted(() => {
// console.log('unmounted');
});
function onUpdate() {
// console.log('');
const app = drawStore.getDrawApp();
app.updateCanvasAndRecord({
...canvas,
viewportTransform: app.canvas.properties.viewportTransform,
});
}
</script>

129
src/drawApp/cctvApp.ts Normal file
View File

@ -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<IGraphicStorage> {
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);
}

View File

@ -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<CCTVGraphicData.CCTVButton>();
}
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);
}
}

View File

@ -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<ICCTVButtonData>();
}
doRepaint(): void {
this._cctvButton.rotation = 0;
this._cctvButton.texture = this.cctvButtonTextures.redBtn;
}
}
export class CCTVButtonTemplate extends JlGraphicTemplate<CCTVButton> {
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<CCTVButtonTextures> {
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;
}
}

View File

@ -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>(
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<CCTVButton> {
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),
});
}
}

View File

@ -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$"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,257 @@
<template>
<q-layout view="hHh LpR fFf">
<q-header reveal class="bg-primary text-white">
<q-toolbar>
<q-toolbar-title class="q-gutter-sm">
<q-btn color="accent" label="功能菜单">
<q-menu>
<q-list style="min-width: 100px">
<q-item
v-for="item in leftMenuConfig"
:key="item.label"
clickable
v-close-popup
@click="item.click"
>
<q-item-section>{{ item.label }}</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
<q-btn-toggle
v-model="selectUtil"
color="brown"
text-color="white"
toggle-color="orange"
toggle-text-color="black"
:options="utilsOption"
@update:model-value="drawSelect"
>
<template
v-for="(ctl, idx) in utilsOption"
:key="idx"
v-slot:[ctl.value]
>
<q-tooltip>{{ ctl.tip }}</q-tooltip>
</template>
</q-btn-toggle>
</q-toolbar-title>
<q-btn square color="purple" style="margin-right: 10px" icon="search">
<q-popup-edit
ref="popupEdit"
v-model="searchId"
:cover="false"
:offset="[0, 10]"
v-slot="scope"
>
<q-input
color="accent"
v-model="scope.value"
label="设备Id"
dense
autofocus
@keyup.enter="scope.set"
>
<template v-slot:prepend>
<q-icon name="search" color="accent" />
</template>
</q-input>
</q-popup-edit>
</q-btn>
<q-btn color="info" label="返回" @click="backConfirm" />
<q-btn dense flat round icon="menu" @click="toggleRightDrawer" />
</q-toolbar>
<q-resize-observer @resize="onHeaderResize" />
</q-header>
<q-drawer show-if-above bordered v-model="rightDrawerOpen" side="right">
<q-resize-observer @resize="onRightResize" />
<draw-properties></draw-properties>
</q-drawer>
<q-page-container>
<div id="draw-app-container" class="overflow-hidden"></div>
</q-page-container>
<q-dialog
v-model="saveAsDialog"
persistent
transition-show="scale"
transition-hide="scale"
>
<q-card style="width: 300px">
<q-card-section>
<div class="text-h6">另存为</div>
</q-card-section>
<q-card-section>
<q-input
outlined
label="草稿名称"
v-model="saveAsName"
:rules="[(val) => val.trim() != '' || '草稿名称不能为空']"
/>
</q-card-section>
<q-card-actions align="right">
<q-btn color="primary" label="提交" @click="saveAs(saveAsName)" />
<q-btn label="取消" v-close-popup />
</q-card-actions>
</q-card>
</q-dialog>
<q-resize-observer @resize="onResize" />
</q-layout>
</template>
<script setup lang="ts">
import DrawProperties from 'src/components/draw-app/CCTVDrawProperties.vue';
import { onMounted, reactive, ref, watch } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { successNotify } from 'src/utils/CommonNotify';
import { useQuasar } from 'quasar';
import { useCCTVDrawStore } from 'src/stores/cctv-draw-store';
import { CCTVButton } from 'src/graphics/CCTV/cctvButton/CCTVButton';
const $q = useQuasar();
const route = useRoute();
const router = useRouter();
const searchId = ref(0);
const drawStore = useCCTVDrawStore();
watch(
() => drawStore.drawMode,
(drawMode) => {
if (!drawMode) {
selectUtil.value = '';
}
}
);
watch(
() => searchId.value,
() => {
try {
if (searchId.value) {
const device = drawStore
.getDrawApp()
.queryStore.queryById(searchId.value);
drawStore.getDrawApp().makeGraphicCenterShow(device);
drawStore.getDrawApp().updateSelected(device);
searchId.value = 0;
}
} catch (err) {
$q.notify({
type: 'negative',
message: `未查找到id为【${searchId.value}】的设备`,
});
}
}
);
const rightDrawerOpen = ref(false);
function toggleRightDrawer() {
rightDrawerOpen.value = !rightDrawerOpen.value;
onResize();
}
//
const selectUtil = ref();
const utilsOption: ControlItem[] = reactive([]);
const drawSelect = (item: string) => {
drawStore.getDrawApp().interactionPlugin(item).resume();
};
class ControlItem {
value: string;
slot: string;
icon: string;
tip: string;
show = true;
constructor(value: string, icon: string, tip: string, show?: boolean) {
this.value = value;
this.slot = value;
this.icon = icon;
this.tip = tip;
if (show != undefined) {
this.show = show;
}
}
}
//
const leftMenuConfig = [
{ label: '保存', click: saveAllDrawDatas },
{ label: '另存为', click: () => (saveAsDialog.value = true) },
];
onMounted(() => {
console.log('绘制应用layout mounted');
const dom = document.getElementById('draw-app-container');
if (dom) {
drawStore.setDraftId(+route.params.id as number);
const drawApp = drawStore.initDrawApp();
drawApp.bindDom(dom);
drawApp.reload();
onResize();
} else {
drawStore.setDraftId(null);
}
const drawAssistantsTypes = [CCTVButton.Type];
drawAssistantsTypes.forEach((type) => {
const drawAssistant = drawStore.getDrawApp().getDrawAssistant(type);
if (drawAssistant) {
utilsOption.push(
new ControlItem(
drawAssistant.name,
drawAssistant.icon,
drawAssistant.description || drawAssistant.name
)
);
}
});
});
const canvasWidth = ref(0);
const canvasHeight = ref(0);
const headerHeight = ref(0);
const rightWidth = ref(0);
function onHeaderResize(size: { height: number; width: number }) {
headerHeight.value = size.height;
onResize();
}
function onRightResize(size: { height: number; width: number }) {
rightWidth.value = size.width;
onResize();
}
function onResize() {
const clientWidth = document.documentElement.clientWidth;
const clientHeight = document.documentElement.clientHeight;
canvasWidth.value =
clientWidth - (rightDrawerOpen.value ? rightWidth.value : 0);
canvasHeight.value = clientHeight - headerHeight.value;
const dom = document.getElementById('draw-app-container');
if (dom) {
dom.style.width = canvasWidth.value + 'px';
dom.style.height = canvasHeight.value + 'px';
}
}
function saveAllDrawDatas() {
// const drawApp = drawStore.getDrawApp();
}
function backConfirm() {
router.go(-1);
}
const saveAsDialog = ref(false);
const saveAsName = ref('');
async function saveAs(name: string) {
successNotify('另存为成功' + name);
}
</script>

View File

@ -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<typeof dependency_1.iscsGraphicData.Canvas.prototype.toObject>;
cctvButtons?: ReturnType<typeof CCTVButton.prototype.toObject>[];
}): 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<typeof dependency_1.iscsGraphicData.Canvas.prototype.toObject>;
cctvButtons?: ReturnType<typeof CCTVButton.prototype.toObject>[];
} = {};
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<typeof dependency_1.iscsGraphicData.CommonInfo.prototype.toObject>;
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<typeof dependency_1.iscsGraphicData.CommonInfo.prototype.toObject>;
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
}
}
}

18
src/protos/picture.ts Normal file
View File

@ -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
}

View File

@ -13,6 +13,11 @@ const routes: RouteRecordRaw[] = [
path: '/:catchAll(.*)*', path: '/:catchAll(.*)*',
component: () => import('pages/ErrorNotFound.vue'), component: () => import('pages/ErrorNotFound.vue'),
}, },
{
path: '/cctvPainting',
name: 'cctvPainting',
component: () => import('layouts/CCTVDrawLayout.vue'),
},
]; ];
export default routes; export default routes;

View File

@ -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;
},
},
});