maxkb/ui/src/components/ai-chat/component/chat-input-operate/TouchChat.vue
2025-03-24 10:26:33 +08:00

161 lines
3.8 KiB
Vue

<template>
<div class="touch-chat w-full mr-8">
<el-button
text
bg
class="microphone-button w-full mt-8 ml-8 mb-8"
style="font-size: 1rem; padding: 1.2rem 0 !important; background-color: #eff0f1"
@touchstart="onTouchStart"
@touchmove="onTouchMove"
@touchend="onTouchEnd"
>
按住说话
</el-button>
<!-- 使用 custom-class 自定义样式 -->
<transition name="el-fade-in-linear">
<el-card class="custom-speech-card" :class="isTouching ? '' : 'active'" v-if="dialogVisible">
<p>
<el-text type="info" v-if="isTouching"
>00:{{ props.time < 10 ? `0${props.time}` : props.time }}</el-text
>
<span class="lighter" v-else>
{{ message }}
</span>
</p>
<div class="close">
<el-icon><Close /></el-icon>
</div>
<p class="lighter" :style="{ visibility: isTouching ? 'visible' : 'hidden' }">
{{ message }}
</p>
<div class="speech-img flex-center border-r-4 mt-16">
<img v-if="isTouching" src="@/assets/acoustic-color.svg" alt="" />
<img v-else src="@/assets/acoustic.svg" alt="" />
</div>
</el-card>
</transition>
</div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
const props = defineProps({
time: {
type: Number,
default: 0
},
start: {
type: Boolean,
default: false
}
})
const emit = defineEmits(['TouchStart', 'TouchEnd'])
// 移动端语音
const startY = ref(0)
const isTouching = ref(false)
const dialogVisible = ref(false)
const message = ref('按住说话')
watch(
() => props.time,
(val) => {
if (val && val === 60) {
dialogVisible.value = false
emit('TouchEnd', isTouching.value)
isTouching.value = false
}
}
)
watch(
() => props.start,
(val) => {
if (val) {
isTouching.value = true
dialogVisible.value = true
message.value = '松开发送,上滑取消'
} else {
dialogVisible.value = false
isTouching.value = false
}
}
)
function onTouchStart(event: any) {
emit('TouchStart')
startY.value = event.touches[0].clientY
// 阻止默认滚动行为
event.preventDefault()
}
function onTouchMove(event: any) {
if (!isTouching.value) return
// 阻止默认滚动行为
event.preventDefault()
const currentY = event.touches[0].clientY
const deltaY = currentY - startY.value
// 判断是否上滑
if (deltaY < -50) {
// -50 是一个阈值,可以根据需要调整
message.value = '松开取消发送'
isTouching.value = false
}
}
function onTouchEnd() {
emit('TouchEnd', isTouching.value)
}
</script>
<style lang="scss" scoped>
.custom-speech-card {
position: fixed;
bottom: 10px;
left: 50%; /* 水平居中 */
transform: translateX(-50%);
width: 92%;
background: #ffffff;
border: 1px solid #ffffff;
box-shadow: 0px 6px 24px 0px rgba(31, 35, 41, 0.08);
z-index: 999;
text-align: center;
color: var(--app-text-color-secondary);
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
.close {
box-shadow: 0px 4px 8px 0px rgba(31, 35, 41, 0.1);
border: 1px solid rgba(222, 224, 227, 1);
background: rgba(255, 255, 255, 1);
border-radius: 100px;
display: inline-block;
width: 43px;
height: 43px;
line-height: 50px;
font-size: 1.8rem;
margin: 20px 0;
}
.speech-img {
text-align: center;
background: #ebf1ff;
padding: 8px;
img {
height: 25px;
}
}
&.active {
.close {
background: #f54a45;
color: #ffffff;
width: 50px;
height: 50px;
line-height: 57px;
font-size: 2rem;
}
.speech-img {
background: #eff0f1;
}
}
}
</style>