|
|
<template>
|
|
|
<div class="imageInfo">
|
|
|
<!-- 标题 -->
|
|
|
<div class="titleDiv">
|
|
|
<div class="titleName">
|
|
|
<span class="infovalue_name" v-if="editNameFlag">
|
|
|
{{ props.nowShowImageData.name }}
|
|
|
<EditOutlined
|
|
|
style="margin-left: 5px; font-size: 20px; color: #07aaed"
|
|
|
@click="editNameChange"
|
|
|
/>
|
|
|
</span>
|
|
|
<span class="infovalue_name" v-if="!editNameFlag">
|
|
|
<a-input
|
|
|
ref="focusInputRef"
|
|
|
v-model:value="editName"
|
|
|
style="width: 60%"
|
|
|
size="small"
|
|
|
@keypress.enter="pressEnterNameFunction"
|
|
|
/>
|
|
|
<CheckOutlined style="margin-left: 10px; color: green" @click="pressEnterNameFunction" />
|
|
|
<CloseOutlined style="margin-left: 10px; color: red" @click="editNameBlur" />
|
|
|
</span>
|
|
|
</div>
|
|
|
<div class="titleTime">
|
|
|
<ClockCircleOutlined />
|
|
|
|
|
|
<span>
|
|
|
{{ dayjs(props.nowShowImageData.createTime).format('YYYY-MM-DD HH:mm:ss (UTCZ)') }}
|
|
|
</span>
|
|
|
|
|
|
<span>
|
|
|
{{
|
|
|
props.nowShowImageData.size
|
|
|
? props.nowShowImageData.size > 1024 * 1024
|
|
|
? parseFloat((props.nowShowImageData.size / (1024 * 1024)).toFixed(2)) + 'MB'
|
|
|
: props.nowShowImageData.size > 1024
|
|
|
? parseFloat((props.nowShowImageData.size / 1024).toFixed(2)) + 'KB'
|
|
|
: parseFloat(props.nowShowImageData.size) + 'B'
|
|
|
: imageSize
|
|
|
}}
|
|
|
</span>
|
|
|
|
|
|
<span>
|
|
|
{{ props.nowShowImageData.width + ' x ' + props.nowShowImageData.height }}
|
|
|
</span>
|
|
|
</div>
|
|
|
<div class="titleCoordinate">
|
|
|
<span>
|
|
|
{{ props.nowShowImageData.lat + '° E' }}
|
|
|
</span>
|
|
|
|
|
|
<span>
|
|
|
{{ props.nowShowImageData.lng + '° N' }}
|
|
|
</span>
|
|
|
|
|
|
<span>
|
|
|
{{ '拍摄高度' + props.nowShowImageData.relativeAltitude + 'm' }}
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- 标签 -->
|
|
|
<div class="tagsDiv">
|
|
|
<a-tag color="success" v-for="tag in props.nowShowImageData.fileTags" :key="tag">
|
|
|
{{ tag }}
|
|
|
</a-tag>
|
|
|
<PlusSquareOutlined style="font-size: 20px; color: #07aaed" @click="addFileTagsChange" />
|
|
|
</div>
|
|
|
<!-- 关闭按钮 -->
|
|
|
<div class="closeButton">
|
|
|
<CloseOutlined @click="closePathImageInfo" style="font-size: 20px; color: white" />
|
|
|
</div>
|
|
|
<!-- 上一张、下一张图片 -->
|
|
|
<div class="leftButton" @click="clickLeftOrRightButton('left')">
|
|
|
<LeftOutlined style="color: #ffffff; font-size: 20px" />
|
|
|
</div>
|
|
|
<div class="rightButton" @click="clickLeftOrRightButton('right')">
|
|
|
<RightOutlined style="color: #ffffff; font-size: 20px" />
|
|
|
</div>
|
|
|
|
|
|
<!-- 涂鸦颜色选择-提示 -->
|
|
|
<div @click="setGraffiti" :class="graffitiFlag ? 'graffitiButton_choose' : 'graffitiButton'">
|
|
|
<a-popover placement="left">
|
|
|
<template #content>
|
|
|
<div style="display: flex; gap: 5px">
|
|
|
<div
|
|
|
class="popoverClass"
|
|
|
v-for="color in ['#2D8CF0', '#19BE6B', '#FFBB00', '#E23C39', '#B620E0']"
|
|
|
:key="color"
|
|
|
:style="{ background: color }"
|
|
|
@click="graffitiColor = color"
|
|
|
>
|
|
|
<CheckOutlined v-if="graffitiColor == color" style="color: white" />
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
<EditOutlined
|
|
|
:style="{
|
|
|
color: graffitiColor,
|
|
|
fontSize: '20px',
|
|
|
}"
|
|
|
/>
|
|
|
</a-popover>
|
|
|
</div>
|
|
|
<!-- 隐藏or显示涂鸦和标签 -->
|
|
|
<div class="showTextboxClass">
|
|
|
<div class="button">
|
|
|
<a-tooltip placement="left">
|
|
|
<template #title>
|
|
|
<span>{{ hideOrShowGraffitiFlag ? '点击隐藏涂鸦信息' : '点击显示涂鸦信息' }}</span>
|
|
|
</template>
|
|
|
<EyeOutlined
|
|
|
@click="hideOrShowGraffiti(false)"
|
|
|
v-if="hideOrShowGraffitiFlag"
|
|
|
style="color: #2d8cf0"
|
|
|
/>
|
|
|
<EyeInvisibleOutlined
|
|
|
@click="hideOrShowGraffiti(true)"
|
|
|
v-if="!hideOrShowGraffitiFlag"
|
|
|
style="color: #595959"
|
|
|
/>
|
|
|
<div style="position: absolute; bottom: -10px; right: -5px; pointer-events: none">
|
|
|
<div
|
|
|
v-html="
|
|
|
`${
|
|
|
hideOrShowGraffitiFlag
|
|
|
? graffiti_svg.replaceAll('currentColor', '#2d8cf0')
|
|
|
: graffiti_svg.replaceAll('currentColor', '#595959')
|
|
|
}`
|
|
|
"
|
|
|
/>
|
|
|
</div>
|
|
|
</a-tooltip>
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- 退出涂鸦 -->
|
|
|
<div class="escTip" v-if="graffitiFlag">
|
|
|
<div class="whiteEsc">Esc</div>
|
|
|
<div class="blackTip">退出涂鸦</div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 图片部分 -->
|
|
|
<div id="imageDiv" class="imageDiv" style="overflow: hidden">
|
|
|
<div
|
|
|
ref="mouseCanvasRef"
|
|
|
class="dragModal"
|
|
|
@mousedown="onMouseDown"
|
|
|
@wheel="onWheel"
|
|
|
:style="{
|
|
|
position: 'relative',
|
|
|
transform: `scale(${scale}) rotate(${rotationAngle}deg)`,
|
|
|
transition: 'transform 0.2s',
|
|
|
width: `${imageWidth}px`,
|
|
|
height: `${imageHeight}px`,
|
|
|
background: `url(${VITE_GLOB_MEDIALIBRARY_IMAGE_URL + props.nowShowImageData.objectKey}) no-repeat center center`,
|
|
|
backgroundSize: 'contain',
|
|
|
backgroundPosition: 'center',
|
|
|
}"
|
|
|
>
|
|
|
<!-- 创建的矩形 -->
|
|
|
<div
|
|
|
v-if="hideOrShowGraffitiFlag"
|
|
|
v-for="(rect, index) in graffitis"
|
|
|
:key="index"
|
|
|
:style="{
|
|
|
position: 'absolute',
|
|
|
left: rect.x + 'px',
|
|
|
top: rect.y + 'px',
|
|
|
width: rect.width + 'px',
|
|
|
height: rect.height + 'px',
|
|
|
zIndex: rect.status == 'edit' ? 1000 : 201,
|
|
|
}"
|
|
|
>
|
|
|
<!-- 文字标签 -->
|
|
|
<div
|
|
|
v-if="nowGraffiti == index || rect.text"
|
|
|
:style="{
|
|
|
position: 'absolute',
|
|
|
left: '0px',
|
|
|
top: rect.height + 'px',
|
|
|
width: '220px',
|
|
|
height: 30 + 'px',
|
|
|
background: nowGraffiti == index ? '#ffffff' : '#ffffff00',
|
|
|
}"
|
|
|
>
|
|
|
<div style="display: block" v-if="nowGraffiti == index">
|
|
|
<a-input
|
|
|
v-model:value="rect.text"
|
|
|
style="width: 110px; height: 30px; margin-right: 10px"
|
|
|
@keypress.enter="
|
|
|
nowGraffiti = -1;
|
|
|
rect.status = 'success';
|
|
|
addGraffiti();
|
|
|
"
|
|
|
/>
|
|
|
<CheckOutlined
|
|
|
style="margin-right: 10px; color: green"
|
|
|
@click="
|
|
|
nowGraffiti = -1;
|
|
|
rect.status = 'success';
|
|
|
addGraffiti();
|
|
|
"
|
|
|
/>
|
|
|
<CloseOutlined
|
|
|
style="margin-right: 10px; color: red"
|
|
|
@click="
|
|
|
rect.text
|
|
|
? ((rect.x = graffitisClone[index].x),
|
|
|
(rect.y = graffitisClone[index].y),
|
|
|
(rect.width = graffitisClone[index].width),
|
|
|
(rect.height = graffitisClone[index].height),
|
|
|
(rect.color = graffitisClone[index].color),
|
|
|
(rect.text = graffitisClone[index].text),
|
|
|
(rect.status = 'success'))
|
|
|
: graffitis.splice(index, 1);
|
|
|
nowGraffiti = -1;
|
|
|
"
|
|
|
/>
|
|
|
<DeleteOutlined
|
|
|
style="margin-right: 10px"
|
|
|
@click="
|
|
|
deleteGraffiti(index, rect.text);
|
|
|
nowGraffiti = -1;
|
|
|
"
|
|
|
/>
|
|
|
<a-popover placement="top">
|
|
|
<template #content>
|
|
|
<div style="display: flex; gap: 5px">
|
|
|
<div
|
|
|
class="popoverClass"
|
|
|
v-for="color in ['#2D8CF0', '#19BE6B', '#FFBB00', '#E23C39', '#B620E0']"
|
|
|
:key="color"
|
|
|
:style="{ background: color }"
|
|
|
@click="rect.color = color"
|
|
|
>
|
|
|
<CheckOutlined v-if="rect.color == color" style="color: white" />
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
<FontColorsOutlined />
|
|
|
</a-popover>
|
|
|
</div>
|
|
|
<div
|
|
|
v-if="nowGraffiti != index"
|
|
|
style="
|
|
|
font-size: 20px;
|
|
|
font-weight: bold;
|
|
|
-webkit-text-stroke: 1px white;
|
|
|
width: fit-content;
|
|
|
"
|
|
|
:style="{
|
|
|
textDecoration: rect.status == 'mouse' ? 'underline' : '',
|
|
|
}"
|
|
|
@mouseenter="graffitiFlag && rect.status != 'edit' ? (rect.status = 'mouse') : ''"
|
|
|
@mouseleave="graffitiFlag && rect.status == 'mouse' ? (rect.status = 'success') : ''"
|
|
|
@click="
|
|
|
graffitiFlag
|
|
|
? ((rect.status = 'edit'),
|
|
|
(graffitisClone = cloneDeep(graffitis)),
|
|
|
(nowGraffiti = index))
|
|
|
: ''
|
|
|
"
|
|
|
>
|
|
|
{{ rect.text }}
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- 上 -->
|
|
|
<div
|
|
|
:style="{
|
|
|
position: 'absolute',
|
|
|
left: rect.status == 'edit' ? '6px' : '0px',
|
|
|
top: '0px',
|
|
|
width: rect.status == 'edit' ? `${rect.width - 14}px` : `${rect.width}px`,
|
|
|
height: '4px',
|
|
|
background: `${rect.color}`,
|
|
|
outline: rect.status != 'success' ? `2px solid #ffffff` : '',
|
|
|
}"
|
|
|
@mouseenter="mouseenter(rect, 'top')"
|
|
|
@mouseleave="mouseleave(rect)"
|
|
|
@click="graffitiFlag ? ((rect.status = 'edit'), (nowGraffiti = index)) : ''"
|
|
|
@mousedown="funMouseDownEdit($event, index, 'top')"
|
|
|
/>
|
|
|
<!-- 下 -->
|
|
|
<div
|
|
|
:style="{
|
|
|
position: 'absolute',
|
|
|
left: rect.status == 'edit' ? '6px' : '0px',
|
|
|
bottom: `0px`,
|
|
|
width: rect.status == 'edit' ? `${rect.width - 14}px` : `${rect.width}px`,
|
|
|
height: '4px',
|
|
|
background: `${rect.color}`,
|
|
|
outline: rect.status != 'success' ? `2px solid #ffffff` : '',
|
|
|
}"
|
|
|
@mouseenter="mouseenter(rect, 'bottom')"
|
|
|
@mouseleave="mouseleave(rect)"
|
|
|
@click="graffitiFlag ? ((rect.status = 'edit'), (nowGraffiti = index)) : ''"
|
|
|
@mousedown="funMouseDownEdit($event, index, 'bottom')"
|
|
|
/>
|
|
|
<!-- 右 -->
|
|
|
<div
|
|
|
:style="{
|
|
|
position: 'absolute',
|
|
|
right: '0px',
|
|
|
top: rect.status == 'edit' ? '6px' : '0px',
|
|
|
width: '4px',
|
|
|
height: rect.status == 'edit' ? `${rect.height - 14}px` : `${rect.height}px`,
|
|
|
background: `${rect.color}`,
|
|
|
outline: rect.status != 'success' ? `2px solid #ffffff` : '',
|
|
|
}"
|
|
|
@mouseenter="mouseenter(rect, 'right')"
|
|
|
@mouseleave="mouseleave(rect)"
|
|
|
@click="graffitiFlag ? ((rect.status = 'edit'), (nowGraffiti = index)) : ''"
|
|
|
@mousedown="funMouseDownEdit($event, index, 'right')"
|
|
|
/>
|
|
|
<!-- 左 -->
|
|
|
<div
|
|
|
:style="{
|
|
|
position: 'absolute',
|
|
|
left: '0px',
|
|
|
top: rect.status == 'edit' ? '6px' : '0px',
|
|
|
width: '4px',
|
|
|
height: rect.status == 'edit' ? `${rect.height - 14}px` : `${rect.height}px`,
|
|
|
background: `${rect.color}`,
|
|
|
outline: rect.status != 'success' ? `2px solid #ffffff` : '',
|
|
|
}"
|
|
|
@mouseenter="mouseenter(rect, 'left')"
|
|
|
@mouseleave="mouseleave(rect)"
|
|
|
@click="graffitiFlag ? ((rect.status = 'edit'), (nowGraffiti = index)) : ''"
|
|
|
@mousedown="funMouseDownEdit($event, index, 'left')"
|
|
|
/>
|
|
|
<!-- 左上 -->
|
|
|
<div
|
|
|
v-if="rect.status == 'edit'"
|
|
|
:style="{
|
|
|
position: 'absolute',
|
|
|
left: '-4px',
|
|
|
top: '-4px',
|
|
|
width: '12px',
|
|
|
height: '12px',
|
|
|
background: `#ffffff`,
|
|
|
}"
|
|
|
@mouseenter="mouseenter(rect, 'leftTop')"
|
|
|
@mouseleave="mouseleave(rect)"
|
|
|
@mousedown="funMouseDownEdit($event, index, 'leftTop')"
|
|
|
/>
|
|
|
<!-- 右下 -->
|
|
|
<div
|
|
|
v-if="rect.status == 'edit'"
|
|
|
:style="{
|
|
|
position: 'absolute',
|
|
|
right: '-4px',
|
|
|
bottom: '-4px',
|
|
|
width: '12px',
|
|
|
height: '12px',
|
|
|
background: `#ffffff`,
|
|
|
}"
|
|
|
@mouseenter="mouseenter(rect, 'rightBottom')"
|
|
|
@mouseleave="mouseleave(rect)"
|
|
|
@mousedown="funMouseDownEdit($event, index, 'rightBottom')"
|
|
|
/>
|
|
|
<!-- 右上 -->
|
|
|
<div
|
|
|
v-if="rect.status == 'edit'"
|
|
|
:style="{
|
|
|
position: 'absolute',
|
|
|
right: '-4px',
|
|
|
top: '-4px',
|
|
|
width: '12px',
|
|
|
height: '12px',
|
|
|
background: `#ffffff`,
|
|
|
}"
|
|
|
@mouseenter="mouseenter(rect, 'rightTop')"
|
|
|
@mouseleave="mouseleave(rect)"
|
|
|
@mousedown="funMouseDownEdit($event, index, 'rightTop')"
|
|
|
/>
|
|
|
<!-- 左下 -->
|
|
|
<div
|
|
|
v-if="rect.status == 'edit'"
|
|
|
:style="{
|
|
|
position: 'absolute',
|
|
|
left: '-4px',
|
|
|
bottom: '-4px',
|
|
|
width: '12px',
|
|
|
height: '12px',
|
|
|
background: `#ffffff`,
|
|
|
}"
|
|
|
@mouseenter="mouseenter(rect, 'leftBottom')"
|
|
|
@mouseleave="mouseleave(rect)"
|
|
|
@mousedown="funMouseDownEdit($event, index, 'leftBottom')"
|
|
|
/>
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- 云台偏航角查看图片 -->
|
|
|
<div class="rimbalGawDegreeButton" @click="rotateGimbalYawDegree">
|
|
|
<a-tooltip placement="left">
|
|
|
<template #title>
|
|
|
<span> {{ rimbalGawDegreeFlag ? '正常查看图片' : '云台偏航角查看图片' }}</span>
|
|
|
</template>
|
|
|
<InstagramOutlined v-if="!rimbalGawDegreeFlag" style="color: #3c3c3c; font-size: 25px" />
|
|
|
<FileImageOutlined v-if="rimbalGawDegreeFlag" style="color: #3c3c3c; font-size: 25px" />
|
|
|
</a-tooltip>
|
|
|
</div>
|
|
|
<!-- 全屏 -->
|
|
|
<div class="expandButton" @click="clickExpandButton">
|
|
|
<ExpandOutlined v-if="!fullscreenFlag" style="color: #3c3c3c; font-size: 25px" />
|
|
|
<CompressOutlined v-if="fullscreenFlag" style="color: #3c3c3c; font-size: 25px" />
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- 底部按钮和图片列表 -->
|
|
|
<div class="bottomDiv">
|
|
|
<div class="buttonList">
|
|
|
<!-- 放大 -->
|
|
|
<div class="button">
|
|
|
<a-tooltip placement="top">
|
|
|
<template #title>
|
|
|
<span>放大</span>
|
|
|
</template>
|
|
|
<ZoomInOutlined @click="zoomIn" />
|
|
|
</a-tooltip>
|
|
|
</div>
|
|
|
<!-- 缩小 -->
|
|
|
<div class="button">
|
|
|
<a-tooltip placement="top">
|
|
|
<template #title>
|
|
|
<span>缩小</span>
|
|
|
</template>
|
|
|
<ZoomOutOutlined @click="zoomOut" />
|
|
|
</a-tooltip>
|
|
|
</div>
|
|
|
<!-- 100%比例 -->
|
|
|
<div class="button">
|
|
|
<a-tooltip placement="top">
|
|
|
<template #title>
|
|
|
<span>100%比例</span>
|
|
|
</template>
|
|
|
<OneToOneOutlined @click="setProportion" />
|
|
|
</a-tooltip>
|
|
|
</div>
|
|
|
<!-- 顺时针旋转 -->
|
|
|
<div class="button">
|
|
|
<a-tooltip placement="top">
|
|
|
<template #title>
|
|
|
<span>顺时针旋转</span>
|
|
|
</template>
|
|
|
<RotateRightOutlined @click="rotateClockwise" />
|
|
|
</a-tooltip>
|
|
|
</div>
|
|
|
<!-- 逆时针旋转 -->
|
|
|
<div class="button">
|
|
|
<a-tooltip placement="top">
|
|
|
<template #title>
|
|
|
<span>逆时针旋转</span>
|
|
|
</template>
|
|
|
<RotateLeftOutlined @click="rotateCounterClockwise" />
|
|
|
</a-tooltip>
|
|
|
</div>
|
|
|
<!-- 刷新 -->
|
|
|
<div class="button">
|
|
|
<a-tooltip placement="top">
|
|
|
<template #title>
|
|
|
<span>复位刷新</span>
|
|
|
</template>
|
|
|
<RedoOutlined @click="refresh" />
|
|
|
</a-tooltip>
|
|
|
</div>
|
|
|
<!-- 回中 -->
|
|
|
<div class="button">
|
|
|
<a-tooltip placement="top">
|
|
|
<template #title>
|
|
|
<span>回中</span>
|
|
|
</template>
|
|
|
<AimOutlined @click="handlerLocation" />
|
|
|
</a-tooltip>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="imageChooseList">
|
|
|
<div
|
|
|
v-for="li in props.allImageDataList.filter((item) => item.display == 1)"
|
|
|
:key="li.id"
|
|
|
@click="setNowShowImageData(li)"
|
|
|
>
|
|
|
<a-tooltip placement="top">
|
|
|
<template #title>
|
|
|
<span>{{ li.name }}</span>
|
|
|
</template>
|
|
|
<div :class="li.id == props.nowShowImageData.id ? 'bottom_div_choose' : 'bottom_div'">
|
|
|
<img
|
|
|
:src="VITE_GLOB_MEDIALIBRARY_IMAGE_URL + li.minipic"
|
|
|
loading="lazy"
|
|
|
width="75"
|
|
|
height="50"
|
|
|
/>
|
|
|
</div>
|
|
|
</a-tooltip>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- 标签弹窗 -->
|
|
|
<a-modal
|
|
|
title="标签设置"
|
|
|
:open="addFileTagsFlag"
|
|
|
:mask="false"
|
|
|
:maskClosable="false"
|
|
|
:closable="false"
|
|
|
:footer="null"
|
|
|
>
|
|
|
<div style="display: block">
|
|
|
<div
|
|
|
style="display: flex; flex-wrap: wrap; gap: 5px; width: 96%; margin: 10px"
|
|
|
v-if="props.nowShowImageData.fileTags && props.nowShowImageData.fileTags.length > 0"
|
|
|
>
|
|
|
已添加的标签:
|
|
|
<div
|
|
|
v-for="la in props.nowShowImageData.fileTags"
|
|
|
:key="la"
|
|
|
style="border: 1px solid #595959; border-radius: 3px"
|
|
|
>
|
|
|
<span style="margin-left: 5px">{{ la }}</span>
|
|
|
<CloseOutlined
|
|
|
style="margin-left: 5px; margin-right: 5px"
|
|
|
@click="deleteFileTags(la)"
|
|
|
/>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div style="display: inline-flex; gap: 5px; width: 96%; margin: 10px">
|
|
|
<a-input v-model:value="newFileTagsName" size="small" placeholder="请输入标签" />
|
|
|
<a-button type="primary" @click="pressEnterFileTagsFunction">添加</a-button>
|
|
|
</div>
|
|
|
<div
|
|
|
style="
|
|
|
display: inline-flex;
|
|
|
gap: 5px;
|
|
|
width: 96%;
|
|
|
margin: 5px 10px 20px 10px;
|
|
|
justify-content: flex-end;
|
|
|
"
|
|
|
>
|
|
|
<a-button
|
|
|
@click="
|
|
|
addFileTagsFlag = false;
|
|
|
newFileTagsName = '';
|
|
|
"
|
|
|
>
|
|
|
关闭
|
|
|
</a-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
</a-modal>
|
|
|
</div>
|
|
|
</template>
|
|
|
<script lang="ts" setup>
|
|
|
import { ref, watch, onMounted, onBeforeUnmount } from 'vue';
|
|
|
import {
|
|
|
CloseOutlined,
|
|
|
RightOutlined,
|
|
|
LeftOutlined,
|
|
|
ZoomOutOutlined,
|
|
|
ZoomInOutlined,
|
|
|
RotateLeftOutlined,
|
|
|
RotateRightOutlined,
|
|
|
DeleteOutlined,
|
|
|
CheckOutlined,
|
|
|
EyeOutlined,
|
|
|
EyeInvisibleOutlined,
|
|
|
EditOutlined,
|
|
|
FontColorsOutlined,
|
|
|
RedoOutlined,
|
|
|
ExpandOutlined,
|
|
|
CompressOutlined,
|
|
|
OneToOneOutlined,
|
|
|
AimOutlined,
|
|
|
ClockCircleOutlined,
|
|
|
PlusSquareOutlined,
|
|
|
InstagramOutlined,
|
|
|
FileImageOutlined,
|
|
|
} from '@ant-design/icons-vue';
|
|
|
import dayjs from 'dayjs';
|
|
|
import { UpdatePicStatus, UpdatePicName } from '@/api/demo/mediaLibrary';
|
|
|
import { graffiti_svg } from './svg';
|
|
|
import { getAppEnvConfig } from '@/utils/env';
|
|
|
import { cloneDeep } from 'lodash-es';
|
|
|
import { useMessage } from '@/hooks/web/useMessage';
|
|
|
const { createMessage, createConfirm } = useMessage();
|
|
|
const { VITE_GLOB_MEDIALIBRARY_IMAGE_URL } = getAppEnvConfig();
|
|
|
|
|
|
const props = defineProps(['nowShowImageData', 'allImageDataList']);
|
|
|
const emits = defineEmits([
|
|
|
'setNowShowImageData',
|
|
|
'closePathImageInfo',
|
|
|
'handleSuccessPath',
|
|
|
'handlerLocation',
|
|
|
'funUpdateDisplayOrShowOnMapData',
|
|
|
]);
|
|
|
|
|
|
// 修改名称--------------------------------
|
|
|
const focusInputRef = ref();
|
|
|
const editNameFlag = ref(true);
|
|
|
const editName = ref();
|
|
|
function editNameChange() {
|
|
|
if (props.nowShowImageData.name.split('.').length <= 1) {
|
|
|
editName.value = props.nowShowImageData.name;
|
|
|
} else {
|
|
|
editName.value = props.nowShowImageData.name.split('.').slice(0, -1).join('.');
|
|
|
}
|
|
|
setTimeout(() => {
|
|
|
if (focusInputRef.value && focusInputRef.value.focus) {
|
|
|
focusInputRef.value.focus(); // 调用 focus 方法
|
|
|
}
|
|
|
}, 300);
|
|
|
editNameFlag.value = false;
|
|
|
}
|
|
|
// 修改名称方法
|
|
|
async function pressEnterNameFunction() {
|
|
|
let newName: any = null;
|
|
|
if (props.nowShowImageData.name.split('.').length <= 1) {
|
|
|
newName = editName.value;
|
|
|
} else {
|
|
|
newName = editName.value + '.' + props.nowShowImageData.name.split('.').pop();
|
|
|
}
|
|
|
let query = {
|
|
|
id: props.nowShowImageData.id,
|
|
|
name: newName,
|
|
|
};
|
|
|
UpdatePicName(query).then((res) => {
|
|
|
props.nowShowImageData.name = newName;
|
|
|
editNameFlag.value = true;
|
|
|
createMessage.success(res);
|
|
|
emits('funUpdateDisplayOrShowOnMapData', props.nowShowImageData);
|
|
|
emits('handleSuccessPath', props.nowShowImageData);
|
|
|
});
|
|
|
}
|
|
|
function editNameBlur() {
|
|
|
editNameFlag.value = true;
|
|
|
editName.value = props.nowShowImageData.name.split('.').slice(0, -1).join('.');
|
|
|
}
|
|
|
|
|
|
// 关闭图片抽屉--------------------------------------------------------------
|
|
|
function closePathImageInfo() {
|
|
|
emits('setNowShowImageData', {});
|
|
|
}
|
|
|
|
|
|
// 上一张、下一张图片--------------------------------------------------------------
|
|
|
function clickLeftOrRightButton(direction) {
|
|
|
const list = props.allImageDataList.filter((item) => item.display == 1);
|
|
|
for (let index = 0; index < list.length; index++) {
|
|
|
if (list[index].id == props.nowShowImageData.id) {
|
|
|
if (direction == 'left') {
|
|
|
if (index == 0) {
|
|
|
setNowShowImageData(list[list.length - 1]);
|
|
|
} else {
|
|
|
setNowShowImageData(list[index - 1]);
|
|
|
}
|
|
|
}
|
|
|
if (direction == 'right') {
|
|
|
if (index == list.length - 1) {
|
|
|
setNowShowImageData(list[0]);
|
|
|
} else {
|
|
|
setNowShowImageData(list[index + 1]);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
// 全屏
|
|
|
const fullscreenFlag = ref(false);
|
|
|
function clickExpandButton() {
|
|
|
const mapContainer = document.getElementById('imageDiv');
|
|
|
if (mapContainer) {
|
|
|
if (!document.fullscreenElement) {
|
|
|
mapContainer.requestFullscreen();
|
|
|
fullscreenFlag.value = true;
|
|
|
} else {
|
|
|
document.exitFullscreen();
|
|
|
fullscreenFlag.value = false;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
// 缩放比例
|
|
|
const scale = ref(0.9);
|
|
|
// 放大函数
|
|
|
function zoomIn() {
|
|
|
if (scale.value < 4) {
|
|
|
// 设置最大缩放倍数为3倍
|
|
|
scale.value += 0.1;
|
|
|
}
|
|
|
}
|
|
|
// 缩小函数
|
|
|
function zoomOut() {
|
|
|
if (scale.value > 0.5) {
|
|
|
// 设置最小缩放倍数为0.5倍
|
|
|
scale.value -= 0.1;
|
|
|
}
|
|
|
}
|
|
|
// 旋转
|
|
|
const rotationAngle = ref(0);
|
|
|
// 顺时针旋转函数
|
|
|
function rotateClockwise() {
|
|
|
rotationAngle.value += 90; // 每次旋转90度
|
|
|
}
|
|
|
// 逆时针旋转
|
|
|
function rotateCounterClockwise() {
|
|
|
rotationAngle.value -= 90; // 每次旋转-90度
|
|
|
}
|
|
|
// 云台偏航角查看图片
|
|
|
const rimbalGawDegreeFlag = ref(true);
|
|
|
function rotateGimbalYawDegree() {
|
|
|
if (!graffitiFlag.value) {
|
|
|
rimbalGawDegreeFlag.value = !rimbalGawDegreeFlag.value;
|
|
|
if (rimbalGawDegreeFlag.value) {
|
|
|
rotationAngle.value = parseFloat(props.nowShowImageData.gimbalYawDegree) + 180;
|
|
|
} else {
|
|
|
rotationAngle.value = 0;
|
|
|
}
|
|
|
} else {
|
|
|
createMessage.warn('涂鸦状态下不能使用云台偏航角查看图片');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 宽高
|
|
|
const imageWidth = ref(1040);
|
|
|
const imageHeight = ref(800);
|
|
|
// 设置高度和宽度
|
|
|
function getImageWidthAndHeight() {
|
|
|
if (
|
|
|
props.nowShowImageData.width &&
|
|
|
props.nowShowImageData.height &&
|
|
|
props.nowShowImageData.width > 1040 &&
|
|
|
props.nowShowImageData.height > 800
|
|
|
) {
|
|
|
imageWidth.value = 1040;
|
|
|
imageHeight.value = (1040 / props.nowShowImageData.width) * props.nowShowImageData.height;
|
|
|
} else {
|
|
|
imageHeight.value = 800;
|
|
|
imageWidth.value = 1040;
|
|
|
}
|
|
|
}
|
|
|
onMounted(() => {
|
|
|
getImageWidthAndHeight();
|
|
|
});
|
|
|
// 100%比例
|
|
|
function setProportion() {
|
|
|
if (
|
|
|
props.nowShowImageData.width &&
|
|
|
props.nowShowImageData.height &&
|
|
|
props.nowShowImageData.width > 1040 &&
|
|
|
props.nowShowImageData.height > 800
|
|
|
) {
|
|
|
scale.value = props.nowShowImageData.width / 1040;
|
|
|
// imageWidth.value = props.nowShowImageData.width;
|
|
|
// imageHeight.value = props.nowShowImageData.height;
|
|
|
} else {
|
|
|
scale.value = 2;
|
|
|
// imageWidth.value = 2080;
|
|
|
// imageHeight.value = 1600;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 刷新
|
|
|
function refresh() {
|
|
|
scale.value = 0.9;
|
|
|
// 是否云台偏航角查看图片
|
|
|
if (rimbalGawDegreeFlag.value) {
|
|
|
rotationAngle.value = parseFloat(props.nowShowImageData.gimbalYawDegree) + 180;
|
|
|
} else {
|
|
|
rotationAngle.value = 0;
|
|
|
}
|
|
|
getImageWidthAndHeight();
|
|
|
// 复位
|
|
|
const dragDocument: any = document.querySelector('.dragModal');
|
|
|
if (dragDocument) {
|
|
|
dragDocument.style.left = 0 + 'px';
|
|
|
dragDocument.style.top = 0 + 'px';
|
|
|
}
|
|
|
document.body.style.cursor = 'default';
|
|
|
}
|
|
|
// 移动到中心位置
|
|
|
function handlerLocation() {
|
|
|
emits('handlerLocation', props.nowShowImageData);
|
|
|
}
|
|
|
|
|
|
// 选择当前展示图片-----------------------------------------------
|
|
|
function setNowShowImageData(chooseValue) {
|
|
|
emits('setNowShowImageData', chooseValue);
|
|
|
graffitiFlag.value = false;
|
|
|
refresh();
|
|
|
}
|
|
|
|
|
|
// 调整滑动条的位置
|
|
|
function setScrollLeft() {
|
|
|
const imageChooseListDocument: any = document.querySelector('.imageChooseList');
|
|
|
if (imageChooseListDocument) {
|
|
|
let index = props.allImageDataList.findIndex((item) => item.id == props.nowShowImageData.id);
|
|
|
let length = props.allImageDataList.length;
|
|
|
if (index < 5) {
|
|
|
imageChooseListDocument.scrollLeft = 0;
|
|
|
} else if (index + 6 > length) {
|
|
|
imageChooseListDocument.scrollLeft = 95 * length;
|
|
|
} else {
|
|
|
imageChooseListDocument.scrollLeft = 95 * (index - 4);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 鼠标拖动or涂鸦-------------------------------------------------
|
|
|
// 鼠标放上去的模式(拖动or涂鸦)
|
|
|
const graffitiFlag = ref(false);
|
|
|
// 设置鼠标格式
|
|
|
function setGraffiti() {
|
|
|
refresh();
|
|
|
graffitiFlag.value = !graffitiFlag.value;
|
|
|
// 正常查看图片
|
|
|
rimbalGawDegreeFlag.value = false;
|
|
|
rotationAngle.value = 0;
|
|
|
if (graffitiFlag.value) {
|
|
|
document.body.style.cursor = 'crosshair';
|
|
|
} else {
|
|
|
document.body.style.cursor = 'pointer';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 标签--------------------------------
|
|
|
const addFileTagsFlag = ref(false);
|
|
|
const newFileTagsName = ref('');
|
|
|
const fileTags: any = ref([]);
|
|
|
// 所有已创建的矩形
|
|
|
const graffitis: any = ref([]);
|
|
|
const graffitisClone: any = ref([]);
|
|
|
|
|
|
watch(
|
|
|
() => props.nowShowImageData,
|
|
|
() => {
|
|
|
graffitis.value = props.nowShowImageData.graffitiJson
|
|
|
? props.nowShowImageData.graffitiJson
|
|
|
: [];
|
|
|
fileTags.value = props.nowShowImageData.fileTags ? props.nowShowImageData.fileTags : [];
|
|
|
if (rimbalGawDegreeFlag.value) {
|
|
|
rotationAngle.value = parseFloat(props.nowShowImageData.gimbalYawDegree) + 180;
|
|
|
}
|
|
|
// 调整滑动条的位置
|
|
|
setScrollLeft();
|
|
|
// 图片大小
|
|
|
getImageSize();
|
|
|
editNameFlag.value = true;
|
|
|
},
|
|
|
{
|
|
|
deep: true,
|
|
|
immediate: true,
|
|
|
},
|
|
|
);
|
|
|
|
|
|
onMounted(() => {
|
|
|
// 调整滑动条的位置
|
|
|
setScrollLeft();
|
|
|
});
|
|
|
|
|
|
// 图片大小
|
|
|
const imageSize = ref('');
|
|
|
async function getImageSize() {
|
|
|
try {
|
|
|
const response = await fetch(
|
|
|
VITE_GLOB_MEDIALIBRARY_IMAGE_URL + props.nowShowImageData.objectKey,
|
|
|
{ method: 'HEAD' },
|
|
|
);
|
|
|
if (!response.ok) {
|
|
|
imageSize.value = '--';
|
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
|
}
|
|
|
const contentLength = response.headers.get('Content-Length');
|
|
|
if (contentLength) {
|
|
|
const sizeInBytes = parseInt(contentLength, 10);
|
|
|
if (sizeInBytes > 1024 * 1024) {
|
|
|
imageSize.value = (sizeInBytes / (1024 * 1024)).toFixed(2) + 'MB';
|
|
|
} else if (sizeInBytes > 1024) {
|
|
|
imageSize.value = (sizeInBytes / 1024).toFixed(2) + 'KB';
|
|
|
} else if (sizeInBytes > 0) {
|
|
|
imageSize.value = sizeInBytes + 'B';
|
|
|
} else {
|
|
|
imageSize.value = '--';
|
|
|
}
|
|
|
} else {
|
|
|
imageSize.value = '--';
|
|
|
}
|
|
|
} catch (error) {
|
|
|
imageSize.value = '--';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 打开标签弹窗
|
|
|
function addFileTagsChange() {
|
|
|
addFileTagsFlag.value = true;
|
|
|
}
|
|
|
// 添加标签方法
|
|
|
async function pressEnterFileTagsFunction() {
|
|
|
if (!newFileTagsName.value) {
|
|
|
return;
|
|
|
}
|
|
|
if (!fileTags.value.includes(newFileTagsName.value)) {
|
|
|
fileTags.value.push(newFileTagsName.value);
|
|
|
UpdatePicStatus({
|
|
|
id: props.nowShowImageData.id,
|
|
|
fileTags: JSON.stringify(fileTags.value),
|
|
|
graffitiJson: JSON.stringify(graffitis.value),
|
|
|
display: props.nowShowImageData.display ? 1 : 0,
|
|
|
showOnMap: props.nowShowImageData.showOnMap ? 1 : 0,
|
|
|
}).then((res) => {
|
|
|
addFileTagsFlag.value = true;
|
|
|
newFileTagsName.value = '';
|
|
|
emits('handleSuccessPath', props.nowShowImageData);
|
|
|
});
|
|
|
} else {
|
|
|
return createMessage.error('此标签已存在!');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 删除标签
|
|
|
function deleteFileTags(value) {
|
|
|
createConfirm({
|
|
|
iconType: 'info',
|
|
|
title: '提醒',
|
|
|
content: '删除标签【' + value + '】,同标签名的涂鸦标记都会被删除!',
|
|
|
onOk: () => {
|
|
|
fileTags.value = fileTags.value.filter((item) => item !== value);
|
|
|
let json = graffitis.value;
|
|
|
if (json.some((item) => item.text == value)) {
|
|
|
json = json.filter((item) => item.text !== value);
|
|
|
graffitis.value = json;
|
|
|
}
|
|
|
UpdatePicStatus({
|
|
|
id: props.nowShowImageData.id,
|
|
|
fileTags: JSON.stringify(fileTags.value),
|
|
|
graffitiJson: JSON.stringify(graffitis.value),
|
|
|
display: props.nowShowImageData.display,
|
|
|
showOnMap: props.nowShowImageData.showOnMap,
|
|
|
}).then((res) => {
|
|
|
emits('handleSuccessPath', props.nowShowImageData);
|
|
|
});
|
|
|
},
|
|
|
onCancel: () => {},
|
|
|
});
|
|
|
}
|
|
|
|
|
|
// 涂鸦
|
|
|
// ref
|
|
|
const mouseCanvasRef = ref();
|
|
|
const graffitiColor = ref('#E23C39');
|
|
|
const nowGraffiti = ref(-1);
|
|
|
|
|
|
// 添加
|
|
|
function addGraffiti() {
|
|
|
graffitis.value.forEach((item) => {
|
|
|
if (item.text && !fileTags.value.includes(item.text)) {
|
|
|
if (item.text) {
|
|
|
fileTags.value.push(item.text);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
UpdatePicStatus({
|
|
|
id: props.nowShowImageData.id,
|
|
|
fileTags: JSON.stringify(fileTags.value),
|
|
|
graffitiJson: JSON.stringify(graffitis.value),
|
|
|
display: props.nowShowImageData.display,
|
|
|
showOnMap: props.nowShowImageData.showOnMap,
|
|
|
}).then((res) => {
|
|
|
emits('handleSuccessPath', props.nowShowImageData);
|
|
|
});
|
|
|
}
|
|
|
// 删除
|
|
|
function deleteGraffiti(index = undefined, value = undefined) {
|
|
|
graffitis.value.splice(index, 1);
|
|
|
// 刷新or删除标签
|
|
|
if (!graffitis.value.some((item) => item.text == value)) {
|
|
|
fileTags.value = fileTags.value.filter((la) => la != value);
|
|
|
}
|
|
|
UpdatePicStatus({
|
|
|
id: props.nowShowImageData.id,
|
|
|
fileTags: JSON.stringify(fileTags.value),
|
|
|
graffitiJson: JSON.stringify(graffitis.value),
|
|
|
display: props.nowShowImageData.display,
|
|
|
showOnMap: props.nowShowImageData.showOnMap,
|
|
|
}).then((res) => {
|
|
|
emits('handleSuccessPath', props.nowShowImageData);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
|
// 状态管理
|
|
|
const dragState = {
|
|
|
isDragging: false,
|
|
|
initialMouseX: 0,
|
|
|
initialMouseY: 0,
|
|
|
initialElementX: 0,
|
|
|
initialElementY: 0,
|
|
|
};
|
|
|
// 临时选框状态
|
|
|
const isDragging = ref(false);
|
|
|
// 涂鸦
|
|
|
let startX = 0;
|
|
|
let startY = 0;
|
|
|
let endX = 0;
|
|
|
let endY = 0;
|
|
|
// 鼠标按下
|
|
|
function onMouseDown(event) {
|
|
|
if (
|
|
|
graffitiFlag.value &&
|
|
|
(graffitis.value.length == 0 || !graffitis.value.some((item) => item.status != 'success'))
|
|
|
) {
|
|
|
// 涂鸦
|
|
|
if (nowGraffiti.value != -1) return;
|
|
|
if (graffitis.value.findIndex((item) => item.status == 'mouse') != -1) return;
|
|
|
// 获取相对于容器的坐标
|
|
|
const rect = mouseCanvasRef.value.getBoundingClientRect();
|
|
|
startX = event.x - rect.x;
|
|
|
startY = event.y - rect.y;
|
|
|
isDragging.value = true;
|
|
|
// 添加矩形到数组中
|
|
|
graffitis.value.push({
|
|
|
x: startX,
|
|
|
y: startY,
|
|
|
width: 0,
|
|
|
height: 0,
|
|
|
color: graffitiColor.value,
|
|
|
text: '',
|
|
|
status: 'edit',
|
|
|
});
|
|
|
graffitisClone.value = cloneDeep(graffitis.value);
|
|
|
window.addEventListener('mousemove', onMouseMoveGraffit);
|
|
|
window.addEventListener('mouseup', onMouseUpGraffit);
|
|
|
}
|
|
|
if (!graffitiFlag.value) {
|
|
|
const dragElement: any = document.querySelector('.dragModal');
|
|
|
if (!dragElement) return;
|
|
|
dragState.isDragging = true;
|
|
|
dragState.initialMouseX = event.clientX;
|
|
|
dragState.initialMouseY = event.clientY;
|
|
|
dragState.initialElementX = dragElement.offsetLeft;
|
|
|
dragState.initialElementY = dragElement.offsetTop;
|
|
|
dragElement.style.cursor = 'grabbing';
|
|
|
document.addEventListener('mousemove', handleMouseMove);
|
|
|
document.addEventListener('mouseup', handleMouseUp);
|
|
|
}
|
|
|
}
|
|
|
// 鼠标移动-涂鸦
|
|
|
function onMouseMoveGraffit(event) {
|
|
|
// 涂鸦
|
|
|
const rect = mouseCanvasRef.value.getBoundingClientRect();
|
|
|
if (!isDragging.value) return;
|
|
|
endX = event.x - rect.x;
|
|
|
endY = event.y - rect.y;
|
|
|
if (endX < 0 && endY < 0) {
|
|
|
endX = startX;
|
|
|
endY = startY;
|
|
|
}
|
|
|
setMouseData();
|
|
|
}
|
|
|
// 鼠标松开-涂鸦
|
|
|
function onMouseUpGraffit(event) {
|
|
|
// 涂鸦
|
|
|
if (!isDragging.value) return;
|
|
|
const rect = mouseCanvasRef.value.getBoundingClientRect();
|
|
|
endX = event.x - rect.x;
|
|
|
endY = event.y - rect.y;
|
|
|
if (endX < 0 && endY < 0) {
|
|
|
endX = startX;
|
|
|
endY = startY;
|
|
|
}
|
|
|
isDragging.value = false;
|
|
|
if (event.x > rect.right || event.y > rect.bottom) {
|
|
|
graffitis.value.splice(graffitis.value.length - 1, 1);
|
|
|
nowGraffiti.value = -1;
|
|
|
} else {
|
|
|
setMouseData();
|
|
|
nowGraffiti.value = graffitis.value.length - 1;
|
|
|
}
|
|
|
window.removeEventListener('mousemove', onMouseMoveGraffit);
|
|
|
window.removeEventListener('mouseup', onMouseUpGraffit);
|
|
|
}
|
|
|
// 鼠标移动-拖动
|
|
|
const handleMouseMove = (event) => {
|
|
|
const dragElement: any = document.querySelector('.dragModal');
|
|
|
if (!dragElement) return;
|
|
|
if (!dragState.isDragging) return;
|
|
|
const deltaX = event.clientX - dragState.initialMouseX;
|
|
|
const deltaY = event.clientY - dragState.initialMouseY;
|
|
|
dragElement.style.left = `${dragState.initialElementX + deltaX}px`;
|
|
|
dragElement.style.top = `${dragState.initialElementY + deltaY}px`;
|
|
|
};
|
|
|
// 鼠标松开-拖动
|
|
|
const handleMouseUp = () => {
|
|
|
const dragElement: any = document.querySelector('.dragModal');
|
|
|
if (!dragElement) return;
|
|
|
dragState.isDragging = false;
|
|
|
dragElement.style.cursor = 'default';
|
|
|
document.removeEventListener('mousemove', handleMouseMove);
|
|
|
document.removeEventListener('mouseup', handleMouseUp);
|
|
|
};
|
|
|
|
|
|
// 鼠标滚轮
|
|
|
function onWheel(event) {
|
|
|
if (!graffitiFlag.value) {
|
|
|
const delta = event.deltaY || event.detail || event.wheelDelta;
|
|
|
// 根据滚轮方向调整缩放比例
|
|
|
if (delta < 0) {
|
|
|
// 向上滚动,放大
|
|
|
scale.value += 0.1;
|
|
|
} else if (scale.value > 0.5) {
|
|
|
// 向下滚动,缩小
|
|
|
scale.value -= 0.1;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
// 设置鼠标涂鸦绘画出的数据
|
|
|
function setMouseData() {
|
|
|
graffitis.value[graffitis.value.length - 1].x = Math.min(startX, endX);
|
|
|
graffitis.value[graffitis.value.length - 1].width = Math.abs(endX - startX);
|
|
|
graffitis.value[graffitis.value.length - 1].y = Math.min(startY, endY);
|
|
|
graffitis.value[graffitis.value.length - 1].height = Math.abs(endY - startY);
|
|
|
}
|
|
|
// 隐藏涂鸦
|
|
|
const hideOrShowGraffitiFlag = ref(true);
|
|
|
function hideOrShowGraffiti(value) {
|
|
|
hideOrShowGraffitiFlag.value = value;
|
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
|
// 鼠标聚焦
|
|
|
function mouseenter(rect, type) {
|
|
|
if (graffitiFlag.value) {
|
|
|
// 鼠标聚焦状态
|
|
|
if (rect.status != 'edit') {
|
|
|
rect.status = 'mouse';
|
|
|
document.body.style.cursor = 'pointer';
|
|
|
}
|
|
|
// 编辑状态
|
|
|
if (rect.status == 'edit') {
|
|
|
if (type == 'top' || type == 'bottom') {
|
|
|
document.body.style.cursor = 'ns-resize';
|
|
|
}
|
|
|
if (type == 'left' || type == 'right') {
|
|
|
document.body.style.cursor = 'ew-resize';
|
|
|
}
|
|
|
if (type == 'leftTop' || type == 'rightBottom') {
|
|
|
document.body.style.cursor = 'nwse-resize';
|
|
|
}
|
|
|
if (type == 'leftBottom' || type == 'rightTop') {
|
|
|
document.body.style.cursor = 'nesw-resize';
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
// 鼠标离开
|
|
|
function mouseleave(rect) {
|
|
|
if (graffitiFlag.value) {
|
|
|
if (rect.status == 'mouse' || rect.status == 'edit') {
|
|
|
if (rect.status == 'mouse') {
|
|
|
rect.status = 'success';
|
|
|
}
|
|
|
if (rect.status == 'edit') {
|
|
|
document.body.style.cursor = 'crosshair';
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
// 编辑状态下的鼠标按下
|
|
|
const mouseEditType = ref('');
|
|
|
function funMouseDownEdit(e, index, type) {
|
|
|
if (graffitiFlag.value) {
|
|
|
// 获取相对于容器的坐标
|
|
|
graffitisClone.value = cloneDeep(graffitis.value);
|
|
|
const rect = mouseCanvasRef.value.getBoundingClientRect();
|
|
|
startX = e.x - rect.x;
|
|
|
startY = e.y - rect.y;
|
|
|
isDragging.value = true;
|
|
|
nowGraffiti.value = index;
|
|
|
mouseEditType.value = type;
|
|
|
window.addEventListener('mousemove', funMouseMoveEdit);
|
|
|
window.addEventListener('mouseup', funMouseUpEdit);
|
|
|
}
|
|
|
}
|
|
|
// 编辑状态下的鼠标移动
|
|
|
function funMouseMoveEdit(e) {
|
|
|
if (graffitiFlag.value) {
|
|
|
const rect = mouseCanvasRef.value.getBoundingClientRect();
|
|
|
if (!isDragging.value) return;
|
|
|
endX = e.x - rect.x;
|
|
|
endY = e.y - rect.y;
|
|
|
if (endX < 0 && endY < 0) {
|
|
|
endX = startX;
|
|
|
endY = startY;
|
|
|
}
|
|
|
funSetMouseDataEdit();
|
|
|
}
|
|
|
}
|
|
|
// 编辑状态下的鼠标松开
|
|
|
function funMouseUpEdit(e) {
|
|
|
if (graffitiFlag.value) {
|
|
|
if (!isDragging.value) return;
|
|
|
const rect = mouseCanvasRef.value.getBoundingClientRect();
|
|
|
endX = e.x - rect.x;
|
|
|
endY = e.y - rect.y;
|
|
|
if (endX < 0 && endY < 0) {
|
|
|
endX = startX;
|
|
|
endY = startY;
|
|
|
}
|
|
|
isDragging.value = false;
|
|
|
if (e.x > rect.right || e.y > rect.bottom) {
|
|
|
graffitis.value[nowGraffiti.value] = graffitisClone.value[nowGraffiti.value];
|
|
|
} else {
|
|
|
funSetMouseDataEdit();
|
|
|
}
|
|
|
window.removeEventListener('mousemove', funMouseMoveEdit);
|
|
|
window.removeEventListener('mouseup', funMouseUpEdit);
|
|
|
}
|
|
|
}
|
|
|
// 编辑状态下的数据
|
|
|
function funSetMouseDataEdit() {
|
|
|
if (['top', 'leftTop', 'rightTop'].includes(mouseEditType.value)) {
|
|
|
graffitis.value[nowGraffiti.value].height =
|
|
|
graffitis.value[nowGraffiti.value].height + graffitis.value[nowGraffiti.value].y - endY;
|
|
|
graffitis.value[nowGraffiti.value].y = endY;
|
|
|
}
|
|
|
if (['bottom', 'leftBottom', 'rightBottom'].includes(mouseEditType.value)) {
|
|
|
graffitis.value[nowGraffiti.value].height = endY - graffitis.value[nowGraffiti.value].y;
|
|
|
}
|
|
|
if (['left', 'leftTop', 'leftBottom'].includes(mouseEditType.value)) {
|
|
|
graffitis.value[nowGraffiti.value].width =
|
|
|
graffitis.value[nowGraffiti.value].width + graffitis.value[nowGraffiti.value].x - endX;
|
|
|
graffitis.value[nowGraffiti.value].x = endX;
|
|
|
}
|
|
|
if (['right', 'rightTop', 'rightBottom'].includes(mouseEditType.value)) {
|
|
|
graffitis.value[nowGraffiti.value].width = endX - graffitis.value[nowGraffiti.value].x;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 添加键盘事件监听器
|
|
|
const addEventListener = () => {
|
|
|
window.addEventListener('keydown', handleKeydown);
|
|
|
};
|
|
|
// 移除键盘事件监听器
|
|
|
const removeEventListener = () => {
|
|
|
window.removeEventListener('keydown', handleKeydown);
|
|
|
};
|
|
|
// 处理按键按下事件
|
|
|
const handleKeydown = (event: KeyboardEvent) => {
|
|
|
if (event.code === 'Escape' && graffitiFlag.value) {
|
|
|
setGraffiti();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 在组件挂载时添加监听器
|
|
|
onMounted(() => {
|
|
|
addEventListener();
|
|
|
});
|
|
|
// 在组件卸载时移除监听器
|
|
|
onBeforeUnmount(() => {
|
|
|
removeEventListener();
|
|
|
});
|
|
|
</script>
|
|
|
<style lang="less" scoped>
|
|
|
.imageInfo {
|
|
|
// 页面不能被选中
|
|
|
-webkit-user-select: none; /* Safari */
|
|
|
-moz-user-select: none; /* Firefox */
|
|
|
-ms-user-select: none; /* IE/Edge */
|
|
|
user-select: none;
|
|
|
|
|
|
position: relative;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
background: #000000;
|
|
|
|
|
|
// 图片部分
|
|
|
.imageDiv {
|
|
|
position: relative;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
width: 100%;
|
|
|
height: calc(100% - 120px);
|
|
|
background: #101010;
|
|
|
|
|
|
// 云台偏航角查看图片
|
|
|
.rimbalGawDegreeButton {
|
|
|
position: absolute;
|
|
|
right: 25px;
|
|
|
bottom: 12%;
|
|
|
z-index: 200;
|
|
|
background: #ffffff;
|
|
|
border-radius: 5px;
|
|
|
width: 40px;
|
|
|
height: 40px;
|
|
|
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
}
|
|
|
|
|
|
// 全屏
|
|
|
.expandButton {
|
|
|
position: absolute;
|
|
|
right: 25px;
|
|
|
bottom: 5%;
|
|
|
z-index: 200;
|
|
|
background: #ffffff;
|
|
|
border-radius: 5px;
|
|
|
width: 40px;
|
|
|
height: 40px;
|
|
|
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 底部按钮和图片列表
|
|
|
.bottomDiv {
|
|
|
width: 100%;
|
|
|
height: 120px;
|
|
|
background: #1c1c1c;
|
|
|
display: block;
|
|
|
display: flex;
|
|
|
flex-wrap: wrap;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
|
|
|
// 按钮列表
|
|
|
.buttonList {
|
|
|
position: relative;
|
|
|
display: inline-flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
width: 100%;
|
|
|
height: 40px;
|
|
|
|
|
|
.button {
|
|
|
position: relative;
|
|
|
padding-left: 10px;
|
|
|
padding-right: 10px;
|
|
|
margin-left: 6px;
|
|
|
margin-right: 6px;
|
|
|
color: #ffffff;
|
|
|
font-size: 24px;
|
|
|
}
|
|
|
|
|
|
.button2 {
|
|
|
padding-top: 3px;
|
|
|
padding-left: 10px;
|
|
|
padding-right: 10px;
|
|
|
margin-left: 6px;
|
|
|
margin-right: 6px;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
}
|
|
|
}
|
|
|
// 图片选择列表
|
|
|
.imageChooseList {
|
|
|
display: inline-flex;
|
|
|
align-items: center;
|
|
|
// justify-content: center;
|
|
|
overflow-x: auto;
|
|
|
white-space: nowrap;
|
|
|
width: 80%;
|
|
|
height: 70px;
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
.bottom_div {
|
|
|
border-radius: 5px;
|
|
|
margin-left: 10px;
|
|
|
margin-right: 10px;
|
|
|
}
|
|
|
|
|
|
.bottom_div_choose {
|
|
|
outline: 3px solid #1088f2;
|
|
|
border-radius: 5px;
|
|
|
margin-left: 10px;
|
|
|
margin-right: 10px;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 强制滚动条一直显示(Chrome 等 Webkit 浏览器) */
|
|
|
.imageChooseList::-webkit-scrollbar {
|
|
|
display: block;
|
|
|
height: 4px;
|
|
|
}
|
|
|
|
|
|
/* Firefox */
|
|
|
.imageChooseList {
|
|
|
scrollbar-width: auto;
|
|
|
scrollbar-color: #888 #1c1c1c;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 标题
|
|
|
.titleDiv {
|
|
|
position: absolute;
|
|
|
top: 1%;
|
|
|
left: 20px;
|
|
|
height: 80px;
|
|
|
width: 80%;
|
|
|
// pointer-events: none;
|
|
|
z-index: 200;
|
|
|
|
|
|
.titleName {
|
|
|
font-size: 20px;
|
|
|
font-weight: bold;
|
|
|
text-decoration: underline;
|
|
|
text-decoration-color: white;
|
|
|
color: #ffffff;
|
|
|
}
|
|
|
.titleTime {
|
|
|
margin-top: 5px;
|
|
|
display: flex;
|
|
|
span {
|
|
|
font-size: 16px;
|
|
|
color: #ffffff;
|
|
|
}
|
|
|
}
|
|
|
.titleCoordinate {
|
|
|
margin-top: 5px;
|
|
|
span {
|
|
|
font-size: 16px;
|
|
|
color: #ffffff;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
// 标签
|
|
|
.tagsDiv {
|
|
|
position: absolute;
|
|
|
top: 11%;
|
|
|
left: 20px;
|
|
|
height: 20px;
|
|
|
width: 80%;
|
|
|
z-index: 200;
|
|
|
display: flex;
|
|
|
flex-wrap: wrap;
|
|
|
align-items: center;
|
|
|
justify-content: flex-start;
|
|
|
}
|
|
|
|
|
|
// 关闭按钮
|
|
|
.closeButton {
|
|
|
position: absolute;
|
|
|
top: 2%;
|
|
|
right: 20px;
|
|
|
z-index: 200;
|
|
|
}
|
|
|
|
|
|
// 上一张、下一张
|
|
|
.leftButton {
|
|
|
position: absolute;
|
|
|
left: 30px;
|
|
|
top: 45%;
|
|
|
z-index: 200;
|
|
|
background: #9c9c9c55;
|
|
|
border-radius: 70px;
|
|
|
width: 70px;
|
|
|
height: 70px;
|
|
|
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
}
|
|
|
.rightButton {
|
|
|
position: absolute;
|
|
|
right: 30px;
|
|
|
top: 45%;
|
|
|
z-index: 200;
|
|
|
background: #9c9c9c55;
|
|
|
border-radius: 70px;
|
|
|
width: 70px;
|
|
|
height: 70px;
|
|
|
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
}
|
|
|
|
|
|
// 涂鸦颜色选择-提示
|
|
|
.graffitiButton {
|
|
|
background: #ffffff;
|
|
|
position: absolute;
|
|
|
right: 25px;
|
|
|
top: 15%;
|
|
|
z-index: 200;
|
|
|
width: 30px;
|
|
|
height: 30px;
|
|
|
border-radius: 3px;
|
|
|
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
}
|
|
|
.graffitiButton_choose {
|
|
|
background: linear-gradient(to bottom left, #2b85e4 10px, transparent 1px), #ffffff;
|
|
|
background-size:
|
|
|
100% 100%,
|
|
|
auto;
|
|
|
position: absolute;
|
|
|
right: 25px;
|
|
|
top: 15%;
|
|
|
z-index: 200;
|
|
|
width: 30px;
|
|
|
height: 30px;
|
|
|
border-radius: 3px;
|
|
|
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
|
|
|
outline: 2px solid #2b85e4;
|
|
|
}
|
|
|
// 涂鸦颜色选择-提示框
|
|
|
.popoverClass {
|
|
|
width: 18px;
|
|
|
height: 18px;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
border-radius: 3px;
|
|
|
}
|
|
|
|
|
|
// 隐藏or显示涂鸦和标签
|
|
|
.showTextboxClass {
|
|
|
position: absolute;
|
|
|
right: 25px;
|
|
|
top: 20%;
|
|
|
width: 30px;
|
|
|
height: 30px;
|
|
|
z-index: 200;
|
|
|
display: block;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
|
|
|
.button {
|
|
|
border-radius: 3px;
|
|
|
position: relative;
|
|
|
color: #2d8cf0;
|
|
|
background: #ffffff;
|
|
|
font-size: 22px;
|
|
|
width: 30px;
|
|
|
height: 30px;
|
|
|
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 退出涂鸦
|
|
|
.escTip {
|
|
|
position: absolute;
|
|
|
left: 0%;
|
|
|
bottom: 120px;
|
|
|
width: 120px;
|
|
|
height: 40px;
|
|
|
background: #9c9c9c77;
|
|
|
border-radius: 5px;
|
|
|
z-index: 1001;
|
|
|
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: flex-start;
|
|
|
|
|
|
.whiteEsc {
|
|
|
height: 30px;
|
|
|
background: #ffffff;
|
|
|
font-size: 16px;
|
|
|
padding: 10px;
|
|
|
border-radius: 5px;
|
|
|
display: flex;
|
|
|
margin-left: 10px;
|
|
|
align-items: center;
|
|
|
}
|
|
|
|
|
|
.blackTip {
|
|
|
display: flex;
|
|
|
margin-left: 5px;
|
|
|
align-items: center;
|
|
|
color: #ffffff;
|
|
|
}
|
|
|
}
|
|
|
</style>
|