alipay-emulator/pages/other/game/sanjiaozhou.vue

834 lines
25 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>
<view class="honor-of-kings">
<nav-bar title="三角洲结算页" bgColor="#F5F5F5" isRightButton :rightButtonText="rightButtonText"
@right-click="onRightClick">
</nav-bar>
<view style="padding: 8px;box-sizing: border-box;">
<view class="painter-container" @click="handlePreview"
:style="`width:calc(100vw - 16px) ; height: ${posterContainerHeight}px; overflow: hidden; position: relative; transform: translateZ(0);`">
<!-- 运用 js 算出的无误差纯数字 scale 来实现高清画板的等比缩小彻底兼容所有老旧内核不再被截断 -->
<view
:style="`width: 750px; transform: scale(${posterScaleRatio}); transform-origin: left top; position: absolute; left: 0; top: 0;`">
<l-painter isCanvasToTempFilePath @success="onPainterSuccess" :css="`width:750px;`">
<l-painter-view :css="`width: 750.0px; position: relative;`">
<!-- 直接使用主背景图撑开父容器移除不必要的 opacity: 0 占位图避免在大屏渲染时产生黑块 -->
<l-painter-image :src="`/static/image/other/game/sanjiaozhou/style-${data.type}.jpg`"
css="width: 750.0px; display: block;"></l-painter-image>
<l-painter-view css="position: absolute; left: 73px; top: 113px; white-space: nowrap;">
<!-- 地图 -->
<l-painter-image :src="`/static/image/other/game/sanjiaozhou/line.png`"
css="display: inline-block; vertical-align: middle; height: 22px; width: 1px;"></l-painter-image>
<l-painter-view
css="display: inline-block; vertical-align: middle; padding-left: 4px; min-width: 60px;">
<l-painter-text
css="display: block; color:#CDCDCD; font-size:6px; line-height:6px; margin-bottom: 4px; white-space: nowrap;"
:text="data.map.level"></l-painter-text>
<l-painter-text
css="display: block; color:#CDCDCD; font-size:10px; line-height:10px; white-space: nowrap;"
:text="data.map.name"></l-painter-text>
</l-painter-view>
<!-- 撤离点 -->
<l-painter-image :src="`/static/image/other/game/sanjiaozhou/line.png`"
css="display: inline-block; vertical-align: middle; height: 22px; width: 1px;margin-left: 2px;"></l-painter-image>
<l-painter-view
css="display: inline-block; vertical-align: middle; padding-left: 4px; min-width: 60px;">
<l-painter-text
css="display: block; color:#CDCDCD; font-size:6px; line-height:6px; margin-bottom: 4px; white-space: nowrap;"
text="撤离点"></l-painter-text>
<l-painter-text
css="display: block; color:#CDCDCD; font-size:10px; line-height:10px; white-space: nowrap;"
:text="data.extractionPoint"></l-painter-text>
</l-painter-view>
<!-- 时长 -->
<l-painter-image :src="`/static/image/other/game/sanjiaozhou/line.png`"
css="display: inline-block; vertical-align: middle; height: 22px; width: 1px;margin-left: 2px;"></l-painter-image>
<l-painter-view
css="display: inline-block; vertical-align: middle; padding-left: 4px; min-width: 60px;">
<l-painter-text
css="display: block; color:#CDCDCD; font-size:6px; line-height:6px; margin-bottom: 4px; white-space: nowrap;"
text="时长"></l-painter-text>
<l-painter-text v-for="(char, idx) in String(data.duration).split('')"
:key="'durationNum_' + idx" :css="getTimeCharStyle(char, idx, $system)"
:text="getDefeatIconText(char)"></l-painter-text>
</l-painter-view>
<!-- 对局时间 -->
<l-painter-image :src="`/static/image/other/game/sanjiaozhou/line.png`"
css="display: inline-block; vertical-align: middle; height: 22px; width: 1px;margin-left: 2px;"></l-painter-image>
<l-painter-view
css="display: inline-block; vertical-align: middle; padding-left: 4px; min-width: 60px;">
<l-painter-text
css="display: block; color:#CDCDCD; font-size:6px; line-height:6px; margin-bottom: 4px; white-space: nowrap;"
text="对局时间"></l-painter-text>
<!-- <l-painter-text
css="display: block; color:#CDCDCD; font-size:10px; line-height:10px; white-space: nowrap;"
:text="data.map.name"></l-painter-text> -->
<l-painter-text v-for="(char, idx) in String(data.matchTime).split('')"
:key="'matchTimeNum_' + idx" :css="getTimeCharStyle(char, idx, $system)"
:text="getDefeatIconText(char)"></l-painter-text>
</l-painter-view>
</l-painter-view>
<!-- 本局收获 -->
<l-painter-view
css="position: absolute; left: 73px; top: 175px; white-space: nowrap; display: block;">
<l-painter-text
v-for="(char, idx) in String(data.harvest).replace(/\B(?=(\d{3})+(?!\d))/g, ',').split('')"
:key="'harvestNum_' + idx" :css="getHarvestCharStyle(char, idx, $system)"
:text="getDefeatIconText(char)"></l-painter-text>
</l-painter-view>
<!-- 击败干员 -->
<l-painter-view
css="position: absolute; left: 73px; top: 250px; white-space: nowrap; display: block;">
<l-painter-text v-for="(char, idx) in String(data.defeat).split('')"
:key="'bigNum_' + idx"
:css="`display: inline-block; color:#DBE5E6; font-size:22px; line-height:6px; margin-bottom: 4px; font-family: myIconFont; margin-left: ${idx === 0 ? '0' : '-2px'};`"
:text="getDefeatIconText(char)"></l-painter-text>
</l-painter-view>
<!-- 高光击败 -->
<l-painter-view v-for="(item, index) in data.defeatInfo" :key="index"
:css="`display: inline-block; vertical-align: middle;position: absolute; left: 73px; top: ${295 + index * 16}px; `">
<l-painter-view css="display: inline-block;">
<l-painter-image src="/static/image/other/game/sanjiaozhou/kill.png"
css="width: 12px; height: 12px; display: inline-block;margin-right:2px"></l-painter-image>
<l-painter-text
css="display: inline-block; color:#DBE5E6; font-size:9px; line-height:6px; margin-bottom: 4px; white-space: nowrap;"
:text="`${item.name} [${item.rank}]`"></l-painter-text>
</l-painter-view>
</l-painter-view>
<!-- 玩家名称 -->
<l-painter-text
css="display: block; color:#CDCDCD; font-size:10px; line-height:10px; white-space: nowrap;transform:rotate(10deg);position:absolute;left:424px;top:310px;"
:text="data.name"></l-painter-text>
<l-painter-text
css="display: block; color:#CDCDCD; font-size:7px; line-height:10px; white-space: nowrap;transform:rotate(10deg);position:absolute;left:422px;top:321px;opacity: 0.6;"
text="信守不渝"></l-painter-text>
<!-- 水印 -->
<l-painter-image v-if="$isVip()" src="/static/image/other/shuiying.png"
:css="`position: absolute; left: 18.8px; bottom: 17.1px; width: 145.38px;height:42.76px`"></l-painter-image>
</l-painter-view>
</l-painter>
</view>
</view>
</view>
<!-- 水印 -->
<view v-if="$isVip()">
<liu-drag-button :canDocking="false"
@clickBtn="$goRechargePage('watermark', 'uni_alipay_other_sanjiaozhou')">
<c-lottie ref="cLottieRef" :src='$watermark()' width="94px" height='74px' :loop="true"></c-lottie>
</liu-drag-button>
</view>
<view class="save-action">
<button class="save-btn" @click="handleSave">保存</button>
</view>
<!-- 主题选择区域 -->
<view class="theme-selector">
<scroll-view scroll-x="true" class="theme-scroll" :show-scrollbar="false">
<view class="theme-list">
<view class="theme-item" v-for="(item, index) in ['样式一', '样式二', '样式三', '样式四']" :key="index + 1"
:class="{ active: data.type == index + 1 }" @click="handleChangeTheme(index + 1)">
<text class="theme-text">{{ item }}</text>
</view>
</view>
</scroll-view>
</view>
<!-- 数据编辑弹窗 -->
<uni-popup ref="editPopup" type="center">
<view class="edit-popup-content">
<view class="popup-header">
<text class="title">编辑主页数据</text>
</view>
<scroll-view scroll-y class="popup-scroll">
<view class="form-item">
<text class="label">玩家名称</text>
<input class="input" type="text" v-model="tempData.name" />
</view>
<view class="form-item">
<text class="label">地图级别</text>
<view class="button-group">
<view class="button-item" :class="{ active: tempData.map.level === '普通' }"
@click="tempData.map.level = '普通'">普通</view>
<view class="button-item" :class="{ active: tempData.map.level === '机密' }"
@click="tempData.map.level = '机密'">机密</view>
<view class="button-item" :class="{ active: tempData.map.level === '绝密' }"
@click="tempData.map.level = '绝密'">绝密</view>
</view>
</view>
<view class="form-item">
<text class="label">地图名称</text>
<input class="input" type="text" v-model="tempData.map.name" />
</view>
<view class="form-item">
<text class="label">撤离点</text>
<input class="input" type="text" v-model="tempData.extractionPoint" />
</view>
<view class="form-item">
<text class="label">对局时间</text>
<picker mode="multiSelector" :range="matchTimeRange" :value="matchTimeIndex"
@change="onMatchTimeChange" class="input"
style="height: 36px; line-height: 36px; display: flex; align-items: center;">
<text>{{ tempData.matchTime || '请选择时间' }}</text>
</picker>
</view>
<view class="form-item">
<text class="label">时长</text>
<picker mode="multiSelector" :range="durationRange" :value="durationIndex"
@change="onDurationChange" class="input"
style="height: 36px; line-height: 36px; display: flex; align-items: center;">
<text>{{ tempData.duration || '请选择时长' }}</text>
</picker>
</view>
<view class="form-item">
<text class="label">本局收获</text>
<input class="input" type="text" v-model="tempData.harvest" />
</view>
<view class="form-item">
<text class="label">击败干员</text>
<input class="input" type="text" v-model="tempData.defeat" @input="onDefeatChange" />
</view>
<view style="border: 1px dashed #007aff;padding: 10px;border-radius: 8px;"
v-if="tempData.defeatInfo && tempData.defeatInfo.length > 0">
<view v-for="(item, index) in tempData.defeatInfo" :key="'defeat_' + index"
style="margin-bottom: 10px;">
<view
style="display: flex; justify-content: flex-end; gap: 15px; margin-bottom: 5px; font-size: 12px; height: 16px;"
v-if="tempData.defeatInfo.length > 1">
<text v-if="index > 0" @click="moveDefeatUp(index)"
style="color: #007aff; cursor: pointer;">↑ 上移</text>
<text v-if="index < tempData.defeatInfo.length - 1" @click="moveDefeatDown(index)"
style="color: #007aff; cursor: pointer;">↓ 下移</text>
</view>
<view class="form-item">
<text class="label">被击败者{{ index + 1 }}昵称</text>
<input class="input" type="text" v-model="item.name" />
</view>
<view class="form-item" style="margin-bottom: 0;">
<text class="label">被击败者{{ index + 1 }}段位</text>
<input class="input" type="text" v-model="item.rank" />
</view>
</view>
</view>
</scroll-view>
<view class="popup-footer">
<button class="cancel-btn" @click="closeEditPopup">取消</button>
<button class="confirm-btn" @click="confirmEdit">确定</button>
</view>
</view>
</uni-popup>
<!-- 横向全屏放大预览层 -->
<view class="preview-overlay" v-if="showPreview" @click="showPreview = false">
<image class="preview-image" :src="finalPosterPath" mode="aspectFit"></image>
</view>
</view>
</template>
<script setup>
import { ref, reactive, onMounted, getCurrentInstance } from 'vue'
import { onLoad, onUnload } from '@dcloudio/uni-app'
const rightButtonText = ref("编辑");
const { proxy } = getCurrentInstance();
const showPreview = ref(false); // 控制全屏预览
const isMountedReady = ref(false);
// 获取系统宽度计算海报缩放比例,代替容易失效的 css calc(),确保全端兼容防截断
const sysInfo = uni.getSystemInfoSync();
const windowWidth = sysInfo.windowWidth || 375;
const posterScaleRatio = windowWidth / 750;
const posterContainerHeight = 430 * posterScaleRatio;
// 页面表单数据字段
const data = reactive({
type: 1, // 样式类型 1.2.3.4
name: '大坝猛攻哥',
map: {
name: '零号大坝',
level: '机密'
},
extractionPoint: '工业电梯',
duration: "00:25:19",
matchTime: '02-32 21:02',
harvest: '13526559',
defeat: '1',
defeatInfo: [
{
name: '大坝贪吃鼠',
rank: "黑鹰II"
},
]
})
// 数字到 my-icon iconfont Unicode 的映射字典
const digitIconMap = {
'0': '\ue629', '1': '\ue627', '2': '\ue62b', '3': '\ue62c', '4': '\ue62f',
'5': '\ue62d', '6': '\ue628', '7': '\ue625', '8': '\ue62a', '9': '\ue62e',
',': '\ue626', ':': '\ue630',
};
const getDefeatIconText = (defeatStr) => {
if (!defeatStr && defeatStr !== 0) return '';
return String(defeatStr).split('').map(char => digitIconMap[char] || char).join('');
};
const getTimeCharStyle = (char, idx, system) => {
const fontSize = char === '-' ? 12 : (char === ':' ? 4 : 10);
let marginLeft = '-2px';
if (idx === 0 || system === 'iOS') {
marginLeft = char === '-' ? '2px' : '0px';
}
let marginRight = '0';
if ([' ', '-', ':'].includes(char)) {
if (char === '-' && system === 'Android') {
marginLeft = '0px'
}
if (char === ':' && system === 'Android') {
marginRight = '-1px';
marginLeft = '-1px'
} else if (char === ' ' && system === 'Android') {
marginRight = '2px';
} else {
marginRight = '1rpx';
}
}
return `display: inline-block; vertical-align: bottom; color:#CDCDCD; font-size:${fontSize}px; line-height:6px; margin-bottom: 4px; font-family:myIconFont; margin-left: ${marginLeft}; margin-right: ${marginRight};`;
};
const getHarvestCharStyle = (char, idx, system) => {
const fontSize = char === ',' ? 6 : 22;
let marginLeft = idx === 0 ? '0' : (char === ',' ? (system === 'iOS' ? '3px' : '1px') : (system === 'iOS' ? '2px' : '-3px'));
let marginRight = char === ',' && system === 'Android' ? '2px' : '0';
let marginTop = char === ',' ? '3px' : '0';
return `display: inline-block; vertical-align: bottom; color:#DBE5E6; font-size:${fontSize}px; margin-bottom: 4px; font-family: myIconFont; margin-left: ${marginLeft}; margin-right: ${marginRight}; margin-top: ${marginTop};`;
};
onLoad(() => {
const cachedData = uni.getStorageSync('sanjiaozhouData');
if (cachedData) {
Object.assign(data, cachedData);
}
uni.$on('editFormPhoto', (info) => {
tempData.avatar = info;
// #ifndef H5
if (info && !info.startsWith('/static/')) {
newAvatars.value.push(info);
}
// #endif
});
// 进入页面埋点
proxy.$apiUserEvent('all', {
type: 'click',
key: 'sanjiaozhou',
prefix: '.uni.other.',
value: "三角洲结算页"
})
// 加载海报需要用到的自定义数字字体
uni.loadFontFace({
family: 'myIconFont',
source: `url("/static/font/iconfont.ttf")`,
success() {
console.log('myIconFont 字体加载成功');
},
fail(err) {
console.error('myIconFont 字体加载失败', err);
}
});
});
onUnload(() => {
uni.$off('editFormPhoto');
})
const finalPosterPath = ref('');
const editPopup = ref(null);
const tempData = reactive({
map: {},
defeatInfo: [{}]
});
const newAvatars = ref([]);
const onDefeatChange = (e) => {
const val = parseInt(e.detail.value) || 0;
const maxAllowed = Math.min(3, Math.max(0, val));
if (tempData.defeatInfo.length < maxAllowed) {
const toAdd = maxAllowed - tempData.defeatInfo.length;
for (let i = 0; i < toAdd; i++) {
tempData.defeatInfo.push({ name: '', rank: '' });
}
} else if (tempData.defeatInfo.length > maxAllowed) {
tempData.defeatInfo.splice(maxAllowed);
}
};
const moveDefeatUp = (index) => {
if (index > 0) {
const item = tempData.defeatInfo.splice(index, 1)[0];
tempData.defeatInfo.splice(index - 1, 0, item);
}
};
const moveDefeatDown = (index) => {
if (index < tempData.defeatInfo.length - 1) {
const item = tempData.defeatInfo.splice(index, 1)[0];
tempData.defeatInfo.splice(index + 1, 0, item);
}
};
// 时长选择器数据
const durationRange = ref([
Array.from({ length: 100 }, (_, i) => (i < 10 ? '0' + i : i + '')),
Array.from({ length: 60 }, (_, i) => (i < 10 ? '0' + i : i + '')),
Array.from({ length: 60 }, (_, i) => (i < 10 ? '0' + i : i + ''))
]);
const durationIndex = ref([0, 0, 0]);
const onDurationChange = (e) => {
const val = e.detail.value;
durationIndex.value = val;
tempData.duration = `${durationRange.value[0][val[0]]}:${durationRange.value[1][val[1]]}:${durationRange.value[2][val[2]]}`;
};
// 对局时间选择器数据
const matchTimeRange = ref([
Array.from({ length: 12 }, (_, i) => (i + 1 < 10 ? '0' + (i + 1) : (i + 1) + '')),
Array.from({ length: 31 }, (_, i) => (i + 1 < 10 ? '0' + (i + 1) : (i + 1) + '')),
Array.from({ length: 24 }, (_, i) => (i < 10 ? '0' + i : i + '')),
Array.from({ length: 60 }, (_, i) => (i < 10 ? '0' + i : i + ''))
]);
const matchTimeIndex = ref([0, 0, 0, 0]);
const onMatchTimeChange = (e) => {
const val = e.detail.value;
matchTimeIndex.value = val;
tempData.matchTime = `${matchTimeRange.value[0][val[0]]}-${matchTimeRange.value[1][val[1]]} ${matchTimeRange.value[2][val[2]]}:${matchTimeRange.value[3][val[3]]}`;
};
const initPickerIndexes = () => {
if (tempData.duration) {
const parts = tempData.duration.split(':');
if (parts.length === 3) {
durationIndex.value = [parseInt(parts[0]) || 0, parseInt(parts[1]) || 0, parseInt(parts[2]) || 0];
}
}
if (tempData.matchTime) {
const spaceSplit = tempData.matchTime.split(' ');
if (spaceSplit.length === 2) {
const dateParts = spaceSplit[0].split('-');
const timeParts = spaceSplit[1].split(':');
if (dateParts.length === 2 && timeParts.length === 2) {
matchTimeIndex.value = [(parseInt(dateParts[0]) || 1) - 1, (parseInt(dateParts[1]) || 1) - 1, parseInt(timeParts[0]) || 0, parseInt(timeParts[1]) || 0];
}
}
}
};
function handleChangeTheme(typeIndex) {
// 切换主题时,先清空旧海报,触发界面“加载中”提示
finalPosterPath.value = '';
data.type = typeIndex;
uni.setStorageSync('sanjiaozhouData', data);
}
function onRightClick() {
Object.assign(tempData, JSON.parse(JSON.stringify(data)));
initPickerIndexes();
newAvatars.value = [];
editPopup.value.open();
}
function closeEditPopup() {
// #ifndef H5
newAvatars.value.forEach(path => {
uni.removeSavedFile({ filePath: path });
});
// #endif
editPopup.value.close();
}
function confirmEdit() {
// #ifndef H5
// 删除多余的新上传文件
newAvatars.value.forEach(path => {
if (path !== tempData.avatar) {
uni.removeSavedFile({ filePath: path });
}
});
// 删除被替换掉的原本地头像
if (data.avatar !== tempData.avatar && data.avatar && !data.avatar.startsWith('/static/')) {
uni.removeSavedFile({ filePath: data.avatar });
}
// #endif
Object.assign(data, tempData);
uni.setStorageSync('sanjiaozhouData', data);
editPopup.value.close();
// 数据修改后,清空旧海报触发“加载中”提示,等待重新生成
finalPosterPath.value = '';
}
// 点击画布触发横向预览
const handlePreview = () => {
if (!finalPosterPath.value) {
uni.showToast({ title: '海报仍在生成中,请稍候', icon: 'none' });
return;
}
showPreview.value = true;
}
// 画布生成成功后触发,保存最终的海报路径
const onPainterSuccess = (path) => {
finalPosterPath.value = path;
}
// 点击保存按钮,将带有渐变字体的最终图片存入相册
const handleSave = () => {
if (!finalPosterPath.value) {
uni.showToast({ title: '图片仍在生成中,请稍候', icon: 'none' })
return
}
uni.saveImageToPhotosAlbum({
filePath: finalPosterPath.value,
success: () => {
uni.showToast({ title: '保存成功', icon: 'success' })
},
fail: () => {
uni.showToast({ title: '保存失败', icon: 'none' })
}
})
}
onMounted(() => {
isMountedReady.value = true;
})
</script>
<style lang="less" scoped>
.preview-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #000;
z-index: 99999;
/* 抛弃 flex 布局,防止 width: 100vh 被父级限制而发生坍缩 */
}
.preview-overlay .preview-image {
position: absolute;
top: 50%;
left: 50%;
width: 100vh;
height: 100vw;
/* 先拉回自身中心点,再围绕中心点旋转 90 度 */
transform: translate(-50%, -50%) rotate(90deg);
}
.honor-of-kings {
width: 100%;
overflow-x: hidden;
}
.painter-container {
/* 强制画板缩放到设备屏幕宽度,避免物理 px 超出屏幕 */
padding: 8px;
zoom: calc(100vw / 798);
width: 100%;
max-width: 1000px;
/* 限制PC/iPad端的最大宽度 */
margin: 0 auto;
}
.save-action {
margin-top: 60rpx;
display: flex;
flex-direction: column;
align-items: center;
padding-bottom: 220rpx;
/* 留出底部主题固定栏的安全空间 */
.save-btn {
margin-top: 60rpx;
width: 316rpx;
background: #1777FF;
color: #fff;
border-radius: 56rpx;
}
}
.theme-selector {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
padding-top: 20rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
z-index: 99;
.theme-scroll {
width: 100%;
white-space: nowrap;
::-webkit-scrollbar {
display: none;
width: 0 !important;
height: 0 !important;
-webkit-appearance: none;
background: transparent;
}
}
.theme-list {
display: inline-block;
padding: 0 20rpx;
.theme-item {
display: inline-flex;
vertical-align: top;
margin: 0 10rpx;
padding: 0 40rpx;
height: 84rpx;
border-radius: 12rpx;
background-color: #FFFFFF;
justify-content: center;
align-items: center;
border: 2rpx solid transparent;
box-sizing: border-box;
transition: all 0.3s;
&.active {
background-color: #fff;
border-color: #3B7BFF;
.theme-text {
color: #3B7BFF;
font-weight: bold;
}
}
.theme-text {
font-size: 28rpx;
color: #666;
}
}
}
}
.edit-popup-content {
background-color: #fff;
border-radius: 20rpx;
width: 85vw;
.popup-header {
display: flex;
justify-content: center;
align-items: center;
padding: 40rpx 0 20rpx 0;
.title {
font-size: 34rpx;
font-weight: bold;
color: #333;
}
}
.popup-scroll {
height: 55vh;
padding: 20rpx 40rpx;
box-sizing: border-box;
}
.form-item {
display: flex;
align-items: center;
margin-bottom: 16rpx;
padding-bottom: 16rpx;
.label {
width: 200rpx;
font-size: 28rpx;
color: #333;
}
.avatar-uploader {
display: flex;
align-items: center;
.upload-btn {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
background-color: #999DA7;
display: flex;
justify-content: center;
align-items: center;
.plus {
font-size: 60rpx;
color: #fff;
font-weight: 300;
margin-top: -6rpx;
}
}
.avatar-preview {
position: relative;
width: 100rpx;
height: 100rpx;
.preview-img {
width: 100%;
height: 100%;
border-radius: 50%;
}
.delete-icon {
position: absolute;
top: -4rpx;
right: -4rpx;
width: 32rpx;
height: 32rpx;
background-color: red;
color: #fff;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
font-size: 30rpx;
line-height: 28rpx;
}
}
}
.input {
flex: 1;
font-size: 28rpx;
background-color: #F7F7F7;
border-radius: 12rpx;
height: 70rpx;
line-height: 70rpx;
padding: 0 20rpx;
color: #333;
}
.radio-group {
display: flex;
align-items: center;
gap: 40rpx;
.radio-item {
display: flex;
align-items: center;
cursor: pointer;
.radio-icon {
width: 28rpx;
height: 28rpx;
border-radius: 50%;
border: 2rpx solid #d9d9d9;
margin-right: 12rpx;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
&.active {
border-color: #3B7BFF;
&::after {
content: '';
width: 14rpx;
height: 14rpx;
border-radius: 50%;
background-color: #3B7BFF;
}
}
}
.radio-text {
font-size: 28rpx;
color: #666;
&.active {
color: #3B7BFF;
}
}
}
}
.button-group {
display: flex;
align-items: center;
flex-wrap: nowrap;
.button-item {
padding: 4rpx 16rpx;
border-radius: 30rpx;
font-size: 26rpx;
margin-right: 16rpx;
color: #666;
background-color: #F7F7F7;
border: 2rpx solid transparent;
white-space: nowrap;
cursor: pointer;
transition: all 0.2s;
&.active {
color: #3B7BFF;
background-color: rgba(59, 123, 255, 0.1);
border-color: #3B7BFF;
}
}
}
}
.popup-footer {
display: flex;
justify-content: space-between;
padding: 20rpx 40rpx 40rpx;
button {
width: 46%;
height: 76rpx;
line-height: 76rpx;
font-size: 30rpx;
border-radius: 12rpx;
margin: 0;
&::after {
border: none;
}
}
.cancel-btn {
background-color: #F4F4F4;
color: #666;
}
.confirm-btn {
background-color: #3B7BFF;
color: #fff;
}
}
}
</style>