2026-05-09 10:34:51 +08:00

315 lines
7.9 KiB
Vue

<script setup lang="ts">
import homeWorkApi from '@/api/system/homeWork'
import { useRoute } from 'vue-router'
const route = useRoute()
const OSS_URL = import.meta.env.VITE_OSS_URL
const activeBg = `url(${OSS_URL}/urm/homeWork/homeWork_temporary_active_bg.svg)`
const nonactiveBg = `url(${OSS_URL}/urm/homeWork/homeWork_temporary_nonactive_bg.svg)`
const activeNav = ref({
name: '原图',
type: 0,
url: '',
})
const nav = ref([
{
name: '原图',
type: 0,
url: '',
},
])
const loading = ref(false)
const dragging = ref(false) // 是否处于拖拽状态
const imgArea = ref()
const img = ref()
const movableData = ref({
x: 0,
y: 0,
scale: 1,
})
const scaleData = ref(1) // 另外存一份放大倍率
const distance = ref({
startDistance: 0,
endDistance: 0,
})
function clickAnswerStatus(i: any) {
activeNav.value = i
movableData.value = {
x: 0,
y: 0,
scale: 1,
}
loading.value = true
setTimeout(() => {
onImageLoad()
}, 150)
}
// 图片加载
function onImageLoad() {
loading.value = false
}
// 放大
function tapEnlarge() {
if (movableData.value.scale < 2) {
movableData.value.scale += 0.1
}
}
// 缩小
function tapLessen() {
if (movableData.value.scale > 0.6) {
movableData.value.scale -= 0.1
}
}
function touchTwo(e: anyObj[], mode: 'startDistance' | 'endDistance') {
// 双指缩放
const one = {
x: e[0].pageX, // 第一根手指的横坐标
y: e[0].pageY, // 第一根手指的纵坐标
} // 第一根手指的横坐标
const two = {
x: e[1].pageX, // 第二根手指的横坐标
y: e[1].pageY, // 第二根手指的纵坐标
}
distance.value[mode] = getDistance(one, two)
}
function getDistance(start: anyObj, stop: anyObj) {
return Math.sqrt(
Math.pow(Math.abs(start.x - stop.x), 2) + Math.pow(Math.abs(start.y - stop.y), 2),
)
}
const startDrag = (event: anyObj) => {
if (event.touches?.length === 2) {
// 两个触点
touchTwo(event.touches, 'startDistance')
return
}
dragging.value = true
const x = (event.touches ? event.touches[0].pageX : event.pageX) - movableData.value.x
const y = (event.touches ? event.touches[0].pageY : event.pageY) - movableData.value.y
const move = (event: anyObj) => {
if (event.touches?.length === 2) {
// 两个触点
touchTwo(event.touches, 'endDistance')
const scale2 =
scaleData.value + distance.value.endDistance / distance.value.startDistance - 1.01 // 减去原本的1倍 0.01是防止小数计算误差
movableData.value.scale = scale2 > 2 ? 2 : scale2 < 0.5 ? 0.5 : scale2 // 最大2倍 最小0.5倍
return
}
if (dragging.value) {
movableData.value.x = (event.touches ? event.touches[0].pageX : event.pageX) - x
movableData.value.y = (event.touches ? event.touches[0].pageY : event.pageY) - y
}
}
const stopDrag = () => {
distance.value.startDistance = distance.value.endDistance = 0
scaleData.value = movableData.value.scale
dragging.value = false
document.removeEventListener('mousemove', move)
document.removeEventListener('touchmove', move)
document.removeEventListener('mouseup', stopDrag)
document.removeEventListener('touchend', stopDrag)
}
document.addEventListener('mousemove', move)
document.addEventListener('touchmove', move)
document.addEventListener('mouseup', stopDrag)
document.addEventListener('touchend', stopDrag)
}
// 获取详情
async function getTemporaryJobDetail() {
loading.value = true
try {
const { data } = await homeWorkApi.temporaryJobDetail(route.params.id)
if (data.data.status === 1) {
nav.value = [
{
name: '原图',
type: 0,
url: data.data.submitUrl,
},
{ name: '批改图', type: 1, url: data.data.markUrl },
]
} else {
nav.value = [
{
name: '原图',
type: 0,
url: data.data.submitUrl,
},
]
}
activeNav.value = nav.value[0]
loading.value = false
} catch (err) {
console.log(err)
loading.value = false
}
}
onUnmounted(() => {
document.removeEventListener('mousemove', () => {})
document.removeEventListener('mouseup', () => {})
document.removeEventListener('touchmove', () => {})
document.removeEventListener('touchend', () => {})
})
onActivated(() => {
getTemporaryJobDetail()
movableData.value = {
x: 0,
y: 0,
scale: 1,
}
})
</script>
<template>
<div class="sinle_temporary">
<div class="top">
<BackBar />
</div>
<div class="main">
<div
class="main_answer"
:style="{
'background-image': `url(${OSS_URL}/urm/homeWork/homeWork_temporary_single_bg.svg)`,
}"
>
<div class="nav">
<div
v-for="i in nav"
:key="i.type"
class="nav_item pointer"
:style="{
'background-image': i.type === activeNav.type ? activeBg : nonactiveBg,
color: i.type === activeNav.type ? '' : '#666',
}"
@click="clickAnswerStatus(i)"
>
{{ i.name }}
</div>
</div>
<Empty v-if="loading" class="empty" type="loading" content=""></Empty>
<div v-else class="area">
<div
ref="imgArea"
:style="{
transform: `translate(${movableData.x}px, ${movableData.y}px) scale(${movableData.scale})`,
}"
class="area-content"
@mousedown.prevent="startDrag"
@touchstart.prevent="startDrag"
>
<img ref="img" :src="activeNav.url" alt="" @load="onImageLoad" />
</div>
<div class="tool">
<Icon
name="homeWork_temporary_fangda"
width="48"
class="pointer tool_fangda"
@click="tapEnlarge"
></Icon>
<Icon
name="homeWork_temporary_suoxiao"
width="48"
class="pointer"
@click="tapLessen"
></Icon>
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.sinle_temporary {
@include main_bg;
height: 100vh;
overflow: hidden;
box-sizing: border-box;
.top {
padding: 3vh 64px 0;
display: flex;
justify-content: space-between;
align-items: flex-end;
}
.main {
padding: 0 64px;
width: 100%;
height: 100%;
display: flex;
&_answer {
position: relative;
width: 1792px;
height: 85.25vh;
background-size: 100%;
.nav {
position: absolute;
top: -4.75vh;
width: calc(100% - 394px);
margin-left: 197px;
display: flex;
justify-content: center;
font-family: $font-special;
font-size: 3.33vh;
font-weight: 400;
line-height: 5vh;
text-align: center;
&_item {
width: 300px;
height: 7.67vh;
line-height: 7.67vh;
border-radius: 3.33vh 3.33vh 0 0;
background-size: 100%;
background-repeat: no-repeat;
&:first-child {
margin-right: 24px;
}
}
}
.area {
position: absolute;
top: 9.58vh;
left: 48px;
display: flex;
align-items: center;
justify-content: center;
width: calc(100% - 96px);
height: 71.92vh;
overflow: hidden;
.tool {
position: absolute;
bottom: 2vh;
display: flex;
align-items: center;
justify-content: center;
width: 188px;
height: 5.33vh;
border-radius: 4.5vh;
background: rgba(0, 0, 0, 0.45);
&_fangda {
margin-right: 32px;
}
}
.area-content {
width: 825px;
height: 71.92vh;
}
img {
width: 100%;
max-height: 100%;
object-fit: contain;
cursor: grab;
}
}
}
}
}
</style>