在家开发了btn按钮样式

This commit is contained in:
终究是寂寞
2026-03-03 00:27:27 +08:00
parent 1aaf78c96b
commit f6b1ef16c3
5 changed files with 293 additions and 151 deletions
+2 -2
View File
@@ -4,10 +4,10 @@ ENV = 'development'
#VITE_APP_BASE_API_Url = 'https://aits.jlbank.com.cn:7001'
VITE_APP_BASE_API_Url = 'https://aits.jlbank.com.cn:7001'
VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001'
#VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001'
# VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7002'
# VITE_APP_BASE_API_Url = 'http://192.168.247.200'
+182 -11
View File
@@ -4,6 +4,7 @@
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.8);
position: relative;
}
/* 1. 定义通用的向右移出动画(核心:添加时长,解决秒没) */
@keyframes moveRightOut {
@@ -24,29 +25,44 @@
left: -400rpx; /* 目标位置:向左移出400rpx */
}
}
/* 2. 定义通用的向左移出动画(适配 btn-box-1) */
@keyframes moveBottomOut {
0% {
transform: translateY(0%);
}
100% {
transform: translateY(100%);
}
}
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.page-1 {
background-color: red;
&.init {
position: absolute;
width: 100%;
bottom: 0;
&.voice_to_text{
.btn-box-1 {
position: absolute; /* 定位是动画生效的前提 */
left: 0; /* 初始位置 */
/* 核心动画配置:时长+曲线+保留最终状态 */
animation: moveLeftOut 0.5s ease-out forwards;
animation: moveLeftOut 0.3s ease-out forwards;
/* 清除冲突样式 */
transform: none !important;
transition: none !important;
}
.btn-box-2 {
position: absolute; /* 定位是动画生效的前提 */
right: 0; /* 初始位置 */
/* 核心动画配置:时长+曲线+保留最终状态 */
animation: moveRightOut 0.5s ease-out forwards;
animation: moveRightOut 0.3s ease-out forwards;
/* 清除冲突样式 */
transform: none !important;
transition: none !important;
}
.circle-bg-box{
animation: moveBottomOut 0.3s ease-out forwards;
}
}
// 两侧按钮
.btns-box {
@@ -93,4 +109,159 @@
line-height: 46px;
}
}
}
.page-2{
width: 100%;
overflow: hidden;
font-size: 28rpx;
text-align: center;
display: none;
z-index: 12000;
justify-content: space-around;
margin-bottom:234rpx;;
position: absolute;
bottom: 0;
opacity: 0;
visibility: hidden; // 初始不可见且不占交互位置
&.voice_to_text {
display: flex !important;
visibility: visible; // 激活后可见
animation: fadeIn 0.4s ease-out 0.1s forwards;
}
.transVoiceIng {
width: 154rpx;
height: 154rpx;
overflow: hidden;
position: relative;
z-index: 12010;
&.cancel-btn {
background: url(@/static/images/course/cancel-btn.png) no-repeat;
background-size: cover;
}
&.trans-btn {
background: url(@/static/images/course/trans-btn.png) no-repeat;
background-size: cover;
}
}
.send-btn {
position: relative;
width: 262rpx;
height: 154rpx;
line-height: 154rpx;
overflow: hidden;
background-color: #d8d8d8;
border-radius: 77rpx;
font-size: 33rpx;
z-index: 12010;
}
}
.talk-dialog-box{
position: absolute;
bottom: 520rpx ;
width: 100%;
display: flex;
justify-content: center;
}
.talk-dialog-div {
width: 506rpx;
min-height: 234rpx;
background-color: #06f;
border-radius: 32rpx;
transition: width 0.3s ease;
// 滑动到离开变红
&.is-out {
background-color: #ff3e49;
&::after {
background-color: #ff3e49;
}
}
// 滑动到转文字变宽
&.is-translate {
width: 706rpx;
.gif-box {
display: none;
}
}
&::after {
content: '';
width: 44rpx;
height: 44rpx;
clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
background-color: #06f;
overflow: hidden;
position: absolute;
bottom: -22rpx;
left: 50%;
margin-left: -22rpx;
transition: left 0.3s ease-out; // 时长0.3秒,ease-out缓动(结束时变慢,更自然)
}
// 控制下边箭头指向发送
&.init::after {
left: 78% !important;
}
&.failed {
width: 506rpx;
height: 114rpx;
min-height: 114rpx;
background-color: #ff3e49;
&::after {
background-color: #ff3e49;
}
// 激活错误提示框
.error-tip-div{
display: flex !important;
visibility: visible; // 激活后可见
// animation: fadeIn 0.4s ease-out 0.1s forwards;
}
}
}
.talk-dialog {
width: 100%;
height: 100%;
overflow: hidden;
position: relative;
.text-div {
overflow-y: scroll;
max-height: 434rpx;
padding: 20rpx;
font-size: 32rpx;
color: #fff;
line-height: 40rpx;
}
.gif-box {
position: absolute;
width: 200rpx;
height: 80rpx;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.error-tip-div{
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
position: absolute;
display: none;
visibility: hidden; // 初始不可见且不占交互位置
display: flex;
align-items: center;
color: #ffffff;
font-size: 24rpx;
font-weight: 400;
.img{
margin-right: 10rpx;
width: 26rpx;
height: 26rpx;
}
}
}
+8 -2
View File
@@ -11,15 +11,21 @@ export const icKeyboardSvg = () : string => {
`;
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
};
export const icMicSvg = () : string => {
export const iconMicSvg = () : string => {
const svgXml = `
<svg t="1772357429950" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1775" width="200" height="200"><path d="M513.788813 938.289925c-113.566274 0-220.223734-44.167967-300.444149-124.388381-80.220415-80.220415-124.388382-186.877876-124.388382-300.44415s44.167967-220.227983 124.388382-300.448398c165.543834-165.548083 435.348714-165.548083 600.892548 0 165.548083 165.548083 165.548083 435.348714 0 600.892548-80.220415 80.220415-186.877876 124.388382-300.44415 124.388381z m0-785.973112c-92.538158 0-185.072066 35.453344-255.379651 105.756681-68.2001 68.204349-105.75668 158.63927-105.756681 255.3839s37.556581 187.175303 105.756681 255.379652c68.204349 68.2001 158.936697 106.054108 255.379651 105.75668 96.74888 0 187.179552-37.556581 255.379652-105.75668 140.912598-140.912598 140.912598-369.850954 0-510.759303-70.303336-70.307585-162.841494-105.75668-255.379652-105.756681z" fill="#515151" p-id="1776"></path><path d="M318.672199 341.705826h46.313693c11.047303 0 19.545228 8.497925 19.545228 19.120332v46.313693c0 10.622407-8.497925 19.120332-19.120332 19.120332h-46.738589c-10.622407 0.424896-19.120332-8.073029-19.120332-18.695436v-46.738589c0-10.622407 8.497925-19.120332 19.120332-19.120332zM488.630705 341.705826h46.313693c11.047303 0 19.545228 8.497925 19.545229 19.120332v46.313693c0 10.622407-8.497925 19.120332-19.120332 19.120332h-46.73859c-10.622407 0.424896-19.120332-8.073029-19.120332-18.695436v-46.738589c0-10.622407 8.497925-19.120332 19.120332-19.120332zM658.589212 341.705826h46.313693c11.047303 0 19.545228 8.497925 19.545228 19.120332v46.313693c0 10.622407-8.497925 19.120332-19.120332 19.120332h-46.738589c-10.622407 0.424896-19.120332-8.073029-19.120332-18.695436v-46.738589c0-10.622407 8.497925-19.120332 19.120332-19.120332zM318.672199 469.174705h46.313693c10.622407 0 19.120332 8.497925 19.120332 19.120332v46.313693c0 10.622407-8.497925 19.120332-19.120332 19.120332H318.672199c-10.622407 0.424896-19.120332-8.073029-19.120332-18.695435v-46.73859c0-10.622407 8.497925-19.120332 19.120332-19.120332zM488.630705 469.174705h46.313693c10.622407 0 19.120332 8.497925 19.120332 19.120332v46.313693c0 10.622407-8.497925 19.120332-19.120332 19.120332h-46.313693c-10.622407 0.424896-19.120332-8.073029-19.120332-18.695435v-46.73859c0-10.622407 8.497925-19.120332 19.120332-19.120332zM658.589212 469.174705h46.313693c10.622407 0 19.120332 8.497925 19.120332 19.120332v46.313693c0 10.622407-8.497925 19.120332-19.120332 19.120332h-46.313693c-10.622407 0.424896-19.120332-8.073029-19.120332-18.695435v-46.73859c0-10.622407 8.497925-19.120332 19.120332-19.120332zM458.887967 660.378025h106.224066c17.420747 0 31.86722 14.446473 31.86722 31.86722s-14.446473 31.86722-31.86722 31.86722h-106.224066c-17.420747 0-31.86722-14.446473-31.86722-31.86722s14.446473-31.86722 31.86722-31.86722z" fill="#515151" p-id="1777"></path></svg>
`;
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
};
export const icSendSvg = () : string => {
export const iconSendSvg = () : string => {
const svgXml = `
<svg t="1772375437715" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="44211" width="200" height="200"><path d="M512 56.888889c251.363556 0 455.111111 203.747556 455.111111 455.111111s-203.747556 455.111111-455.111111 455.111111S56.888889 763.363556 56.888889 512 260.636444 56.888889 512 56.888889z m-28.444444 324.664889V711.111111a28.444444 28.444444 0 0 0 56.888888 0V381.553778l150.556445 150.556444a28.444444 28.444444 0 0 0 40.220444-40.220444l-199.111111-199.111111a28.444444 28.444444 0 0 0-40.220444 0l-199.111111 199.111111a28.444444 28.444444 0 0 0 40.220444 40.220444L483.555556 381.553778z" fill="#0066FF" p-id="44212"></path></svg>
`;
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
};
export const iconRecognizeErrorSvg = () : string => {
const svgXml = `
<svg t="1772464917665" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5331" width="64" height="64"><path d="M512 4.12672c280.49408 0 507.87328 227.3792 507.87328 507.87328 0 280.49408-227.3792 507.87328-507.87328 507.87328C231.50592 1019.87328 4.12672 792.49408 4.12672 512 4.12672 231.50592 231.50592 4.12672 512 4.12672zM512 685.96736c-42.47552 0-76.91264 34.42688-76.91264 76.91264 0 42.47552 34.43712 76.91264 76.91264 76.91264 42.47552 0 76.91264-34.43712 76.91264-76.91264C588.91264 720.39424 554.47552 685.96736 512 685.96736zM509.78816 625.83808c36.58752 0 66.24256-29.66528 66.24256-66.24256l0-309.1456c0-36.58752-29.65504-66.24256-66.24256-66.24256-36.58752 0-66.24256 29.66528-66.24256 66.24256l0 309.1456C443.5456 596.18304 473.20064 625.83808 509.78816 625.83808z" fill="#ffffff" p-id="5332"></path></svg>
`;
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
};
@@ -12,6 +12,7 @@ export type StatusType = 'default' | 'voice_recording' | 'text_input' | 'voice_t
* 语音转文字的子状态(仅当主状态为 voice_to_text 时生效)
*/
export type VoiceToTextSubStatus =
| '' // 纯空
| 'init' // 初始化(刚进入语音转文字页面)
| 'loading' // 转换中(正在处理语音→文字)
| 'success' // 转换完成(成功得到文字结果)
+100 -136
View File
@@ -2,8 +2,8 @@
<view>
<view class="talk-btns" :class="{action:isRecording, inputMode:!isInputVisible}">
<view class="touch-btn" @click="disabled_click">
<button v-if="!isTextOnlyMode && isInputVisible" class="voice-btn" @touchstart="startRecord" @touchend="stopRecord()" @touchmove="handleMove"
@touchcancel="stopRecord()" :plain="true">
<button v-if="!isTextOnlyMode && isInputVisible" class="voice-btn" @touchstart="startRecord"
@touchend="stopRecord()" @touchmove="handleMove" @touchcancel="stopRecord()" :plain="true">
<text class="voice-text">{{ isRecording ? '松开发送' : '按住说话' }}</text>
</button>
<input v-if="!isVoiceOnlyMode && !isInputVisible" class="input-box" ref="inputRef" v-model="inputText"
@@ -15,43 +15,54 @@
<image class="talk-right-icon" :src="talkRightIcon" mode="widthFix" @click="changeBtn"></image>
</view>
</view>
<!-- :class="{ 'is-out': isOutStatus === '02', 'is-translate': isOutStatus === '03', voice_to_text_status: status === 'voice_to_text'}" -->
<uni-popup ref="popupRef" class="popup">
<view class="overlay-box">
<view class="fl1"></view>
<view class="talk-dialog"
:class="{ 'is-out': isOutStatus === '02', 'is-translate': isOutStatus === '03' }">
<image :src="voiceWhiteBtn" mode="" class="gif-box"></image>
<uv-textarea ref="inputRef" v-model="textAreaText" :maxlength="255" @click.stop
customStyle="background: #ffffff00; padding-bottom: 50rpx; color: #fff; caret-color: #fff"
text-style="color: #fff" border="none" placeholderStyle="color:#999999;font-size:26rpx;"
placeholder=""></uv-textarea>
<view class="talk-dialog-box">
<view class="talk-dialog-div" :class="dialogDynamicClasses">
<view class="talk-dialog" >
<image :src="voiceWhiteBtn" mode="" class="gif-box"></image>
<uv-textarea ref="inputRef" v-model="textAreaText" :maxlength="255" @click.stop
customStyle="background: #ffffff00; padding-bottom: 50rpx; color: #fff; caret-color: #fff"
text-style="color: #fff" border="none" placeholderStyle="color:#999999;font-size:26rpx;"
placeholder=""></uv-textarea>
<view class="error-tip-div">
<image :src="iconRecognizeErrorSvg()" mode="aspectFill" class="img"></image>
<view class="">
未识别到文字
</view>
</view>
</view>
</view>
</view>
<view class="page-1"
:class="[
status === 'voice_to_text' ? `${voice_to_text_status}` : ''
]">
<!-- 第一形态两侧按钮 -->
<!-- 第一形态两侧按钮 -->
<view class="page-1" :class="[ status]">
<view class="btns-box">
<!-- 左侧取消按钮 -->
<image class="btn-box btn-box-1" :src="isOutStatus == '02' ? cancelActiveBtn : cancelBtn" mode="heightFix" @click="closePopup()"></image>
<image class="btn-box btn-box-1" :src="isOutStatus == '02' ? cancelActiveBtn : cancelBtn"
mode="heightFix" @click="closePopup()"></image>
<!-- 右侧转文字按钮 -->
<image class="btn-box btn-box-2" :src="isOutStatus == '03' ? translateActiveBtn : translateBtn" mode="heightFix"></image>
<image class="btn-box btn-box-2" :src="isOutStatus == '03' ? translateActiveBtn : translateBtn"
mode="heightFix"></image>
</view>
<!-- 下方按钮 -->
<view class="circle-bg-box">
<view class="tips-box">松开发送</view>
</view>
</view>
<!-- <view class="page-2">
<view class="cancel-btn transVoiceIng" @click="closeModel()"></view>
<view class="trans-btn transVoiceIng" @click="sendVoice()" v-show="props.answerMethod !== '02'"></view>
<view class="send-btn" @click="sendText()">发送</view>
</view> -->
<!-- 第二形态 -->
<view class="page-2" :class="[ status, voice_to_text_status]">
<!-- 左侧XX -->
<view class="transVoiceIng cancel-btn" @click="closePopup()"></view>
<!-- 中间发送原语音 -->
<view class="transVoiceIng trans-btn" @click="testFun()"></view>
<!-- 右侧发送按钮椭圆 -->
<view class="send-btn">发送</view>
</view>
</view>
</uni-popup>
</view>
@@ -59,8 +70,8 @@
<script setup lang="ts">
// 导出图片
import { cancelBtn, cancelActiveBtn, translateBtn, translateActiveBtn, voiceWhiteBtn, icKeyboardSvg, icMicSvg,icSendSvg } from './touch-btn.images';
import { StatusType,VoiceToTextSubStatus } from './touch-btn.types';
import { cancelBtn, cancelActiveBtn, translateBtn, translateActiveBtn, voiceWhiteBtn, icKeyboardSvg, iconMicSvg, iconSendSvg, iconRecognizeErrorSvg } from './touch-btn.images';
import { StatusType, VoiceToTextSubStatus } from './touch-btn.types';
import { wsUrl, bottomAreaTopBoundary, horizontalSplitX, initWebSocket } from './touch-btn';
import { ref, computed, onMounted, nextTick, watch, reactive } from 'vue';
import common from '@/common/common';
@@ -118,12 +129,20 @@
}
});
const textAreaText = computed({
get() {
return allText.value + tempText.value;
},
set(newValue) {
allText.value = newValue;
}
get() {
return allText.value + tempText.value;
},
set(newValue) {
allText.value = newValue;
}
});
const dialogDynamicClasses = computed(() => {
const classes = [];
isOutStatus.value === '02' && classes.push('is-out')
isOutStatus.value === '03' && classes.push('is-translate')
voice_to_text_status.value !== '' && classes.push(voice_to_text_status.value)
return classes;
});
const allText = ref('');
const tempText = ref('');
@@ -140,9 +159,9 @@
const isVoiceOnlyMode = computed(() => props.mode === 'voice-only');
const isTextOnlyMode = computed(() => props.mode === 'text-only');
const talkRightIcon = computed(() => {
if(isInputVisible.value) return icKeyboardSvg();
if(inputText.value) return icSendSvg();
return icMicSvg();
if (isInputVisible.value) return icKeyboardSvg();
if (inputText.value) return iconSendSvg();
return iconMicSvg();
});
// 计算是否超出按下盒子位置01代表下方盒子,02代表左上03代表右上
const isOutStatus = computed(() => {
@@ -156,7 +175,9 @@
touchPos.x = pageX;
touchPos.y = pageY;
};
const testFun = () => {
voice_to_text_status.value = 'failed'
}
// 开启语音
const startRecord = async (obj : { touches : any[]; }) => {
try {
@@ -172,13 +193,14 @@
// 标记录音开始
isRecording.value = true;
status.value = 'voice_recording'
voice_to_text_status.value = ''
tempText.value = '';
allText.value = '';
initWebSocket(wsUrl).then(socketTask => {
ws.value = socketTask
wsStatus.value = true;
console.log('WS连接成功');
ws.value.onMessage((res: { data: Uint8Array | ArrayBuffer; }) => {
ws.value.onMessage((res : { data : Uint8Array | ArrayBuffer; }) => {
try {
const { msgType, body } = ProtocolCodec.unpack(res.data);
if (msgType === MessageType.TEXT_MESSAGE) {
@@ -208,9 +230,9 @@
recordStartTime.value = Date.now();
// 弹出录音界面
popupRef.value.open();
startAudioRecord({
startAudioRecord({
onFrame: (pcmData : any) => {
if(wsStatus.value) {
if (wsStatus.value) {
console.log('已连接', pcmData.length);
ws.value.send({
data: ProtocolCodec.pack(MessageType.AUDIO_DATA, pcmData)
@@ -232,32 +254,32 @@
});
}, 140)
};
// 结束录音
const closePopup = () => {
const closePopup = () => {
popupRef.value.close();
}
const stopRecord = async () => {
clearTimeout(pressTimer.value);
if (!isRecording.value) return; // 未处于录音状态
if(isOutStatus.value === '03') { // 转换文字状态
if (isOutStatus.value === '03') { // 转换文字状态
console.log('已发送', '03转文字');
switchFromVoiceToText()
}
const recordDurationMs = Date.now() - recordStartTime.value;
if(isOutStatus.value !== '02') { // 取消的时候,不校验最低时间
if (isOutStatus.value !== '02') { // 取消的时候,不校验最低时间
// 核心:计算录音总时长(毫秒转秒,保留1位小数)
if (recordDurationMs < 600) {
await new Promise<void>((resolve) => {
setTimeout(() => {
resolve()
}, 600-recordDurationMs)
}, 600 - recordDurationMs)
})
}
}
isRecording.value = false;
if(isOutStatus.value === '02' && ws.value) { // 取消的时候自己主动关闭websocket,其他的时候需要等待后端的消息关闭
if (isOutStatus.value === '02' && ws.value) { // 取消的时候自己主动关闭websocket,其他的时候需要等待后端的消息关闭
ws.value.close({
code: 1000,
reason: '挂断',
@@ -268,32 +290,32 @@
});
}
stopAudioRecord(); // 关掉录音
if(isOutStatus.value !== '03') { // 转文字时候不关遮罩层
if (isOutStatus.value !== '03') { // 转文字时候不关遮罩层
popupRef.value.close();
if(isOutStatus.value !== '02') { // 取消的时候,不校验最低时间
if(recordDurationMs <= 1200) {
if (isOutStatus.value !== '02') { // 取消的时候,不校验最低时间
if (recordDurationMs <= 1200) {
setTimeout(() => {
uni.showToast({
title: '说话时间太短,没有听清!',
icon: 'none'
});
}, 200)
return
return
}
}
}
};
// 从录音状态切换成转文字状态
const switchFromVoiceToText = () => {
status.value = 'voice_to_text'
ws.value && ws.value.send({data: ProtocolCodec.pack(MessageType.CONTROL_CMD, { type: ControlCode.FRNOT_TO_SERVER_OVER, ossID:'', text:'' })});
ws.value && ws.value.send({ data: ProtocolCodec.pack(MessageType.CONTROL_CMD, { type: ControlCode.FRNOT_TO_SERVER_OVER, ossID: '', text: '' }) });
voice_to_text_status.value = 'init'
// 执行动画
11
}
// 发送文本
const showKeyboard = () => {
if (isInputVisible.value) {
@@ -324,7 +346,7 @@
console.log('调用结束语音回答');
stopRecord();
};
// 外部调用,清理输入框数据
const clearinputText = (text = '') => {
const old_text = inputText.value;
@@ -332,7 +354,6 @@
return old_text;
};
defineExpose({ clearinputText, give_up });
</script>
<style lang="scss" scoped>
@@ -340,91 +361,34 @@
@import "./style/popup.scss";
.talk-dialog {
width: 506rpx;
min-height: 234rpx;
margin: 0 auto 160rpx auto;
background-color: #06f;
border-radius: 32rpx;
position: relative;
overflow: hidden;
transition: width 0.3s ease;
.text-div {
overflow-y: scroll;
max-height: 434rpx;
padding: 20rpx;
font-size: 32rpx;
color: #fff;
line-height: 40rpx;
}
.white-bg-box {
height: 365rpx;
background-color: #fff;
overflow: hidden;
border-radius: 32rpx 32rpx 0 0;
padding: 58rpx 36rpx;
&.is-translate {
width: 706rpx;
.gif-box {
display: none;
}
}
&.is-out {
background-color: #ff3e49;
&::after {
background-color: #ff3e49;
}
}
.gif-box {
position: absolute;
width: 200rpx;
height: 80rpx;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
&::after {
content: '';
width: 44rpx;
height: 44rpx;
clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
background-color: #06f;
overflow: hidden;
position: absolute;
bottom: -22rpx;
left: 50%;
margin-left: -22rpx;
}
.box-title {
font-size: 32rpx;
font-weight: bold;
line-height: 46rpx;
margin-bottom: 46rpx;
}
.white-bg-box {
height: 365rpx;
background-color: #fff;
overflow: hidden;
border-radius: 32rpx 32rpx 0 0;
padding: 58rpx 36rpx;
.box-btns {
height: 46rpx;
line-height: 46rpx;
display: flex;
justify-content: space-between;
color: #999;
.box-title {
font-size: 32rpx;
font-weight: bold;
line-height: 46rpx;
margin-bottom: 46rpx;
}
.box-btns {
height: 46rpx;
line-height: 46rpx;
display: flex;
justify-content: space-between;
color: #999;
.is-active {
color: #06f;
}
.is-active {
color: #06f;
}
}
}
::v-deep .uv-input__content__field-wrapper__field {
padding-right: 60rpx;