同步数据

This commit is contained in:
乘风
2026-04-02 19:20:19 +08:00
parent 76965adb23
commit 9ec4e0f9bd
903 changed files with 130902 additions and 15896 deletions

View File

@@ -31,7 +31,8 @@ Component({
},
data: {
svgData: ''
svgData: '',
fontGlyph: ''
},
lifetimes: {
@@ -41,28 +42,205 @@ Component({
},
methods: {
// SVG 图标数据映射
getSvgPath(name) {
const svgMap = {
'share': '<svg viewBox="0 0 24 24" fill="none" stroke="COLOR" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.59" y1="13.51" x2="15.42" y2="17.49"/><line x1="15.41" y1="6.51" x2="8.59" y2="10.49"/></svg>',
'arrow-up-right': '<svg viewBox="0 0 24 24" fill="none" stroke="COLOR" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="7" y1="17" x2="17" y2="7"/><polyline points="7 7 17 7 17 17"/></svg>',
'chevron-left': '<svg viewBox="0 0 24 24" fill="none" stroke="COLOR" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>',
'search': '<svg viewBox="0 0 24 24" fill="none" stroke="COLOR" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>',
'heart': '<svg viewBox="0 0 24 24" fill="none" stroke="COLOR" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>'
// iconfont 映射:与 static/iconfont.wxss 一一对应icon-xxx -> xxx
// 小程序不支持通过 :before { content } 渲染,因此必须直接输出 unicode 字符
getFontGlyph(name) {
const map = {
// === 来自 iconfont.wxss 完整映射 ===
'qianbao': '\ue6c8',
'gift': '\ue6c9',
'zap1': '\ue75c',
'user': '\ue6b9',
'upload': '\ue6ba',
'work': '\ue6bb',
'training': '\ue6bc',
'warning': '\ue6bd',
'zoom-in': '\ue6be',
'zoom-out': '\ue6bf',
'arrow-left-bold': '\ue6c1',
'arrow-up-bold': '\ue6c2',
'close-bold': '\ue6c3',
'arrow-down-bold': '\ue6c4',
'minus-bold': '\ue6c5',
'arrow-right-bold': '\ue6c6',
'select-bold': '\ue6c7',
'money-wallet': '\ue833',
'book-open': '\ue993',
'biaoshilei_yonghuzu': '\ue61b',
'add': '\ue664',
'add-circle': '\ue665',
'adjust': '\ue666',
'arrow-up-circle': '\ue667',
'arrow-right-circle': '\ue668',
'arrow-down': '\ue669',
'ashbin': '\ue66a',
'arrow-right': '\ue66b',
'browse': '\ue66c',
'bottom': '\ue66d',
'back': '\ue66e',
'bad': '\ue66f',
'arrow-left-circle': '\ue670',
'camera': '\ue671',
'chart-bar': '\ue672',
'attachment': '\ue673',
'code': '\ue674',
'close': '\ue675',
'check-item': '\ue676',
'calendar': '\ue677',
'comment': '\ue678',
'complete': '\ue679',
'direction-down': '\ue67a',
'direction-down-circle': '\ue67b',
'direction-right': '\ue67c',
'direction-up': '\ue67d',
'discount': '\ue67e',
'electronics': '\ue681',
'elipsis': '\ue682',
'export': '\ue683',
'explain': '\ue684',
'edit': '\ue685',
'eye-close': '\ue686',
'email': '\ue687',
'error': '\ue688',
'favorite': '\ue689',
'file-common': '\ue68a',
'file-delete': '\ue68b',
'file-add': '\ue68c',
'film': '\ue68d',
'fabulous': '\ue68e',
'file': '\ue68f',
'folder-close': '\ue690',
'filter': '\ue691',
'good': '\ue692',
'hide': '\ue693',
'home': '\ue694',
'file-open': '\ue695',
'forward': '\ue696',
'import': '\ue697',
'layers': '\ue698',
'lock': '\ue699',
'map': '\ue69a',
'menu': '\ue69b',
'help': '\ue69c',
'minus-circle': '\ue69d',
'notification': '\ue69e',
'more': '\ue69f',
'mobile-phone': '\ue6a0',
'minus': '\ue6a1',
'navigation': '\ue6a2',
'prompt': '\ue6a3',
'refresh': '\ue6a4',
'run-up': '\ue6a5',
'picture': '\ue6a6',
'run-in': '\ue6a7',
'pin': '\ue6a8',
'save': '\ue6a9',
'search': '\ue6aa',
'share': '\ue6ab',
'scanning': '\ue6ac',
'security': '\ue6ad',
'sign-out': '\ue6ae',
'select': '\ue6af',
'stop': '\ue6b0',
'success': '\ue6b1',
'switch': '\ue6b2',
'setting': '\ue6b3',
'survey': '\ue6b4',
'time': '\ue6b5',
'telephone': '\ue6b6',
'top': '\ue6b7',
'unlock': '\ue6b8',
// === 业务别名(兼容 lucide 等命名)===
'wallet': '\ue6c8',
'chevron-left': '\ue6c1',
'chevron-right': '\ue6c6',
'chevron-down': '\ue6c4',
'chevron-up': '\ue6c2',
'x': '\ue6c3',
'check': '\ue6c7',
'trash-2': '\ue66a',
'pencil': '\ue685',
'zap': '\ue75c',
'info': '\ue69c',
'map-pin': '\ue6a8',
'message-circle': '\ue678',
'smartphone': '\ue6a0',
'refresh-cw': '\ue6a4',
'shield': '\ue6ad',
'star': '\ue689',
'heart': '\ue68e',
'bar-chart': '\ue672',
'clock': '\ue6b5',
}
return map[name] || ''
},
// SVG 图标数据映射Lucide 风格,替换原 emoji
getSvgPath(name) {
const s = '<svg viewBox="0 0 24 24" fill="none" stroke="COLOR" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">'
const svgMap = {
'share': s + '<circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.59" y1="13.51" x2="15.42" y2="17.49"/><line x1="15.41" y1="6.51" x2="8.59" y2="10.49"/></svg>',
'arrow-up-right': s + '<line x1="7" y1="17" x2="17" y2="7"/><polyline points="7 7 17 7 17 17"/></svg>',
'chevron-left': s + '<polyline points="15 18 9 12 15 6"/></svg>',
'search': s + '<circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>',
'heart': s + '<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>',
'user': s + '<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>',
'smartphone': s + '<rect x="5" y="2" width="14" height="20" rx="2" ry="2"/><line x1="12" y1="18" x2="12.01" y2="18"/></svg>',
'map-pin': s + '<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>',
'home': s + '<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>',
'star': s + '<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>',
'message-circle': s + '<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/></svg>',
'package': s + '<line x1="16.5" y1="9.4" x2="7.5" y2="4.21"/><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>',
'book-open': s + '<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>',
'lightbulb': s + '<path d="M9 18h6"/><path d="M10 22h4"/><path d="M15.09 14c.18-.98.65-1.74 1.41-2.5A4.65 4.65 0 0 0 18 8 6 6 0 0 0 6 8c0 1 .23 2.23 1.5 3.5A4.61 4.61 0 0 1 8.91 14"/></svg>',
'handshake': s + '<path d="m11 17 2 2a1 1 0 1 0 3-3"/><path d="m14 14 2.5 2.5a1 1 0 1 0 3-3l-3.88-3.88a1 1 0 0 0-1.4 1.4l.88.88"/><path d="M15 9 9.03 9"/><path d="m14 14-2.5-2.5"/><path d="m18 15-3-3"/><path d="m15 12-3-3"/><path d="m9 12 2 2"/></svg>',
'rocket': s + '<path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z"/><path d="m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z"/><path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0"/><path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5"/></svg>',
'trophy': s + '<path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6"/><path d="M18 9h1.5a2.5 2.5 0 0 0 0-5H18"/><path d="M4 22h16"/><path d="M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20 7 22"/><path d="M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20 17 22"/><path d="M18 2H6v7a6 6 0 0 0 12 0V2Z"/></svg>',
'refresh-cw': s + '<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>',
'shield': s + '<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>',
'wallet': s + '<path d="M21 12V7H5a2 2 0 0 1 0-4h14v4"/><path d="M3 5v14a2 2 0 0 0 2 2h16v-5"/><path d="M18 12a2 2 0 0 0 0 4h4v-4h-4z"/></svg>',
'wrench': s + '<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>',
'camera': s + '<path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z"/><circle cx="12" cy="13" r="3"/></svg>',
'phone': s + '<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"/></svg>',
'clipboard': s + '<rect x="8" y="2" width="8" height="4" rx="1" ry="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/><rect x="8" y="6" width="8" height="12" rx="1"/></svg>',
'megaphone': s + '<path d="m3 11 18-5v12L3 14v-3z"/><path d="M11.6 16.8a3 3 0 1 1-5.8-1.6"/></svg>',
'image': s + '<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/></svg>',
'gift': s + '<polyline points="20 12 20 22 4 22 4 12"/><rect x="2" y="7" width="20" height="5"/><line x1="12" y1="22" x2="12" y2="7"/><path d="M12 7H7.5a2.5 2.5 0 0 1 0-5C11 2 12 7 12 7z"/><path d="M12 7h4.5a2.5 2.5 0 0 0 0-5C13 2 12 7 12 7z"/></svg>',
'lock': s + '<rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>',
'lock-open': s + '<rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 9.9-1"/></svg>',
'sparkles': s + '<path d="m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z"/></svg>',
'save': s + '<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg>',
'globe': s + '<circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>',
'users': s + '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>',
'gamepad': s + '<line x1="6" y1="12" x2="10" y2="12"/><line x1="8" y1="10" x2="8" y2="14"/><line x1="15" y1="13" x2="15.01" y2="13"/><line x1="18" y1="11" x2="18.01" y2="11"/><rect x="2" y="6" width="20" height="12" rx="2"/></svg>',
'check': s + '<polyline points="20 6 9 17 4 12"/></svg>',
'trash-2': s + '<polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><line x1="10" y1="11" x2="10" y2="17"/><line x1="14" y1="11" x2="14" y2="17"/></svg>',
'clock': s + '<circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>',
'plus': s + '<line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>',
'briefcase': s + '<rect x="2" y="7" width="20" height="14" rx="2" ry="2"/><path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/></svg>',
'target': s + '<circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/></svg>',
'rotate-ccw': s + '<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>',
'corner-down-left': s + '<polyline points="9 10 4 15 9 20"/><path d="M20 4v7a4 4 0 0 1-4 4H4"/></svg>',
'folder': s + '<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/><line x1="12" y1="11" x2="12" y2="17"/></svg>',
'bar-chart': s + '<line x1="12" y1="20" x2="12" y2="10"/><line x1="18" y1="20" x2="18" y2="4"/><line x1="6" y1="20" x2="6" y2="16"/></svg>',
'link': s + '<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>'
}
return svgMap[name] || ''
},
// 更新图标
updateIcon() {
const { name, color } = this.data
const fontGlyph = this.getFontGlyph(name)
let svgString = this.getSvgPath(name)
// 若 iconfont 存在映射,则优先用字体图标;否则走 SVG
if (fontGlyph) {
this.setData({ fontGlyph, svgData: '' })
return
}
if (svgString) {
// 替换颜色占位符
svgString = svgString.replace(/COLOR/g, color)
@@ -71,11 +249,13 @@ Component({
const svgData = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgString)}`
this.setData({
svgData: svgData
svgData: svgData,
fontGlyph: ''
})
} else {
this.setData({
svgData: ''
svgData: '',
fontGlyph: ''
})
}
}

View File

@@ -1,5 +1,11 @@
<!-- components/icon/icon.wxml -->
<view class="icon icon-{{name}} {{customClass}}" style="width: {{size}}rpx; height: {{size}}rpx; {{customStyle}}">
<image wx:if="{{svgData}}" class="icon-image" src="{{svgData}}" mode="aspectFit" style="width: {{size}}rpx; height: {{size}}rpx;" />
<!-- 优先 iconfont其次 SVG dataUrl最后兜底 name 文本 -->
<text
wx:if="{{fontGlyph}}"
class="iconfont"
style="font-size: {{size}}rpx; line-height: {{size}}rpx; color: {{color}};"
>{{fontGlyph}}</text>
<image wx:elif="{{svgData}}" class="icon-image" src="{{svgData}}" mode="aspectFit" style="width: {{size}}rpx; height: {{size}}rpx;" />
<text wx:else class="icon-text">{{name}}</text>
</view>

View File

@@ -1,4 +1,5 @@
/* components/icon/icon.wxss */
.icon {
display: inline-flex;
align-items: center;
@@ -6,6 +7,13 @@
flex-shrink: 0;
}
.iconfont {
font-family: "iconfont" !important;
display: inline-flex;
align-items: center;
justify-content: center;
}
.icon-image {
display: block;
width: 100%;

View File

@@ -0,0 +1,79 @@
/**
* Soul 创业派对 - 公用登录弹窗
* 手机号一键登录 + 隐私协议
*/
Component({
properties: {
show: { type: Boolean, value: false },
desc: { type: String, value: '登录后可购买章节、解锁更多内容' },
showPrivacyModal: { type: Boolean, value: false },
showCancel: { type: Boolean, value: false }
},
data: {
agreeProtocol: false,
isLoggingIn: false
},
observers: {
show(v) {
if (!v) this.setData({ agreeProtocol: false, isLoggingIn: false })
}
},
methods: {
stopPropagation() {},
onClose() {
this.triggerEvent('close')
},
onToggleAgree() {
this.setData({ agreeProtocol: !this.data.agreeProtocol })
},
onOpenUserProtocol() {
wx.navigateTo({ url: '/pages/agreement/agreement' })
},
onOpenPrivacy() {
wx.navigateTo({ url: '/pages/privacy/privacy' })
},
onAgreePrivacy() {
const app = getApp()
if (app._privacyResolve) {
app._privacyResolve({ buttonId: 'agree-privacy-btn', event: 'agree' })
app._privacyResolve = null
}
this.triggerEvent('privacyagree')
},
async onPhoneLogin(e) {
if (!e.detail.code) {
return this._fallbackWechatLogin()
}
const app = getApp()
this.setData({ isLoggingIn: true })
try {
const result = await app.loginWithPhone(e.detail.code)
this.setData({ isLoggingIn: false })
if (result) {
this.triggerEvent('success')
} else {
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
}
} catch (err) {
this.setData({ isLoggingIn: false })
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
}
},
async _fallbackWechatLogin() {
const app = getApp()
this.setData({ isLoggingIn: true })
try {
const result = await app.login()
this.setData({ isLoggingIn: false })
if (result) {
this.triggerEvent('success')
} else {
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
}
} catch (err) {
this.setData({ isLoggingIn: false })
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
}
}
}
})

View File

@@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"icon": "/components/icon/icon"
}
}

View File

@@ -0,0 +1,27 @@
<!-- Soul 创业派对 - 公用登录弹窗 -->
<view class="modal-overlay" wx:if="{{show}}" bindtap="onClose">
<view class="modal-content login-modal" catchtap="stopPropagation">
<view class="modal-close" bindtap="onClose"><icon name="x" size="36" color="#8e8e93"></icon></view>
<view class="login-icon"><icon name="lock" size="80" color="#00CED1"></icon></view>
<text class="login-title">登录 卡若创业派对</text>
<text class="login-desc">{{desc}}</text>
<button id="agree-phone-btn" class="btn-wechat {{agreeProtocol ? '' : 'btn-wechat-disabled'}}" open-type="getPhoneNumber|agreePrivacyAuthorization" bindgetphonenumber="onPhoneLogin" bindagreeprivacyauthorization="onAgreePrivacy" disabled="{{isLoggingIn || !agreeProtocol}}" hover-class="btn-wechat-hover">
<text class="btn-wechat-icon">微</text>
<text>{{isLoggingIn ? '登录中...' : '手机号一键登录'}}</text>
</button>
<view class="privacy-wechat-row" wx:if="{{showPrivacyModal}}">
<text class="privacy-wechat-desc">为获取手机号,请先同意《用户隐私保护指引》</text>
<button id="agree-privacy-btn" class="privacy-agree-btn" open-type="agreePrivacyAuthorization" bindagreeprivacyauthorization="onAgreePrivacy" hover-class="privacy-agree-btn-hover">同意</button>
</view>
<view class="login-modal-cancel" wx:if="{{showCancel}}" bindtap="onClose">取消</view>
<view class="login-agree-row" catchtap="onToggleAgree">
<view class="agree-checkbox {{agreeProtocol ? 'agree-checked' : ''}}"><icon wx:if="{{agreeProtocol}}" name="check" size="24" color="#34C759"></icon></view>
<text class="agree-text">我已阅读并同意</text>
<text class="agree-link" catchtap="onOpenUserProtocol">《用户协议》</text>
<text class="agree-text">和</text>
<text class="agree-link" catchtap="onOpenPrivacy">《隐私政策》</text>
</view>
</view>
</view>

View File

@@ -0,0 +1,140 @@
/* Soul 创业派对 - 公用登录弹窗 */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.7);
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
padding: 48rpx;
}
.modal-content {
width: 100%;
max-width: 600rpx;
background: #1c1c1e;
border-radius: 32rpx;
overflow: hidden;
}
.modal-close {
position: absolute;
top: 24rpx;
right: 24rpx;
z-index: 1;
padding: 16rpx;
}
.login-modal {
padding: 48rpx 32rpx;
text-align: center;
}
.login-icon {
font-size: 80rpx;
display: block;
margin-bottom: 24rpx;
}
.login-title {
font-size: 36rpx;
font-weight: 700;
color: #ffffff;
display: block;
margin-bottom: 16rpx;
}
.login-desc {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.5);
display: block;
margin-bottom: 48rpx;
}
.btn-wechat {
display: flex;
align-items: center;
justify-content: center;
gap: 16rpx;
padding: 28rpx;
background: #07C160;
color: #ffffff;
font-size: 30rpx;
font-weight: 600;
border-radius: 24rpx;
margin-bottom: 20rpx;
border: none;
}
.btn-wechat::after { border: none; }
.btn-wechat-icon {
width: 40rpx;
height: 40rpx;
background: rgba(255, 255, 255, 0.2);
border-radius: 8rpx;
font-size: 24rpx;
display: flex;
align-items: center;
justify-content: center;
}
.btn-wechat-disabled { opacity: 0.6; }
.login-modal-cancel {
margin-top: 24rpx;
padding: 24rpx;
font-size: 28rpx;
color: rgba(255, 255, 255, 0.5);
text-align: center;
}
.privacy-wechat-row {
margin: 24rpx 0;
padding: 24rpx;
background: rgba(0, 206, 209, 0.1);
border-radius: 16rpx;
}
.privacy-wechat-desc {
display: block;
font-size: 26rpx;
color: rgba(255, 255, 255, 0.8);
margin-bottom: 16rpx;
}
.privacy-agree-btn {
width: 100%;
padding: 20rpx;
background: #07C160;
color: #fff;
font-size: 28rpx;
border-radius: 16rpx;
border: none;
}
.privacy-agree-btn::after { border: none; }
.login-agree-row {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
margin-top: 32rpx;
font-size: 22rpx;
color: rgba(255, 255, 255, 0.5);
}
.agree-checkbox {
width: 32rpx;
height: 32rpx;
border: 2rpx solid rgba(255, 255, 255, 0.5);
border-radius: 6rpx;
margin-right: 12rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 22rpx;
flex-shrink: 0;
}
.agree-checked {
background: #00CED1;
border-color: #00CED1;
}
.agree-text { color: rgba(255, 255, 255, 0.6); }
.agree-link {
color: #00CED1;
text-decoration: underline;
padding: 0 4rpx;
}
/* 显式 hover 类名,避免基础库 3.x 报 hoverClass / hoverClassDisable 类型非法 */
.btn-wechat-hover { opacity: 0.92; }
.privacy-agree-btn-hover { opacity: 0.88; }