初始提交:一场soul的创业实验-永平 网站与小程序
Made-with: Cursor
This commit is contained in:
200
miniprogram/pages/member-detail/member-detail.js
Normal file
200
miniprogram/pages/member-detail/member-detail.js
Normal file
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* Soul创业派对 - 超级个体/会员详情页
|
||||
* 接口:优先 /api/miniprogram/vip/members?id=xx(VIP),回退 /api/miniprogram/users?id=xx(任意用户)
|
||||
* 头像/昵称:统一用用户资料(nickname/avatar)优先,随「我的」修改实时生效
|
||||
* mbti, region, industry, position, businessScale, skills,
|
||||
* storyBestMonth→bestMonth, storyAchievement→achievement, storyTurning→turningPoint,
|
||||
* helpOffer→canHelp, helpNeed→needHelp
|
||||
*/
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
data: { statusBarHeight: 44, member: null, loading: true },
|
||||
|
||||
onLoad(options) {
|
||||
wx.showShareMenu({ withShareTimeline: true })
|
||||
this.setData({ statusBarHeight: app.globalData.statusBarHeight })
|
||||
if (options.id) this.loadMember(options.id)
|
||||
},
|
||||
|
||||
async loadMember(id) {
|
||||
try {
|
||||
const res = await app.request({ url: `/api/miniprogram/vip/members?id=${id}`, silent: true })
|
||||
if (res?.success && res.data) {
|
||||
const d = Array.isArray(res.data) ? res.data[0] : res.data
|
||||
if (d) { this.setData({ member: this.enrichAndFormat(d), loading: false }); return }
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
const dbRes = await app.request({ url: `/api/miniprogram/users?id=${id}`, silent: true })
|
||||
if (dbRes?.success && dbRes.data) {
|
||||
const u = Array.isArray(dbRes.data) ? dbRes.data[0] : dbRes.data
|
||||
if (u) {
|
||||
this.setData({ member: this.enrichAndFormat({
|
||||
id: u.id, name: u.nickname || u.vipName || u.vip_name || '创业者',
|
||||
avatar: u.avatar || u.vipAvatar || u.vip_avatar || '', isVip: !!(u.is_vip),
|
||||
contactRaw: u.vipContact || u.vip_contact || u.phone || '',
|
||||
wechatId: u.wechatId || u.wechat_id,
|
||||
project: u.vipProject || u.vip_project || u.projectIntro || u.project_intro || '',
|
||||
industry: u.industry, position: u.position, businessScale: u.businessScale || u.business_scale,
|
||||
skills: u.skills, mbti: u.mbti, region: u.region,
|
||||
storyBestMonth: u.storyBestMonth || u.story_best_month,
|
||||
storyAchievement: u.storyAchievement || u.story_achievement,
|
||||
storyTurning: u.storyTurning || u.story_turning,
|
||||
helpOffer: u.helpOffer || u.help_offer,
|
||||
helpNeed: u.helpNeed || u.help_need,
|
||||
}), loading: false })
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
this.setData({ loading: false })
|
||||
},
|
||||
|
||||
// 将空值、「未填写」、纯空格均视为未填写(用于隐藏对应项)
|
||||
_emptyIfPlaceholder(v) {
|
||||
if (v == null || v === undefined) return ''
|
||||
const s = String(v).trim()
|
||||
return (s === '' || s === '未填写') ? '' : s
|
||||
},
|
||||
|
||||
enrichAndFormat(raw) {
|
||||
const e = (v) => this._emptyIfPlaceholder(v)
|
||||
const merged = {
|
||||
id: raw.id,
|
||||
name: raw.nickname || raw.name || raw.vipName || raw.vip_name || '创业者',
|
||||
avatar: raw.avatar || raw.vipAvatar || raw.vip_avatar || '',
|
||||
isVip: !!(raw.isVip || raw.is_vip),
|
||||
mbti: e(raw.mbti),
|
||||
region: e(raw.region),
|
||||
industry: e(raw.industry),
|
||||
position: e(raw.position),
|
||||
businessScale: e(raw.businessScale || raw.business_scale),
|
||||
skills: e(raw.skills),
|
||||
contactRaw: raw.contactRaw || raw.vipContact || raw.vip_contact || raw.phone || '',
|
||||
wechatRaw: raw.wechatRaw || raw.wechatId || raw.wechat_id || '',
|
||||
bestMonth: e(raw.bestMonth || raw.storyBestMonth || raw.story_best_month),
|
||||
achievement: e(raw.achievement || raw.storyAchievement || raw.story_achievement),
|
||||
turningPoint: e(raw.turningPoint || raw.storyTurning || raw.story_turning),
|
||||
canHelp: e(raw.canHelp || raw.helpOffer || raw.help_offer),
|
||||
needHelp: e(raw.needHelp || raw.helpNeed || raw.help_need),
|
||||
project: e(raw.project || raw.vipProject || raw.vip_project || raw.projectIntro || raw.project_intro)
|
||||
}
|
||||
|
||||
const contact = merged.contactRaw || ''
|
||||
const wechat = merged.wechatRaw || ''
|
||||
const isMatched = (app.globalData.matchedUsers || []).includes(merged.id)
|
||||
const unlockData = this._getUnlockData(merged.id)
|
||||
merged.contactDisplay = contact ? (contact.slice(0, 3) + '****' + (contact.length > 7 ? contact.slice(-2) : '')) : ''
|
||||
merged.contactUnlocked = isMatched || unlockData.contact
|
||||
merged.contactFull = contact
|
||||
merged.wechatDisplay = wechat ? (wechat.slice(0, 4) + '****' + (wechat.length > 8 ? wechat.slice(-3) : '')) : ''
|
||||
merged.wechatUnlocked = isMatched || unlockData.wechat
|
||||
merged.wechatFull = wechat
|
||||
return merged
|
||||
},
|
||||
|
||||
_getUnlockData(memberId) {
|
||||
const userId = app.globalData.userInfo?.id
|
||||
if (!userId || !memberId) return { contact: false, wechat: false }
|
||||
try {
|
||||
const raw = wx.getStorageSync('member_unlocks_' + userId)
|
||||
if (Array.isArray(raw) && raw.includes(memberId)) {
|
||||
return { contact: true, wechat: true }
|
||||
}
|
||||
const data = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {}
|
||||
const member = data[memberId]
|
||||
return {
|
||||
contact: !!(member && member.contact),
|
||||
wechat: !!(member && member.wechat)
|
||||
}
|
||||
} catch (e) { return { contact: false, wechat: false } }
|
||||
},
|
||||
|
||||
_addUnlock(memberId, field) {
|
||||
const userId = app.globalData.userInfo?.id
|
||||
if (!userId || !memberId || !field) return
|
||||
let obj = wx.getStorageSync('member_unlocks_' + userId)
|
||||
if (Array.isArray(obj)) {
|
||||
obj = obj.reduce((o, id) => { o[id] = { contact: true, wechat: true }; return o }, {})
|
||||
}
|
||||
obj = obj && typeof obj === 'object' ? obj : {}
|
||||
if (!obj[memberId]) obj[memberId] = {}
|
||||
obj[memberId][field] = true
|
||||
wx.setStorageSync('member_unlocks_' + userId, obj)
|
||||
},
|
||||
|
||||
_hasUsedFreeForMember(memberId) {
|
||||
const d = this._getUnlockData(memberId)
|
||||
return d.contact || d.wechat
|
||||
},
|
||||
|
||||
unlockField(e) {
|
||||
const field = e.currentTarget.dataset.field
|
||||
if (!field) return
|
||||
const member = this.data.member
|
||||
if (!member?.id || (field !== 'contact' && field !== 'wechat')) return
|
||||
const isLoggedIn = app.globalData.isLoggedIn
|
||||
if (!isLoggedIn) {
|
||||
wx.showModal({
|
||||
title: '需要登录',
|
||||
content: '请先登录后再解锁超级个体联系方式',
|
||||
confirmText: '去登录',
|
||||
cancelText: '取消',
|
||||
success: (res) => { if (res.confirm) wx.switchTab({ url: '/pages/my/my' }) }
|
||||
})
|
||||
return
|
||||
}
|
||||
const d = this._getUnlockData(member.id)
|
||||
if (d[field]) return
|
||||
const isVip = app.globalData.hasFullBook
|
||||
const usedFree = this._hasUsedFreeForMember(member.id)
|
||||
if (isVip || !usedFree) {
|
||||
this._addUnlock(member.id, field)
|
||||
const m = this.enrichAndFormat(member)
|
||||
this.setData({ member: m })
|
||||
wx.showToast({ title: field === 'contact' ? '已解锁联系方式' : '已解锁微信号', icon: 'success' })
|
||||
return
|
||||
}
|
||||
wx.showModal({
|
||||
title: '解锁' + (field === 'contact' ? '联系方式' : '微信号'),
|
||||
content: '您的免费解锁次数已用完,开通VIP会员(¥1980/年)可无限解锁',
|
||||
confirmText: '去开通',
|
||||
cancelText: '取消',
|
||||
success: (res) => { if (res.confirm) wx.navigateTo({ url: '/pages/vip/vip' }) }
|
||||
})
|
||||
},
|
||||
|
||||
copyContact() {
|
||||
const c = this.data.member?.contactFull
|
||||
if (!c) return
|
||||
wx.setClipboardData({ data: c, success: () => wx.showToast({ title: '已复制', icon: 'success' }) })
|
||||
},
|
||||
|
||||
copyWechat() {
|
||||
const w = this.data.member?.wechatFull
|
||||
if (!w) return
|
||||
wx.setClipboardData({ data: w, success: () => wx.showToast({ title: '已复制', icon: 'success' }) })
|
||||
},
|
||||
|
||||
goToMatch() { wx.switchTab({ url: '/pages/match/match' }) },
|
||||
goToVip() { wx.navigateTo({ url: '/pages/vip/vip' }) },
|
||||
goBack() { getApp().goBackOrToHome() },
|
||||
|
||||
onShareAppMessage() {
|
||||
const ref = app.getMyReferralCode()
|
||||
const id = this.data.member?.id
|
||||
return {
|
||||
title: 'Soul创业派对 - 创业者详情',
|
||||
path: id && ref ? `/pages/member-detail/member-detail?id=${id}&ref=${ref}` : id ? `/pages/member-detail/member-detail?id=${id}` : ref ? `/pages/member-detail/member-detail?ref=${ref}` : '/pages/member-detail/member-detail'
|
||||
}
|
||||
},
|
||||
|
||||
onShareTimeline() {
|
||||
const ref = app.getMyReferralCode()
|
||||
const id = this.data.member?.id
|
||||
const q = id ? (ref ? `id=${id}&ref=${ref}` : `id=${id}`) : (ref ? `ref=${ref}` : '')
|
||||
return { title: 'Soul创业派对 - 创业者详情', query: q }
|
||||
}
|
||||
})
|
||||
1
miniprogram/pages/member-detail/member-detail.json
Normal file
1
miniprogram/pages/member-detail/member-detail.json
Normal file
@@ -0,0 +1 @@
|
||||
{ "usingComponents": {}, "navigationStyle": "custom" }
|
||||
150
miniprogram/pages/member-detail/member-detail.wxml
Normal file
150
miniprogram/pages/member-detail/member-detail.wxml
Normal file
@@ -0,0 +1,150 @@
|
||||
<!-- Soul创业派对 - 超级个体详情(按 enhanced_professional_profile 1:1 还原) -->
|
||||
<view class="page">
|
||||
<!-- 导航栏 -->
|
||||
<view class="nav-bar" style="padding-top: {{statusBarHeight}}px;">
|
||||
<view class="nav-back" bindtap="goBack">
|
||||
<text class="nav-icon">‹</text>
|
||||
</view>
|
||||
<text class="nav-title">个人资料</text>
|
||||
<view class="nav-placeholder"></view>
|
||||
</view>
|
||||
<view style="height: {{statusBarHeight + 44}}px;"></view>
|
||||
|
||||
<scroll-view scroll-y class="scroll-wrap" wx:if="{{member}}">
|
||||
<!-- 顶部 profile 卡片 -->
|
||||
<view class="card-profile">
|
||||
<view class="profile-deco"></view>
|
||||
<view class="profile-body">
|
||||
<view class="avatar-outer">
|
||||
<view class="avatar-wrap {{member.isVip ? 'vip-ring' : ''}}">
|
||||
<image class="avatar-img" wx:if="{{member.avatar}}" src="{{member.avatar}}" mode="aspectFill"/>
|
||||
<view class="avatar-ph" wx:else><text>{{member.name[0] || '创'}}</text></view>
|
||||
</view>
|
||||
<view class="vip-tag" wx:if="{{member.isVip}}">VIP</view>
|
||||
</view>
|
||||
<text class="profile-name">{{member.name}}</text>
|
||||
<view class="profile-tags" wx:if="{{member.mbti || member.region}}">
|
||||
<text class="tag tag-mbti" wx:if="{{member.mbti}}">{{member.mbti}}</text>
|
||||
<text class="tag tag-region" wx:if="{{member.region}}"><text class="pin-icon">📍</text>{{member.region}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 基本信息(未填写行已隐藏) -->
|
||||
<view class="card" wx:if="{{member.industry || member.position || member.businessScale || member.skills || member.contactRaw || member.contactDisplay || member.wechatRaw || member.wechatDisplay}}">
|
||||
<view class="card-head">
|
||||
<text class="card-icon">👤</text>
|
||||
<text class="card-label">基本信息</text>
|
||||
</view>
|
||||
<view class="card-body">
|
||||
<view class="field" wx:if="{{member.industry}}">
|
||||
<text class="f-key">行业</text>
|
||||
<text class="f-val">{{member.industry}}</text>
|
||||
</view>
|
||||
<view class="field" wx:if="{{member.position}}">
|
||||
<text class="f-key">职位</text>
|
||||
<text class="f-val">{{member.position}}</text>
|
||||
</view>
|
||||
<view class="field" wx:if="{{member.businessScale}}">
|
||||
<text class="f-key">业务体量</text>
|
||||
<text class="f-val">{{member.businessScale}}</text>
|
||||
</view>
|
||||
<view class="divider" wx:if="{{member.industry || member.position || member.businessScale}}"></view>
|
||||
<view class="field" wx:if="{{member.skills}}">
|
||||
<text class="f-key">我擅长</text>
|
||||
<text class="f-val">{{member.skills}}</text>
|
||||
</view>
|
||||
<view class="field" wx:if="{{member.contactRaw || member.contactDisplay}}">
|
||||
<text class="f-key">联系方式</text>
|
||||
<view class="f-row">
|
||||
<text class="f-val mono">{{member.contactUnlocked ? member.contactFull : (member.contactDisplay || member.contactRaw)}}</text>
|
||||
<view class="icon-copy icon-eye-off" wx:if="{{member.contactRaw && !member.contactUnlocked}}" bindtap="unlockField" data-field="contact">
|
||||
<image class="icon-img" src="/assets/icons/eye-off.svg" mode="aspectFit"/>
|
||||
</view>
|
||||
<view class="icon-copy" wx:elif="{{member.contactRaw && member.contactUnlocked}}" bindtap="copyContact">📋</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="field" wx:if="{{member.wechatRaw || member.wechatDisplay}}">
|
||||
<text class="f-key">微信号</text>
|
||||
<view class="f-row">
|
||||
<text class="f-val mono">{{member.wechatUnlocked ? member.wechatFull : (member.wechatDisplay || member.wechatRaw)}}</text>
|
||||
<view class="icon-copy icon-eye-off" wx:if="{{member.wechatRaw && !member.wechatUnlocked}}" bindtap="unlockField" data-field="wechat">
|
||||
<image class="icon-img" src="/assets/icons/eye-off.svg" mode="aspectFit"/>
|
||||
</view>
|
||||
<view class="icon-copy" wx:elif="{{member.wechatRaw && member.wechatUnlocked}}" bindtap="copyWechat">📋</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 个人故事(未填写行已隐藏) -->
|
||||
<view class="card" wx:if="{{member.bestMonth || member.achievement || member.turningPoint}}">
|
||||
<view class="card-head">
|
||||
<text class="card-icon bulb">💡</text>
|
||||
<text class="card-label">个人故事</text>
|
||||
</view>
|
||||
<view class="card-body">
|
||||
<view class="story" wx:if="{{member.bestMonth}}">
|
||||
<view class="story-head"><text class="story-icon">🏆</text><text class="story-q">最赚钱的一个月做的是什么</text></view>
|
||||
<text class="story-a">{{member.bestMonth}}</text>
|
||||
</view>
|
||||
<view class="divider" wx:if="{{member.bestMonth}}"></view>
|
||||
<view class="story" wx:if="{{member.achievement}}">
|
||||
<view class="story-head"><text class="story-icon">⭐</text><text class="story-q">最有成就感的一件事</text></view>
|
||||
<text class="story-a">{{member.achievement}}</text>
|
||||
</view>
|
||||
<view class="divider" wx:if="{{member.achievement}}"></view>
|
||||
<view class="story" wx:if="{{member.turningPoint}}">
|
||||
<view class="story-head"><text class="story-icon turn">🔄</text><text class="story-q">人生的转折点</text></view>
|
||||
<text class="story-a">{{member.turningPoint}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 互助需求(未填写行已隐藏) -->
|
||||
<view class="card" wx:if="{{member.canHelp || member.needHelp}}">
|
||||
<view class="card-head">
|
||||
<text class="card-icon">🤝</text>
|
||||
<text class="card-label">互助需求</text>
|
||||
</view>
|
||||
<view class="card-body">
|
||||
<view class="help-box help-give" wx:if="{{member.canHelp}}">
|
||||
<text class="help-tag">我能帮你</text>
|
||||
<text class="help-txt">{{member.canHelp}}</text>
|
||||
</view>
|
||||
<view class="help-box help-need" wx:if="{{member.needHelp}}">
|
||||
<text class="help-tag need">我需要帮助</text>
|
||||
<text class="help-txt">{{member.needHelp}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 项目介绍 -->
|
||||
<view class="card" wx:if="{{member.project}}">
|
||||
<view class="card-head">
|
||||
<text class="card-icon rocket">🚀</text>
|
||||
<text class="card-label">项目介绍</text>
|
||||
</view>
|
||||
<text class="proj-txt">{{member.project}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 底部按钮 -->
|
||||
<view class="bottom-wrap">
|
||||
<view class="btn-super" bindtap="goToVip">
|
||||
<text>成为超级个体</text>
|
||||
<text class="btn-arrow">→</text>
|
||||
</view>
|
||||
</view>
|
||||
<view style="height:160rpx;"></view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 加载和空状态 -->
|
||||
<view class="state-wrap" wx:if="{{loading}}">
|
||||
<view class="loading-dot"></view>
|
||||
<text class="state-txt">加载中...</text>
|
||||
</view>
|
||||
<view class="state-wrap" wx:if="{{!loading && !member}}">
|
||||
<text class="state-emoji">👤</text>
|
||||
<text class="state-txt">暂无该超级个体信息</text>
|
||||
</view>
|
||||
</view>
|
||||
172
miniprogram/pages/member-detail/member-detail.wxss
Normal file
172
miniprogram/pages/member-detail/member-detail.wxss
Normal file
@@ -0,0 +1,172 @@
|
||||
/* Soul创业派对 - 个人资料页(enhanced_professional_profile 1:1 还原) */
|
||||
.page { background: #050B14; min-height: 100vh; color: #fff; }
|
||||
|
||||
/* 导航栏 */
|
||||
.nav-bar {
|
||||
position: fixed; top: 0; left: 0; right: 0; z-index: 999;
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
padding: 0 32rpx; height: 44px;
|
||||
background: rgba(5, 11, 20, 0.9);
|
||||
backdrop-filter: blur(24rpx);
|
||||
-webkit-backdrop-filter: blur(24rpx);
|
||||
border-bottom: 1rpx solid rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
.nav-back { width: 80rpx; height: 80rpx; display: flex; align-items: center; justify-content: flex-start; }
|
||||
.nav-icon { font-size: 44rpx; color: #5EEAD4; font-weight: 300; }
|
||||
.nav-title { font-size: 34rpx; font-weight: 700; color: #fff; letter-spacing: 2rpx; }
|
||||
.nav-right { display: flex; align-items: center; gap: 16rpx; }
|
||||
.nav-icon-wrap { padding: 8rpx; }
|
||||
.nav-icon-dot { font-size: 28rpx; color: rgba(255,255,255,0.8); }
|
||||
|
||||
.scroll-wrap { height: calc(100vh - 88px); }
|
||||
|
||||
/* ===== 顶部 Profile 卡片 ===== */
|
||||
.card-profile {
|
||||
position: relative; margin: 32rpx 32rpx 0;
|
||||
padding: 64rpx 40rpx 48rpx;
|
||||
border-radius: 32rpx;
|
||||
background: #0F1720;
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.08);
|
||||
overflow: hidden;
|
||||
}
|
||||
.profile-deco {
|
||||
position: absolute; top: 0; left: 0; right: 0; height: 128rpx;
|
||||
background: linear-gradient(180deg, rgba(30, 58, 69, 0.3) 0%, transparent 100%);
|
||||
pointer-events: none;
|
||||
}
|
||||
.profile-body { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; }
|
||||
.avatar-outer {
|
||||
position: relative;
|
||||
width: 176rpx; height: 176rpx;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
.avatar-wrap {
|
||||
position: relative;
|
||||
width: 100%; height: 100%;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
border: 2rpx solid rgba(255, 255, 255, 0.1);
|
||||
box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
.avatar-wrap.vip-ring {
|
||||
border: 4rpx solid transparent;
|
||||
background: linear-gradient(135deg, #F59E0B, #5EEAD4, #F59E0B);
|
||||
background-size: 200% 200%;
|
||||
animation: vipGlow 4s ease infinite;
|
||||
}
|
||||
@keyframes vipGlow {
|
||||
0%, 100% { background-position: 0% 50%; }
|
||||
50% { background-position: 100% 50%; }
|
||||
}
|
||||
.avatar-img { width: 100%; height: 100%; object-fit: cover; }
|
||||
.avatar-ph {
|
||||
width: 100%; height: 100%;
|
||||
background: #17212F;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 56rpx; color: #5EEAD4; font-weight: 700;
|
||||
}
|
||||
.vip-tag {
|
||||
position: absolute; bottom: -4rpx; right: -4rpx;
|
||||
background: linear-gradient(135deg, #F59E0B, #e8920d);
|
||||
color: #000; font-size: 20rpx; font-weight: 800;
|
||||
padding: 6rpx 14rpx; border-radius: 16rpx;
|
||||
z-index: 2;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.profile-name { font-size: 40rpx; font-weight: 700; color: #fff; margin-bottom: 24rpx; letter-spacing: 2rpx; }
|
||||
.profile-tags { display: flex; align-items: center; justify-content: center; gap: 24rpx; flex-wrap: wrap; }
|
||||
.tag { font-size: 24rpx; font-weight: 500; padding: 8rpx 24rpx; border-radius: 999rpx; }
|
||||
.tag-mbti { background: #134E4A; color: #5EEAD4; border: 1rpx solid rgba(94, 234, 212, 0.2); }
|
||||
.tag-region { background: #1F2937; color: #D1D5DB; border: 1rpx solid rgba(255, 255, 255, 0.1); display: flex; align-items: center; gap: 8rpx; }
|
||||
.pin-icon { color: #EF4444; font-size: 22rpx; }
|
||||
|
||||
/* ===== 通用卡片 ===== */
|
||||
.card {
|
||||
margin: 32rpx;
|
||||
padding: 40rpx 40rpx;
|
||||
border-radius: 32rpx;
|
||||
background: #0F1720;
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
.card-head { display: flex; align-items: center; gap: 20rpx; margin-bottom: 40rpx; }
|
||||
.card-icon { font-size: 40rpx; }
|
||||
.card-icon.bulb { filter: sepia(1) saturate(3) hue-rotate(15deg); }
|
||||
.card-icon.rocket { opacity: 0.9; }
|
||||
.card-label { font-size: 30rpx; font-weight: 700; color: #fff; letter-spacing: 1rpx; }
|
||||
|
||||
.card-body { }
|
||||
.field { margin-bottom: 32rpx; }
|
||||
.field:last-child { margin-bottom: 0; }
|
||||
.f-key { display: block; font-size: 26rpx; color: #94A3B8; margin-bottom: 12rpx; }
|
||||
.f-val { font-size: 30rpx; font-weight: 500; color: #fff; line-height: 1.6; }
|
||||
.f-val.mono { font-family: ui-monospace, monospace; letter-spacing: 2rpx; }
|
||||
.f-row { display: flex; align-items: center; gap: 16rpx; }
|
||||
.icon-copy { font-size: 36rpx; color: #94A3B8; opacity: 0.6; padding: 8rpx; }
|
||||
.icon-eye-off { display: flex; align-items: center; justify-content: center; }
|
||||
.icon-eye-off .icon-img { width: 40rpx; height: 40rpx; }
|
||||
|
||||
.divider { height: 1rpx; background: rgba(255, 255, 255, 0.05); margin: 32rpx 0; }
|
||||
|
||||
/* ===== 个人故事 ===== */
|
||||
.story { margin-bottom: 32rpx; }
|
||||
.story:last-child { margin-bottom: 0; }
|
||||
.story-head { display: flex; align-items: center; gap: 12rpx; margin-bottom: 12rpx; }
|
||||
.story-icon { font-size: 32rpx; }
|
||||
.story-icon.turn { opacity: 0.9; }
|
||||
.story-q { font-size: 26rpx; font-weight: 500; color: #94A3B8; }
|
||||
.story-a { display: block; font-size: 28rpx; color: #E5E7EB; line-height: 1.7; }
|
||||
|
||||
/* ===== 互助需求 ===== */
|
||||
.help-box {
|
||||
padding: 32rpx;
|
||||
border-radius: 24rpx;
|
||||
margin-bottom: 24rpx;
|
||||
background: #17212F;
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
.help-box:last-child { margin-bottom: 0; }
|
||||
.help-tag {
|
||||
display: inline-block;
|
||||
font-size: 22rpx; font-weight: 600;
|
||||
padding: 6rpx 16rpx; border-radius: 12rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
.help-give .help-tag { color: #5EEAD4; background: #112D2A; }
|
||||
.help-need .help-tag { color: #F59E0B; background: #2D1F0D; }
|
||||
.help-txt { display: block; font-size: 26rpx; color: #fff; line-height: 1.6; letter-spacing: 1rpx; }
|
||||
|
||||
/* ===== 项目介绍 ===== */
|
||||
.proj-txt { font-size: 28rpx; color: #E5E7EB; line-height: 1.7; }
|
||||
|
||||
/* ===== 底部按钮 ===== */
|
||||
.bottom-wrap {
|
||||
padding: 48rpx 32rpx 0;
|
||||
}
|
||||
.btn-super {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12rpx;
|
||||
width: 100%;
|
||||
padding: 32rpx 0;
|
||||
border-radius: 999rpx;
|
||||
background: transparent;
|
||||
border: 1rpx solid rgba(245, 158, 11, 0.3);
|
||||
color: #F59E0B;
|
||||
font-size: 30rpx; font-weight: 500;
|
||||
letter-spacing: 2rpx;
|
||||
}
|
||||
.btn-arrow { font-size: 36rpx; font-weight: 300; }
|
||||
|
||||
/* ===== 状态 ===== */
|
||||
.state-wrap { display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 60vh; gap: 24rpx; }
|
||||
.state-txt { font-size: 28rpx; color: #64748B; }
|
||||
.state-emoji { font-size: 96rpx; }
|
||||
.loading-dot {
|
||||
width: 56rpx; height: 56rpx;
|
||||
border-radius: 50%;
|
||||
border: 4rpx solid rgba(94, 234, 212, 0.2);
|
||||
border-top-color: #5EEAD4;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
@keyframes spin { to { transform: rotate(360deg); } }
|
||||
Reference in New Issue
Block a user