feat: implement miniapp C-group pages with real API calls and design tokens

This commit is contained in:
Codex
2026-09-14 10:02:22 +08:00
parent bb380d40f6
commit 63cbbff2de
20 changed files with 300 additions and 23 deletions
@@ -1 +1,65 @@
Page({data:{services:['资料填写协助','公益红娘咨询','活动报名指导','婚恋咨询预约']},call(){wx.showModal({title:'联系服务站',content:'服务热线:0511-00000000',showCancel:false})},book(){wx.navigateTo({url:'/pages/service-appointment/service-appointment'})}})
const api = require('../../utils/api')
Page({
data: {
serviceLocation: null,
loading: true,
loadError: false,
},
onLoad() {
this.loadStation()
},
async loadStation() {
this.setData({ loading: true, loadError: false })
try {
const home = await api.get('/home')
this.setData({ serviceLocation: home?.serviceLocation || null, loading: false })
} catch (error) {
console.error('加载服务站失败', error)
this.setData({ loading: false, loadError: true })
}
},
call() {
const station = this.data.serviceLocation
const phoneNumber = station?.contactPhone || station?.contactPhoneDisplay || ''
const digitCount = phoneNumber.replace(/\D/g, '').length
if (!phoneNumber || phoneNumber.includes('*') || digitCount < 5) {
wx.showToast({ title: '联系电话请以预约确认为准', icon: 'none' })
return
}
wx.makePhoneCall({ phoneNumber })
},
openMap() {
const station = this.data.serviceLocation
const latitude = Number(station?.latitude)
const longitude = Number(station?.longitude)
if (Number.isFinite(latitude) && Number.isFinite(longitude) && latitude && longitude) {
wx.openLocation({
latitude,
longitude,
name: station.name,
address: station.address || '',
})
return
}
if (station?.address) {
wx.setClipboardData({ data: station.address })
return
}
wx.showToast({ title: '暂未提供地图位置', icon: 'none' })
},
book() {
const id = this.data.serviceLocation?.id
const query = id ? `?serviceLocationId=${encodeURIComponent(id)}` : ''
wx.navigateTo({ url: `/pages/service-appointment/service-appointment${query}` })
},
onRetry() {
this.loadStation()
},
})
@@ -1 +1,10 @@
{"navigationBarTitleText":"善缘服务站","backgroundColor":"#FAFAF8"}
{
"navigationBarTitleText": "善缘服务站",
"backgroundColor": "#F4F5FA",
"usingComponents": {
"ui-service-hero": "/components/service-hero/index",
"ui-loading": "/components/loading/index",
"ui-empty": "/components/empty/index",
"ui-error-state": "/components/error-state/index"
}
}
@@ -1 +1,23 @@
<view class="service-page reference-page"><view class="hero"><text class="eyebrow">固定公益服务阵地</text><text class="hero-title">善缘丹阳公益服务站</text><text class="hero-desc">提供面对面的婚恋服务咨询,让线上服务在丹阳有真实落点。</text></view><view class="content"><view class="block"><text class="block-title">服务站信息</text><view class="card"><view class="feature-row"><view class="feature-icon">址</view><view class="feature-copy"><text class="feature-title">丹阳市城区公益服务中心</text><text class="feature-desc">丹阳市云阳街道(具体地址以预约确认为准)</text></view></view><view class="feature-row"><view class="feature-icon">时</view><view class="feature-copy"><text class="feature-title">周二至周日 09:00–17:30</text><text class="feature-desc">节假日开放时间以平台通知为准</text></view></view></view></view><view class="block"><text class="block-title">可预约服务</text><view class="card"><view wx:for="{{services}}" wx:key="*this" class="menu-row"><view class="feature-icon">{{index+1}}</view><text class="feature-title" style="flex:1">{{item}}</text><text class="arrow">›</text></view></view></view><view class="notice">服务站人员仅处理现场预约与指定服务,不会浏览无关用户资料。</view></view><view class="fixed-action"><view class="primary-btn" bindtap="book">预约到站服务</view></view></view>
<view class="service-shell station-page app-page reference-page">
<ui-service-hero eyebrow="公益服务 · 就在身边" title="善缘服务站" subtitle="面对面提供可靠、温暖的本地婚恋服务" image-src="/assets/service/station-hero.jpg" tone="rose" />
<view class="service-content">
<ui-loading wx:if="{{loading}}" mode="skeleton" rows="4" />
<ui-error-state wx:elif="{{loadError}}" title="暂时无法加载服务站" description="请检查网络后重试" bind:retry="onRetry" />
<ui-empty wx:elif="{{!serviceLocation}}" illustration="default" title="所在区域暂无服务站" description="新的公益服务阵地正在筹备中" />
<block wx:else>
<view class="station-name-card"><image src="/assets/icons/home/service-station.png" mode="aspectFit" /><view><text class="station-name">{{serviceLocation.name}}</text><text class="station-short-name">{{serviceLocation.shortName || '善缘丹阳公益婚恋服务阵地'}}</text></view></view>
<view class="station-info-card">
<view class="station-info-row"><image src="/assets/icons/home/service-station.png" mode="aspectFit" /><view><text class="station-info-label">地址</text><text class="station-info-value">{{serviceLocation.address || '以预约确认为准'}}</text></view></view>
<view class="station-info-row" bindtap="call"><image src="/assets/icons/home/counseling.png" mode="aspectFit" /><view><text class="station-info-label">联系电话</text><text class="station-info-value">{{serviceLocation.contactPhoneDisplay || '以预约确认为准'}}</text></view><image class="station-arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" /></view>
<view class="station-info-row"><image src="/assets/icons/home/activity.png" mode="aspectFit" /><view><text class="station-info-label">开放时间</text><text class="station-info-value">{{serviceLocation.openingHoursText || '以平台通知为准'}}</text></view></view>
</view>
<view class="block"><text class="block-title">服务项目</text><view class="station-services"><view wx:for="{{serviceLocation.services}}" wx:key="*this" class="station-service"><image src="/assets/icons/home/matchmaker.png" mode="aspectFit" /><text>{{item}}</text></view></view></view>
<view class="privacy-note"><image src="/assets/icons/home/anti-fraud.png" mode="aspectFit" /><text>服务站人员仅处理现场预约与指定服务,不会浏览无关用户资料。</text></view>
<view class="map-button" bindtap="openMap"><image src="/assets/icons/home/service-station.png" mode="aspectFit" /><text>地图定位</text></view>
</block>
</view>
<view wx:if="{{serviceLocation}}" class="fixed-action"><view class="service-actions"><view class="secondary-btn" bindtap="call">联系服务站</view><view class="primary-btn" bindtap="book">预约到站服务</view></view></view>
</view>
@@ -1 +1,2 @@
@import "../../styles/service-page.wxss";
@import "../../styles/service-page.wxss";
.station-name-card{display:flex;align-items:center;gap:18rpx;margin-top:24rpx;padding:24rpx;border-radius:26rpx;background:linear-gradient(135deg,#F1FFFA,#FFF7F9);box-shadow:0 8rpx 26rpx rgba(35,35,95,.06)}.station-name-card>image{width:66rpx;height:66rpx}.station-name-card>view{display:flex;flex:1;flex-direction:column}.station-name{color:#283056;font-size:27rpx;font-weight:700}.station-short-name{margin-top:6rpx;color:#7E859B;font-size:19rpx}.station-info-card{overflow:hidden;margin-top:18rpx;border-radius:26rpx;background:#fff;box-shadow:0 8rpx 26rpx rgba(35,35,95,.06)}.station-info-row{display:flex;align-items:center;gap:16rpx;min-height:104rpx;padding:14rpx 20rpx;border-bottom:1rpx solid #EFF0F5}.station-info-row:last-child{border-bottom:0}.station-info-row>image:first-child{width:42rpx;height:42rpx;flex:none}.station-info-row>view{display:flex;flex:1;flex-direction:column}.station-info-label{color:#303654;font-size:22rpx;font-weight:650}.station-info-value{margin-top:5rpx;color:#858A9E;font-size:19rpx;line-height:1.45}.station-info-row .station-arrow{width:24rpx;height:24rpx}.station-services{display:grid;grid-template-columns:repeat(2,1fr);gap:14rpx;margin-top:18rpx}.station-service{display:flex;align-items:center;gap:12rpx;min-height:74rpx;padding:12rpx 16rpx;border-radius:20rpx;background:#fff;color:#505874;font-size:20rpx;box-shadow:0 6rpx 20rpx rgba(35,35,95,.05)}.station-service image{width:34rpx;height:34rpx}.map-button{display:flex;align-items:center;justify-content:center;gap:10rpx;height:78rpx;margin-top:20rpx;border:1rpx solid #E5E7F0;border-radius:39rpx;background:#fff;color:#53607F;font-size:22rpx}.map-button image{width:34rpx;height:34rpx}