Backend - Service Station: expose the 「临时公告」 chain end-to-end (V042 table/service existed but had ZERO endpoints -> both admin and miniapp could never reach it): 5 operator endpoints (list/create/update/publish/archive) + 1 user-facing read endpoint. - Fix privilege escalation: create/update were guarded only by the class-level service_location.view, making V015's service_location.manage a never-used dead permission -> read-only roles could edit stations. Permissions moved to method level. - Add ServiceLocationOperatorController to OperatorEndpointPermissionCoverageTest (it was NOT scanned, which is why the escalation stayed invisible). - Add create/update validation (address NOT NULL + status CHECK only blew up on PG). - Banner: validation failures threw bare RuntimeException -> 500; now VALIDATION_ERROR -> 400. Add deleted_at IS NULL to both home queries (soft-deleted banners stayed live). - Content: operator list/detail split (admin «publish» was a dead end because it reused the published-only public API); category deactivate/reactivate; article body on edit. - Service Program: operator member list now includes pending (approval reachable); active-only public visibility (draft leak); memberCount/pendingCount aggregation; withdraw/removeMember; reuse row on re-apply (UNIQUE(program_id,user_id) crash). - MeController: add the missing GET /me/service-history route. Schema / guards - schema-h2.sql: add service_location_announcements (+ chk_announcement_status) and content_categories (+ uk_content_category_code, chk_category_status); move both into REQUIRED_IN_TEST_SCHEMA. MigrationValidationTest baseline 41 -> 42. - V11PermissionMatrixContractTest now scans ALL migrations instead of hardcoding V015+V029. - New: ServiceLocationAnnouncementPhase19IntegrationTest (24), ServiceLocationControllerPermissionContractTest (5), ServiceLocationAnnouncementConstraintParityTest (5, prod DDL <-> test schema <-> backend whitelist <-> admin labels). Frontend - admin-web: ServiceStationView gains announcement management (statuses, create/edit, publish/archive with confirm, expiry); write buttons gated by service_location.manage. - miniapp: U50 renders the 临时公告 block via new serviceStationService; page no longer talks to utils/api directly; announcement failure degrades to [] instead of erroring. - ui-tests: U37 four-group + U50 announcement contracts; /home assertion retargeted to the service layer. Verification - Negative verification: 3 injected defects (drop soft-delete filter / drop test-schema CHECK / downgrade write endpoint to view) -> 4 named tests fail precisely, no collateral failures; restored, NEG-VAL residue = 0. - Backend full regression: 602 tests, 0 failures, 0 errors, 3 skipped (baseline 420). - admin-web: vue-tsc --noEmit EXIT=0, vite build EXIT=0. Miniapp: tsc --noEmit EXIT=0. - ui-tests 14/14 PASS.
80 lines
7.3 KiB
Plaintext
80 lines
7.3 KiB
Plaintext
<view class="page app-page reference-page">
|
|
<view wx:if="{{!isLoggedIn}}" class="mine-guest">
|
|
<view class="guest-brand"><image src="/assets/brand/logo-mark.png" mode="aspectFit" /><text>善缘丹阳</text><text class="guest-subtitle">公益婚恋服务平台</text></view>
|
|
<ui-empty illustration="default" title="登录后查看我的服务" description="管理资料、缘分与公益服务记录" actions="{{loginActions}}" bind:action="onLoginAction" />
|
|
</view>
|
|
<ui-loading wx:elif="{{loadStatus === 'loading' && !profile}}" mode="skeleton" rows="6" />
|
|
<block wx:else>
|
|
<view class="profile-hero">
|
|
<view class="mine-nav"><text>我的</text><image src="/assets/icons/home/service-station.png" mode="aspectFit" bindtap="onGoSettings" /></view>
|
|
<view class="profile-main">
|
|
<ui-avatar src="{{profile.avatarUrl || ''}}" size="xl" default-text="{{profile.displayName || '善缘用户'}}" verified="{{isRealNameVerified}}" reviewed="{{isProfileApproved}}" />
|
|
<view class="profile-copy">
|
|
<view class="profile-name-row"><text class="profile-name">{{profile.displayName || '未填写昵称'}}</text><text class="profile-status">{{relationshipText}}</text></view>
|
|
<text class="profile-meta">资料完整度 {{profileCompleteness}}%</text>
|
|
<view class="profile-progress"><view style="width:{{profileCompleteness}}%"></view></view>
|
|
<view class="profile-badges"><ui-status-badge kind="{{isRealNameVerified ? 'success' : 'warning'}}" label="{{isRealNameVerified ? '已实名' : '未实名'}}" /><ui-status-badge kind="{{isProfileApproved ? 'success' : 'warning'}}" label="{{isProfileApproved ? '资料已审核' : '资料待审核'}}" /></view>
|
|
</view>
|
|
<text class="edit-profile" bindtap="onEditProfile">编辑资料</text>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="profile-stats">
|
|
<view class="profile-stat"><text class="stat-value">{{profileCompleteness}}%</text><text class="stat-label">资料完整</text></view>
|
|
<view class="profile-stat" bindtap="onGoLikers"><text class="stat-value">{{likersCount}}</text><text class="stat-label">喜欢我的</text></view>
|
|
<view class="profile-stat" bindtap="onGoFate"><text class="stat-value">{{matchCount}}</text><text class="stat-label">当前缘分</text></view>
|
|
<view class="profile-stat"><text class="stat-value stat-value--text">{{reviewStatusText}}</text><text class="stat-label">资料状态</text></view>
|
|
</view>
|
|
|
|
<view class="public-identity-card" bindtap="onEditProfile">
|
|
<image src="/assets/brand/logo-mark.png" mode="aspectFit" />
|
|
<view><text class="identity-title">我在善缘丹阳</text><text class="identity-desc">用真诚遇见美好,让爱在丹阳绽放</text></view>
|
|
<image class="identity-arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" />
|
|
</view>
|
|
|
|
<!-- 分组一:我的资料与缘分(U37 四组结构)-->
|
|
<ui-section-header title="我的资料与缘分" subtitle="资料、择偶条件与当前缘分" />
|
|
<view class="list-group">
|
|
<view class="list-row" bindtap="onEditProfile"><text class="list-label">我的资料</text><text class="list-value">{{reviewStatusText}}</text><image class="list-arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" /></view>
|
|
<view class="list-row" bindtap="onEditPreference"><text class="list-label">择偶条件</text><image class="list-arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" /></view>
|
|
<view class="list-row" bindtap="onGoFate"><text class="list-label">我的缘分</text><image class="list-arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" /></view>
|
|
</view>
|
|
|
|
<!-- 分组二:公益服务(U49 公益服务中心入口 + 四类服务 + 服务记录)-->
|
|
<ui-section-header title="我的公益服务" subtitle="服务进度与预约记录" />
|
|
<view class="list-group">
|
|
<view class="list-row" bindtap="onGoServiceCenter"><text class="list-label">公益服务中心</text><text class="list-value">咨询 · 预约 · 课堂</text><image class="list-arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" /></view>
|
|
</view>
|
|
<view class="service-grid">
|
|
<view class="service-entry" bindtap="onGoMatchmaker"><view class="service-icon rose"><image src="/assets/icons/home/matchmaker.png" mode="aspectFit" /></view><text>我的红娘</text></view>
|
|
<view class="service-entry" bindtap="onGoCounseling"><view class="service-icon blue"><image src="/assets/icons/home/counseling.png" mode="aspectFit" /></view><text>我的咨询</text></view>
|
|
<view class="service-entry" bindtap="onGoActivities"><view class="service-icon amber"><image src="/assets/icons/home/activity.png" mode="aspectFit" /></view><text>我的活动</text></view>
|
|
<view class="service-entry" bindtap="onGoAppointments"><view class="service-icon green"><image src="/assets/icons/home/service-station.png" mode="aspectFit" /></view><text>我的预约</text></view>
|
|
</view>
|
|
<view class="list-group">
|
|
<view class="list-row" bindtap="onGoServiceHistory"><text class="list-label">公益服务记录</text><text class="list-value">仅本人可见</text><image class="list-arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" /></view>
|
|
</view>
|
|
|
|
<!-- 分组三:安全与隐私 -->
|
|
<ui-section-header title="安全与隐私" subtitle="隐私、黑名单与账号" />
|
|
<view class="list-group secondary-list">
|
|
<view class="list-row" bindtap="onGoPrivacy"><text class="list-label">隐私设置</text><image class="list-arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" /></view>
|
|
<view class="list-row" bindtap="onGoBlacklist"><text class="list-label">黑名单</text><image class="list-arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" /></view>
|
|
<view class="list-row" bindtap="onGoSafety"><text class="list-label">举报与安全</text><image class="list-arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" /></view>
|
|
<view class="list-row" bindtap="onGoSettings"><text class="list-label">账号设置</text><image class="list-arrow" src="/assets/icons/ui/chevron-right.png" mode="aspectFit" /></view>
|
|
</view>
|
|
|
|
<!-- 分组四:公益信息 -->
|
|
<ui-section-header title="公益信息" subtitle="课堂、反诈与服务站" />
|
|
<view class="service-grid">
|
|
<view class="service-entry" bindtap="onGoClassroom"><view class="service-icon amber"><image src="/assets/icons/home/classroom.png" mode="aspectFit" /></view><text>婚恋课堂</text></view>
|
|
<view class="service-entry" bindtap="onGoAntiFraud"><view class="service-icon rose"><image src="/assets/icons/home/anti-fraud.png" mode="aspectFit" /></view><text>婚恋反诈</text></view>
|
|
<view class="service-entry" bindtap="onGoStation"><view class="service-icon green"><image src="/assets/icons/home/service-station.png" mode="aspectFit" /></view><text>善缘服务站</text></view>
|
|
<view class="service-entry" bindtap="onGoAbout"><view class="service-icon blue"><image src="/assets/brand/logo-mark.png" mode="aspectFit" /></view><text>关于善缘丹阳</text></view>
|
|
</view>
|
|
|
|
<view class="logout-row" bindtap="onLogout">退出登录</view>
|
|
<ui-danger-action-dialog visible="{{showLogoutDialog}}" action="{{logoutAction}}" bind:confirm="onConfirmLogout" bind:cancel="onCancelLogout" />
|
|
</block>
|
|
</view>
|