配置: - manifest.json mp-weixin.appid = wx40ca4b02d4d1cb58(构建产物已自动同步) - .env 新增 [sms] 段:mock / mock_code,手机号登录验证码改为配置驱动 (Auth::login 不再硬编码 123456;mock=0 时返回 2010 提示接入短信) - 服务端 .env [wechat] appid/secret 已就位并与小程序一致 加固: - 新增 utils/wxlogin.js:微信登录单飞(防静默登录与手动登录抢同一个一次性 code) + 40029/40163 自动换新 code 重试一次 - Auth::wxlogin 失败时回传 wx_errcode,供客户端判断是否重试 - 登录失败自动展开手机号兜底通道 新增 tests/config_check.js:一键核对 appid 三处一致性 / 接口连通 / HTTPS 证书 / 短信开关 验证:config_check 8/8 + 163 项断言回归全通过
1214 行
28 KiB
Vue
1214 行
28 KiB
Vue
<!--
|
||
优匠优服 · 首页(UI 设计稿)
|
||
主题:橙金体系 主橙 #F0710D / 亮橙 #FFA93F / 线稿棕橙 #B85E2A
|
||
说明:全部图标由纯 CSS 绘制(数据驱动),无图片资源依赖,小程序端 100% 兼容
|
||
-->
|
||
<template>
|
||
<view class="page">
|
||
|
||
<!-- ==================== 橙色渐变头部 ==================== -->
|
||
<view class="header">
|
||
<view class="header-bg">
|
||
<view class="deco deco-1"></view>
|
||
<view class="deco deco-2"></view>
|
||
<view class="deco deco-3"></view>
|
||
</view>
|
||
|
||
<!-- 自定义导航 -->
|
||
<view class="nav" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||
<view class="nav-inner" :style="{ height: navBarHeight + 'px' }">
|
||
<view class="nav-home" @tap="onHome">
|
||
<view class="nh-roof"></view>
|
||
<view class="nh-body"></view>
|
||
</view>
|
||
<text class="nav-title">优匠优服</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 问候 + 优惠券 -->
|
||
<view class="greet">
|
||
<view class="greet-l">
|
||
<view class="avatar-ring">
|
||
<view class="avatar">
|
||
<view class="av-head"></view>
|
||
<view class="av-body"></view>
|
||
</view>
|
||
</view>
|
||
<view class="greet-txt">
|
||
<text class="greet-hi">{{ greeting }},欢迎回来</text>
|
||
<text class="greet-name">qbdjsj1308160</text>
|
||
</view>
|
||
</view>
|
||
<view class="coupon" @tap="onCoupon">
|
||
<text class="coupon-tag">券</text>
|
||
<text class="coupon-text">优惠券待领取</text>
|
||
<view class="coupon-btn">领取</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- ==================== 悬浮搜索 ==================== -->
|
||
<view class="search-wrap">
|
||
<view class="search">
|
||
<view class="search-ic">
|
||
<view class="si-ring"></view>
|
||
<view class="si-handle"></view>
|
||
</view>
|
||
<text class="search-ph">搜索服务 / 师傅 / 品类</text>
|
||
</view>
|
||
<view class="search-btn" @tap="onSearch">搜索</view>
|
||
</view>
|
||
|
||
<!-- ==================== 内容区 ==================== -->
|
||
<view class="content">
|
||
|
||
<!-- 服务保障 -->
|
||
<view class="assure">
|
||
<view class="assure-item" v-for="(a, i) in assures" :key="i">
|
||
<view class="assure-dot"></view>
|
||
<text class="assure-txt">{{ a }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 全部服务 -->
|
||
<view class="panel">
|
||
<view class="panel-head">
|
||
<view class="panel-title-box">
|
||
<view class="title-bar"></view>
|
||
<text class="panel-title">全部服务</text>
|
||
</view>
|
||
<view class="panel-more" @tap="onMore">
|
||
<text class="panel-more-txt">查看全部</text>
|
||
<view class="arrow-r gray"></view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="cats">
|
||
<view class="cat" v-for="(c, i) in cats" :key="c.id" @tap="onCat(c)">
|
||
<view class="cat-circle">
|
||
<image class="cat-img" :src="'/static/icons/' + iconOf(c.icon) + '.png'" mode="aspectFit"></image>
|
||
</view>
|
||
<text class="cat-name">{{ c.name }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 下单教程 -->
|
||
<view class="tutorial" @tap="onLearn">
|
||
<view class="tutorial-ic">
|
||
<view class="ti-play"></view>
|
||
</view>
|
||
<view class="tutorial-txt">
|
||
<text class="tutorial-title">下单找师傅教程</text>
|
||
<text class="tutorial-sub">3 分钟看懂,下单不踩坑</text>
|
||
</view>
|
||
<view class="tutorial-btn">
|
||
<text class="tutorial-btn-txt">立即学习</text>
|
||
<view class="arrow-r blue"></view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 大促 Banner -->
|
||
<view class="banner">
|
||
<view class="banner-deco bd1"></view>
|
||
<view class="banner-deco bd2"></view>
|
||
<view class="banner-deco bd3"></view>
|
||
<view class="banner-close" @tap="onCloseBanner">×</view>
|
||
<view class="banner-inner">
|
||
<view class="banner-tags">
|
||
<view class="banner-tag">家装季</view>
|
||
<view class="banner-tag ghost">限时</view>
|
||
</view>
|
||
<text class="banner-title">双11 狂欢大促</text>
|
||
<text class="banner-desc">下单立减 · 满额再返券</text>
|
||
<view class="banner-date">10.23 - 11.15</view>
|
||
</view>
|
||
<view class="banner-cta" @tap="onBanner">立即抢购</view>
|
||
</view>
|
||
|
||
<!-- 平台实力 -->
|
||
<view class="stats">
|
||
<view class="stats-glare"></view>
|
||
<view class="stats-head">
|
||
<view class="stats-line"></view>
|
||
<text class="stats-title">平台实力</text>
|
||
</view>
|
||
<view class="stats-grid">
|
||
<view class="stats-cell">
|
||
<text class="stats-num">460<text class="stats-unit">万+</text></text>
|
||
<text class="stats-label">专业师傅</text>
|
||
</view>
|
||
<view class="stats-div"></view>
|
||
<view class="stats-cell">
|
||
<text class="stats-num">99.9<text class="stats-unit">%</text></text>
|
||
<text class="stats-label">区域覆盖到村镇</text>
|
||
</view>
|
||
<view class="stats-div"></view>
|
||
<view class="stats-cell">
|
||
<text class="stats-num">1762<text class="stats-unit">万</text></text>
|
||
<text class="stats-label">成功订单</text>
|
||
</view>
|
||
</view>
|
||
<view class="stats-foot">
|
||
<text class="stats-foot-txt">已有 176276994 个订单找到师傅</text>
|
||
<view class="stats-seal">下单越多 · 越优惠</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 商城开店 -->
|
||
<view class="mall" @tap="onMall">
|
||
<view class="mall-ic">
|
||
<view class="mi-body"></view>
|
||
<view class="mi-handle"></view>
|
||
</view>
|
||
<view class="mall-l">
|
||
<text class="mall-title">到象柚商城开店</text>
|
||
<text class="mall-sub">460万+ 全国师傅 · 一键接单</text>
|
||
</view>
|
||
<view class="mall-btn">一键开店</view>
|
||
</view>
|
||
|
||
<view class="foot-tip">优匠优服 · 让手艺人有活干,让家有温度</view>
|
||
</view>
|
||
|
||
<!-- ==================== 自定义底部导航 ==================== -->
|
||
<view class="tabbar">
|
||
<view class="tab" :class="{ on: tabIndex === 0 }" @tap="switchTab(0)">
|
||
<view class="tic">
|
||
<view class="tr" style="left:10rpx;top:4rpx"></view>
|
||
<view class="ol" style="left:13rpx;top:16rpx;width:18rpx;height:18rpx;border-top:none"></view>
|
||
</view>
|
||
<text class="tab-txt">首页</text>
|
||
</view>
|
||
<view class="tab" :class="{ on: tabIndex === 1 }" @tap="switchTab(1)">
|
||
<view class="tic">
|
||
<view class="ol" style="left:11rpx;top:5rpx;width:22rpx;height:30rpx;border-radius:3rpx"></view>
|
||
<view class="ln" style="left:16rpx;top:13rpx;width:12rpx;height:3rpx"></view>
|
||
<view class="ln" style="left:16rpx;top:21rpx;width:12rpx;height:3rpx"></view>
|
||
</view>
|
||
<text class="tab-txt">订单</text>
|
||
</view>
|
||
<view class="tab tab-center">
|
||
<view class="fab" @tap="onOrder">
|
||
<view class="fic">
|
||
<view class="fo" style="left:5rpx;top:2rpx;width:32rpx;height:32rpx;border-radius:5rpx"></view>
|
||
<view class="fl" style="left:11rpx;top:11rpx;width:14rpx;height:3rpx"></view>
|
||
<view class="fl" style="left:11rpx;top:19rpx;width:14rpx;height:3rpx"></view>
|
||
<view class="fp" style="left:25rpx;top:22rpx;width:21rpx;height:6rpx"></view>
|
||
</view>
|
||
<text class="fab-txt">立即下单</text>
|
||
</view>
|
||
</view>
|
||
<view class="tab" :class="{ on: tabIndex === 2 }" @tap="switchTab(2)">
|
||
<view class="tic">
|
||
<view class="ol" style="left:6rpx;top:7rpx;width:32rpx;height:24rpx;border-radius:12rpx"></view>
|
||
<view class="tr-d" style="left:14rpx;top:29rpx"></view>
|
||
</view>
|
||
<text class="tab-txt">消息</text>
|
||
</view>
|
||
<view class="tab" :class="{ on: tabIndex === 3 }" @tap="switchTab(3)">
|
||
<view class="tic">
|
||
<view class="ol ct" style="left:14rpx;top:3rpx;width:16rpx;height:16rpx"></view>
|
||
<view class="ol" style="left:7rpx;top:21rpx;width:30rpx;height:16rpx;border-radius:15rpx 15rpx 0 0;border-bottom:none"></view>
|
||
</view>
|
||
<text class="tab-txt">我的</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref } from 'vue'
|
||
import { onShow } from '@dcloudio/uni-app'
|
||
import api from '@/utils/api.js'
|
||
import { isLogin, toLogin } from '@/utils/request.js'
|
||
import { ensureSilentLogin } from '@/utils/wxlogin.js'
|
||
|
||
/* ---------- 系统适配:状态栏 / 导航栏高度(刘海屏 + 胶囊按钮) ---------- */
|
||
const statusBarHeight = ref(20)
|
||
const navBarHeight = ref(44)
|
||
const tabIndex = ref(0)
|
||
|
||
try {
|
||
const info = uni.getSystemInfoSync()
|
||
if (info && info.statusBarHeight) statusBarHeight.value = info.statusBarHeight
|
||
if (typeof uni.getMenuButtonBoundingClientRect === 'function') {
|
||
const menu = uni.getMenuButtonBoundingClientRect()
|
||
if (menu && menu.height) navBarHeight.value = (menu.top - statusBarHeight.value) * 2 + menu.height
|
||
}
|
||
} catch (e) {}
|
||
|
||
/* ---------- 问候语 ---------- */
|
||
const hh = new Date().getHours()
|
||
const greeting = hh < 6 ? '夜深了' : hh < 11 ? '上午好' : hh < 14 ? '中午好' : hh < 18 ? '下午好' : '晚上好'
|
||
|
||
/* ---------- 服务保障 ---------- */
|
||
const assures = ['平台认证', '先行赔付', '极速上门', '售后无忧']
|
||
|
||
/* ---------- 服务图标:纯 CSS 图元,零图片依赖
|
||
o=描边框 l=实心线 d=圆形描边 t=三角
|
||
格式 [类型, left, top, w, h, radius, rotate],画布 56×56rpx */
|
||
/* 服务图标资源:static/icons/<key>.png(双色扁平,由 SVG 渲染) */
|
||
const ICON_KEYS = ['sofa','bath','lamp','lock','curtain','frame','water','rack','door','appliance','tv','shower','kitchen','fitness','more']
|
||
const iconOf = (key) => (ICON_KEYS.indexOf(key) > -1 ? key : 'more')
|
||
|
||
/* 服务类目(真实接口) */
|
||
const cats = ref([])
|
||
const badge = ref({ coupon: 0, unread: 0 })
|
||
|
||
/**
|
||
* 进主页即尝试静默微信登录(单飞 + 失效自动重试),失败保持游客态
|
||
*/
|
||
async function loadHome() {
|
||
await ensureSilentLogin()
|
||
try {
|
||
const res = await api.home()
|
||
cats.value = res.cats || []
|
||
badge.value = res.badge || { coupon: 0, unread: 0 }
|
||
} catch (e) {}
|
||
}
|
||
|
||
|
||
/* ---------- 交互 ---------- */
|
||
const toast = (title) => uni.showToast({ title, icon: 'none' })
|
||
|
||
function needLogin() {
|
||
if (isLogin()) return true
|
||
toLogin()
|
||
return false
|
||
}
|
||
|
||
const onHome = () => toast('已是首页')
|
||
const onCoupon = () => toast(badge.value.coupon > 0 ? ('您有 ' + badge.value.coupon + ' 张优惠券待使用') : '暂无可用优惠券')
|
||
const onSearch = () => uni.navigateTo({ url: '/pages/service/list?keyword=' + encodeURIComponent('坐便器') })
|
||
const onCat = (c) => uni.navigateTo({
|
||
url: '/pages/service/list?cat_id=' + c.id + '&cat_name=' + encodeURIComponent(c.name)
|
||
})
|
||
const onMore = () => uni.navigateTo({ url: '/pages/service/list?cat_id=15&cat_name=' + encodeURIComponent('更多服务') })
|
||
const onLearn = () => toast('教程模块开发中')
|
||
const onBanner = () => uni.navigateTo({ url: '/pages/service/list?cat_id=1&cat_name=' + encodeURIComponent('家具') })
|
||
const onCloseBanner = () => toast('已关闭')
|
||
const onMall = () => toast('商城模块开发中')
|
||
const onOrder = () => {
|
||
if (!needLogin()) return
|
||
uni.showToast({ title: '请先选择服务类目', icon: 'none' })
|
||
}
|
||
const onUser = () => {
|
||
if (!needLogin()) return
|
||
uni.navigateTo({ url: '/pages/mine/mine' })
|
||
}
|
||
|
||
const switchTab = (i) => {
|
||
if (i === 1) {
|
||
if (!needLogin()) return
|
||
uni.navigateTo({ url: '/pages/order/list' })
|
||
return
|
||
}
|
||
if (i === 3) {
|
||
onUser()
|
||
return
|
||
}
|
||
tabIndex.value = i
|
||
}
|
||
|
||
onShow(() => loadHome())
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* ============================================================
|
||
优匠优服 · 设计令牌
|
||
主橙 #F0710D / 亮橙 #FFA93F / 深橙 #EC6E0C
|
||
线稿棕橙 #B85E2A / 圆形底 #FDF4EC / 页面底 #F5F6F8
|
||
============================================================ */
|
||
.page {
|
||
min-height: 100vh;
|
||
background: #F5F6F8;
|
||
padding-bottom: 200rpx;
|
||
}
|
||
|
||
/* ---------- 橙色渐变头部 ---------- */
|
||
.header {
|
||
position: relative;
|
||
padding-bottom: 100rpx;
|
||
}
|
||
.header-bg {
|
||
position: absolute;
|
||
left: 0;
|
||
right: 0;
|
||
top: 0;
|
||
bottom: 0;
|
||
border-radius: 0 0 48rpx 48rpx;
|
||
overflow: hidden;
|
||
background: linear-gradient(160deg, #FFB85C 0%, #F98D25 46%, #ED6F0E 100%);
|
||
}
|
||
.deco {
|
||
position: absolute;
|
||
border-radius: 50%;
|
||
}
|
||
.deco-1 {
|
||
width: 360rpx;
|
||
height: 360rpx;
|
||
right: -130rpx;
|
||
top: -150rpx;
|
||
background: rgba(255, 255, 255, 0.14);
|
||
}
|
||
.deco-2 {
|
||
width: 220rpx;
|
||
height: 220rpx;
|
||
left: -100rpx;
|
||
top: 110rpx;
|
||
background: rgba(255, 255, 255, 0.10);
|
||
}
|
||
.deco-3 {
|
||
width: 120rpx;
|
||
height: 120rpx;
|
||
right: 110rpx;
|
||
bottom: -70rpx;
|
||
background: rgba(255, 255, 255, 0.09);
|
||
}
|
||
|
||
/* ---------- 导航 ---------- */
|
||
.nav {
|
||
position: relative;
|
||
z-index: 3;
|
||
}
|
||
.nav-inner {
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.nav-title {
|
||
font-size: 36rpx;
|
||
font-weight: 700;
|
||
color: #ffffff;
|
||
letter-spacing: 6rpx;
|
||
text-shadow: 0 2rpx 10rpx rgba(180, 80, 10, 0.30);
|
||
}
|
||
.nav-home {
|
||
position: absolute;
|
||
left: 24rpx;
|
||
top: 50%;
|
||
width: 64rpx;
|
||
height: 64rpx;
|
||
margin-top: -32rpx;
|
||
border-radius: 50%;
|
||
background: rgba(255, 255, 255, 0.18);
|
||
}
|
||
.nh-roof {
|
||
position: absolute;
|
||
left: 17rpx;
|
||
top: 16rpx;
|
||
width: 0;
|
||
height: 0;
|
||
border-left: 15rpx solid transparent;
|
||
border-right: 15rpx solid transparent;
|
||
border-bottom: 14rpx solid #ffffff;
|
||
}
|
||
.nh-body {
|
||
position: absolute;
|
||
left: 21rpx;
|
||
top: 30rpx;
|
||
width: 22rpx;
|
||
height: 17rpx;
|
||
border: 3rpx solid #ffffff;
|
||
border-top: none;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
/* ---------- 问候行 ---------- */
|
||
.greet {
|
||
position: relative;
|
||
z-index: 3;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 6rpx 28rpx 0;
|
||
}
|
||
.greet-l {
|
||
display: flex;
|
||
align-items: center;
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
.avatar-ring {
|
||
width: 96rpx;
|
||
height: 96rpx;
|
||
border-radius: 50%;
|
||
background: rgba(255, 255, 255, 0.30);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
box-shadow: 0 6rpx 16rpx rgba(170, 70, 10, 0.18);
|
||
}
|
||
.avatar {
|
||
position: relative;
|
||
width: 84rpx;
|
||
height: 84rpx;
|
||
border-radius: 50%;
|
||
background: #FFF4E8;
|
||
overflow: hidden;
|
||
}
|
||
.av-head {
|
||
position: absolute;
|
||
left: 27rpx;
|
||
top: 17rpx;
|
||
width: 30rpx;
|
||
height: 30rpx;
|
||
border-radius: 50%;
|
||
background: #EDA162;
|
||
}
|
||
.av-body {
|
||
position: absolute;
|
||
left: 15rpx;
|
||
top: 53rpx;
|
||
width: 54rpx;
|
||
height: 40rpx;
|
||
border-radius: 28rpx 28rpx 0 0;
|
||
background: #EDA162;
|
||
}
|
||
.greet-txt {
|
||
display: flex;
|
||
flex-direction: column;
|
||
margin-left: 18rpx;
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
.greet-hi {
|
||
font-size: 22rpx;
|
||
line-height: 30rpx;
|
||
color: rgba(255, 255, 255, 0.86);
|
||
}
|
||
.greet-name {
|
||
font-size: 28rpx;
|
||
line-height: 38rpx;
|
||
font-weight: 600;
|
||
color: #ffffff;
|
||
overflow: hidden;
|
||
white-space: nowrap;
|
||
text-overflow: ellipsis;
|
||
}
|
||
.coupon {
|
||
display: flex;
|
||
align-items: center;
|
||
height: 64rpx;
|
||
padding: 0 8rpx;
|
||
border-radius: 32rpx;
|
||
background: linear-gradient(135deg, #FFFAF3 0%, #FFE5C4 100%);
|
||
box-shadow: 0 6rpx 16rpx rgba(170, 70, 10, 0.20);
|
||
flex-shrink: 0;
|
||
}
|
||
.coupon-tag {
|
||
width: 32rpx;
|
||
height: 32rpx;
|
||
line-height: 32rpx;
|
||
text-align: center;
|
||
border-radius: 8rpx;
|
||
background: linear-gradient(135deg, #FFB24D 0%, #F0740F 100%);
|
||
color: #ffffff;
|
||
font-size: 18rpx;
|
||
}
|
||
.coupon-text {
|
||
margin: 0 10rpx;
|
||
font-size: 22rpx;
|
||
font-weight: 600;
|
||
color: #BF5507;
|
||
}
|
||
.coupon-btn {
|
||
height: 48rpx;
|
||
line-height: 48rpx;
|
||
padding: 0 18rpx;
|
||
border-radius: 24rpx;
|
||
background: linear-gradient(135deg, #FFA93F 0%, #F0710D 100%);
|
||
color: #ffffff;
|
||
font-size: 22rpx;
|
||
}
|
||
|
||
/* ---------- 悬浮搜索 ---------- */
|
||
.search-wrap {
|
||
position: relative;
|
||
z-index: 4;
|
||
margin: -80rpx 28rpx 0;
|
||
height: 100rpx;
|
||
}
|
||
.search {
|
||
display: flex;
|
||
align-items: center;
|
||
height: 100rpx;
|
||
padding: 0 170rpx 0 30rpx;
|
||
box-sizing: border-box;
|
||
border-radius: 50rpx;
|
||
background: #ffffff;
|
||
box-shadow: 0 12rpx 32rpx rgba(226, 120, 26, 0.22);
|
||
}
|
||
.search-ic {
|
||
position: relative;
|
||
width: 34rpx;
|
||
height: 34rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
.si-ring {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
width: 24rpx;
|
||
height: 24rpx;
|
||
border: 3rpx solid #C2C2C2;
|
||
border-radius: 50%;
|
||
box-sizing: border-box;
|
||
}
|
||
.si-handle {
|
||
position: absolute;
|
||
left: 22rpx;
|
||
top: 21rpx;
|
||
width: 12rpx;
|
||
height: 3rpx;
|
||
background: #C2C2C2;
|
||
transform: rotate(45deg);
|
||
transform-origin: 0 50%;
|
||
}
|
||
.search-ph {
|
||
margin-left: 16rpx;
|
||
font-size: 28rpx;
|
||
color: #A8A8A8;
|
||
}
|
||
.search-btn {
|
||
position: absolute;
|
||
right: 10rpx;
|
||
top: 10rpx;
|
||
width: 150rpx;
|
||
height: 80rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 40rpx;
|
||
background: linear-gradient(135deg, #FFA93F 0%, #F0710D 100%);
|
||
color: #ffffff;
|
||
font-size: 30rpx;
|
||
font-weight: 600;
|
||
letter-spacing: 2rpx;
|
||
box-shadow: 0 6rpx 16rpx rgba(240, 113, 13, 0.34);
|
||
}
|
||
|
||
/* ---------- 内容区 ---------- */
|
||
.content {
|
||
padding: 40rpx 28rpx 0;
|
||
}
|
||
|
||
/* ---------- 服务保障 ---------- */
|
||
.assure {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 22rpx 24rpx;
|
||
background: #ffffff;
|
||
border-radius: 20rpx;
|
||
box-shadow: 0 6rpx 20rpx rgba(240, 129, 31, 0.07);
|
||
margin-bottom: 24rpx;
|
||
}
|
||
.assure-item {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.assure-dot {
|
||
width: 10rpx;
|
||
height: 10rpx;
|
||
border-radius: 50%;
|
||
background: linear-gradient(135deg, #FFB24D 0%, #F0740F 100%);
|
||
margin-right: 10rpx;
|
||
}
|
||
.assure-txt {
|
||
font-size: 22rpx;
|
||
color: #7A7A7A;
|
||
}
|
||
|
||
/* ---------- 全部服务面板 ---------- */
|
||
.panel {
|
||
background: #ffffff;
|
||
border-radius: 24rpx;
|
||
padding: 26rpx 16rpx 8rpx;
|
||
box-shadow: 0 8rpx 24rpx rgba(240, 129, 31, 0.07);
|
||
}
|
||
.panel-head {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 12rpx 14rpx;
|
||
}
|
||
.panel-title-box {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.title-bar {
|
||
width: 8rpx;
|
||
height: 30rpx;
|
||
border-radius: 4rpx;
|
||
background: linear-gradient(180deg, #FFB24D 0%, #F0740F 100%);
|
||
margin-right: 12rpx;
|
||
}
|
||
.panel-title {
|
||
font-size: 32rpx;
|
||
font-weight: 700;
|
||
color: #1F1F1F;
|
||
letter-spacing: 1rpx;
|
||
}
|
||
.panel-more {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.panel-more-txt {
|
||
font-size: 24rpx;
|
||
color: #9A9A9A;
|
||
}
|
||
|
||
/* ---------- 分类宫格 ---------- */
|
||
.cats {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
padding-bottom: 10rpx;
|
||
}
|
||
.cat {
|
||
width: 20%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding: 10rpx 0 16rpx;
|
||
}
|
||
.cat-circle {
|
||
width: 96rpx;
|
||
height: 96rpx;
|
||
border-radius: 50%;
|
||
background: linear-gradient(160deg, #FFF7F0 0%, #FCE9D6 100%);
|
||
box-shadow: inset 0 0 0 2rpx rgba(255, 255, 255, 0.9), 0 4rpx 10rpx rgba(240, 150, 60, 0.10);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.cat-img {
|
||
width: 58rpx;
|
||
height: 58rpx;
|
||
}
|
||
.cat-name {
|
||
display: block;
|
||
margin-top: 12rpx;
|
||
font-size: 24rpx;
|
||
line-height: 30rpx;
|
||
color: #333333;
|
||
text-align: center;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
/* ---------- 纯 CSS 图标绘制原语 ---------- */
|
||
.ic {
|
||
position: relative;
|
||
width: 56rpx;
|
||
height: 56rpx;
|
||
}
|
||
.ic view {
|
||
position: absolute;
|
||
box-sizing: border-box;
|
||
}
|
||
.ic .ol {
|
||
border: 3rpx solid #B85E2A;
|
||
border-radius: 3rpx;
|
||
}
|
||
.ic .ln {
|
||
background: #B85E2A;
|
||
}
|
||
.ic .ct {
|
||
border-radius: 50%;
|
||
}
|
||
.tri {
|
||
width: 0;
|
||
height: 0;
|
||
}
|
||
|
||
/* ---------- 下单教程 ---------- */
|
||
.tutorial {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-top: 24rpx;
|
||
padding: 24rpx;
|
||
background: #ffffff;
|
||
border-radius: 20rpx;
|
||
box-shadow: 0 6rpx 20rpx rgba(240, 129, 31, 0.07);
|
||
}
|
||
.tutorial-ic {
|
||
width: 64rpx;
|
||
height: 64rpx;
|
||
border-radius: 20rpx;
|
||
background: linear-gradient(135deg, #EAF2FF 0%, #D6E6FF 100%);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
}
|
||
.ti-play {
|
||
width: 0;
|
||
height: 0;
|
||
border-top: 11rpx solid transparent;
|
||
border-bottom: 11rpx solid transparent;
|
||
border-left: 17rpx solid #4A7CFF;
|
||
margin-left: 6rpx;
|
||
}
|
||
.tutorial-txt {
|
||
display: flex;
|
||
flex-direction: column;
|
||
flex: 1;
|
||
min-width: 0;
|
||
margin-left: 18rpx;
|
||
}
|
||
.tutorial-title {
|
||
font-size: 30rpx;
|
||
font-weight: 600;
|
||
color: #1F1F1F;
|
||
}
|
||
.tutorial-sub {
|
||
margin-top: 4rpx;
|
||
font-size: 22rpx;
|
||
color: #9A9A9A;
|
||
}
|
||
.tutorial-btn {
|
||
display: flex;
|
||
align-items: center;
|
||
height: 56rpx;
|
||
padding: 0 20rpx;
|
||
border-radius: 28rpx;
|
||
background: linear-gradient(90deg, #EDF3FF 0%, #DCE8FF 100%);
|
||
flex-shrink: 0;
|
||
}
|
||
.tutorial-btn-txt {
|
||
font-size: 24rpx;
|
||
color: #4A7CFF;
|
||
}
|
||
.arrow-r {
|
||
width: 12rpx;
|
||
height: 12rpx;
|
||
margin-left: 10rpx;
|
||
border-top: 3rpx solid #4A7CFF;
|
||
border-right: 3rpx solid #4A7CFF;
|
||
transform: rotate(45deg);
|
||
box-sizing: border-box;
|
||
}
|
||
.arrow-r.blue {
|
||
border-top-color: #4A7CFF;
|
||
border-right-color: #4A7CFF;
|
||
}
|
||
.arrow-r.gray {
|
||
border-top-color: #BFBFBF;
|
||
border-right-color: #BFBFBF;
|
||
}
|
||
|
||
/* ---------- 大促 Banner ---------- */
|
||
.banner {
|
||
position: relative;
|
||
height: 300rpx;
|
||
margin-top: 24rpx;
|
||
border-radius: 24rpx;
|
||
overflow: hidden;
|
||
background: linear-gradient(125deg, #FFF3E2 0%, #FFE0BE 42%, #FFC894 100%);
|
||
box-shadow: 0 10rpx 26rpx rgba(240, 150, 60, 0.16);
|
||
}
|
||
.banner-deco {
|
||
position: absolute;
|
||
border-radius: 50%;
|
||
}
|
||
.bd1 {
|
||
width: 300rpx;
|
||
height: 300rpx;
|
||
right: -90rpx;
|
||
top: -120rpx;
|
||
background: rgba(255, 255, 255, 0.55);
|
||
}
|
||
.bd2 {
|
||
width: 170rpx;
|
||
height: 170rpx;
|
||
left: -70rpx;
|
||
bottom: -80rpx;
|
||
background: rgba(255, 138, 60, 0.16);
|
||
}
|
||
.bd3 {
|
||
width: 90rpx;
|
||
height: 90rpx;
|
||
right: 160rpx;
|
||
bottom: 26rpx;
|
||
background: rgba(255, 138, 60, 0.14);
|
||
}
|
||
.banner-inner {
|
||
position: relative;
|
||
z-index: 2;
|
||
padding: 28rpx 0 0 30rpx;
|
||
}
|
||
.banner-tags {
|
||
display: flex;
|
||
}
|
||
.banner-tag {
|
||
padding: 0 14rpx;
|
||
line-height: 34rpx;
|
||
border-radius: 17rpx;
|
||
background: linear-gradient(135deg, #F5452B 0%, #D92210 100%);
|
||
color: #FFE9A8;
|
||
font-size: 20rpx;
|
||
letter-spacing: 1rpx;
|
||
}
|
||
.banner-tag.ghost {
|
||
margin-left: 10rpx;
|
||
background: rgba(232, 51, 27, 0.12);
|
||
color: #C0392B;
|
||
}
|
||
.banner-title {
|
||
display: block;
|
||
margin-top: 14rpx;
|
||
font-size: 52rpx;
|
||
font-weight: 800;
|
||
color: #E8331B;
|
||
letter-spacing: 2rpx;
|
||
text-shadow: 0 3rpx 0 #FFE9A8;
|
||
}
|
||
.banner-desc {
|
||
display: block;
|
||
margin-top: 8rpx;
|
||
font-size: 24rpx;
|
||
color: #C0392B;
|
||
}
|
||
.banner-date {
|
||
display: inline-block;
|
||
margin-top: 14rpx;
|
||
padding: 0 16rpx;
|
||
line-height: 34rpx;
|
||
border-radius: 17rpx;
|
||
background: rgba(232, 51, 27, 0.10);
|
||
color: #C0392B;
|
||
font-size: 21rpx;
|
||
}
|
||
.banner-cta {
|
||
position: absolute;
|
||
right: 26rpx;
|
||
bottom: 30rpx;
|
||
z-index: 3;
|
||
height: 60rpx;
|
||
padding: 0 26rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
border-radius: 30rpx;
|
||
background: linear-gradient(135deg, #FF9E2E 0%, #EE6C05 100%);
|
||
color: #ffffff;
|
||
font-size: 24rpx;
|
||
font-weight: 600;
|
||
box-shadow: 0 6rpx 16rpx rgba(238, 108, 5, 0.32);
|
||
}
|
||
.banner-close {
|
||
position: absolute;
|
||
right: 20rpx;
|
||
top: 20rpx;
|
||
z-index: 3;
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
line-height: 36rpx;
|
||
text-align: center;
|
||
border-radius: 50%;
|
||
background: rgba(0, 0, 0, 0.22);
|
||
color: #ffffff;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
/* ---------- 平台实力 ---------- */
|
||
.stats {
|
||
position: relative;
|
||
margin-top: 24rpx;
|
||
padding: 28rpx 26rpx 22rpx;
|
||
border-radius: 24rpx;
|
||
overflow: hidden;
|
||
background: linear-gradient(125deg, #FFB062 0%, #F68A22 48%, #EC6E0C 100%);
|
||
box-shadow: 0 12rpx 28rpx rgba(236, 110, 12, 0.28);
|
||
}
|
||
.stats-glare {
|
||
position: absolute;
|
||
right: -110rpx;
|
||
top: -130rpx;
|
||
width: 340rpx;
|
||
height: 340rpx;
|
||
border-radius: 50%;
|
||
background: rgba(255, 255, 255, 0.12);
|
||
}
|
||
.stats-head {
|
||
position: relative;
|
||
z-index: 2;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.stats-line {
|
||
width: 6rpx;
|
||
height: 26rpx;
|
||
border-radius: 3rpx;
|
||
background: #FFF0C9;
|
||
margin-right: 10rpx;
|
||
}
|
||
.stats-title {
|
||
font-size: 26rpx;
|
||
font-weight: 600;
|
||
color: #FFF3DF;
|
||
letter-spacing: 1rpx;
|
||
}
|
||
.stats-grid {
|
||
position: relative;
|
||
z-index: 2;
|
||
display: flex;
|
||
align-items: flex-end;
|
||
margin-top: 20rpx;
|
||
}
|
||
.stats-cell {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
.stats-num {
|
||
font-size: 46rpx;
|
||
line-height: 56rpx;
|
||
font-weight: 800;
|
||
color: #ffffff;
|
||
letter-spacing: 1rpx;
|
||
}
|
||
.stats-unit {
|
||
font-size: 24rpx;
|
||
font-weight: 600;
|
||
}
|
||
.stats-label {
|
||
margin-top: 6rpx;
|
||
font-size: 22rpx;
|
||
color: rgba(255, 255, 255, 0.85);
|
||
}
|
||
.stats-div {
|
||
width: 2rpx;
|
||
height: 56rpx;
|
||
background: rgba(255, 255, 255, 0.28);
|
||
margin-bottom: 26rpx;
|
||
}
|
||
.stats-foot {
|
||
position: relative;
|
||
z-index: 2;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-top: 20rpx;
|
||
padding-top: 18rpx;
|
||
border-top: 2rpx solid rgba(255, 255, 255, 0.22);
|
||
}
|
||
.stats-foot-txt {
|
||
font-size: 22rpx;
|
||
color: rgba(255, 255, 255, 0.90);
|
||
}
|
||
.stats-seal {
|
||
padding: 6rpx 14rpx;
|
||
border-radius: 8rpx;
|
||
background: #FFF4E3;
|
||
color: #E8331B;
|
||
font-size: 20rpx;
|
||
font-weight: 700;
|
||
}
|
||
|
||
/* ---------- 商城开店 ---------- */
|
||
.mall {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-top: 24rpx;
|
||
padding: 26rpx 24rpx;
|
||
background: #ffffff;
|
||
border-radius: 20rpx;
|
||
box-shadow: 0 6rpx 20rpx rgba(240, 129, 31, 0.07);
|
||
}
|
||
.mall-ic {
|
||
position: relative;
|
||
width: 72rpx;
|
||
height: 72rpx;
|
||
border-radius: 20rpx;
|
||
background: linear-gradient(135deg, #FFF0DE 0%, #FFDDB8 100%);
|
||
flex-shrink: 0;
|
||
}
|
||
.mi-body {
|
||
position: absolute;
|
||
left: 16rpx;
|
||
top: 24rpx;
|
||
width: 40rpx;
|
||
height: 30rpx;
|
||
border: 3rpx solid #E88A2C;
|
||
border-radius: 4rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
.mi-handle {
|
||
position: absolute;
|
||
left: 26rpx;
|
||
top: 15rpx;
|
||
width: 20rpx;
|
||
height: 12rpx;
|
||
border: 3rpx solid #E88A2C;
|
||
border-bottom: none;
|
||
border-radius: 10rpx 10rpx 0 0;
|
||
box-sizing: border-box;
|
||
}
|
||
.mall-l {
|
||
display: flex;
|
||
flex-direction: column;
|
||
flex: 1;
|
||
min-width: 0;
|
||
margin-left: 18rpx;
|
||
}
|
||
.mall-title {
|
||
font-size: 30rpx;
|
||
font-weight: 600;
|
||
color: #1F1F1F;
|
||
}
|
||
.mall-sub {
|
||
margin-top: 4rpx;
|
||
font-size: 22rpx;
|
||
color: #9A9A9A;
|
||
}
|
||
.mall-btn {
|
||
height: 60rpx;
|
||
padding: 0 28rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
border-radius: 30rpx;
|
||
background: linear-gradient(135deg, #FFA93F 0%, #F0710D 100%);
|
||
color: #ffffff;
|
||
font-size: 24rpx;
|
||
font-weight: 600;
|
||
flex-shrink: 0;
|
||
box-shadow: 0 6rpx 14rpx rgba(240, 113, 13, 0.28);
|
||
}
|
||
.foot-tip {
|
||
padding: 36rpx 0 10rpx;
|
||
text-align: center;
|
||
font-size: 20rpx;
|
||
color: #BDBDBD;
|
||
letter-spacing: 1rpx;
|
||
}
|
||
|
||
/* ---------- 自定义底部导航 ---------- */
|
||
.tabbar {
|
||
position: fixed;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
z-index: 99;
|
||
height: 112rpx;
|
||
padding-bottom: constant(safe-area-inset-bottom);
|
||
padding-bottom: env(safe-area-inset-bottom);
|
||
display: flex;
|
||
background: #ffffff;
|
||
box-shadow: 0 -6rpx 24rpx rgba(0, 0, 0, 0.07);
|
||
}
|
||
.tab {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding-bottom: 8rpx;
|
||
}
|
||
.tab-txt {
|
||
margin-top: 8rpx;
|
||
font-size: 22rpx;
|
||
color: #9A9A9A;
|
||
}
|
||
.tab.on .tab-txt {
|
||
color: #F0710D;
|
||
font-weight: 600;
|
||
}
|
||
|
||
/* 底部图标 */
|
||
.tic {
|
||
position: relative;
|
||
width: 44rpx;
|
||
height: 40rpx;
|
||
}
|
||
.tic view {
|
||
position: absolute;
|
||
box-sizing: border-box;
|
||
}
|
||
.tic .ol {
|
||
border: 3rpx solid #9A9A9A;
|
||
border-radius: 3rpx;
|
||
}
|
||
.tic .ln {
|
||
background: #9A9A9A;
|
||
}
|
||
.tic .ct {
|
||
border-radius: 50%;
|
||
}
|
||
.tic .tr {
|
||
width: 0;
|
||
height: 0;
|
||
border-left: 11rpx solid transparent;
|
||
border-right: 11rpx solid transparent;
|
||
border-bottom: 11rpx solid #9A9A9A;
|
||
}
|
||
.tic .tr-d {
|
||
width: 0;
|
||
height: 0;
|
||
border-left: 7rpx solid transparent;
|
||
border-right: 7rpx solid transparent;
|
||
border-top: 7rpx solid #9A9A9A;
|
||
}
|
||
.tab.on .tic .ol {
|
||
border-color: #F0710D;
|
||
}
|
||
.tab.on .tic .ln {
|
||
background: #F0710D;
|
||
}
|
||
.tab.on .tic .tr {
|
||
border-bottom-color: #F0710D;
|
||
}
|
||
.tab.on .tic .tr-d {
|
||
border-top-color: #F0710D;
|
||
}
|
||
|
||
/* ---------- 中央上浮主按钮 ---------- */
|
||
.tab-center {
|
||
position: relative;
|
||
}
|
||
.fab {
|
||
position: absolute;
|
||
left: 50%;
|
||
top: -52rpx;
|
||
width: 128rpx;
|
||
height: 128rpx;
|
||
margin-left: -64rpx;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: linear-gradient(180deg, #FFB65E 0%, #EE7412 100%);
|
||
box-shadow: 0 10rpx 26rpx rgba(238, 116, 18, 0.45);
|
||
}
|
||
.fic {
|
||
position: relative;
|
||
width: 44rpx;
|
||
height: 36rpx;
|
||
}
|
||
.fic view {
|
||
position: absolute;
|
||
box-sizing: border-box;
|
||
}
|
||
.fo {
|
||
border: 3rpx solid #ffffff;
|
||
border-radius: 5rpx;
|
||
}
|
||
.fl {
|
||
background: #ffffff;
|
||
}
|
||
.fp {
|
||
background: #ffffff;
|
||
border-radius: 3rpx;
|
||
transform: rotate(-45deg);
|
||
}
|
||
.fab-txt {
|
||
margin-top: 4rpx;
|
||
font-size: 22rpx;
|
||
color: #ffffff;
|
||
}
|
||
</style>
|