diff --git a/apps/miniprogram/README.md b/apps/miniprogram/README.md index 50901b1..89a09c3 100644 --- a/apps/miniprogram/README.md +++ b/apps/miniprogram/README.md @@ -1,5 +1,7 @@ # 微信小程序 -微信原生小程序 + TypeScript。Phase 1 已接入微信登录和短期会话;Phase 2–4 提供服务申请、协作任务和闭环;Phase 5 提供公开公益项目/活动、在线报名、志愿者认证、个人报名进度和服务时长。敏感申请草稿、志愿者资料和工单内容不写入本地持久化。 +微信原生小程序 + TypeScript。公众端使用“首页 / 服务 / 公益 / 我的”四栏导航:首页突出本人/代申请与六类服务,服务页承载求助闭环,公益页展示公开项目和活动,我的页面按身份提供申请、消息、志愿服务和协作任务。Phase 1 已接入微信登录和短期会话;Phase 2–4 提供服务申请、协作任务和闭环;Phase 5 提供公开公益项目/活动、在线报名、志愿者认证、个人报名进度和服务时长。敏感申请草稿、志愿者资料和工单内容不写入本地持久化。 + +视觉系统集中定义在 `miniprogram/app.wxss`,包含暖橙主色、语义色、适老字号、圆角、阴影、状态卡和按钮基线;自定义底部导航位于 `miniprogram/custom-tab-bar/`。新增页面必须复用这些令牌并保持 loading、empty、error 与权限感知状态,不得加入未批准的捐赠交易或虚构业务数据。 使用微信开发者工具导入本目录;真实 AppID 只保存在本地私有配置中,不提交仓库。本地默认 API 为 `http://localhost:3000`;提审或发布前必须把 `miniprogram/app.ts` 中的地址替换为已加入微信 request 合法域名的 HTTPS 地址,不得发布本地 HTTP 配置。 diff --git a/apps/miniprogram/miniprogram/app.json b/apps/miniprogram/miniprogram/app.json index c17d055..288439a 100644 --- a/apps/miniprogram/miniprogram/app.json +++ b/apps/miniprogram/miniprogram/app.json @@ -1,6 +1,9 @@ { "pages": [ "pages/index/index", + "pages/service-hub/service-hub", + "pages/public-welfare/public-welfare", + "pages/profile/profile", "pages/application-form/application-form", "pages/application-success/application-success", "pages/my-applications/my-applications", @@ -17,11 +20,23 @@ "pages/notifications/notifications" ], "window": { - "backgroundColor": "#F5F5F5", + "backgroundColor": "#F7F5F2", "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#FFFFFF", "navigationBarTextStyle": "black", "navigationBarTitleText": "乐活公益" }, + "tabBar": { + "custom": true, + "color": "#77716B", + "selectedColor": "#F05A28", + "backgroundColor": "#FFFFFF", + "list": [ + { "pagePath": "pages/index/index", "text": "首页" }, + { "pagePath": "pages/service-hub/service-hub", "text": "服务" }, + { "pagePath": "pages/public-welfare/public-welfare", "text": "公益" }, + { "pagePath": "pages/profile/profile", "text": "我的" } + ] + }, "sitemapLocation": "sitemap.json" } diff --git a/apps/miniprogram/miniprogram/app.wxss b/apps/miniprogram/miniprogram/app.wxss index e1a67c0..0d94a84 100644 --- a/apps/miniprogram/miniprogram/app.wxss +++ b/apps/miniprogram/miniprogram/app.wxss @@ -1,15 +1,27 @@ page { - --color-primary: #ff6b35; - --color-primary-pressed: #e95a28; - --color-primary-soft: #fff1eb; - --color-success: #2f8f2f; - --color-info: #1677c8; + /* 乐活公益公众端设计令牌:暖、可信、适老。 */ + --color-primary: #f05a28; + --color-primary-pressed: #d94718; + --color-primary-soft: #fff0e8; + --color-primary-pale: #fff8f4; + --color-secondary: #f6a23c; + --color-success: #2f9b58; + --color-success-soft: #eaf7ef; + --color-info: #287fd1; + --color-info-soft: #ebf4fd; + --color-warning: #b76e00; + --color-warning-soft: #fff6dd; --color-danger: #b42318; - --color-text: #1f2329; - --color-text-secondary: #646a73; - --color-border: #e5e6eb; - --color-background: #f5f5f5; + --color-text: #24211f; + --color-text-secondary: #6e6862; + --color-text-tertiary: #918a83; + --color-border: #e9e3dd; + --color-background: #f7f5f2; --color-surface: #ffffff; + --radius-sm: 16rpx; + --radius-md: 24rpx; + --radius-lg: 32rpx; + --shadow-card: 0 10rpx 32rpx rgba(91, 62, 45, 0.07); min-height: 100%; color: var(--color-text); background: var(--color-background); @@ -17,27 +29,63 @@ page { -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Microsoft YaHei', sans-serif; font-size: 32rpx; + line-height: 1.5; } button { font: inherit; } - button::after { border: 0; } .page { min-height: 100vh; - padding: 32rpx 32rpx calc(48rpx + env(safe-area-inset-bottom)); + padding: 28rpx 28rpx calc(152rpx + env(safe-area-inset-bottom)); box-sizing: border-box; } +.page-heading { + margin: 8rpx 4rpx 28rpx; +} +.page-title, +.page-subtitle, +.section-title, +.section-note { + display: block; +} +.page-title { + font-size: 44rpx; + font-weight: 700; + letter-spacing: 1rpx; +} +.page-subtitle { + margin-top: 8rpx; + color: var(--color-text-secondary); + font-size: 28rpx; + line-height: 1.65; +} + +.section-heading { + display: flex; + margin: 40rpx 4rpx 20rpx; + align-items: flex-end; + justify-content: space-between; + gap: 20rpx; +} +.section-title { + font-size: 36rpx; + font-weight: 700; +} +.section-note { + color: var(--color-text-secondary); + font-size: 26rpx; +} .eyebrow { display: block; color: var(--color-primary-pressed); - font-size: 28rpx; - font-weight: 600; + font-size: 26rpx; + font-weight: 700; } .primary-button, @@ -48,105 +96,149 @@ button::after { padding: 20rpx 32rpx; align-items: center; justify-content: center; - border-radius: 24rpx; + border-radius: 999rpx; box-sizing: border-box; font-size: 34rpx; - font-weight: 600; + font-weight: 700; line-height: 1.4; } - .primary-button { - color: #ffffff; - background: var(--color-primary); + color: #fff; + background: linear-gradient(135deg, #ff713d, var(--color-primary)); + box-shadow: 0 12rpx 24rpx rgba(240, 90, 40, 0.2); } - .primary-button:active { background: var(--color-primary-pressed); } - .secondary-button { color: var(--color-primary-pressed); - background: var(--color-primary-soft); - border: 2rpx solid var(--color-primary); + background: #fff; + border: 2rpx solid #f5a083; } - .primary-button[disabled], .secondary-button[disabled] { opacity: 0.5; + box-shadow: none; } .state-card, .form-card, .detail-card, .detail-summary, +.success-card, +.action-card, +.case-card, +.application-card { + border: 2rpx solid var(--color-border); + border-radius: var(--radius-lg); + background: var(--color-surface); + box-shadow: var(--shadow-card); +} +.form-card, +.detail-card, +.detail-summary, .success-card { padding: 32rpx; - border: 2rpx solid var(--color-border); - border-radius: 32rpx; - background: var(--color-surface); - box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.05); } - .state-card { display: flex; min-height: 280rpx; + padding: 36rpx 30rpx; flex-direction: column; align-items: stretch; justify-content: center; + box-sizing: border-box; text-align: center; } - +.state-card::before { + content: '♡'; + margin-bottom: 12rpx; + color: #f6a07d; + font-size: 56rpx; +} .state-title { font-size: 38rpx; - font-weight: 600; + font-weight: 700; } - .state-text { display: block; - margin-top: 16rpx; + margin-top: 14rpx; color: var(--color-text-secondary); line-height: 1.7; } -.skeleton-card, -.skeleton-line { - overflow: hidden; - border-radius: 20rpx; - background: linear-gradient(90deg, #f0f1f3 25%, #fafafa 50%, #f0f1f3 75%); - background-size: 200% 100%; - animation: skeleton 1.4s ease-in-out infinite; +.action-card { + display: flex; + width: 100%; + min-height: 144rpx; + margin: 0 0 20rpx; + padding: 28rpx 30rpx; + flex-direction: column; + align-items: flex-start; + justify-content: center; + box-sizing: border-box; + color: var(--color-text); + text-align: left; +} +.action-card:active, +.case-card:active, +.application-card:active { + transform: scale(0.99); + opacity: 0.84; +} +.action-title { + font-size: 34rpx; + font-weight: 700; +} +.action-description { + display: block; + margin-top: 8rpx; + color: var(--color-text-secondary); + font-size: 28rpx; + line-height: 1.55; +} +.card-meta { + display: block; + margin-top: 16rpx; + color: var(--color-text-tertiary); + font-size: 25rpx; } -.skeleton-card { - height: 160rpx; - margin-bottom: 24rpx; +.notice-card { + margin: 20rpx 0; + padding: 26rpx 28rpx; + border: 2rpx solid #f4dfc8; + border-radius: var(--radius-md); + background: #fffaf4; } - -.skeleton-line { - width: 60%; - height: 28rpx; - margin: 12rpx auto; +.notice-title, +.notice-text { + display: block; } - -.skeleton-line--wide { - width: 84%; - height: 44rpx; +.notice-title { + font-weight: 700; +} +.notice-text { + margin-top: 8rpx; + color: #6f583f; + font-size: 28rpx; + line-height: 1.7; } .status-pill { display: inline-flex; min-height: 48rpx; - padding: 8rpx 16rpx; + padding: 7rpx 16rpx; align-items: center; - border-radius: 12rpx; - color: #145ea8; - background: #eaf4ff; - font-size: 26rpx; - font-weight: 600; + border-radius: 999rpx; + color: #17653a; + background: var(--color-success-soft); + font-size: 25rpx; + font-weight: 700; line-height: 1.2; } - -.inline-error { +.inline-error, +.form-message { display: block; margin: 20rpx 8rpx 0; color: var(--color-danger); @@ -154,6 +246,61 @@ button::after { line-height: 1.6; } +.skeleton-card, +.skeleton-line { + overflow: hidden; + border-radius: var(--radius-md); + background: linear-gradient(90deg, #eeeae6 25%, #faf8f6 50%, #eeeae6 75%); + background-size: 200% 100%; + animation: skeleton 1.4s ease-in-out infinite; +} +.skeleton-card { + height: 170rpx; + margin-bottom: 20rpx; +} +.skeleton-line { + width: 60%; + height: 28rpx; + margin: 12rpx auto; +} +.skeleton-line--wide { + width: 84%; + height: 44rpx; +} + +.brand-card { + margin-bottom: 24rpx; + padding: 38rpx 32rpx; + overflow: hidden; + border-radius: var(--radius-lg); + color: #762b12; + background: linear-gradient(135deg, #fff4ea 0%, #ffd4be 100%); + box-shadow: 0 14rpx 36rpx rgba(208, 93, 41, 0.13); +} +.title { + display: block; + margin-top: 10rpx; + font-size: 46rpx; + font-weight: 700; + line-height: 1.3; +} +.message { + display: block; + margin-top: 14rpx; + color: #70432e; + font-size: 29rpx; + line-height: 1.7; +} + +input, +textarea, +.picker-field, +.filter-picker { + color: var(--color-text); + background: #fff; + border-color: #dcd5ce !important; +} + @keyframes skeleton { 0% { background-position: 200% 0; @@ -162,3 +309,9 @@ button::after { background-position: -200% 0; } } +@media (prefers-reduced-motion: reduce) { + .skeleton-card, + .skeleton-line { + animation: none; + } +} diff --git a/apps/miniprogram/miniprogram/custom-tab-bar/index.json b/apps/miniprogram/miniprogram/custom-tab-bar/index.json new file mode 100644 index 0000000..67f8e03 --- /dev/null +++ b/apps/miniprogram/miniprogram/custom-tab-bar/index.json @@ -0,0 +1 @@ +{ "component": true } diff --git a/apps/miniprogram/miniprogram/custom-tab-bar/index.ts b/apps/miniprogram/miniprogram/custom-tab-bar/index.ts new file mode 100644 index 0000000..f8c98ff --- /dev/null +++ b/apps/miniprogram/miniprogram/custom-tab-bar/index.ts @@ -0,0 +1,25 @@ +Component({ + data: { + selected: 0, + tabs: [ + { pagePath: '/pages/index/index', text: '首页', icon: '⌂' }, + { pagePath: '/pages/service-hub/service-hub', text: '服务', icon: '♡' }, + { pagePath: '/pages/public-welfare/public-welfare', text: '公益', icon: '◎' }, + { pagePath: '/pages/profile/profile', text: '我的', icon: '○' }, + ], + }, + lifetimes: { + attached() { + const route = `/${getCurrentPages().at(-1)?.route ?? 'pages/index/index'}`; + const selected = this.data.tabs.findIndex((item) => item.pagePath === route); + if (selected >= 0) this.setData({ selected }); + }, + }, + methods: { + switchTab(event: WechatMiniprogram.BaseEvent) { + const index = Number(event.currentTarget.dataset['index']); + const tab = this.data.tabs[index]; + if (tab) void wx.switchTab({ url: tab.pagePath }); + }, + }, +}); diff --git a/apps/miniprogram/miniprogram/custom-tab-bar/index.wxml b/apps/miniprogram/miniprogram/custom-tab-bar/index.wxml new file mode 100644 index 0000000..395842f --- /dev/null +++ b/apps/miniprogram/miniprogram/custom-tab-bar/index.wxml @@ -0,0 +1,8 @@ + + + + + diff --git a/apps/miniprogram/miniprogram/custom-tab-bar/index.wxss b/apps/miniprogram/miniprogram/custom-tab-bar/index.wxss new file mode 100644 index 0000000..ff82d75 --- /dev/null +++ b/apps/miniprogram/miniprogram/custom-tab-bar/index.wxss @@ -0,0 +1,45 @@ +.tab-bar { + position: fixed; + z-index: 100; + right: 0; + bottom: 0; + left: 0; + padding-bottom: env(safe-area-inset-bottom); + background: rgba(255, 255, 255, 0.98); + border-top: 2rpx solid #eee8e2; + box-shadow: 0 -8rpx 28rpx rgba(74, 55, 43, 0.06); +} +.tab-bar__inner { + display: flex; + height: 112rpx; + align-items: stretch; +} +.tab { + display: flex; + min-width: 0; + margin: 0; + padding: 10rpx 4rpx 8rpx; + flex: 1; + flex-direction: column; + align-items: center; + justify-content: center; + color: #77716b; + background: transparent; + font-size: 23rpx; + line-height: 1; +} +.tab__icon { + height: 40rpx; + font-size: 38rpx; + font-weight: 700; + line-height: 40rpx; +} +.tab__text { + margin-top: 7rpx; +} +.tab--active { + color: #f05a28; +} +.tab--active .tab__text { + font-weight: 700; +} diff --git a/apps/miniprogram/miniprogram/pages/activities/activities.wxml b/apps/miniprogram/miniprogram/pages/activities/activities.wxml index 6ae64b0..0569e95 100644 --- a/apps/miniprogram/miniprogram/pages/activities/activities.wxml +++ b/apps/miniprogram/miniprogram/pages/activities/activities.wxml @@ -1 +1 @@ -公益活动已认证志愿者可在线报名正在加载活动…{{message}}暂无可查看活动 +公益活动已认证志愿者可在线报名,报名结果请在志愿者中心查看。活动暂时无法加载{{message}}暂无可查看活动有新的志愿活动时会展示在这里。 diff --git a/apps/miniprogram/miniprogram/pages/activities/activities.wxss b/apps/miniprogram/miniprogram/pages/activities/activities.wxss index 27dcb37..7d10b6f 100644 --- a/apps/miniprogram/miniprogram/pages/activities/activities.wxss +++ b/apps/miniprogram/miniprogram/pages/activities/activities.wxss @@ -1,7 +1,56 @@ -@import '../../app.wxss'; -.card-meta { - display: block; - margin-top: 12rpx; - color: #646a73; +.activity-card { + display: flex; + width: 100%; + min-height: 210rpx; + margin: 0 0 20rpx; + padding: 28rpx; + flex-direction: column; + align-items: stretch; + color: var(--color-text); + border: 2rpx solid var(--color-border); + border-radius: 28rpx; + background: #fff; + text-align: left; + box-shadow: var(--shadow-card); +} +.activity-card__top, +.activity-card__footer { + display: flex; + align-items: center; + justify-content: space-between; +} +.activity-card__tag { + padding: 6rpx 14rpx; + border-radius: 999rpx; + color: #17653a; + background: var(--color-success-soft); + font-size: 23rpx; + font-weight: 700; +} +.activity-card__count { + color: var(--color-text-tertiary); font-size: 24rpx; } +.activity-card__title { + margin-top: 18rpx; + font-size: 34rpx; + font-weight: 700; +} +.activity-card__copy { + display: -webkit-box; + margin-top: 8rpx; + overflow: hidden; + color: var(--color-text-secondary); + font-size: 27rpx; + line-height: 1.55; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; +} +.activity-card__footer { + margin-top: 20rpx; + padding-top: 16rpx; + color: var(--color-primary); + border-top: 2rpx solid #f0ece8; + font-size: 26rpx; + font-weight: 700; +} diff --git a/apps/miniprogram/miniprogram/pages/activity-detail/activity-detail.wxml b/apps/miniprogram/miniprogram/pages/activity-detail/activity-detail.wxml index 18a2134..06904c7 100644 --- a/apps/miniprogram/miniprogram/pages/activity-detail/activity-detail.wxml +++ b/apps/miniprogram/miniprogram/pages/activity-detail/activity-detail.wxml @@ -1 +1 @@ -正在加载…{{message}}{{activity.statusLabel}}{{activity.title}}{{activity.summary}}时间与地点{{activity.startAt}} 至 {{activity.endAt}}{{activity.locationText}}报名截止:{{activity.registrationDeadline}}活动介绍{{activity.content}}{{message}} +活动暂时无法查看{{message}}{{activity.statusLabel}}{{activity.title}}{{activity.summary}}时活动时间{{activity.startAt}} 至 {{activity.endAt}}地活动地点{{activity.locationText}}止报名截止{{activity.registrationDeadline}}活动介绍{{activity.content}}{{message}} diff --git a/apps/miniprogram/miniprogram/pages/activity-detail/activity-detail.wxss b/apps/miniprogram/miniprogram/pages/activity-detail/activity-detail.wxss index e5418df..ec77c1a 100644 --- a/apps/miniprogram/miniprogram/pages/activity-detail/activity-detail.wxss +++ b/apps/miniprogram/miniprogram/pages/activity-detail/activity-detail.wxss @@ -1 +1,83 @@ -@import '../../app.wxss'; +.activity-hero { + padding: 38rpx 32rpx; + border-radius: 34rpx; + color: #fff; + background: linear-gradient(145deg, #54b775, #29944e); + box-shadow: 0 14rpx 32rpx rgba(36, 137, 69, 0.18); +} +.activity-hero__status, +.activity-hero__title, +.activity-hero__copy { + display: block; +} +.activity-hero__status { + font-size: 24rpx; + font-weight: 700; +} +.activity-hero__title { + margin-top: 14rpx; + font-size: 42rpx; + font-weight: 700; +} +.activity-hero__copy { + margin-top: 12rpx; + font-size: 28rpx; + line-height: 1.65; +} +.info-card { + margin: 20rpx 0; + padding: 4rpx 28rpx; + border: 2rpx solid var(--color-border); + border-radius: 28rpx; + background: #fff; + box-shadow: var(--shadow-card); +} +.info-card > view { + display: grid; + min-height: 106rpx; + padding: 18rpx 0; + grid-template-columns: 54rpx 128rpx 1fr; + align-items: center; + gap: 12rpx; + border-bottom: 2rpx solid #f0ece8; +} +.info-card > view:last-child { + border-bottom: 0; +} +.info-icon { + display: flex; + width: 48rpx; + height: 48rpx; + align-items: center; + justify-content: center; + border-radius: 15rpx; + color: #fff; + background: #f16b39; + font-size: 22rpx; +} +.info-icon.green { + background: #38a45c; +} +.info-icon.blue { + background: #3b89cf; +} +.info-label { + font-weight: 700; +} +.info-value { + color: var(--color-text-secondary); + font-size: 26rpx; + line-height: 1.5; +} +.detail-section-title { + display: block; + font-size: 34rpx; + font-weight: 700; +} +.detail-copy { + display: block; + margin-top: 14rpx; + color: #544f4a; + line-height: 1.8; + white-space: pre-wrap; +} diff --git a/apps/miniprogram/miniprogram/pages/application-form/application-form.ts b/apps/miniprogram/miniprogram/pages/application-form/application-form.ts index 36292f9..6b0bae0 100644 --- a/apps/miniprogram/miniprogram/pages/application-form/application-form.ts +++ b/apps/miniprogram/miniprogram/pages/application-form/application-form.ts @@ -61,6 +61,12 @@ Page({ const mode = options.mode as ApplicationApplyMode; this.setData({ applyMode: mode, applyModeLabel: APPLICATION_APPLY_MODE_LABELS[mode] }); } + if (options.category && isServiceCategory(options.category)) { + this.setData({ + serviceCategory: options.category, + serviceCategoryLabel: SERVICE_CATEGORY_LABELS[options.category], + }); + } void this.loadCategories(); }, diff --git a/apps/miniprogram/miniprogram/pages/index/index.ts b/apps/miniprogram/miniprogram/pages/index/index.ts index 94696ab..4af3f1c 100644 --- a/apps/miniprogram/miniprogram/pages/index/index.ts +++ b/apps/miniprogram/miniprogram/pages/index/index.ts @@ -8,6 +8,14 @@ Page({ message: '正在安全登录,请稍候…', title: MINI_PROGRAM_TITLE, canCollaborate: false, + serviceCategories: [ + { code: 'OLD_AGE', label: '关爱老人', icon: '人', tone: 'orange' }, + { code: 'WOMEN_CHILDREN', label: '妇女帮扶', icon: '爱', tone: 'rose' }, + { code: 'WOMEN_CHILDREN', label: '儿童关爱', icon: '苗', tone: 'green' }, + { code: 'DISABILITY', label: '残障帮扶', icon: '助', tone: 'blue' }, + { code: 'DIFFICULT_FAMILY', label: '生活困难', icon: '家', tone: 'gold' }, + { code: 'OTHER', label: '其他服务', icon: '心', tone: 'purple' }, + ], }, onLoad() { @@ -47,6 +55,13 @@ Page({ void wx.navigateTo({ url: '/pages/application-form/application-form?mode=FAMILY' }); }, + applyForCategory(event: WechatMiniprogram.BaseEvent) { + const category = event.currentTarget.dataset['code'] as string; + void wx.navigateTo({ + url: `/pages/application-form/application-form?mode=SELF&category=${category}`, + }); + }, + viewMyApplications() { void wx.navigateTo({ url: '/pages/my-applications/my-applications' }); }, diff --git a/apps/miniprogram/miniprogram/pages/index/index.wxml b/apps/miniprogram/miniprogram/pages/index/index.wxml index 5da5b83..0ff70bc 100644 --- a/apps/miniprogram/miniprogram/pages/index/index.wxml +++ b/apps/miniprogram/miniprogram/pages/index/index.wxml @@ -1,63 +1,37 @@ - - - 乐活公益 · 暖心服务平台 - 用爱连接,让爱传递 - 为老人、妇女儿童、残障人士和困难家庭提供公益服务支持。 + + + + 乐活公益 ♡ + 用爱连接,让爱传递 + 有需要,告诉我们;想帮忙,也欢迎加入。 + 公益服务隐私保护专人跟进 - - - - 正在安全登录,请稍候… - - - - 暂时无法登录 - {{message}} - - + 正在安全登录,请稍候… + 暂时无法登录{{message}} - - 需要哪种帮助? - 选择后只需几步即可提交 + + + - - - - - 参与公益 - 了解项目,报名志愿活动 + + + + 我们能帮什么六类暖心服务 + + - - - - 了解我们经审核发布的公益内容 - - - - - - 温馨提示 - 提交后工作人员会根据实际服务能力与您联系。遇到危及生命安全的紧急情况,请及时联系 110 或 120。 + + 一起参与公益每份行动都有温度 + + + + + + 乐活动态内容均经审核发布 + + 紧急情况请先求助公共服务如遇危及生命安全的情况,请及时联系 110 或 120。 diff --git a/apps/miniprogram/miniprogram/pages/index/index.wxss b/apps/miniprogram/miniprogram/pages/index/index.wxss index d50555d..0deeae1 100644 --- a/apps/miniprogram/miniprogram/pages/index/index.wxss +++ b/apps/miniprogram/miniprogram/pages/index/index.wxss @@ -1,115 +1,293 @@ -.brand-card { - margin-bottom: 32rpx; - padding: 40rpx 32rpx; - border-radius: 32rpx; - color: #7a2e12; - background: linear-gradient(135deg, #fff7f0, #ffe2d2); +.home-page { + padding-top: 20rpx; } - -.title { +.home-hero { + position: relative; + margin-bottom: 24rpx; + padding: 40rpx 34rpx 34rpx; + overflow: hidden; + border-radius: 36rpx; + color: #fff; + background: linear-gradient(135deg, #ff7845 0%, #f05225 100%); + box-shadow: 0 16rpx 36rpx rgba(224, 75, 25, 0.22); +} +.hero-orb { + position: absolute; + border: 3rpx solid rgba(255, 255, 255, 0.25); + border-radius: 50%; +} +.hero-orb--one { + width: 180rpx; + height: 180rpx; + right: -54rpx; + top: 30rpx; +} +.hero-orb--two { + width: 90rpx; + height: 90rpx; + right: 92rpx; + bottom: -32rpx; +} +.hero-brand, +.hero-title, +.hero-copy { + position: relative; + z-index: 1; display: block; +} +.hero-brand { + font-size: 27rpx; + font-weight: 700; +} +.hero-title { + margin-top: 18rpx; + font-size: 46rpx; + font-weight: 700; + letter-spacing: 2rpx; +} +.hero-copy { margin-top: 12rpx; - font-size: 48rpx; - font-weight: 600; - line-height: 1.3; -} - -.message { - display: block; - margin-top: 16rpx; - color: #653b2c; - line-height: 1.7; -} - -.section-heading { - display: flex; - margin: 40rpx 0 20rpx; - flex-direction: column; - gap: 8rpx; -} - -.section-title { - font-size: 40rpx; - font-weight: 600; -} - -.section-note, -.action-description { - color: var(--color-text-secondary); font-size: 28rpx; } - -.action-card { +.hero-trust { + position: relative; + z-index: 1; display: flex; - min-height: 152rpx; - margin: 0 0 24rpx; - padding: 28rpx 32rpx; + margin-top: 28rpx; + gap: 12rpx; +} +.hero-trust text { + padding: 7rpx 14rpx; + border-radius: 999rpx; + background: rgba(255, 255, 255, 0.18); + font-size: 23rpx; +} +.primary-actions { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 18rpx; +} +.primary-action { + position: relative; + display: flex; + min-height: 190rpx; + margin: 0; + padding: 26rpx 22rpx; flex-direction: column; align-items: flex-start; - justify-content: center; - border: 2rpx solid var(--color-border); - border-radius: 28rpx; - color: var(--color-text); - background: #ffffff; + color: #5e2715; + border: 2rpx solid #ffd2bd; + border-radius: 30rpx; text-align: left; } - -.action-card--primary { - border-color: #ffb08e; - background: var(--color-primary-soft); +.primary-action--warm { + background: #fff2ea; } - -.action-card:active, -.progress-link:active { - opacity: 0.72; +.primary-action--green { + color: #185f37; + border-color: #cdebd9; + background: #edf9f1; } - -.action-title { - font-size: 36rpx; - font-weight: 600; -} - -.action-description { - margin-top: 8rpx; -} - -.progress-link { +.primary-action__icon { display: flex; - min-height: 104rpx; - margin: 8rpx 0 32rpx; - padding: 20rpx 28rpx; + width: 58rpx; + height: 58rpx; align-items: center; - justify-content: space-between; - border-radius: 24rpx; - color: #145ea8; - background: #eaf4ff; - font-weight: 600; + justify-content: center; + border-radius: 18rpx; + color: #fff; + background: #f05a28; + font-size: 35rpx; } -.progress-link--volunteer { - margin-top: -16rpx; - color: #237a2b; - background: #edf8ee; +.primary-action--green .primary-action__icon { + background: #35a864; } - -.notice-card { - padding: 28rpx; - border-left: 8rpx solid #faad14; - border-radius: 20rpx; - background: #fff9e8; -} - -.notice-title, -.notice-text { +.primary-action__title, +.primary-action__copy { display: block; } - -.notice-title { +.primary-action__title { + margin-top: 18rpx; + font-size: 33rpx; + font-weight: 700; +} +.primary-action__copy { + margin-top: 6rpx; + color: #755447; + font-size: 24rpx; + line-height: 1.5; +} +.primary-action--green .primary-action__copy { + color: #52705f; +} +.primary-action__arrow { + position: absolute; + right: 18rpx; + top: 20rpx; + font-size: 36rpx; +} +.progress-banner { + display: flex; + width: 100%; + min-height: 104rpx; + margin: 20rpx 0 0; + padding: 20rpx 26rpx; + align-items: center; + justify-content: space-between; + color: #235f91; + border-radius: 24rpx; + background: #edf6fd; + text-align: left; +} +.progress-banner__label, +.progress-banner__copy { + display: block; +} +.progress-banner__label { + font-weight: 700; +} +.progress-banner__copy { + margin-top: 4rpx; + color: #607b91; + font-size: 24rpx; +} +.progress-banner__arrow { + font-size: 26rpx; + font-weight: 700; +} +.service-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 16rpx; +} +.service-item { + display: flex; + min-height: 142rpx; + margin: 0; + padding: 20rpx 8rpx; + flex-direction: column; + align-items: center; + justify-content: center; + border: 2rpx solid #eee7e1; + border-radius: 26rpx; + background: #fff; +} +.service-item__icon { + display: flex; + width: 58rpx; + height: 58rpx; + align-items: center; + justify-content: center; + border-radius: 20rpx; + color: #fff; + background: #f47745; + font-size: 30rpx; +} +.service-item--green .service-item__icon { + background: #46a956; +} +.service-item--blue .service-item__icon { + background: #378fd6; +} +.service-item--purple .service-item__icon { + background: #8564cf; +} +.service-item--gold .service-item__icon { + background: #e69a31; +} +.service-item--rose .service-item__icon { + background: #e96878; +} +.service-item__label { + margin-top: 12rpx; + font-size: 26rpx; font-weight: 600; } - -.notice-text { - margin-top: 8rpx; - color: #654f17; - font-size: 28rpx; - line-height: 1.7; +.participation-card { + padding: 0 26rpx; + border: 2rpx solid var(--color-border); + border-radius: 30rpx; + background: #fff; + box-shadow: var(--shadow-card); +} +.participation-item { + display: grid; + width: 100%; + min-height: 122rpx; + margin: 0; + padding: 20rpx 0; + grid-template-columns: 64rpx 1fr auto; + align-items: center; + gap: 18rpx; + color: var(--color-text); + border-bottom: 2rpx solid #f0ece8; + background: transparent; + text-align: left; +} +.participation-item:last-child { + border-bottom: 0; +} +.participation-item__icon { + display: flex; + width: 62rpx; + height: 62rpx; + align-items: center; + justify-content: center; + border-radius: 20rpx; + color: #fff; + font-size: 32rpx; +} +.orange { + background: #f47745; +} +.blue { + background: #378fd6; +} +.green { + background: #38a862; +} +.participation-item__title, +.participation-item__copy { + display: block; +} +.participation-item__title { + font-weight: 700; +} +.participation-item__copy { + margin-top: 4rpx; + color: var(--color-text-secondary); + font-size: 25rpx; +} +.content-links { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 16rpx; +} +.content-links button { + display: flex; + min-height: 96rpx; + margin: 0; + padding: 20rpx 24rpx; + align-items: center; + justify-content: space-between; + color: #544d47; + border: 2rpx solid var(--color-border); + border-radius: 24rpx; + background: #fff; + font-weight: 600; +} +.safety-note { + display: flex; + margin-top: 30rpx; + padding: 24rpx; + flex-direction: column; + color: #735818; + border-radius: 22rpx; + background: #fff7df; + font-size: 26rpx; + line-height: 1.65; +} +.safety-note__title { + margin-bottom: 5rpx; + font-weight: 700; } diff --git a/apps/miniprogram/miniprogram/pages/profile/profile.json b/apps/miniprogram/miniprogram/pages/profile/profile.json new file mode 100644 index 0000000..5fea596 --- /dev/null +++ b/apps/miniprogram/miniprogram/pages/profile/profile.json @@ -0,0 +1 @@ +{ "navigationBarTitleText": "我的" } diff --git a/apps/miniprogram/miniprogram/pages/profile/profile.ts b/apps/miniprogram/miniprogram/pages/profile/profile.ts new file mode 100644 index 0000000..23ef3e0 --- /dev/null +++ b/apps/miniprogram/miniprogram/pages/profile/profile.ts @@ -0,0 +1,49 @@ +import type { AuthUser } from '@lehuo/contracts'; +import { loginWithWechat, restoreCurrentSession } from '../../services/auth'; + +Page({ + data: { + loading: true, + error: '', + user: null as AuthUser | null, + canCollaborate: false, + isVolunteer: false, + }, + onShow() { + void this.load(); + }, + async load() { + this.setData({ loading: true, error: '' }); + try { + const session = await restoreCurrentSession(); + const user = session?.user ?? (await loginWithWechat()).user; + this.setData({ + user, + canCollaborate: user.permissions.includes('assigned_cases:read'), + isVolunteer: user.roles.includes('VOLUNTEER'), + }); + } catch (error) { + this.setData({ error: error instanceof Error ? error.message : '暂时无法读取个人信息' }); + } finally { + this.setData({ loading: false }); + } + }, + applications() { + void wx.navigateTo({ url: '/pages/my-applications/my-applications' }); + }, + volunteer() { + void wx.navigateTo({ url: '/pages/volunteer-center/volunteer-center' }); + }, + notifications() { + void wx.navigateTo({ url: '/pages/notifications/notifications' }); + }, + assignedCases() { + void wx.navigateTo({ url: '/pages/assigned-cases/assigned-cases' }); + }, + content() { + void wx.navigateTo({ url: '/pages/content/content' }); + }, + organization() { + void wx.navigateTo({ url: '/pages/content/content?type=ORGANIZATION_INTRO' }); + }, +}); diff --git a/apps/miniprogram/miniprogram/pages/profile/profile.wxml b/apps/miniprogram/miniprogram/pages/profile/profile.wxml new file mode 100644 index 0000000..5610a9e --- /dev/null +++ b/apps/miniprogram/miniprogram/pages/profile/profile.wxml @@ -0,0 +1,13 @@ + + + 暂时无法打开个人中心{{error}} + + 乐{{user.displayName || '乐活用户'}}账号已安全登录{{isVolunteer ? '认证志愿者' : '公益伙伴'}} + + 我的服务 + + 消息与帮助 + + 您的服务资料仅用于提供公益服务,并按最小权限原则保护。 + + diff --git a/apps/miniprogram/miniprogram/pages/profile/profile.wxss b/apps/miniprogram/miniprogram/pages/profile/profile.wxss new file mode 100644 index 0000000..87097d8 --- /dev/null +++ b/apps/miniprogram/miniprogram/pages/profile/profile.wxss @@ -0,0 +1,165 @@ +.profile-page { + padding-top: 20rpx; +} +.profile-hero { + position: relative; + display: flex; + min-height: 170rpx; + padding: 32rpx; + align-items: center; + gap: 22rpx; + border-radius: 34rpx; + color: #fff; + background: linear-gradient(135deg, #39aa61, #24934d); + box-shadow: 0 14rpx 32rpx rgba(35, 139, 70, 0.18); +} +.avatar { + display: flex; + width: 92rpx; + height: 92rpx; + flex: 0 0 92rpx; + align-items: center; + justify-content: center; + border: 4rpx solid rgba(255, 255, 255, 0.75); + border-radius: 50%; + background: #fff3e8; + color: #e45424; + font-size: 39rpx; + font-weight: 700; +} +.profile-name, +.profile-id { + display: block; +} +.profile-name { + font-size: 36rpx; + font-weight: 700; +} +.profile-id { + margin-top: 7rpx; + font-size: 25rpx; + opacity: 0.88; +} +.profile-badge { + position: absolute; + right: 24rpx; + top: 24rpx; + padding: 7rpx 13rpx; + border-radius: 999rpx; + background: rgba(255, 255, 255, 0.2); + font-size: 22rpx; +} +.summary-card { + display: grid; + margin-top: 20rpx; + padding: 20rpx 8rpx; + grid-template-columns: repeat(3, 1fr); + border: 2rpx solid var(--color-border); + border-radius: 28rpx; + background: #fff; + box-shadow: var(--shadow-card); +} +.summary-card button { + display: flex; + min-height: 110rpx; + margin: 0; + padding: 10rpx; + flex-direction: column; + align-items: center; + justify-content: center; + color: var(--color-text); + border-right: 2rpx solid #eeeae6; + background: transparent; + font-size: 25rpx; +} +.summary-card button:last-child { + border-right: 0; +} +.summary-card__icon { + display: flex; + width: 52rpx; + height: 52rpx; + align-items: center; + justify-content: center; + border-radius: 17rpx; + color: #fff; + background: #f06b39; + font-size: 24rpx; +} +.summary-card__icon.green { + background: #37a85e; +} +.summary-card__icon.blue { + background: #3b89cf; +} +.summary-card__label { + margin-top: 8rpx; + font-weight: 600; +} +.menu-card { + padding: 0 26rpx; + border: 2rpx solid var(--color-border); + border-radius: 28rpx; + background: #fff; + box-shadow: var(--shadow-card); +} +.menu-card button { + display: grid; + width: 100%; + min-height: 118rpx; + margin: 0; + padding: 20rpx 0; + grid-template-columns: 58rpx 1fr auto; + align-items: center; + gap: 18rpx; + color: var(--color-text); + border-bottom: 2rpx solid #f0ece8; + background: transparent; + text-align: left; +} +.menu-card button:last-child { + border-bottom: 0; +} +.menu-icon { + display: flex; + width: 54rpx; + height: 54rpx; + align-items: center; + justify-content: center; + border-radius: 17rpx; + color: #fff; + background: #ef7040; + font-size: 23rpx; +} +.menu-icon.green { + background: #37a85e; +} +.menu-icon.blue { + background: #3b89cf; +} +.menu-icon.purple { + background: #8065c4; +} +.menu-title, +.menu-copy { + display: block; +} +.menu-title { + font-weight: 700; +} +.menu-copy { + margin-top: 4rpx; + color: var(--color-text-secondary); + font-size: 24rpx; +} +.menu-arrow { + color: #aaa39d; + font-size: 34rpx; +} +.privacy-footnote { + margin: 28rpx 18rpx 0; + color: var(--color-text-tertiary); + font-size: 24rpx; + line-height: 1.6; + text-align: center; +} diff --git a/apps/miniprogram/miniprogram/pages/project-detail/project-detail.wxml b/apps/miniprogram/miniprogram/pages/project-detail/project-detail.wxml index f5e866d..d6a2294 100644 --- a/apps/miniprogram/miniprogram/pages/project-detail/project-detail.wxml +++ b/apps/miniprogram/miniprogram/pages/project-detail/project-detail.wxml @@ -1 +1 @@ -正在加载…{{message}}{{project.statusLabel}}{{project.name}}{{project.summary}}项目周期{{project.startDate}} 至 {{project.endDate}} · 负责人 {{project.managerDisplayName}}项目介绍{{project.content}} +项目暂时无法查看{{message}}♡{{project.statusLabel}}{{project.name}}{{project.summary}}项目周期{{project.startDate}} 至 {{project.endDate}}项目介绍{{project.content}}参与说明查看项目关联活动,选择适合的时间报名参与。平台暂不提供公开募捐交易。 diff --git a/apps/miniprogram/miniprogram/pages/project-detail/project-detail.wxss b/apps/miniprogram/miniprogram/pages/project-detail/project-detail.wxss index e5418df..d75f166 100644 --- a/apps/miniprogram/miniprogram/pages/project-detail/project-detail.wxss +++ b/apps/miniprogram/miniprogram/pages/project-detail/project-detail.wxss @@ -1 +1,85 @@ -@import '../../app.wxss'; +.project-cover { + position: relative; + display: flex; + height: 300rpx; + align-items: center; + justify-content: center; + overflow: hidden; + border-radius: 34rpx; + background: linear-gradient(145deg, #ffc09e, #f26935); + box-shadow: 0 14rpx 32rpx rgba(210, 86, 35, 0.18); +} +.project-cover::after { + position: absolute; + width: 240rpx; + height: 240rpx; + right: -60rpx; + top: -40rpx; + border: 3rpx solid rgba(255, 255, 255, 0.28); + border-radius: 50%; + content: ''; +} +.project-cover__heart { + color: #fff; + font-size: 120rpx; +} +.project-cover__status { + position: absolute; + left: 24rpx; + bottom: 22rpx; + padding: 7rpx 15rpx; + border-radius: 999rpx; + color: #fff; + background: rgba(106, 35, 12, 0.3); + font-size: 24rpx; + font-weight: 700; +} +.project-title-card { + margin: -18rpx 16rpx 20rpx; + padding: 30rpx; + position: relative; + z-index: 1; + border-radius: 28rpx; + background: #fff; + box-shadow: var(--shadow-card); +} +.project-title, +.project-summary { + display: block; +} +.project-title { + font-size: 40rpx; + font-weight: 700; +} +.project-summary { + margin-top: 12rpx; + color: var(--color-text-secondary); + font-size: 28rpx; + line-height: 1.65; +} +.project-period { + display: flex; + margin-top: 22rpx; + padding-top: 20rpx; + align-items: center; + justify-content: space-between; + gap: 20rpx; + color: var(--color-text-secondary); + border-top: 2rpx solid #f0ece8; + font-size: 25rpx; +} +.detail-card { + margin-bottom: 20rpx; +} +.detail-section-title { + display: block; + font-size: 34rpx; + font-weight: 700; +} +.detail-copy { + display: block; + margin-top: 14rpx; + color: #544f4a; + line-height: 1.8; + white-space: pre-wrap; +} diff --git a/apps/miniprogram/miniprogram/pages/projects/projects.wxml b/apps/miniprogram/miniprogram/pages/projects/projects.wxml index 1fef769..afdcfea 100644 --- a/apps/miniprogram/miniprogram/pages/projects/projects.wxml +++ b/apps/miniprogram/miniprogram/pages/projects/projects.wxml @@ -1 +1 @@ -公益项目了解正在开展的公益服务正在加载项目…{{message}}暂无公开项目 +公益项目了解正在开展的服务,看见每一份善意如何落地。项目暂时无法加载{{message}}暂无公开项目项目经审核发布后会展示在这里。 diff --git a/apps/miniprogram/miniprogram/pages/projects/projects.wxss b/apps/miniprogram/miniprogram/pages/projects/projects.wxss index 8a08799..37cc541 100644 --- a/apps/miniprogram/miniprogram/pages/projects/projects.wxss +++ b/apps/miniprogram/miniprogram/pages/projects/projects.wxss @@ -1,10 +1,55 @@ -@import '../../app.wxss'; -.card-meta { - display: block; - margin-top: 12rpx; - color: #646a73; - font-size: 24rpx; +.feature-card { + display: grid; + width: 100%; + min-height: 196rpx; + margin: 0 0 20rpx; + padding: 0; + overflow: hidden; + grid-template-columns: 180rpx 1fr; + color: var(--color-text); + border: 2rpx solid var(--color-border); + border-radius: 28rpx; + background: #fff; + text-align: left; + box-shadow: var(--shadow-card); } -.state-card { - margin-top: 24rpx; +.feature-card__art { + display: flex; + min-height: 196rpx; + align-items: center; + justify-content: center; + color: #fff; + background: linear-gradient(145deg, #ffb38e, #f26834); + font-size: 72rpx; +} +.feature-card__body { + display: flex; + padding: 22rpx 24rpx; + flex-direction: column; + justify-content: center; +} +.feature-card__tag { + color: var(--color-primary); + font-size: 23rpx; + font-weight: 700; +} +.feature-card__title { + margin-top: 5rpx; + font-size: 31rpx; + font-weight: 700; +} +.feature-card__copy { + display: -webkit-box; + margin-top: 6rpx; + overflow: hidden; + color: var(--color-text-secondary); + font-size: 25rpx; + line-height: 1.5; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; +} +.feature-card__meta { + margin-top: 10rpx; + color: var(--color-text-tertiary); + font-size: 23rpx; } diff --git a/apps/miniprogram/miniprogram/pages/public-welfare/public-welfare.json b/apps/miniprogram/miniprogram/pages/public-welfare/public-welfare.json new file mode 100644 index 0000000..c0cadae --- /dev/null +++ b/apps/miniprogram/miniprogram/pages/public-welfare/public-welfare.json @@ -0,0 +1 @@ +{ "navigationBarTitleText": "公益同行" } diff --git a/apps/miniprogram/miniprogram/pages/public-welfare/public-welfare.ts b/apps/miniprogram/miniprogram/pages/public-welfare/public-welfare.ts new file mode 100644 index 0000000..66e1fe9 --- /dev/null +++ b/apps/miniprogram/miniprogram/pages/public-welfare/public-welfare.ts @@ -0,0 +1,56 @@ +import type { ActivityListItem, ProjectListItem } from '@lehuo/contracts'; +import { fetchPublicActivities, fetchPublicProjects } from '../../services/participation'; + +Page({ + data: { + loading: true, + error: '', + projects: [] as ProjectListItem[], + activities: [] as ActivityListItem[], + }, + onShow() { + void this.load(); + }, + async load() { + this.setData({ loading: true, error: '' }); + try { + const [projects, activities] = await Promise.all([ + fetchPublicProjects(), + fetchPublicActivities(), + ]); + this.setData({ + projects: projects.items.slice(0, 3), + activities: activities.items.slice(0, 3), + }); + } catch { + this.setData({ error: '公益内容暂时无法加载,请稍后重试。' }); + } finally { + this.setData({ loading: false }); + } + }, + projects() { + void wx.navigateTo({ url: '/pages/projects/projects' }); + }, + activities() { + void wx.navigateTo({ url: '/pages/activities/activities' }); + }, + volunteer() { + void wx.navigateTo({ url: '/pages/volunteer-center/volunteer-center' }); + }, + content() { + void wx.navigateTo({ url: '/pages/content/content' }); + }, + organization() { + void wx.navigateTo({ url: '/pages/content/content?type=ORGANIZATION_INTRO' }); + }, + openProject(event: WechatMiniprogram.BaseEvent) { + void wx.navigateTo({ + url: `/pages/project-detail/project-detail?publicId=${event.currentTarget.dataset['id'] as string}`, + }); + }, + openActivity(event: WechatMiniprogram.BaseEvent) { + void wx.navigateTo({ + url: `/pages/activity-detail/activity-detail?publicId=${event.currentTarget.dataset['id'] as string}`, + }); + }, +}); diff --git a/apps/miniprogram/miniprogram/pages/public-welfare/public-welfare.wxml b/apps/miniprogram/miniprogram/pages/public-welfare/public-welfare.wxml new file mode 100644 index 0000000..077a87f --- /dev/null +++ b/apps/miniprogram/miniprogram/pages/public-welfare/public-welfare.wxml @@ -0,0 +1,15 @@ + + 一起让善意落地公益不是围观,是共同参与了解真实项目,报名志愿活动,看见每一次服务留下的改变。 + + 暂时无法加载{{error}} + + 公益项目 + 暂无公开项目 + + 公益活动 + 暂无可查看活动 + + 了解乐活所有内容均经审核发布 + + + diff --git a/apps/miniprogram/miniprogram/pages/public-welfare/public-welfare.wxss b/apps/miniprogram/miniprogram/pages/public-welfare/public-welfare.wxss new file mode 100644 index 0000000..374ac62 --- /dev/null +++ b/apps/miniprogram/miniprogram/pages/public-welfare/public-welfare.wxss @@ -0,0 +1,144 @@ +.welfare-hero { + padding: 38rpx 32rpx; + border-radius: 34rpx; + color: #fff; + background: linear-gradient(135deg, #f46a34, #ed4f22); + box-shadow: 0 15rpx 34rpx rgba(219, 70, 22, 0.2); +} +.welfare-hero__eyebrow, +.welfare-hero__title, +.welfare-hero__copy { + display: block; +} +.welfare-hero__eyebrow { + font-size: 25rpx; + font-weight: 700; +} +.welfare-hero__title { + margin-top: 14rpx; + font-size: 42rpx; + font-weight: 700; + line-height: 1.35; +} +.welfare-hero__copy { + margin-top: 12rpx; + font-size: 27rpx; + line-height: 1.65; +} +.welfare-hero button { + display: flex; + min-height: 78rpx; + margin: 26rpx 0 0; + padding: 14rpx 24rpx; + align-items: center; + justify-content: space-between; + color: #d94819; + border-radius: 999rpx; + background: #fff; + font-weight: 700; +} +.section-more { + min-height: auto; + margin: 0; + padding: 8rpx; + color: var(--color-primary); + background: transparent; + font-size: 26rpx; +} +.feature-card { + display: grid; + width: 100%; + min-height: 190rpx; + margin: 0 0 18rpx; + padding: 0; + overflow: hidden; + grid-template-columns: 180rpx 1fr; + color: var(--color-text); + border: 2rpx solid var(--color-border); + border-radius: 28rpx; + background: #fff; + text-align: left; + box-shadow: var(--shadow-card); +} +.feature-card__art { + display: flex; + min-height: 190rpx; + align-items: center; + justify-content: center; + color: #fff; + background: linear-gradient(145deg, #ffb38e, #f26834); + font-size: 72rpx; +} +.feature-card__art.green { + background: linear-gradient(145deg, #7bce8f, #349e57); +} +.feature-card__body { + display: flex; + padding: 22rpx 24rpx; + flex-direction: column; + justify-content: center; +} +.feature-card__tag { + color: var(--color-primary); + font-size: 23rpx; + font-weight: 700; +} +.feature-card__title { + margin-top: 4rpx; + font-size: 31rpx; + font-weight: 700; +} +.feature-card__copy { + display: -webkit-box; + margin-top: 6rpx; + overflow: hidden; + color: var(--color-text-secondary); + font-size: 25rpx; + line-height: 1.5; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; +} +.feature-card__meta { + margin-top: 8rpx; + color: var(--color-text-tertiary); + font-size: 23rpx; +} +.empty-strip { + padding: 36rpx; + border-radius: 24rpx; + color: var(--color-text-secondary); + background: #fff; + text-align: center; +} +.link-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 16rpx; +} +.link-grid button { + display: grid; + min-height: 96rpx; + margin: 0; + padding: 16rpx 20rpx; + grid-template-columns: 48rpx 1fr auto; + align-items: center; + color: var(--color-text); + border: 2rpx solid var(--color-border); + border-radius: 24rpx; + background: #fff; + text-align: left; +} +.link-grid__icon { + display: flex; + width: 44rpx; + height: 44rpx; + align-items: center; + justify-content: center; + border-radius: 14rpx; + color: #fff; + background: #ed7040; + font-size: 23rpx; +} +.link-grid__icon.blue { + background: #3b89cf; +} diff --git a/apps/miniprogram/miniprogram/pages/service-hub/service-hub.json b/apps/miniprogram/miniprogram/pages/service-hub/service-hub.json new file mode 100644 index 0000000..33bfa65 --- /dev/null +++ b/apps/miniprogram/miniprogram/pages/service-hub/service-hub.json @@ -0,0 +1 @@ +{ "navigationBarTitleText": "暖心服务" } diff --git a/apps/miniprogram/miniprogram/pages/service-hub/service-hub.ts b/apps/miniprogram/miniprogram/pages/service-hub/service-hub.ts new file mode 100644 index 0000000..725d53a --- /dev/null +++ b/apps/miniprogram/miniprogram/pages/service-hub/service-hub.ts @@ -0,0 +1,56 @@ +Page({ + data: { + categories: [ + { + code: 'OLD_AGE', + label: '关爱老人', + description: '生活照料、陪伴关怀、健康支持', + icon: '人', + tone: 'orange', + }, + { + code: 'WOMEN_CHILDREN', + label: '妇女儿童帮扶', + description: '困境支持、成长陪伴与权益关爱', + icon: '爱', + tone: 'rose', + }, + { + code: 'DISABILITY', + label: '残障帮扶', + description: '生活协助、康复支持与无障碍关怀', + icon: '助', + tone: 'blue', + }, + { + code: 'DIFFICULT_FAMILY', + label: '困难家庭服务', + description: '生活困难、资源链接与持续关爱', + icon: '家', + tone: 'green', + }, + { + code: 'OTHER', + label: '其他服务', + description: '不确定类型也可以先告诉我们', + icon: '心', + tone: 'purple', + }, + ], + }, + applyForSelf() { + void wx.navigateTo({ url: '/pages/application-form/application-form?mode=SELF' }); + }, + applyForFamily() { + void wx.navigateTo({ url: '/pages/application-form/application-form?mode=FAMILY' }); + }, + applyCategory(event: WechatMiniprogram.BaseEvent) { + const category = event.currentTarget.dataset['code'] as string; + void wx.navigateTo({ + url: `/pages/application-form/application-form?mode=SELF&category=${category}`, + }); + }, + applications() { + void wx.navigateTo({ url: '/pages/my-applications/my-applications' }); + }, +}); diff --git a/apps/miniprogram/miniprogram/pages/service-hub/service-hub.wxml b/apps/miniprogram/miniprogram/pages/service-hub/service-hub.wxml new file mode 100644 index 0000000..8125bc7 --- /dev/null +++ b/apps/miniprogram/miniprogram/pages/service-hub/service-hub.wxml @@ -0,0 +1,8 @@ + + 乐活暖心服务有困难,您可以告诉我们填写基本情况后,工作人员会根据实际服务能力与您联系。 + + + 选择服务类型不知道选什么也没关系 + + 温馨提示平台不承诺即时救援。如遇危及生命安全的紧急情况,请及时联系 110 或 120。 + diff --git a/apps/miniprogram/miniprogram/pages/service-hub/service-hub.wxss b/apps/miniprogram/miniprogram/pages/service-hub/service-hub.wxss new file mode 100644 index 0000000..3793518 --- /dev/null +++ b/apps/miniprogram/miniprogram/pages/service-hub/service-hub.wxss @@ -0,0 +1,164 @@ +.service-hero { + padding: 36rpx 32rpx; + border-radius: 32rpx; + color: #723018; + background: linear-gradient(135deg, #fff4eb, #ffd7c2); +} +.service-hero__eyebrow, +.service-hero__title, +.service-hero__copy { + display: block; +} +.service-hero__eyebrow { + font-size: 25rpx; + font-weight: 700; +} +.service-hero__title { + margin-top: 12rpx; + font-size: 42rpx; + font-weight: 700; +} +.service-hero__copy { + margin-top: 12rpx; + color: #765241; + font-size: 28rpx; + line-height: 1.65; +} +.quick-actions { + display: grid; + margin-top: 20rpx; + grid-template-columns: 1fr 1fr; + gap: 18rpx; +} +.quick-actions button { + display: flex; + min-height: 170rpx; + margin: 0; + padding: 24rpx; + flex-direction: column; + align-items: flex-start; + border: 2rpx solid #f2ded4; + border-radius: 28rpx; + background: #fff; +} +.quick-actions__icon { + display: flex; + width: 54rpx; + height: 54rpx; + align-items: center; + justify-content: center; + border-radius: 17rpx; + color: #fff; + background: #f05a28; +} +.quick-actions__icon.green { + background: #35a864; +} +.quick-actions__title, +.quick-actions__copy { + display: block; +} +.quick-actions__title { + margin-top: 14rpx; + font-weight: 700; +} +.quick-actions__copy { + margin-top: 5rpx; + color: var(--color-text-secondary); + font-size: 25rpx; +} +.progress-entry { + display: flex; + width: 100%; + min-height: 104rpx; + margin: 20rpx 0; + padding: 20rpx 26rpx; + align-items: center; + justify-content: space-between; + color: #245e8f; + border-radius: 24rpx; + background: #edf6fd; + text-align: left; +} +.progress-entry__title, +.progress-entry__copy { + display: block; +} +.progress-entry__title { + font-weight: 700; +} +.progress-entry__copy { + margin-top: 5rpx; + color: #60788b; + font-size: 25rpx; +} +.category-card { + display: grid; + width: 100%; + min-height: 126rpx; + margin: 0 0 16rpx; + padding: 22rpx 24rpx; + grid-template-columns: 66rpx 1fr auto; + align-items: center; + gap: 18rpx; + color: var(--color-text); + border: 2rpx solid var(--color-border); + border-radius: 26rpx; + background: #fff; + text-align: left; +} +.category-card__icon { + display: flex; + width: 62rpx; + height: 62rpx; + align-items: center; + justify-content: center; + border-radius: 20rpx; + color: #fff; + background: #f47745; +} +.category-card__icon.rose { + background: #df6979; +} +.category-card__icon.blue { + background: #398bd0; +} +.category-card__icon.green { + background: #43a15a; +} +.category-card__icon.purple { + background: #8065c4; +} +.category-card__title, +.category-card__copy { + display: block; +} +.category-card__title { + font-size: 31rpx; + font-weight: 700; +} +.category-card__copy { + margin-top: 5rpx; + color: var(--color-text-secondary); + font-size: 25rpx; + line-height: 1.5; +} +.category-card__arrow { + color: #aaa39c; + font-size: 36rpx; +} +.safety-note { + display: flex; + margin-top: 28rpx; + padding: 24rpx; + flex-direction: column; + color: #735818; + border-radius: 22rpx; + background: #fff7df; + font-size: 26rpx; + line-height: 1.65; +} +.safety-note__title { + margin-bottom: 5rpx; + font-weight: 700; +} diff --git a/apps/miniprogram/miniprogram/pages/volunteer-center/volunteer-center.wxml b/apps/miniprogram/miniprogram/pages/volunteer-center/volunteer-center.wxml index 84227d0..dbb069b 100644 --- a/apps/miniprogram/miniprogram/pages/volunteer-center/volunteer-center.wxml +++ b/apps/miniprogram/miniprogram/pages/volunteer-center/volunteer-center.wxml @@ -1 +1 @@ -志愿者中心认证资料、报名进度与服务时长正在加载…认证状态:{{profile.statusLabel}}累计 {{profile.completedActivityCount}} 次活动,{{profile.totalServiceMinutes}} 分钟服务服务技能服务意向{{message}}我的活动报名暂无报名记录{{item.activityTitle}}{{item.statusLabel}} · {{item.checkInStatusLabel}}服务时长:{{item.serviceMinutes === null ? '待核定' : item.serviceMinutes + ' 分钟'}} +愿志愿者中心让每一次参与都有记录{{profile.statusLabel}}认证状态{{profile.completedActivityCount}}完成活动{{profile.totalServiceMinutes}}服务分钟{{profile ? '我的志愿资料' : '申请志愿者认证'}}仅收集服务所需信息服务技能服务意向{{message}}我的活动报名审核、签到与服务时长暂无报名记录您可以从“公益”页面查看已发布活动。{{item.activityTitle}}{{item.statusLabel}} · {{item.checkInStatusLabel}}{{item.serviceMinutes === null ? '待核定' : item.serviceMinutes + ' 分钟'}} diff --git a/apps/miniprogram/miniprogram/pages/volunteer-center/volunteer-center.wxss b/apps/miniprogram/miniprogram/pages/volunteer-center/volunteer-center.wxss index 614e1ec..65cebd5 100644 --- a/apps/miniprogram/miniprogram/pages/volunteer-center/volunteer-center.wxss +++ b/apps/miniprogram/miniprogram/pages/volunteer-center/volunteer-center.wxss @@ -1,29 +1,144 @@ -@import '../../app.wxss'; -.form-card { - padding: 28rpx; - border-radius: 24rpx; +.volunteer-hero { + display: flex; + padding: 34rpx; + align-items: center; + gap: 22rpx; + border-radius: 34rpx; + color: #fff; + background: linear-gradient(135deg, #3dac62, #248f4c); +} +.volunteer-avatar { + display: flex; + width: 84rpx; + height: 84rpx; + align-items: center; + justify-content: center; + border: 4rpx solid rgba(255, 255, 255, 0.7); + border-radius: 50%; background: #fff; + color: #27924e; + font-size: 34rpx; + font-weight: 700; +} +.volunteer-title, +.volunteer-subtitle { + display: block; +} +.volunteer-title { + font-size: 38rpx; + font-weight: 700; +} +.volunteer-subtitle { + margin-top: 6rpx; + font-size: 26rpx; + opacity: 0.9; +} +.volunteer-stats { + display: grid; + margin-top: 20rpx; + padding: 24rpx 12rpx; + grid-template-columns: repeat(3, 1fr); + border: 2rpx solid var(--color-border); + border-radius: 28rpx; + background: #fff; + box-shadow: var(--shadow-card); +} +.volunteer-stats view { + display: flex; + flex-direction: column; + align-items: center; + color: var(--color-text-secondary); + border-right: 2rpx solid #eeeae6; + font-size: 24rpx; +} +.volunteer-stats view:last-child { + border-right: 0; +} +.volunteer-stats__value { + margin-bottom: 5rpx; + color: var(--color-text); + font-size: 30rpx; + font-weight: 700; } .form-card label, .field-label { display: block; - margin-top: 24rpx; - font-weight: 600; + margin-top: 26rpx; + font-weight: 700; +} +.form-card > label:first-child { + margin-top: 0; } .form-card input, .form-card textarea { width: 100%; - min-height: 88rpx; + min-height: 92rpx; margin-top: 12rpx; - padding: 18rpx; - border: 2rpx solid #d9dce1; - border-radius: 16rpx; + padding: 20rpx 22rpx; + border: 2rpx solid #d9d3cd; + border-radius: 18rpx; box-sizing: border-box; + font-size: 30rpx; } -.check-row { - display: flex !important; - min-height: 72rpx; - align-items: center; +.form-card textarea { + min-height: 180rpx; +} +.option-grid { + display: grid; + margin-top: 12rpx; + grid-template-columns: 1fr 1fr; gap: 12rpx; +} +.check-chip { + display: flex !important; + min-height: 76rpx !important; + margin: 0 !important; + padding: 10rpx 14rpx; + align-items: center; + gap: 8rpx; + border: 2rpx solid #e6e0da; + border-radius: 18rpx; + background: #faf9f7; + font-size: 26rpx; font-weight: 400 !important; } +.consent-row { + display: flex !important; + min-height: 96rpx; + margin-top: 26rpx !important; + align-items: flex-start; + gap: 12rpx; + color: var(--color-text-secondary); + font-size: 26rpx; + line-height: 1.6; + font-weight: 400 !important; +} +.registration-card { + display: flex; + min-height: 112rpx; + margin-bottom: 16rpx; + padding: 24rpx 26rpx; + align-items: center; + justify-content: space-between; + gap: 20rpx; + border: 2rpx solid var(--color-border); + border-radius: 24rpx; + background: #fff; +} +.registration-card__title, +.registration-card__meta { + display: block; +} +.registration-card__title { + font-weight: 700; +} +.registration-card__meta { + margin-top: 5rpx; + color: var(--color-text-secondary); + font-size: 25rpx; +} +.registration-card__minutes { + color: var(--color-primary); + font-size: 26rpx; + font-weight: 700; +} diff --git a/docs/07_UI_UX.md b/docs/07_UI_UX.md index 921b01e..926d9b6 100644 --- a/docs/07_UI_UX.md +++ b/docs/07_UI_UX.md @@ -146,3 +146,14 @@ P2:5. 公益项目 6. 公益活动 7. 我要做公益 - 志愿者中心只收集姓名、手机号、地区、可参与时间、固定技能和服务意向,并明确资料使用同意;同页展示资格状态、报名进度与核定服务分钟。 - 管理端新增志愿者审核、公益项目、活动与报名三个独立导航;危险状态推进二次确认,手机号列表脱敏,所有主要按钮保持至少 44px 点击高度。 - 沿用已批准的橙色主色、系统字体和功能型布局;采用高对比、可见焦点、文字+状态、加载/空/失败反馈与渐进披露,不引入复杂动画、密集仪表盘或新品牌方向。 + +--- + +## 11. 公众端视觉重设计落地(2026-08-13) + +- 底部导航固定为“首页 / 服务 / 公益 / 我的”,分别承担首要入口、求助闭环、社会参与和个人事务;协作任务按权限在“我的”中显示,不另设同级导航。 +- 首页保持“我需要帮助 / 帮家人申请”为最高视觉权重,六类服务入口次之;服务进度使用独立横幅,宣传内容不挤占求助任务。 +- 暖橙 `#F05A28` 为主色,绿色表示志愿参与与正向状态,蓝色表示进度和消息;颜色始终配合文字、标签或图形,不作为唯一信息来源。 +- 全局使用 16/24/32rpx 级圆角、低强度暖灰阴影、至少约 96rpx 的主按钮/主要点击高度和系统字体;不使用闪烁、强动画、玻璃拟态或科技大屏视觉。 +- 项目、活动和志愿者页面只展示 API 返回的真实事实;封面缺失时使用轻量公益图形占位,不生成虚构人物、捐赠额、服务人数或活动成果。 +- 参考图中的公开捐赠交易、证书、培训和团队入口不属于当前 V1 已实现能力,不在公众端显示;项目详情明确不提供公开募捐交易。 diff --git a/docs/10_TASK_STATE.md b/docs/10_TASK_STATE.md index 00e57ba..2bf890f 100644 --- a/docs/10_TASK_STATE.md +++ b/docs/10_TASK_STATE.md @@ -116,6 +116,18 @@ YYYY-MM-DD 遗留问题: ``` +2026-08-13 + +任务:参考已批准视觉方向重设计微信小程序公众端(不含管理端)。 + +完成:分析用户提供的前端参考图并按现有 V1 业务边界重构公众端信息架构;建立暖橙主色、语义色、圆角、阴影、字号和间距设计令牌,新增“首页 / 服务 / 公益 / 我的”四栏自定义底部导航;重做首页品牌区、本人/代申请双主任务、六类服务入口、服务进度和公益参与分区;新增服务、公益和个人中心三个聚合页,全部连接现有真实申请、项目、活动、志愿者、协作任务、内容和消息链路;重做项目/活动列表与详情、志愿者中心的卡片层级和适老交互。保留 loading / empty / error / permission-aware 状态,不加入参考图中的公开捐赠交易、证书、培训、团队或虚构业务统计,不修改管理端、API、数据库、认证或权限。 + +测试:format check、lint、全仓 typecheck、27 个 unit tests、全仓 production build 全部通过;小程序独立 typecheck、3 个 unit tests 和 build 通过。真实 MySQL 集成测试未得到新的完整通过结果:migration 重试两次均被本机 Windows Prisma Schema Engine 启动异常阻止;随后在已迁移的健康 `lehuo_test` 库直接执行时进入测试但超过 5 分钟工具时限,残留测试进程已按命令行精确结束。本任务无 schema/API/后端变更,上一阶段 34 个集成测试通过基线保持不变,但本次不把超时运行记录为通过。 + +文档变化:更新小程序 README、UI/UX 规范和本任务状态;未产生新的架构或产品决策,因此不新增 ADR。 + +遗留问题:本机未定位到微信开发者工具 CLI,且真实 AppID/AppSecret 与微信环境仍按用户计划后期提供,因此未生成开发者工具/真机截图;当前完成代码级视觉对照、类型与构建验证,真机适老化与安全区验收仍需在微信环境执行。项目/活动真实封面继续依赖现有私有对象存储配置,未使用假图片冒充生产内容。 + 2026-08-12 任务:Phase 7 统计、安全与上线工程。