1362 行
35 KiB
Vue
1362 行
35 KiB
Vue
<template>
|
||
<view class="create-activity-container" :class="{ 'theme-warm': currentThemeKey === 'warm' }">
|
||
<!-- 模式选择 Tab (AA制 / 项目制) -->
|
||
<view class="mode-switch-wrap">
|
||
<view
|
||
class="mode-item btn-active"
|
||
:class="{ active: form.payType === 'AA' }"
|
||
@click="form.payType = 'AA'"
|
||
>
|
||
<image class="mode-svg" :src="ICONS.bolt" mode="aspectFit" />
|
||
<view class="mode-text-box">
|
||
<text class="mode-title">AA制拼桌</text>
|
||
<text class="mode-desc">报名人均平摊费用</text>
|
||
</view>
|
||
</view>
|
||
<view
|
||
class="mode-item btn-active"
|
||
:class="{ active: form.payType === 'PROJECT' }"
|
||
@click="form.payType = 'PROJECT'"
|
||
>
|
||
<image class="mode-svg" :src="ICONS.trophy" mode="aspectFit" />
|
||
<view class="mode-text-box">
|
||
<text class="mode-title">房主请客</text>
|
||
<text class="mode-desc">房主全额买单请客</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 品类选择 -->
|
||
<view class="form-card">
|
||
<view class="card-label">选择活动品类</view>
|
||
<view class="game-pills">
|
||
<view
|
||
v-for="g in games"
|
||
:key="g"
|
||
class="game-pill btn-active"
|
||
:class="{ selected: form.game === g }"
|
||
@click="form.game = g"
|
||
>
|
||
{{ g }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 基础信息录入 -->
|
||
<view class="form-card">
|
||
<view class="input-row">
|
||
<text class="row-label">活动标题</text>
|
||
<input
|
||
class="row-input"
|
||
v-model="form.title"
|
||
placeholder="如:三里屯铜锅涮肉AA探店 / 工体纯K麦霸欢唱局"
|
||
placeholder-class="ph"
|
||
/>
|
||
</view>
|
||
|
||
<view class="input-row">
|
||
<text class="row-label">活动时段</text>
|
||
<input
|
||
class="row-input"
|
||
v-model="form.startTime"
|
||
placeholder="点选快捷时段或自定义输入"
|
||
placeholder-class="ph"
|
||
/>
|
||
</view>
|
||
|
||
<!-- 快捷时段点选胶囊 (告别纯手打易错) -->
|
||
<view class="quick-chip-row">
|
||
<text class="chip-label">快捷时段:</text>
|
||
<view class="quick-chips">
|
||
<view
|
||
v-for="timeItem in presetTimeOptions"
|
||
:key="timeItem"
|
||
class="time-chip btn-active"
|
||
:class="{ selected: form.startTime === timeItem }"
|
||
@click="form.startTime = timeItem"
|
||
>
|
||
{{ timeItem }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="input-row">
|
||
<view class="label-with-action">
|
||
<text class="row-label">地点/商圈</text>
|
||
<text class="btn-choose-loc btn-active" @click="handleChooseLocation">地图选点</text>
|
||
</view>
|
||
<input
|
||
class="row-input"
|
||
v-model="form.location"
|
||
placeholder="如:北京市朝阳区三里屯聚宝源 / 工体纯KTV 888包厢"
|
||
placeholder-class="ph"
|
||
/>
|
||
</view>
|
||
|
||
<!-- 合规示范商圈一键点选 (防风控与合规保障) -->
|
||
<view class="quick-chip-row">
|
||
<text class="chip-label">合规商圈:</text>
|
||
<view class="quick-chips">
|
||
<view
|
||
v-for="zoneItem in recommendPublicZones.slice(0, 4)"
|
||
:key="zoneItem"
|
||
class="zone-chip-item btn-active"
|
||
:class="{ selected: form.location === zoneItem }"
|
||
@click="form.location = zoneItem"
|
||
>
|
||
{{ zoneItem.split(' ')[0] }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 席位与费用配置 -->
|
||
<view class="form-card">
|
||
<view class="stepper-row">
|
||
<view class="stepper-info">
|
||
<text class="row-label">招募席位 (人)</text>
|
||
<text class="sub-label">包含房主在内的组局总人数 ({{ minParticipants }}-{{ maxParticipants }}人)</text>
|
||
</view>
|
||
<view class="stepper-box">
|
||
<button class="step-btn btn-active" :disabled="form.maxParticipants <= minParticipants" @click="changeParticipants(-1)">-</button>
|
||
<text class="step-val">{{ form.maxParticipants }} 人</text>
|
||
<button class="step-btn btn-active" :disabled="form.maxParticipants >= maxParticipants" @click="changeParticipants(1)">+</button>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="input-row" v-if="form.payType === 'AA'">
|
||
<text class="row-label">人均分摊 (元/人)</text>
|
||
<input
|
||
class="row-input price-input"
|
||
type="digit"
|
||
v-model="form.aaFee"
|
||
placeholder="如:50"
|
||
placeholder-class="price-ph"
|
||
/>
|
||
</view>
|
||
|
||
<view v-else>
|
||
<!-- 房主请客 / 悬赏组队 出价模式切换 -->
|
||
<view class="pricing-mode-row">
|
||
<text class="row-label">出价方式</text>
|
||
<view class="pricing-mode-group">
|
||
<view
|
||
class="pricing-mode-btn"
|
||
:class="{ active: form.pricingMode === 'PER_PERSON' }"
|
||
@click="form.pricingMode = 'PER_PERSON'"
|
||
>
|
||
按人出价
|
||
</view>
|
||
<view
|
||
class="pricing-mode-btn"
|
||
:class="{ active: form.pricingMode === 'TOTAL' }"
|
||
@click="form.pricingMode = 'TOTAL'"
|
||
>
|
||
包场总预算
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="input-row" v-if="form.pricingMode === 'PER_PERSON'">
|
||
<text class="row-label">单人出价 (元/人)</text>
|
||
<input
|
||
class="row-input price-input"
|
||
type="digit"
|
||
v-model="form.perPersonFee"
|
||
placeholder="如:500"
|
||
placeholder-class="price-ph"
|
||
/>
|
||
</view>
|
||
|
||
<!-- 常用赏金快捷选项 (按人出价) -->
|
||
<view class="preset-price-row" v-if="form.pricingMode === 'PER_PERSON'">
|
||
<text class="preset-label">快捷赏金:</text>
|
||
<view class="preset-chips">
|
||
<view
|
||
v-for="amt in presetPerPersonFees"
|
||
:key="amt"
|
||
class="preset-chip btn-active"
|
||
:class="{ selected: Number(form.perPersonFee) === amt }"
|
||
@click="form.perPersonFee = amt"
|
||
>
|
||
¥{{ amt }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="input-row" v-else>
|
||
<text class="row-label">房主买单总预算 (元)</text>
|
||
<input
|
||
class="row-input price-input"
|
||
type="digit"
|
||
v-model="form.totalFee"
|
||
placeholder="如:2000"
|
||
placeholder-class="price-ph"
|
||
/>
|
||
</view>
|
||
|
||
<!-- 常用总预算快捷选项 (包场总预算) -->
|
||
<view class="preset-price-row" v-if="form.pricingMode === 'TOTAL'">
|
||
<text class="preset-label">快捷预算:</text>
|
||
<view class="preset-chips">
|
||
<view
|
||
v-for="amt in presetTotalFees"
|
||
:key="amt"
|
||
class="preset-chip btn-active"
|
||
:class="{ selected: Number(form.totalFee) === amt }"
|
||
@click="form.totalFee = amt"
|
||
>
|
||
¥{{ amt }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="calc-preview">
|
||
<text class="preview-label">预算测算:</text>
|
||
<text class="preview-val highlight">
|
||
{{
|
||
form.payType === 'AA'
|
||
? `总费用预估约 ¥${calcTotalFee} (人均 ¥${form.aaFee || 0})`
|
||
: form.pricingMode === 'PER_PERSON'
|
||
? `单人出价 ¥${form.perPersonFee || 0} × 招募${form.maxParticipants}人 = 预估总额 ¥${calcTotalFee} (发单后可随时追加金额)`
|
||
: `房主全额买单请客,总预算约 ¥${form.totalFee || 0} (发单后可随时追加预算)`
|
||
}}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 房主调价与追加金额设置 (随时灵活追加) -->
|
||
<view class="form-card dynamic-price-card" v-if="form.payType === 'PROJECT'">
|
||
<view class="card-header-switch">
|
||
<view class="switch-title-box">
|
||
<text class="form-title">灵活调价与追加金额设置</text>
|
||
<text class="sub-label">组局进行中允许房主随时追加金额、加赏加急或修改单价</text>
|
||
</view>
|
||
<switch
|
||
:checked="form.allowDynamicPrice"
|
||
@change="form.allowDynamicPrice = $event.detail.value"
|
||
color="#6366F1"
|
||
/>
|
||
</view>
|
||
|
||
<view class="dynamic-config-body" v-if="form.allowDynamicPrice">
|
||
<text class="config-sec-title">追加金额/改价补差规则</text>
|
||
<view class="rule-cards">
|
||
<view
|
||
class="rule-card"
|
||
:class="{ active: form.priceAdjustRule === 'UNIFIED_HIGH' }"
|
||
@click="form.priceAdjustRule = 'UNIFIED_HIGH'"
|
||
>
|
||
<view class="rule-card-header">
|
||
<text class="rule-name">全员同享追加新高价</text>
|
||
<text class="rule-tag recommend">推荐</text>
|
||
</view>
|
||
<text class="rule-desc">
|
||
房主追加金额提价时(如从 500元/人 追加提高到 800元/人),已报名的成员自动同步补齐 300元 差额。先行者不吃亏,大幅提升组队热度。
|
||
</text>
|
||
</view>
|
||
|
||
<view
|
||
class="rule-card"
|
||
:class="{ active: form.priceAdjustRule === 'TIERED' }"
|
||
@click="form.priceAdjustRule = 'TIERED'"
|
||
>
|
||
<view class="rule-card-header">
|
||
<text class="rule-name">阶梯差价招募</text>
|
||
</view>
|
||
<text class="rule-desc">
|
||
追加金额仅对后续新加入的成员生效。已报名的老成员按其报名时的出价结算,互不影响。
|
||
</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 调价场景与降价提示说明 -->
|
||
<view class="scenario-notice">
|
||
<text class="notice-title">灵活追加金额说明:</text>
|
||
<text class="notice-item">• 随时追加金额:如原定 500元/人 招募4人,已有2人报名;房主在活动页可随时点击【追加金额】,选择按人追加(如每人追加 +¥300)或整局追加预算,系统自动完成老成员差额补偿与看板刷新。</text>
|
||
<text class="notice-item">• 降价调整保护:若房主手动调低单价,已报名的 2 人仍按原价受协议保护,新报名单人出价生效。</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 底部发起操作栏 (适配安全区) -->
|
||
<view class="bottom-bar">
|
||
<button class="btn-submit btn-active" @click="handleSubmit">
|
||
立即发起同城组局
|
||
</button>
|
||
</view>
|
||
|
||
<!-- 敏感商圈智能风控友好预检弹窗 (P1安全风控) -->
|
||
<view class="risk-modal-mask" v-if="riskModalVisible" @click.self="riskModalVisible = false">
|
||
<view class="risk-modal-box">
|
||
<view class="risk-modal-header">
|
||
<image class="risk-shield-icon" :src="ICONS.shield" mode="aspectFit" />
|
||
<text class="risk-title">同城线下组局安全风控提示</text>
|
||
</view>
|
||
<view class="risk-body">
|
||
<text class="risk-desc">
|
||
平台严格保障人身安全,严禁将私人住宅、酒店客房、封闭公寓等非公开场所作为履约地点。
|
||
</text>
|
||
<text class="risk-sub-tip">请选择以下平台认证的示范公开商圈:</text>
|
||
<view class="recommend-zones">
|
||
<view
|
||
v-for="zone in recommendPublicZones"
|
||
:key="zone"
|
||
class="zone-chip btn-active"
|
||
@click="applyRecommendZone(zone)"
|
||
>
|
||
<image class="zone-pin-icon" :src="ICONS.mapPin" mode="aspectFit" />
|
||
<text class="zone-text">{{ zone }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="risk-footer">
|
||
<button class="risk-cancel-btn btn-active" @click="riskModalVisible = false">修改地点</button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed, onMounted, onUnmounted } from 'vue';
|
||
import { onShow } from '@dcloudio/uni-app';
|
||
import { ICONS } from '@/common/icons.js';
|
||
import { createActivity, getSafetyPlaces, getNavCategories } from '@/common/api.js';
|
||
import { getCurrentThemeKey, applyThemeToNativeUI } from '@/common/theme.js';
|
||
|
||
const games = ref(['美食陪吃', '同城陪唱', '下午茶陪喝', '同城微醺', '同城桌游', '热门电竞']);
|
||
const currentThemeKey = ref(getCurrentThemeKey());
|
||
|
||
const onThemeChanged = (key) => {
|
||
currentThemeKey.value = key;
|
||
applyThemeToNativeUI(key);
|
||
};
|
||
|
||
onMounted(() => {
|
||
currentThemeKey.value = getCurrentThemeKey();
|
||
applyThemeToNativeUI(currentThemeKey.value);
|
||
uni.$on('theme-change', onThemeChanged);
|
||
loadLivePlaces();
|
||
});
|
||
|
||
onShow(() => {
|
||
currentThemeKey.value = getCurrentThemeKey();
|
||
applyThemeToNativeUI(currentThemeKey.value);
|
||
loadLivePlaces();
|
||
});
|
||
|
||
onUnmounted(() => {
|
||
uni.$off('theme-change', onThemeChanged);
|
||
});
|
||
|
||
const form = ref({
|
||
payType: 'PROJECT',
|
||
game: '美食陪吃',
|
||
title: '',
|
||
startTime: '周六 18:30',
|
||
location: '北京市朝阳区三里屯商圈',
|
||
maxParticipants: 4,
|
||
aaFee: 50,
|
||
pricingMode: 'PER_PERSON',
|
||
perPersonFee: 500,
|
||
totalFee: 2000,
|
||
allowDynamicPrice: true,
|
||
priceAdjustRule: 'UNIFIED_HIGH',
|
||
});
|
||
|
||
const calcTotalFee = computed(() => {
|
||
if (form.value.payType === 'AA') {
|
||
return (Number(form.value.aaFee) || 0) * form.value.maxParticipants;
|
||
}
|
||
if (form.value.pricingMode === 'PER_PERSON') {
|
||
return (Number(form.value.perPersonFee) || 0) * form.value.maxParticipants;
|
||
}
|
||
return Number(form.value.totalFee) || 0;
|
||
});
|
||
|
||
const riskModalVisible = ref(false);
|
||
const recommendPublicZones = ref([
|
||
'北京市朝阳区三里屯太古里 (AAA公开商圈)',
|
||
'北京市朝阳区工体纯K量贩KTV (正规量贩)',
|
||
'北京市朝阳区国贸CBD商业街 (阳光示范商圈)',
|
||
'北京市海淀区五道口购物中心 (高校商圈)'
|
||
]);
|
||
|
||
const presetTimeOptions = ref([
|
||
'今晚 19:30',
|
||
'今晚 20:30',
|
||
'明天 14:00',
|
||
'周六 18:30',
|
||
'周日 15:00'
|
||
]);
|
||
|
||
const handleChooseLocation = () => {
|
||
// #ifdef MP-WEIXIN || APP-PLUS
|
||
uni.chooseLocation({
|
||
success: (res) => {
|
||
if (res && (res.name || res.address)) {
|
||
form.value.location = res.name ? `${res.address ? res.address + ' ' : ''}${res.name}` : res.address;
|
||
uni.showToast({ title: '已选取地点', icon: 'success' });
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
console.warn('[ActivityCreate] 地图选点取消或未授权:', err);
|
||
// 若未授权或在H5/开发环境,平滑引导点选推荐公开商圈
|
||
if (recommendPublicZones.value.length > 0) {
|
||
form.value.location = recommendPublicZones.value[0];
|
||
uni.showToast({ title: '已填入推荐商圈', icon: 'none' });
|
||
}
|
||
}
|
||
});
|
||
// #endif
|
||
|
||
// #ifndef MP-WEIXIN || APP-PLUS
|
||
if (recommendPublicZones.value.length > 0) {
|
||
form.value.location = recommendPublicZones.value[0];
|
||
uni.showToast({ title: '已为您填入示范商圈', icon: 'none' });
|
||
}
|
||
// #endif
|
||
};
|
||
|
||
const minParticipants = ref(2);
|
||
const maxParticipants = ref(10);
|
||
const presetPerPersonFees = ref([200, 300, 500, 800, 1000]);
|
||
const presetTotalFees = ref([500, 1000, 2000, 3000, 5000]);
|
||
|
||
const loadLivePlaces = async () => {
|
||
try {
|
||
const [placesList, catList, configsRes] = await Promise.allSettled([
|
||
getSafetyPlaces(),
|
||
getNavCategories(),
|
||
getPlatformConfigs()
|
||
]);
|
||
|
||
if (placesList.status === 'fulfilled' && Array.isArray(placesList.value) && placesList.value.length > 0) {
|
||
recommendPublicZones.value = placesList.value
|
||
.filter((p) => p.status === '正常营业')
|
||
.map((p) => `${p.area} · ${p.name}`);
|
||
}
|
||
|
||
if (catList.status === 'fulfilled' && Array.isArray(catList.value) && catList.value.length > 0) {
|
||
const activeCats = catList.value
|
||
.filter((c) => c.status === 1 && c.name && c.name !== '全部活动')
|
||
.map((c) => c.name);
|
||
if (activeCats.length > 0) {
|
||
games.value = activeCats;
|
||
if (!games.value.includes(form.value.game)) {
|
||
form.value.game = games.value[0];
|
||
}
|
||
}
|
||
}
|
||
|
||
if (configsRes.status === 'fulfilled' && configsRes.value?.activity_rules) {
|
||
const actRules = configsRes.value.activity_rules;
|
||
if (actRules.minParticipants) minParticipants.value = Number(actRules.minParticipants);
|
||
if (actRules.maxParticipants) maxParticipants.value = Number(actRules.maxParticipants);
|
||
if (Array.isArray(actRules.presetPerPersonFees) && actRules.presetPerPersonFees.length > 0) {
|
||
presetPerPersonFees.value = actRules.presetPerPersonFees;
|
||
}
|
||
if (Array.isArray(actRules.presetTotalFees) && actRules.presetTotalFees.length > 0) {
|
||
presetTotalFees.value = actRules.presetTotalFees;
|
||
}
|
||
}
|
||
} catch (e) {
|
||
console.warn('[ActivityCreate] 加载合规场所与品类异常降级:', e);
|
||
}
|
||
};
|
||
|
||
const applyRecommendZone = (zone) => {
|
||
form.value.location = zone;
|
||
riskModalVisible.value = false;
|
||
uni.showToast({
|
||
title: '已选定合规商圈,请继续发起',
|
||
icon: 'none',
|
||
duration: 1500
|
||
});
|
||
};
|
||
|
||
const changeParticipants = (delta) => {
|
||
form.value.maxParticipants = Math.max(
|
||
minParticipants.value,
|
||
Math.min(maxParticipants.value, form.value.maxParticipants + delta)
|
||
);
|
||
};
|
||
|
||
const handleSubmit = async () => {
|
||
// P1 敏感商圈安全风控友好预检拦截
|
||
const sensitivePattern = /(酒店|客房|宾馆|民宿|旅馆|公寓|小区|住宅|私密|住宅区|私人房|卧室)/;
|
||
if (sensitivePattern.test(form.value.location)) {
|
||
riskModalVisible.value = true;
|
||
return;
|
||
}
|
||
|
||
if (!form.value.title.trim()) {
|
||
form.value.title = `【${form.value.game}】同城聚会组局`;
|
||
}
|
||
|
||
const isProject = form.value.payType === 'PROJECT';
|
||
const perPerson = isProject && form.value.pricingMode === 'PER_PERSON' ? (Number(form.value.perPersonFee) || 0) : 0;
|
||
|
||
const newActivityPayload = {
|
||
creatorId: 1001,
|
||
game: form.value.game,
|
||
title: form.value.title,
|
||
payType: form.value.payType,
|
||
pricingMode: isProject ? form.value.pricingMode : 'AA',
|
||
perPersonFee: perPerson,
|
||
allowDynamicPrice: isProject ? form.value.allowDynamicPrice : false,
|
||
priceAdjustRule: form.value.priceAdjustRule,
|
||
totalFee: calcTotalFee.value,
|
||
aaFee: Number(form.value.aaFee) || 0,
|
||
maxParticipants: form.value.maxParticipants,
|
||
startTime: form.value.startTime,
|
||
location: form.value.location,
|
||
creatorNickname: '同城局长',
|
||
creatorAvatar: 'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=150&h=150&fit=crop',
|
||
};
|
||
|
||
uni.showLoading({ title: '正在发布组局...' });
|
||
|
||
try {
|
||
await createActivity(newActivityPayload);
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: '组局发起成功!等待好友加入',
|
||
icon: 'success',
|
||
duration: 1500
|
||
});
|
||
setTimeout(() => {
|
||
uni.switchTab({
|
||
url: '/pages/activity/list'
|
||
});
|
||
}, 1200);
|
||
} catch (err) {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: err.message || '发布异常,请重试',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.create-activity-container {
|
||
min-height: 100vh;
|
||
background-color: #0A0F1D;
|
||
padding: 24rpx 32rpx calc(160rpx + env(safe-area-inset-bottom));
|
||
}
|
||
|
||
.mode-switch-wrap {
|
||
display: flex;
|
||
gap: 16rpx;
|
||
margin-bottom: 24rpx;
|
||
|
||
.mode-item {
|
||
flex: 1;
|
||
background: #151D30;
|
||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||
border-radius: 20rpx;
|
||
padding: 20rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 14rpx;
|
||
|
||
.mode-svg {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
}
|
||
|
||
.mode-text-box {
|
||
display: flex;
|
||
flex-direction: column;
|
||
|
||
.mode-title {
|
||
font-size: 26rpx;
|
||
font-weight: 700;
|
||
color: #F8FAFC;
|
||
margin-bottom: 4rpx;
|
||
}
|
||
.mode-desc {
|
||
font-size: 18rpx;
|
||
color: #64748B;
|
||
}
|
||
}
|
||
|
||
&.active {
|
||
background: linear-gradient(135deg, rgba(99, 102, 241, 0.18) 0%, rgba(139, 92, 246, 0.1) 100%);
|
||
border-color: #6366F1;
|
||
box-shadow: 0 0 16rpx rgba(99, 102, 241, 0.3);
|
||
|
||
.mode-title {
|
||
color: #818CF8;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.form-card {
|
||
background: #151D30;
|
||
border-radius: 24rpx;
|
||
padding: 28rpx;
|
||
margin-bottom: 24rpx;
|
||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||
|
||
.card-label {
|
||
font-size: 26rpx;
|
||
font-weight: 700;
|
||
color: #F8FAFC;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.game-pills {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 14rpx;
|
||
|
||
.game-pill {
|
||
font-size: 24rpx;
|
||
color: #94A3B8;
|
||
background: rgba(255, 255, 255, 0.04);
|
||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||
padding: 10rpx 24rpx;
|
||
border-radius: 28rpx;
|
||
|
||
&.selected {
|
||
background: rgba(99, 102, 241, 0.2);
|
||
color: #818CF8;
|
||
border-color: #6366F1;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
}
|
||
|
||
.input-row {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 20rpx 0;
|
||
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
|
||
|
||
&:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.row-label {
|
||
width: 220rpx;
|
||
font-size: 26rpx;
|
||
color: #CBD5E1;
|
||
height: 48rpx;
|
||
line-height: 48rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.row-input {
|
||
flex: 1;
|
||
font-size: 26rpx;
|
||
color: #F8FAFC;
|
||
height: 48rpx;
|
||
line-height: 48rpx;
|
||
box-sizing: border-box;
|
||
|
||
&.price-input {
|
||
font-size: 34rpx;
|
||
font-weight: 700;
|
||
color: #F8FAFC;
|
||
letter-spacing: 0.5px;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
}
|
||
|
||
.ph {
|
||
color: #475569;
|
||
}
|
||
|
||
.price-ph {
|
||
font-size: 26rpx;
|
||
font-weight: normal;
|
||
color: #475569;
|
||
}
|
||
|
||
.label-with-action {
|
||
width: 220rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding-right: 16rpx;
|
||
box-sizing: border-box;
|
||
|
||
.row-label {
|
||
width: auto;
|
||
}
|
||
|
||
.btn-choose-loc {
|
||
font-size: 20rpx;
|
||
color: #38BDF8;
|
||
background: rgba(56, 189, 248, 0.12);
|
||
padding: 4rpx 10rpx;
|
||
border-radius: 6rpx;
|
||
cursor: pointer;
|
||
}
|
||
}
|
||
}
|
||
|
||
.quick-chip-row {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 12rpx 0 16rpx;
|
||
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
|
||
|
||
.chip-label {
|
||
font-size: 22rpx;
|
||
color: #64748B;
|
||
width: 140rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.quick-chips {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 12rpx;
|
||
|
||
.time-chip, .zone-chip-item {
|
||
font-size: 22rpx;
|
||
color: #94A3B8;
|
||
background: rgba(255, 255, 255, 0.04);
|
||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||
padding: 6rpx 16rpx;
|
||
border-radius: 12rpx;
|
||
transition: all 0.15s;
|
||
|
||
&.selected {
|
||
color: #818CF8;
|
||
border-color: #6366F1;
|
||
background: rgba(99, 102, 241, 0.15);
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
|
||
.zone-chip-item.selected {
|
||
color: #38BDF8;
|
||
border-color: #38BDF8;
|
||
background: rgba(56, 189, 248, 0.15);
|
||
}
|
||
}
|
||
}
|
||
|
||
.stepper-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding-bottom: 20rpx;
|
||
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
|
||
|
||
.stepper-info {
|
||
display: flex;
|
||
flex-direction: column;
|
||
|
||
.row-label {
|
||
font-size: 26rpx;
|
||
color: #CBD5E1;
|
||
font-weight: 600;
|
||
}
|
||
.sub-label {
|
||
font-size: 20rpx;
|
||
color: #64748B;
|
||
margin-top: 4rpx;
|
||
}
|
||
}
|
||
|
||
.stepper-box {
|
||
display: flex;
|
||
align-items: center;
|
||
background: rgba(255, 255, 255, 0.04);
|
||
border-radius: 16rpx;
|
||
padding: 6rpx;
|
||
|
||
.step-btn {
|
||
width: 68rpx;
|
||
height: 68rpx;
|
||
line-height: 64rpx;
|
||
padding: 0;
|
||
background: #1E2942;
|
||
color: #FFF;
|
||
font-size: 32rpx;
|
||
border-radius: 12rpx;
|
||
border: none;
|
||
margin: 0;
|
||
}
|
||
|
||
.step-val {
|
||
font-size: 28rpx;
|
||
color: #F8FAFC;
|
||
font-weight: 600;
|
||
margin: 0 20rpx;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
}
|
||
}
|
||
|
||
.calc-preview {
|
||
margin-top: 20rpx;
|
||
padding: 16rpx 20rpx;
|
||
background: rgba(99, 102, 241, 0.08);
|
||
border-radius: 14rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.preview-label {
|
||
font-size: 22rpx;
|
||
color: #94A3B8;
|
||
}
|
||
.preview-val {
|
||
font-size: 22rpx;
|
||
color: #10B981;
|
||
font-weight: 600;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
}
|
||
|
||
.pricing-mode-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 20rpx 0;
|
||
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
|
||
|
||
.pricing-mode-group {
|
||
display: flex;
|
||
gap: 12rpx;
|
||
|
||
.pricing-mode-btn {
|
||
font-size: 22rpx;
|
||
padding: 8rpx 22rpx;
|
||
border-radius: 20rpx;
|
||
background: rgba(255, 255, 255, 0.05);
|
||
color: #94A3B8;
|
||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||
|
||
&.active {
|
||
background: rgba(99, 102, 241, 0.2);
|
||
color: #818CF8;
|
||
border-color: #6366F1;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
.preset-price-row {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 14rpx 0;
|
||
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
|
||
|
||
.preset-label {
|
||
font-size: 20rpx;
|
||
color: #94A3B8;
|
||
width: 140rpx;
|
||
}
|
||
|
||
.preset-chips {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 12rpx;
|
||
|
||
.preset-chip {
|
||
font-size: 22rpx;
|
||
padding: 6rpx 18rpx;
|
||
border-radius: 12rpx;
|
||
background: rgba(255, 255, 255, 0.04);
|
||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||
color: #CBD5E1;
|
||
|
||
&.selected {
|
||
background: rgba(99, 102, 241, 0.2);
|
||
border-color: #6366F1;
|
||
color: #818CF8;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
&.dynamic-price-card {
|
||
.card-header-switch {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
|
||
.switch-title-box {
|
||
display: flex;
|
||
flex-direction: column;
|
||
|
||
.form-title {
|
||
font-size: 28rpx;
|
||
font-weight: 700;
|
||
color: #F8FAFC;
|
||
}
|
||
.sub-label {
|
||
font-size: 20rpx;
|
||
color: #64748B;
|
||
margin-top: 4rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
.dynamic-config-body {
|
||
margin-top: 24rpx;
|
||
padding-top: 20rpx;
|
||
border-top: 1px solid rgba(255, 255, 255, 0.04);
|
||
|
||
.config-sec-title {
|
||
font-size: 22rpx;
|
||
font-weight: 600;
|
||
color: #94A3B8;
|
||
display: block;
|
||
margin-bottom: 14rpx;
|
||
}
|
||
|
||
.rule-cards {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 14rpx;
|
||
|
||
.rule-card {
|
||
background: rgba(255, 255, 255, 0.03);
|
||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||
border-radius: 16rpx;
|
||
padding: 18rpx 20rpx;
|
||
|
||
&.active {
|
||
background: rgba(99, 102, 241, 0.12);
|
||
border-color: #6366F1;
|
||
}
|
||
|
||
.rule-card-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12rpx;
|
||
margin-bottom: 8rpx;
|
||
|
||
.rule-name {
|
||
font-size: 26rpx;
|
||
font-weight: 700;
|
||
color: #F8FAFC;
|
||
}
|
||
|
||
.rule-tag {
|
||
font-size: 18rpx;
|
||
padding: 2rpx 10rpx;
|
||
border-radius: 6rpx;
|
||
|
||
&.recommend {
|
||
background: rgba(16, 185, 129, 0.2);
|
||
color: #10B981;
|
||
}
|
||
}
|
||
}
|
||
|
||
.rule-desc {
|
||
font-size: 20rpx;
|
||
color: #94A3B8;
|
||
line-height: 1.45;
|
||
display: block;
|
||
}
|
||
}
|
||
}
|
||
|
||
.scenario-notice {
|
||
margin-top: 20rpx;
|
||
padding: 16rpx 20rpx;
|
||
background: rgba(99, 102, 241, 0.08);
|
||
border: 1px dashed rgba(99, 102, 241, 0.3);
|
||
border-radius: 14rpx;
|
||
|
||
.notice-title {
|
||
font-size: 22rpx;
|
||
font-weight: 700;
|
||
color: #818CF8;
|
||
display: block;
|
||
margin-bottom: 6rpx;
|
||
}
|
||
|
||
.notice-item {
|
||
font-size: 20rpx;
|
||
color: #94A3B8;
|
||
line-height: 1.5;
|
||
display: block;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.bottom-bar {
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: calc(120rpx + env(safe-area-inset-bottom));
|
||
padding: 0 32rpx env(safe-area-inset-bottom);
|
||
box-sizing: border-box;
|
||
background-color: rgba(21, 29, 48, 0.95);
|
||
backdrop-filter: blur(12px);
|
||
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
||
display: flex;
|
||
align-items: center;
|
||
z-index: 100;
|
||
max-width: 450px;
|
||
margin: 0 auto;
|
||
|
||
.btn-submit {
|
||
flex: 1;
|
||
background: linear-gradient(135deg, #6366F1 0%, #8B5CF6 100%);
|
||
color: #FFF;
|
||
font-size: 28rpx;
|
||
font-weight: 700;
|
||
border-radius: 44rpx;
|
||
height: 84rpx;
|
||
line-height: 84rpx;
|
||
box-shadow: 0 4rpx 20rpx rgba(99, 102, 241, 0.4);
|
||
margin: 0;
|
||
}
|
||
}
|
||
|
||
.create-activity-container.theme-warm {
|
||
background-color: #FDFBF7;
|
||
|
||
.mode-switch-wrap .mode-item {
|
||
background-color: #FFFFFF;
|
||
border-color: #F0ECE4;
|
||
box-shadow: 0 4rpx 16rpx rgba(28, 25, 23, 0.04);
|
||
|
||
.mode-text-box .mode-title {
|
||
color: #1C1917;
|
||
}
|
||
.mode-text-box .mode-desc {
|
||
color: #78716C;
|
||
}
|
||
|
||
&.active {
|
||
background: rgba(234, 88, 12, 0.08);
|
||
border-color: #EA580C;
|
||
.mode-text-box .mode-title {
|
||
color: #EA580C;
|
||
}
|
||
}
|
||
}
|
||
|
||
.form-card {
|
||
background-color: #FFFFFF;
|
||
border-color: #F0ECE4;
|
||
box-shadow: 0 4rpx 20rpx rgba(28, 25, 23, 0.05);
|
||
|
||
.card-label {
|
||
color: #1C1917;
|
||
}
|
||
|
||
.game-pills .game-pill {
|
||
background: #F8F5F0;
|
||
border-color: #E7E5E4;
|
||
color: #78716C;
|
||
|
||
&.selected {
|
||
background: rgba(234, 88, 12, 0.1);
|
||
border-color: #EA580C;
|
||
color: #EA580C;
|
||
font-weight: 700;
|
||
}
|
||
}
|
||
|
||
.stepper-row {
|
||
border-bottom-color: #F5F2EC;
|
||
|
||
.stepper-info {
|
||
.row-label {
|
||
color: #1C1917;
|
||
}
|
||
.sub-label {
|
||
color: #78716C;
|
||
}
|
||
}
|
||
|
||
.stepper-box {
|
||
background: #F8F5F0;
|
||
border: 1px solid #E7E5E4;
|
||
|
||
.step-btn {
|
||
background: #FFFFFF;
|
||
color: #1C1917;
|
||
border: 1px solid #E7E5E4;
|
||
box-shadow: 0 2rpx 6rpx rgba(28, 25, 23, 0.04);
|
||
|
||
&:disabled {
|
||
color: #A8A29E;
|
||
background: #F5F2EC;
|
||
border-color: #E7E5E4;
|
||
}
|
||
}
|
||
|
||
.step-val {
|
||
color: #1C1917;
|
||
font-weight: 700;
|
||
}
|
||
}
|
||
}
|
||
|
||
.form-title {
|
||
color: #1C1917;
|
||
}
|
||
.input-row {
|
||
border-bottom-color: #F5F2EC;
|
||
.row-label {
|
||
color: #1C1917;
|
||
}
|
||
.row-input {
|
||
color: #1C1917;
|
||
|
||
&.price-input {
|
||
color: #000000;
|
||
font-weight: 800;
|
||
}
|
||
}
|
||
.price-ph {
|
||
color: #A8A29E;
|
||
}
|
||
}
|
||
.calc-preview {
|
||
background: #F8F5F0;
|
||
.preview-label {
|
||
color: #78716C;
|
||
}
|
||
}
|
||
|
||
.pricing-mode-row {
|
||
border-bottom-color: #F5F2EC;
|
||
.pricing-mode-btn {
|
||
background: #F8F5F0;
|
||
color: #78716C;
|
||
border-color: #E7E5E4;
|
||
&.active {
|
||
background: rgba(234, 88, 12, 0.1);
|
||
color: #EA580C;
|
||
border-color: #EA580C;
|
||
}
|
||
}
|
||
}
|
||
|
||
.preset-price-row {
|
||
border-bottom-color: #F5F2EC;
|
||
.preset-label {
|
||
color: #78716C;
|
||
}
|
||
.preset-chips .preset-chip {
|
||
background: #F8F5F0;
|
||
border-color: #E7E5E4;
|
||
color: #78716C;
|
||
&.selected {
|
||
background: rgba(234, 88, 12, 0.1);
|
||
border-color: #EA580C;
|
||
color: #EA580C;
|
||
font-weight: 700;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
&.dynamic-price-card {
|
||
.card-header-switch .switch-title-box .form-title {
|
||
color: #1C1917;
|
||
}
|
||
.dynamic-config-body {
|
||
border-top-color: #F5F2EC;
|
||
.config-sec-title {
|
||
color: #78716C;
|
||
}
|
||
.rule-cards .rule-card {
|
||
background: #FAFAF9;
|
||
border-color: #E7E5E4;
|
||
&.active {
|
||
background: rgba(234, 88, 12, 0.06);
|
||
border-color: #EA580C;
|
||
.rule-card-header .rule-name {
|
||
color: #EA580C;
|
||
}
|
||
}
|
||
.rule-card-header .rule-name {
|
||
color: #1C1917;
|
||
}
|
||
.rule-desc {
|
||
color: #78716C;
|
||
}
|
||
}
|
||
.scenario-notice {
|
||
background: #FFF7ED;
|
||
border-color: #FDBA74;
|
||
.notice-title {
|
||
color: #EA580C;
|
||
}
|
||
.notice-item {
|
||
color: #78716C;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.bottom-bar {
|
||
background-color: rgba(253, 251, 247, 0.95);
|
||
border-top-color: #F0ECE4;
|
||
|
||
.btn-submit {
|
||
background: linear-gradient(135deg, #F97316 0%, #EA580C 100%);
|
||
box-shadow: 0 4rpx 20rpx rgba(234, 88, 12, 0.35);
|
||
}
|
||
}
|
||
|
||
.risk-modal-box {
|
||
background: #FFFFFF;
|
||
border-color: rgba(239, 68, 68, 0.4);
|
||
|
||
.risk-modal-header .risk-title {
|
||
color: #DC2626;
|
||
}
|
||
|
||
.risk-body {
|
||
.risk-desc {
|
||
color: #475569;
|
||
}
|
||
.risk-sub-tip {
|
||
color: #64748B;
|
||
}
|
||
.recommend-zones .zone-chip {
|
||
background: rgba(234, 88, 12, 0.08);
|
||
border-color: rgba(234, 88, 12, 0.25);
|
||
.zone-text {
|
||
color: #EA580C;
|
||
}
|
||
}
|
||
}
|
||
|
||
.risk-footer .risk-cancel-btn {
|
||
background: #F1F5F9;
|
||
color: #334155;
|
||
border-color: #CBD5E1;
|
||
}
|
||
}
|
||
}
|
||
|
||
.risk-modal-mask {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: rgba(0, 0, 0, 0.75);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 999;
|
||
padding: 40rpx;
|
||
backdrop-filter: blur(6px);
|
||
}
|
||
|
||
.risk-modal-box {
|
||
width: 100%;
|
||
max-width: 620rpx;
|
||
background: #151D30;
|
||
border: 1px solid rgba(239, 68, 68, 0.35);
|
||
border-radius: 28rpx;
|
||
padding: 36rpx;
|
||
box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.6);
|
||
|
||
.risk-modal-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 14rpx;
|
||
margin-bottom: 20rpx;
|
||
|
||
.risk-shield-icon {
|
||
width: 44rpx;
|
||
height: 44rpx;
|
||
}
|
||
|
||
.risk-title {
|
||
font-size: 30rpx;
|
||
font-weight: 700;
|
||
color: #F87171;
|
||
}
|
||
}
|
||
|
||
.risk-body {
|
||
margin-bottom: 30rpx;
|
||
|
||
.risk-desc {
|
||
display: block;
|
||
font-size: 24rpx;
|
||
color: #CBD5E1;
|
||
line-height: 1.6;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.risk-sub-tip {
|
||
display: block;
|
||
font-size: 22rpx;
|
||
color: #94A3B8;
|
||
margin-bottom: 16rpx;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.recommend-zones {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12rpx;
|
||
|
||
.zone-chip {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12rpx;
|
||
background: rgba(99, 102, 241, 0.12);
|
||
border: 1px solid rgba(99, 102, 241, 0.3);
|
||
border-radius: 14rpx;
|
||
padding: 16rpx 20rpx;
|
||
|
||
.zone-pin-icon {
|
||
width: 28rpx;
|
||
height: 28rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.zone-text {
|
||
font-size: 24rpx;
|
||
color: #A5B4FC;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.risk-footer {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
|
||
.risk-cancel-btn {
|
||
width: 100%;
|
||
height: 72rpx;
|
||
line-height: 72rpx;
|
||
background: #1E293B;
|
||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||
color: #E2E8F0;
|
||
font-size: 26rpx;
|
||
border-radius: 16rpx;
|
||
}
|
||
}
|
||
}
|
||
</style>
|