第一版本
This commit is contained in:
parent
1c69d38cee
commit
4b9f936347
Binary file not shown.
Binary file not shown.
@ -184,8 +184,8 @@ const displayMainValue = computed(() => {
|
|||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.report-metric-card {
|
.report-metric-card {
|
||||||
width: 158px;
|
width: 168px;
|
||||||
height: 158px;
|
height: 168px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
|||||||
4
src/types/silly-datetime.d.ts
vendored
Normal file
4
src/types/silly-datetime.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
declare module 'silly-datetime' {
|
||||||
|
export function format(date: Date | number | string, pattern?: string): string;
|
||||||
|
}
|
||||||
|
|
||||||
@ -13,7 +13,6 @@
|
|||||||
:src="tipsVideoSrc"
|
:src="tipsVideoSrc"
|
||||||
muted
|
muted
|
||||||
playsinline
|
playsinline
|
||||||
autoplay
|
|
||||||
preload="auto"
|
preload="auto"
|
||||||
@ended="onTipsEnded"
|
@ended="onTipsEnded"
|
||||||
@timeupdate="onTipsTimeUpdate"
|
@timeupdate="onTipsTimeUpdate"
|
||||||
@ -63,7 +62,7 @@ import { Capacitor } from '@capacitor/core';
|
|||||||
import { StatusBar, Style } from '@capacitor/status-bar';
|
import { StatusBar, Style } from '@capacitor/status-bar';
|
||||||
import { CameraPreview } from '@capgo/camera-preview';
|
import { CameraPreview } from '@capgo/camera-preview';
|
||||||
import { Circle as VanCircle } from 'vant';
|
import { Circle as VanCircle } from 'vant';
|
||||||
import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
|
import { computed, nextTick, onBeforeUnmount, onMounted, ref } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import tips2Url from '@/assets/step2/2.mp4?url';
|
import tips2Url from '@/assets/step2/2.mp4?url';
|
||||||
|
|
||||||
@ -81,7 +80,8 @@ const PREVIEW_ASPECT = 4 / 3; // 4:3,不裁剪;想更宽可改 16/9
|
|||||||
const RETICLE_CENTER_Y = 0.3;
|
const RETICLE_CENTER_Y = 0.3;
|
||||||
|
|
||||||
const tipsVideoEl = ref<HTMLVideoElement | null>(null);
|
const tipsVideoEl = ref<HTMLVideoElement | null>(null);
|
||||||
const showTipsVideo = ref(true);
|
// 相机未授权/未启动时不要播放提示视频
|
||||||
|
const showTipsVideo = ref(false);
|
||||||
const tipsVideoSrc = computed(() => tips2Url);
|
const tipsVideoSrc = computed(() => tips2Url);
|
||||||
let navigatingToStep3 = false;
|
let navigatingToStep3 = false;
|
||||||
function onTipsTimeUpdate() {
|
function onTipsTimeUpdate() {
|
||||||
@ -119,7 +119,7 @@ function onTipsEnded() {
|
|||||||
// 进度到 100%:停止录制拿到 videoFilePath,并跳转 step3
|
// 进度到 100%:停止录制拿到 videoFilePath,并跳转 step3
|
||||||
if (!navigatingToStep3) {
|
if (!navigatingToStep3) {
|
||||||
navigatingToStep3 = true;
|
navigatingToStep3 = true;
|
||||||
setTimeout(() => {
|
// setTimeout(() => {
|
||||||
queueMicrotask(async () => {
|
queueMicrotask(async () => {
|
||||||
try {
|
try {
|
||||||
await teardownRecorder(); // 内部会写 sessionStorage['step2_video_path']
|
await teardownRecorder(); // 内部会写 sessionStorage['step2_video_path']
|
||||||
@ -127,7 +127,7 @@ function onTipsEnded() {
|
|||||||
router.push('/step3');
|
router.push('/step3');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, 5000);
|
// }, 2000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,6 +247,7 @@ onMounted(async () => {
|
|||||||
document.documentElement.classList.add('step2-camera-active');
|
document.documentElement.classList.add('step2-camera-active');
|
||||||
progress.value = 0;
|
progress.value = 0;
|
||||||
currentRate.value = 0;
|
currentRate.value = 0;
|
||||||
|
showTipsVideo.value = false;
|
||||||
|
|
||||||
if (!Capacitor.isNativePlatform()) {
|
if (!Capacitor.isNativePlatform()) {
|
||||||
statusText.value = '请在真机或模拟器(Capacitor)中打开以使用前置录像';
|
statusText.value = '请在真机或模拟器(Capacitor)中打开以使用前置录像';
|
||||||
@ -267,11 +268,23 @@ onMounted(async () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await setupNativeRecorder();
|
await setupNativeRecorder();
|
||||||
// 相机正常启动后再播放提示视频
|
// 相机正常启动后再显示/播放提示视频
|
||||||
|
showTipsVideo.value = true;
|
||||||
|
await nextTick();
|
||||||
tryPlayTips();
|
tryPlayTips();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
statusText.value = '无法启动相机或麦克风,请检查系统权限';
|
statusText.value = '无法启动相机或麦克风,请检查系统权限';
|
||||||
|
showTipsVideo.value = false;
|
||||||
|
const el = tipsVideoEl.value;
|
||||||
|
if (el) {
|
||||||
|
try {
|
||||||
|
el.pause();
|
||||||
|
el.currentTime = 0;
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
import { Capacitor } from '@capacitor/core';
|
import { Capacitor } from '@capacitor/core';
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { format } from 'silly-datetime';
|
|
||||||
const showHelp = ref(true);
|
const showHelp = ref(true);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const start = () => {
|
const start = () => {
|
||||||
@ -147,12 +147,40 @@ onMounted(async () => {
|
|||||||
// router.push('/step4');
|
// router.push('/step4');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const now =
|
||||||
|
typeof performance !== 'undefined' && typeof performance.now === 'function'
|
||||||
|
? () => performance.now()
|
||||||
|
: () => Date.now();
|
||||||
|
const t0 = now();
|
||||||
|
|
||||||
|
const tBlob0 = now();
|
||||||
const blob = await videoUrlToBlob(videoPath);
|
const blob = await videoUrlToBlob(videoPath);
|
||||||
|
const tBlob1 = now();
|
||||||
|
|
||||||
|
const tDataUrl0 = now();
|
||||||
const dataUrl = await blobToDataUrl(blob);
|
const dataUrl = await blobToDataUrl(blob);
|
||||||
|
const tDataUrl1 = now();
|
||||||
|
|
||||||
|
const tArk0 = now();
|
||||||
const result = await analyzeVideoWithArk(dataUrl);
|
const result = await analyzeVideoWithArk(dataUrl);
|
||||||
|
const tArk1 = now();
|
||||||
|
|
||||||
sessionStorage.setItem('step2_ark_result', JSON.stringify(result));
|
sessionStorage.setItem('step2_ark_result', JSON.stringify(result));
|
||||||
|
const tSave = now();
|
||||||
|
|
||||||
|
const timing = {
|
||||||
|
total_ms: Math.round(tSave - t0),
|
||||||
|
steps_ms: {
|
||||||
|
videoUrlToBlob: Math.round(tBlob1 - tBlob0),
|
||||||
|
blobToDataUrl: Math.round(tDataUrl1 - tDataUrl0),
|
||||||
|
analyzeVideoWithArk: Math.round(tArk1 - tArk0),
|
||||||
|
saveResult: Math.round(tSave - tArk1)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
sessionStorage.setItem('step3_timing', JSON.stringify(timing));
|
||||||
|
|
||||||
router.push('/step4');
|
router.push('/step4');
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
@ -161,7 +189,7 @@ onMounted(async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 拿到接口返回(成功/失败都算)再进入 step4
|
// 拿到接口返回(成功/失败都算)再进入 step4
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@ -233,6 +261,7 @@ onMounted(async () => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
|
||||||
.tips-icon {
|
.tips-icon {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
@ -250,6 +279,7 @@ onMounted(async () => {
|
|||||||
from {
|
from {
|
||||||
transform: rotate(0deg);
|
transform: rotate(0deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
to {
|
||||||
transform: rotate(360deg);
|
transform: rotate(360deg);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,12 +47,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="r" @click="router.replace('/')"><img src="@/assets/close.png" alt=""></div>
|
<div class="r" @click="router.replace('/')"><img src="@/assets/close.png" alt=""></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="main">
|
<div v-html="summaryText" class="summary-text"> </div>
|
||||||
|
<!-- <div class="main">
|
||||||
<img class="tips" src="@/assets/step5/tips.png" alt="">
|
<img class="tips" src="@/assets/step5/tips.png" alt="">
|
||||||
<img class="ip" src="@/assets/step1/ip.png" alt="">
|
<img class="ip" src="@/assets/step1/ip.png" alt="">
|
||||||
|
|
||||||
</div>
|
</div> -->
|
||||||
<div class="info">
|
<!-- <div class="info">
|
||||||
<div class="title">以下是你的心理压力指数MSI指标</div>
|
<div class="title">以下是你的心理压力指数MSI指标</div>
|
||||||
<div class="msi-card">
|
<div class="msi-card">
|
||||||
<div class="msi-score">
|
<div class="msi-score">
|
||||||
@ -84,7 +85,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<p> 适度参与户外活动(如散步、慢跑、瑜伽),每周 2-3 次,每次 30 分钟以上,通过运动释放负面情绪,提升身心愉悦感。</p>
|
<p> 适度参与户外活动(如散步、慢跑、瑜伽),每周 2-3 次,每次 30 分钟以上,通过运动释放负面情绪,提升身心愉悦感。</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
@ -139,7 +140,7 @@ if (arkResult) {
|
|||||||
// console.log(summaryText.value); //文本
|
// console.log(summaryText.value); //文本
|
||||||
data.value = JSON.parse(result?.output[1]?.content[0]?.text);
|
data.value = JSON.parse(result?.output[1]?.content[0]?.text);
|
||||||
creatTime.value = format(new Date(result.created_at ? result.created_at * 1000 : new Date()), 'YYYY-MM-DD HH:mm:ss')
|
creatTime.value = format(new Date(result.created_at ? result.created_at * 1000 : new Date()), 'YYYY-MM-DD HH:mm:ss')
|
||||||
|
summaryText.value = data.value?.brief_report?.summary_text;
|
||||||
list1.value = [
|
list1.value = [
|
||||||
{
|
{
|
||||||
type: 4 as const,
|
type: 4 as const,
|
||||||
@ -363,7 +364,7 @@ if (arkResult) {
|
|||||||
|
|
||||||
.l {
|
.l {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 155px;
|
width: 168px;
|
||||||
top: 125px;
|
top: 125px;
|
||||||
left: -222px;
|
left: -222px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -374,7 +375,7 @@ if (arkResult) {
|
|||||||
|
|
||||||
.r {
|
.r {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 155px;
|
width: 168px;
|
||||||
top: 125px;
|
top: 125px;
|
||||||
right: -222px;
|
right: -222px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -399,9 +400,6 @@ if (arkResult) {
|
|||||||
padding: 0 24px;
|
padding: 0 24px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 详情页(原 step5)的样式直接复用 */
|
/* 详情页(原 step5)的样式直接复用 */
|
||||||
@ -409,7 +407,7 @@ if (arkResult) {
|
|||||||
padding-top: 52px;
|
padding-top: 52px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
// justify-content: space-between;
|
||||||
|
|
||||||
.top {
|
.top {
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -583,6 +581,9 @@ if (arkResult) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.summary-text{
|
||||||
|
padding: 50px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 内部切换动画:上下滑 + 淡入淡出(支持正/反向) */
|
/* 内部切换动画:上下滑 + 淡入淡出(支持正/反向) */
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user