Files
xk-doctor-wx/components/ai-generation-loading/ai-generation-loading.vue

301 lines
6.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<!--
AI 生成专属 Loading对齐 PC PrescriptionLoading 视觉
仅用于真正调用 AI 生成接口时历史加载请用普通文案/u-loading
type: prescription=药丸 / medical_record=病历本
-->
<view class="ai-load">
<view class="ai-load__stage">
<view class="ai-load__ring" />
<view class="ai-load__arc" />
<view class="ai-load__cross ai-load__cross--1" />
<view class="ai-load__cross ai-load__cross--2" />
<view class="ai-load__cross ai-load__cross--3" />
<!-- 中心图标处方药丸 -->
<view v-if="type !== 'medical_record'" class="ai-load__pill">
<view class="ai-load__pill-left" />
<view class="ai-load__pill-right" />
</view>
<!-- 中心图标病历本 -->
<view v-else class="ai-load__mr">
<view class="ai-load__mr-spine" />
<view class="ai-load__mr-title" />
<view class="ai-load__mr-line" />
<view class="ai-load__mr-line" />
<view class="ai-load__mr-line" />
</view>
</view>
<view class="ai-load__text-row">
<text class="ai-load__text">{{ displayText }}</text>
<view class="ai-load__dots">
<view class="ai-load__dot ai-load__dot--1" />
<view class="ai-load__dot ai-load__dot--2" />
<view class="ai-load__dot ai-load__dot--3" />
</view>
</view>
</view>
</template>
<script>
/**
* AI 生成 Loading
* 用 CSS 动画贴近 PC 端 canvas 效果,避免小程序 canvas 生命周期问题
*/
export default {
name: 'AiGenerationLoading',
props: {
/** prescription | medical_record */
type: {
type: String,
default: 'prescription',
},
/** 底部文案;空则按 type 给默认 */
text: {
type: String,
default: '',
},
},
computed: {
displayText() {
const t = String(this.text || '').trim()
if (t) return t
return this.type === 'medical_record' ? 'AI正在生成病历' : 'AI正在生成处方'
},
},
}
</script>
<style scoped>
.ai-load {
width: 100%;
min-height: 420rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 24rpx 0 40rpx;
box-sizing: border-box;
}
.ai-load__stage {
position: relative;
width: 280rpx;
height: 280rpx;
}
.ai-load__ring {
position: absolute;
left: 50%;
top: 50%;
width: 220rpx;
height: 220rpx;
margin-left: -110rpx;
margin-top: -110rpx;
border-radius: 50%;
border: 2rpx dashed rgba(180, 195, 200, 0.55);
box-sizing: border-box;
animation: ai-load-spin 12s linear infinite;
}
.ai-load__arc {
position: absolute;
left: 50%;
top: 50%;
width: 220rpx;
height: 220rpx;
margin-left: -110rpx;
margin-top: -110rpx;
border-radius: 50%;
border: 6rpx solid transparent;
border-top-color: #3dd6d0;
border-right-color: #3dd6d0;
box-sizing: border-box;
animation: ai-load-spin 1.4s linear infinite;
}
.ai-load__cross {
position: absolute;
left: 50%;
top: 50%;
width: 16rpx;
height: 16rpx;
margin-left: -8rpx;
margin-top: -8rpx;
}
.ai-load__cross::before,
.ai-load__cross::after {
content: '';
position: absolute;
left: 50%;
top: 50%;
background: #3dd6d0;
border-radius: 4rpx;
}
.ai-load__cross::before {
width: 16rpx;
height: 4rpx;
margin-left: -8rpx;
margin-top: -2rpx;
}
.ai-load__cross::after {
width: 4rpx;
height: 16rpx;
margin-left: -2rpx;
margin-top: -8rpx;
}
.ai-load__cross--1 {
animation: ai-load-orbit 3.2s linear infinite;
}
.ai-load__cross--2 {
animation: ai-load-orbit 3.2s linear infinite;
animation-delay: -1.06s;
}
.ai-load__cross--3 {
animation: ai-load-orbit 3.2s linear infinite;
animation-delay: -2.13s;
}
.ai-load__pill {
position: absolute;
left: 50%;
top: 50%;
width: 140rpx;
height: 48rpx;
margin-left: -70rpx;
margin-top: -24rpx;
border-radius: 24rpx;
overflow: hidden;
display: flex;
flex-direction: row;
box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.12);
animation: ai-load-float 2.2s ease-in-out infinite;
}
.ai-load__pill-left {
width: 50%;
height: 100%;
background: linear-gradient(90deg, #fdfbf7, #ede8df);
}
.ai-load__pill-right {
width: 50%;
height: 100%;
background: linear-gradient(90deg, #5dd9d1, #2cb8b0);
}
.ai-load__mr {
position: absolute;
left: 50%;
top: 50%;
width: 100rpx;
height: 120rpx;
margin-left: -50rpx;
margin-top: -60rpx;
background: #fff;
border-radius: 10rpx;
border: 2rpx solid rgba(180, 200, 200, 0.55);
box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.12);
box-sizing: border-box;
padding: 18rpx 12rpx 12rpx 28rpx;
display: flex;
flex-direction: column;
animation: ai-load-float 2.2s ease-in-out infinite;
}
.ai-load__mr-spine {
position: absolute;
left: 0;
top: 6rpx;
bottom: 6rpx;
width: 16rpx;
background: #3dd6d0;
border-radius: 0 4rpx 4rpx 0;
}
.ai-load__mr-title {
width: 60%;
height: 12rpx;
border-radius: 4rpx;
background: rgba(61, 214, 208, 0.35);
margin-bottom: 14rpx;
}
.ai-load__mr-line {
width: 100%;
height: 6rpx;
border-radius: 3rpx;
background: rgba(61, 214, 208, 0.3);
margin-bottom: 12rpx;
}
.ai-load__text-row {
margin-top: 28rpx;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.ai-load__text {
font-size: 28rpx;
color: #4a5568;
animation: ai-load-blink 1.6s ease-in-out infinite;
}
.ai-load__dots {
display: flex;
flex-direction: row;
margin-left: 10rpx;
}
.ai-load__dot {
width: 8rpx;
height: 8rpx;
border-radius: 50%;
background: #3dd6d0;
margin-left: 8rpx;
opacity: 0.25;
}
.ai-load__dot--1 {
animation: ai-load-dot 1.4s ease-in-out infinite;
}
.ai-load__dot--2 {
animation: ai-load-dot 1.4s ease-in-out infinite;
animation-delay: 0.2s;
}
.ai-load__dot--3 {
animation: ai-load-dot 1.4s ease-in-out infinite;
animation-delay: 0.4s;
}
@keyframes ai-load-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes ai-load-float {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-10rpx);
}
}
@keyframes ai-load-blink {
0%,
100% {
opacity: 0.55;
}
50% {
opacity: 1;
}
}
@keyframes ai-load-dot {
0%,
100% {
opacity: 0.2;
transform: scale(0.85);
}
50% {
opacity: 1;
transform: scale(1.15);
}
}
@keyframes ai-load-orbit {
from {
transform: rotate(0deg) translateX(110rpx) rotate(0deg);
}
to {
transform: rotate(360deg) translateX(110rpx) rotate(-360deg);
}
}
</style>