forked from zhongyidian/super_video
feat: 完善课程引导与实战评价体验
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
6f8252472f
commit
1f8723aabd
122 files changed
+2595
-1325
No files matched your search
@@ -35,7 +35,7 @@ const {
|
||||
getTransform,
|
||||
currentOffsetX,
|
||||
currentOffsetY,
|
||||
handleWheel
|
||||
handleWheel,
|
||||
} = useViewfinderA()
|
||||
|
||||
// 刻度盘配置常量
|
||||
@@ -88,7 +88,7 @@ const dialTicks = computed<DialTick[]>(() => {
|
||||
angle,
|
||||
isMajor,
|
||||
isInteger,
|
||||
label: isInteger ? zoom + 'x' : ''
|
||||
label: isInteger ? zoom + 'x' : '',
|
||||
})
|
||||
}
|
||||
return ticks
|
||||
@@ -116,7 +116,7 @@ const capturePhoto = async () => {
|
||||
if (isLoading.value) return
|
||||
|
||||
isCapturing.value = true
|
||||
await new Promise(resolve => setTimeout(resolve, FLASH_DURATION))
|
||||
await new Promise((resolve) => setTimeout(resolve, FLASH_DURATION))
|
||||
|
||||
await capture({
|
||||
width: CANVAS_WIDTH,
|
||||
@@ -124,7 +124,7 @@ const capturePhoto = async () => {
|
||||
scale: CANVAS_SCALE,
|
||||
delay: UI_UPDATE_DELAY,
|
||||
resultDelay: RESULT_DISPLAY_DELAY,
|
||||
onDraw: ctx => {
|
||||
onDraw: (ctx) => {
|
||||
if (!photoImage.value) {
|
||||
throw new Error('Photo image not found')
|
||||
}
|
||||
@@ -142,12 +142,12 @@ const capturePhoto = async () => {
|
||||
-CANVAS_WIDTH / 2,
|
||||
-CANVAS_HEIGHT / 2,
|
||||
CANVAS_WIDTH,
|
||||
CANVAS_HEIGHT
|
||||
CANVAS_HEIGHT,
|
||||
)
|
||||
},
|
||||
onComplete: () => {
|
||||
isCapturing.value = false
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -156,18 +156,31 @@ const capturePhoto = async () => {
|
||||
<div class="w-full h-full">
|
||||
<div
|
||||
class="relative w-full h-full bg-cover bg-center bg-no-repeat shooting-bg"
|
||||
:style="{ backgroundImage: getBackgroundImage('interview/shooting/操场-模糊.png') }"
|
||||
:style="{
|
||||
backgroundImage: getBackgroundImage('interview/shooting/操场-模糊.png'),
|
||||
}"
|
||||
>
|
||||
<ImgButton
|
||||
image="interview/shooting/操场-侧边标题.png"
|
||||
class="title-button absolute left-0"
|
||||
/>
|
||||
<ImgButton image="shooting/返回.png" class="back-button absolute right-0" @click="back" />
|
||||
<ImgButton
|
||||
image="shooting/返回.png"
|
||||
class="back-button absolute right-0"
|
||||
@click="back"
|
||||
/>
|
||||
|
||||
<StartOverlay v-if="!start" @start="start = true" />
|
||||
<StartOverlay
|
||||
scene="a"
|
||||
v-if="!start"
|
||||
@start="start = true"
|
||||
/>
|
||||
|
||||
<!-- 手机拍照界面 -->
|
||||
<div class="absolute bottom-0 w-full h-[766px]" v-else>
|
||||
<div
|
||||
class="absolute bottom-0 w-full h-[766px]"
|
||||
v-else
|
||||
>
|
||||
<img
|
||||
class="phone-frame absolute w-full h-[766px] z-10 pointer-events-none"
|
||||
src="@/assets/images/shooting/shoot.png"
|
||||
@@ -186,7 +199,7 @@ const capturePhoto = async () => {
|
||||
:class="{
|
||||
'transition-transform duration-300': !isDragging,
|
||||
'cursor-grab': !isDragging,
|
||||
'cursor-grabbing': isDragging
|
||||
'cursor-grabbing': isDragging,
|
||||
}"
|
||||
:style="{ transform: getTransform() }"
|
||||
src="@/assets/images/interview/shooting/操场-清晰.png"
|
||||
@@ -213,7 +226,9 @@ const capturePhoto = async () => {
|
||||
|
||||
<div
|
||||
class="shooting-decor relative pointer-events-none top-[19.2%] left-[48.3%] -translate-x-1/2 w-[871px] h-[420px] bg-cover bg-center bg-no-repeat"
|
||||
:style="{ backgroundImage: getBackgroundImage('shooting/拍摄装饰.png') }"
|
||||
:style="{
|
||||
backgroundImage: getBackgroundImage('shooting/拍摄装饰.png'),
|
||||
}"
|
||||
>
|
||||
<!-- 仿苹果半圆盘缩放控件 -->
|
||||
<div
|
||||
@@ -237,13 +252,17 @@ const capturePhoto = async () => {
|
||||
<!-- 圆心在容器右侧外部,形成左侧弧形 -->
|
||||
<div
|
||||
class="dial-wheel absolute top-1/2 right-[-480px] w-[600px] h-[600px] rounded-full bg-black/30 backdrop-blur-md border-[5px] border-white/20 transition-transform duration-100 ease-out origin-center cursor-grab active:cursor-grabbing"
|
||||
:style="{ transform: `translateY(-50%) rotate(${dialRotation}deg)` }"
|
||||
:style="{
|
||||
transform: `translateY(-50%) rotate(${dialRotation}deg)`,
|
||||
}"
|
||||
>
|
||||
<div
|
||||
v-for="tick in dialTicks"
|
||||
:key="tick.zoom"
|
||||
class="absolute top-1/2 left-0 w-full h-0 flex justify-start items-center origin-center pointer-events-auto"
|
||||
:style="{ transform: `translate(0, -50%) rotate(${tick.angle}deg)` }"
|
||||
:style="{
|
||||
transform: `translate(0, -50%) rotate(${tick.angle}deg)`,
|
||||
}"
|
||||
@click.stop="setZoom(tick.zoom)"
|
||||
>
|
||||
<!-- 刻度线本体 (位于圆盘左边缘) -->
|
||||
@@ -252,17 +271,21 @@ const capturePhoto = async () => {
|
||||
:class="{
|
||||
'w-10 h-1 opacity-90': tick.isInteger,
|
||||
'w-6 h-0.5 opacity-60': !tick.isInteger && tick.isMajor,
|
||||
'w-3 h-[1px] opacity-40': !tick.isMajor
|
||||
'w-3 h-[1px] opacity-40': !tick.isMajor,
|
||||
}"
|
||||
></div>
|
||||
<!-- 刻度文字 -->
|
||||
<div
|
||||
v-if="tick.isInteger"
|
||||
class="absolute left-[52px] text-white/90 font-bold text-lg drop-shadow-md"
|
||||
:style="{ transform: `rotate(${-tick.angle - dialRotation}deg)` }"
|
||||
:style="{
|
||||
transform: `rotate(${-tick.angle - dialRotation}deg)`,
|
||||
}"
|
||||
>
|
||||
<span
|
||||
:class="{ 'text-yellow-400 scale-110': currentZoom === tick.zoom }"
|
||||
:class="{
|
||||
'text-yellow-400 scale-110': currentZoom === tick.zoom,
|
||||
}"
|
||||
class="block transition-all duration-200"
|
||||
>
|
||||
{{ tick.label }}
|
||||
@@ -282,22 +305,39 @@ const capturePhoto = async () => {
|
||||
</div>
|
||||
|
||||
<!-- 结果弹窗 -->
|
||||
<Overlay :visible="showModal" @close="handleModalClose">
|
||||
<div class="relative w-[1000px] h-[600px] flex items-center justify-center">
|
||||
<Overlay
|
||||
:visible="showModal"
|
||||
@close="handleModalClose"
|
||||
>
|
||||
<div
|
||||
class="relative w-[1000px] h-[600px] flex items-center justify-center"
|
||||
>
|
||||
<!-- 截图内容 -->
|
||||
<div v-if="capturedImageUrl" class="bg-white p-2 rounded-md -rotate-6">
|
||||
<img :src="capturedImageUrl" alt="拍摄结果" />
|
||||
<div
|
||||
v-if="capturedImageUrl"
|
||||
class="bg-white p-2 rounded-md -rotate-6"
|
||||
>
|
||||
<img
|
||||
:src="capturedImageUrl"
|
||||
alt="拍摄结果"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="absolute bottom-1/2 -right-1/3 translate-y-1/2">
|
||||
<ImgButton image="shooting/按钮-前往下一个取景地" @click="handleFinish" />
|
||||
<ImgButton
|
||||
image="shooting/按钮-前往下一个取景地"
|
||||
@click="handleFinish"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Overlay>
|
||||
</div>
|
||||
|
||||
<LoadingOverlay :visible="isLoading" text="正在出片中..." />
|
||||
<LoadingOverlay
|
||||
:visible="isLoading"
|
||||
text="正在出片中..."
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -321,7 +361,19 @@ const capturePhoto = async () => {
|
||||
}
|
||||
|
||||
.mask-gradient {
|
||||
mask-image: linear-gradient(to bottom, transparent, black 15%, black 85%, transparent);
|
||||
-webkit-mask-image: linear-gradient(to bottom, transparent, black 15%, black 85%, transparent);
|
||||
mask-image: linear-gradient(
|
||||
to bottom,
|
||||
transparent,
|
||||
black 15%,
|
||||
black 85%,
|
||||
transparent
|
||||
);
|
||||
-webkit-mask-image: linear-gradient(
|
||||
to bottom,
|
||||
transparent,
|
||||
black 15%,
|
||||
black 85%,
|
||||
transparent
|
||||
);
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user