diff --git a/pwuniapp/pages.json b/pwuniapp/pages.json index 3626291..82e8510 100644 --- a/pwuniapp/pages.json +++ b/pwuniapp/pages.json @@ -56,6 +56,15 @@ "backgroundColor": "#0A0F1D" } }, + { + "path": "pages/expert/apply", + "style": { + "navigationBarTitleText": "大神入驻认证", + "navigationBarBackgroundColor": "#0A0F1D", + "navigationBarTextStyle": "white", + "backgroundColor": "#0A0F1D" + } + }, { "path": "pages/order/create", "style": { diff --git a/pwuniapp/pages/expert/apply.vue b/pwuniapp/pages/expert/apply.vue new file mode 100644 index 0000000..0318ef7 --- /dev/null +++ b/pwuniapp/pages/expert/apply.vue @@ -0,0 +1,983 @@ + + + + + diff --git a/pwuniapp/pages/user/index.vue b/pwuniapp/pages/user/index.vue index 497b306..2700470 100644 --- a/pwuniapp/pages/user/index.vue +++ b/pwuniapp/pages/user/index.vue @@ -261,74 +261,6 @@ - - - - - 陪伴师 / 大神入驻实名申请 - - - - - - - - 提交真实有效资料,平台将在 24 小时内由运营团队人工核验后开通接单工作台。 - - - - 真实姓名 - - - - - 身份证号码 - - - - - 主营陪伴品类 - - - {{ trk }} - - - - - - 期望服务单价 (元/小时,平台限价: ¥{{ expertPriceMin }} - ¥{{ expertPriceMax }}) - - - - - 技能专长标签 (最多选6项) - - - {{ tg }} - - - - - - - - - - - - @@ -346,7 +278,7 @@ import { ICONS } from '@/common/icons.js'; import { getCurrentThemeKey, setTheme, THEME_KEYS, applyThemeToNativeUI } from '@/common/theme.js'; import { getCurrentRole, setCurrentRole, ROLE_TYPES, toggleRole as toggleUserRole, isExpertCertified, getExpertCertStatus, setExpertCertStatus, CERT_STATUS } from '@/common/role.js'; import { getNavBarInfo } from '@/common/nav.js'; -import { getUserProfile, rechargeBalance, withdrawCommission, getUserFinanceRecords, updateUserProfile, uploadImage, getRechargeTiers, getPlatformConfigs } from '@/common/api.js'; +import { getUserProfile, rechargeBalance, withdrawCommission, getUserFinanceRecords, updateUserProfile, uploadImage, getRechargeTiers, getPlatformConfigs, applyExpertCert } from '@/common/api.js'; const DEFAULT_GUEST_AVATAR = 'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=200'; const isLoggedIn = ref(true); @@ -895,115 +827,14 @@ const showInvitePoster = () => { }); }; +// 大神实名入驻认证已全面升级重构为独立专享页面 /pages/expert/apply const showExpertCertModal = ref(false); -const expertCertForm = ref({ - realName: '', - idCard: '', - track: '同城陪吃', - hourlyRate: 88, - tags: [] -}); - -const expertPriceMin = computed(() => { - return platformConfigs.value.expert_rules?.minHourlyRate || 30; -}); -const expertPriceMax = computed(() => { - return platformConfigs.value.expert_rules?.maxHourlyRate || 500; -}); -const expertDefaultRate = computed(() => { - return platformConfigs.value.expert_rules?.defaultHourlyRate || 88; -}); -const expertCandidateTags = computed(() => { - return platformConfigs.value.expert_rules?.candidateTags || [ - '国服王者', '声优达人', '幽默风趣', '随叫随到', '暖心倾听', - '百星野王', '金牌探店', '量贩麦霸', '微醺搭子' - ]; -}); - -const toggleCertTag = (tag) => { - const idx = expertCertForm.value.tags.indexOf(tag); - if (idx > -1) { - expertCertForm.value.tags.splice(idx, 1); - } else { - if (expertCertForm.value.tags.length >= 6) { - uni.showToast({ title: '最多选择6个技能标签', icon: 'none' }); - return; - } - expertCertForm.value.tags.push(tag); - } -}; - -const submitExpertCertForm = async () => { - if (!expertCertForm.value.realName || !expertCertForm.value.realName.trim()) { - uni.showToast({ title: '请输入真实姓名', icon: 'none' }); - return; - } - if (!expertCertForm.value.idCard || expertCertForm.value.idCard.length < 15) { - uni.showToast({ title: '请输入有效身份证号', icon: 'none' }); - return; - } - - const rate = Number(expertCertForm.value.hourlyRate) || expertDefaultRate.value; - if (rate < expertPriceMin.value || rate > expertPriceMax.value) { - uni.showToast({ title: `单价需在 ¥${expertPriceMin.value} - ¥${expertPriceMax.value} 之间`, icon: 'none' }); - return; - } - - uni.showLoading({ title: '正在提交认证...' }); - try { - await applyExpertCert({ - userId: user.value.id || 1001, - name: expertCertForm.value.realName.trim(), - idCard: expertCertForm.value.idCard.trim(), - track: expertCertForm.value.track, - hourlyRate: rate, - tags: expertCertForm.value.tags, - avatar: user.value.avatar, - gender: user.value.gender === 'male' ? '男' : '女' - }); - setExpertCertStatus(CERT_STATUS.PENDING); - showExpertCertModal.value = false; - uni.hideLoading(); - uni.showModal({ - title: '申请已提交', - content: '您的入驻申请已成功提交至平台审核中心,运营团队核准后即可自动开通接单工作台。', - showCancel: false, - confirmText: '我知道了' - }); - } catch (e) { - uni.hideLoading(); - uni.showToast({ title: e.message || '提交申请失败', icon: 'none' }); - } -}; const applyExpert = () => { if (!ensureLoggedIn()) return; - const certStatus = getExpertCertStatus(); - if (certStatus === CERT_STATUS.APPROVED) { - uni.showToast({ - title: '您已通过大神实名认证,接单权限正常', - icon: 'none' - }); - return; - } - if (certStatus === CERT_STATUS.PENDING) { - uni.showModal({ - title: '认证审核中', - content: '您的入驻申请正在平台运营端审核中,请耐心等待核准。', - showCancel: false, - confirmText: '我知道了' - }); - return; - } - - expertCertForm.value = { - realName: '', - idCard: '', - track: '同城陪吃', - hourlyRate: expertDefaultRate.value, - tags: [] - }; - showExpertCertModal.value = true; + uni.navigateTo({ + url: '/pages/expert/apply' + }); }; const contactService = () => { @@ -1854,73 +1685,6 @@ const navTo = (url) => { } } -.expert-cert-modal { - max-height: 85vh; - overflow-y: auto; - - .cert-alert { - background: rgba(99, 102, 241, 0.08); - border: 1px solid rgba(99, 102, 241, 0.2); - border-radius: 12rpx; - padding: 16rpx 20rpx; - margin-bottom: 24rpx; - - .cert-alert-text { - font-size: 24rpx; - color: #6366F1; - line-height: 1.5; - } - } - - .track-chips, .tags-chips { - display: flex; - flex-wrap: wrap; - gap: 14rpx; - margin-top: 10rpx; - - .track-chip, .tag-pill { - font-size: 24rpx; - padding: 12rpx 24rpx; - border-radius: 30rpx; - background: var(--bg-card, #1E293B); - color: #94A3B8; - border: 1px solid rgba(255, 255, 255, 0.1); - transition: all 0.2s ease; - - &.active { - background: #6366F1; - color: #FFFFFF; - border-color: #6366F1; - box-shadow: 0 4rpx 12rpx rgba(99, 102, 241, 0.35); - } - } - } -} - -.theme-warm .expert-cert-modal { - .cert-alert { - background: #FFF7ED; - border-color: #FDBA74; - - .cert-alert-text { - color: #EA580C; - } - } - - .track-chips .track-chip, .tags-chips .tag-pill { - background: #FDFBF7; - color: #78716C; - border-color: #E7E2D8; - - &.active { - background: linear-gradient(135deg, #EA580C, #F97316); - color: #FFFFFF; - border-color: #EA580C; - box-shadow: 0 4rpx 14rpx rgba(234, 88, 12, 0.35); - } - } -} - .guest-badge { font-size: 20rpx; color: #94A3B8; diff --git a/server/tests/content-security.spec.ts b/server/tests/content-security.spec.ts index bd7e57b..ea1a3cb 100644 --- a/server/tests/content-security.spec.ts +++ b/server/tests/content-security.spec.ts @@ -130,7 +130,7 @@ describe('ContentSecurityService & Compliance Architecture (TDD 微信内容安 const raw = fs.readFileSync(pagesJsonPath, 'utf-8'); const config = JSON.parse(raw); expect(Array.isArray(config.pages)).toBe(true); - expect(config.pages.length).toBe(13); + expect(config.pages.length).toBe(14); for (const pageItem of config.pages) { const vueFilePath = path.join(rootDir, 'pwuniapp', `${pageItem.path}.vue`); @@ -407,5 +407,44 @@ describe('ContentSecurityService & Compliance Architecture (TDD 微信内容安 expect(emojiRegex.test(text)).toBe(false); }); }); + + describe('11. 大神实名认证专属独立页面与多态流程验证 (pages/expert/apply.vue)', () => { + it('pages.json 必须成功注册 pages/expert/apply 且物理文件必须存在', () => { + const applyPath = path.join(rootDir, 'pwuniapp', 'pages', 'expert', 'apply.vue'); + expect(fs.existsSync(applyPath)).toBe(true); + const pagesJsonPath = path.join(rootDir, 'pwuniapp', 'pages.json'); + const pagesJson = fs.readFileSync(pagesJsonPath, 'utf-8'); + expect(pagesJson).toContain('pages/expert/apply'); + expect(pagesJson).toContain('大神入驻认证'); + }); + + it('大神入驻申请独立页面必须包含完整表单、协议声明与提交接口', () => { + const applyPath = path.join(rootDir, 'pwuniapp', 'pages', 'expert', 'apply.vue'); + const content = fs.readFileSync(applyPath, 'utf-8'); + expect(content).toContain('applyForm'); + expect(content).toContain('applyExpertCert'); + expect(content).toContain('TRACK_OPTIONS'); + expect(content).toContain('expertPriceMin'); + expect(content).toContain('expertPriceMax'); + expect(content).toContain('candidateTags'); + expect(content).toContain('submitApply'); + expect(content).toContain('实名认证审核中'); + expect(content).toContain('已通过大神实名认证'); + }); + + it('个人中心的大神入驻入口必须路由跳转至 /pages/expert/apply', () => { + const userIndexPath = path.join(rootDir, 'pwuniapp', 'pages', 'user', 'index.vue'); + const content = fs.readFileSync(userIndexPath, 'utf-8'); + expect(content).toContain('/pages/expert/apply'); + }); + + it('新页面与改造代码严禁包含任何系统 Emoji', () => { + const applyPath = path.join(rootDir, 'pwuniapp', 'pages', 'expert', 'apply.vue'); + const content = fs.readFileSync(applyPath, 'utf-8'); + const emojiRegex = /(?:\p{Extended_Pictographic}|\p{Emoji_Presentation}|[\u2600-\u27BF])/u; + expect(emojiRegex.test(content)).toBe(false); + }); + }); }); +