feat: redesign onboarding and home UI
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
设计原则
|
||||
整合四位专家的核心诉求:
|
||||
|
||||
冷静但不冷漠、有趣但不幼稚、净化而非刺激
|
||||
|
||||
最终界面布局(完整结构)
|
||||
📐 整体高度:约手机一屏半,单页垂直流
|
||||
【顶部区】个人状态栏(高度 30%)
|
||||
*.txt
|
||||
Plaintext
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ [头像] 意志骑士 Lv.3 💰 ×24 │ ← 毛玻璃背景
|
||||
│ │ backdrop-blur: 12px
|
||||
│ ╭─────────────────────────────────────────────╮ │
|
||||
│ │ ████████████████░░░░░░░░░░░░░░░░░░░░░░░░░ │ │ ← HP生命槽
|
||||
│ │ HP: 72% 浊→清 视觉语言 │ │ 渐变填充 #6EE7B7→#67E8F9
|
||||
│ ╰─────────────────────────────────────────────╯ │ 24px高,12px圆角
|
||||
│ │
|
||||
│ ✦ 深度含氧(已坚持 2 小时 17 分) │ ← Buff标签
|
||||
│ [薰衣草紫边框] │ 胶囊形
|
||||
└─────────────────────────────────────────────────────┘
|
||||
设计决策说明:
|
||||
|
||||
保留游戏化元素(等级/称号),但降低视觉优先级——置于次要位置
|
||||
采用色彩心理学专家的"浊清动效"替代碎裂动效,保护用户情绪
|
||||
毛玻璃背景融合未来主义美学,但保持经典主义的秩序感
|
||||
【中部区】核心控制台(高度 35%)
|
||||
*.txt
|
||||
Plaintext
|
||||
【中下区】健康仪表盘(高度 20%)
|
||||
*.txt
|
||||
Plaintext
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ ╭─────────╮ ╭────────────────────────╮ │
|
||||
│ │ ◐ │ │ 呼吸系统 +12% │ │
|
||||
│ │ 84% │ │ 心脏功能 +8% │ │
|
||||
│ │ 健康 │ │ 血液纯净 +15% │ │
|
||||
│ ╰─────────╯ │ ──────────────────── │ │
|
||||
│ 健康指数 │ +3.2 小时 │ │ ← 生命回收
|
||||
│ (圆环图) │ 生命已回收 │ │ 强调色24px
|
||||
│ ╰────────────────────────╯ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
设计决策说明:
|
||||
|
||||
健康指数圆环图代替多个独立卡片,符合极简主义减法原则
|
||||
生命回收概念来自未来主义,成为核心数据展示
|
||||
【底部区】成长曲线(高度 15%)
|
||||
*.txt
|
||||
Plaintext
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ 7 天趋势 │
|
||||
│ │ │
|
||||
│ 5 ├ ● │ ← 琥珀金转折点
|
||||
│ │ ●────────────╱ │
|
||||
│ 3 ├──●────────────────╱ │
|
||||
│ │╱ │
|
||||
│ 0 └──┬────┬────┬────┬────┬────┬────┬────→ │
|
||||
│ 周一 周二 周三 周四 周五 周六 周日 │
|
||||
│ │
|
||||
│ 背景:极淡青绿渐变 (#ECFDF5 → #F0F9FF) │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
最终色板
|
||||
用途 色值 来源 说明
|
||||
HP高填充 #67E8F9 心理学专家调整 降低饱和度,更持久
|
||||
HP低填充 #D97706 暗琥珀 心理学专家 警示非恐惧
|
||||
主渐变起 #6EE7B7 心理学专家调整 生命力、成长
|
||||
SOS/里程碑 #FBBF24 全场共识 温暖、成就
|
||||
Buff标签 #A78BFA 薰衣草紫 心理学专家原创 成长、过渡
|
||||
背景 #F8FAFC 微蓝白 经典主义 干净、呼吸感
|
||||
文字主色 #1E293B 深蓝灰 经典主义 冷静、专业
|
||||
动效规范
|
||||
动效 实现 周期 意义
|
||||
HP呼吸闪烁 微弱明度变化 ±5% 4-6秒 与身体节奏共振
|
||||
浊清过渡 颜色从暗琥珀→清澈渐变 2秒 非破坏性反馈
|
||||
呼吸线脉动 顶部细线不透明度 10-20% 6秒 身体自愈暗示
|
||||
设计决策摘要
|
||||
问题 最终决策 采纳来源
|
||||
HP碎裂动效 ❌ 取消 → 改用"浊清"视觉语言 色彩心理学专家
|
||||
等级/称号 ✅ 保留,但降低视觉优先级 未来主义
|
||||
金币奖励 ✅ 保留图标形式,删除独立卡片 极简主义融合
|
||||
游戏化整体 ⚠️ 保留数值化反馈,删除幼稚外壳 经典主义+未来主义融合
|
||||
布局风格 瑞士网格+毛玻璃 经典主义+未来主义融合
|
||||
配色饱和度 降低15-20% 经典主义+色彩心理学
|
||||
一句话总结
|
||||
"一个冷静的生物数据仪表盘,用颜色的语言告诉用户:你的每一次选择,都在让生命更加清澈。"
|
||||
@@ -11,83 +11,85 @@
|
||||
</view>
|
||||
|
||||
<view class="dialog-body">
|
||||
<view v-if="quickModeActive" class="quick-banner">
|
||||
<view class="quick-banner-chip">
|
||||
<text class="quick-banner-chip-label">默认时间</text>
|
||||
<text class="quick-banner-chip-value">{{ formData.smoke_time_only }}</text>
|
||||
<template v-if="quickModeActive">
|
||||
<view class="quick-banner">
|
||||
<view class="quick-banner-chip">
|
||||
<text class="quick-banner-chip-label">默认时间</text>
|
||||
<text class="quick-banner-chip-value">{{ formData.smoke_time_only }}</text>
|
||||
</view>
|
||||
<view class="quick-banner-chip" v-if="type === 'smoke'">
|
||||
<text class="quick-banner-chip-label">默认数量</text>
|
||||
<text class="quick-banner-chip-value">{{ formData.num }} 支</text>
|
||||
</view>
|
||||
<text class="quick-banner-tip">先选择系统场景;如果选“其他”,再补充自定义原因。</text>
|
||||
</view>
|
||||
<view class="quick-banner-chip" v-if="type === 'smoke'">
|
||||
<text class="quick-banner-chip-label">默认数量</text>
|
||||
<text class="quick-banner-chip-value">{{ formData.num }} 支</text>
|
||||
</view>
|
||||
<text class="quick-banner-tip">选择原因和烟瘾等级即可快速保存,需要时再展开高级项。</text>
|
||||
</view>
|
||||
|
||||
<view v-if="quickModeActive && type === 'smoke'" class="section-card level-section-quick">
|
||||
<view class="level-header">
|
||||
<text class="section-title">烟瘾等级</text>
|
||||
<view class="level-badge">Level {{ formData.level }}</view>
|
||||
</view>
|
||||
<slider
|
||||
class="level-slider"
|
||||
:value="formData.level"
|
||||
:min="1"
|
||||
:max="5"
|
||||
:step="1"
|
||||
activeColor="#22C55E"
|
||||
backgroundColor="#E5E7EB"
|
||||
block-color="#22C55E"
|
||||
:block-size="20"
|
||||
@change="onLevelChange"
|
||||
/>
|
||||
<view class="level-scale">
|
||||
<text class="level-scale-text">无感</text>
|
||||
<text class="level-scale-text">强烈</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="section-card">
|
||||
<view class="section-heading">
|
||||
<text class="section-title">{{ reasonSectionTitle }}</text>
|
||||
<text class="section-caption">可多选</text>
|
||||
</view>
|
||||
<view class="reason-chip-grid">
|
||||
<view
|
||||
v-for="item in quickReasonOptions"
|
||||
:key="item.key"
|
||||
class="reason-chip"
|
||||
:class="{ 'reason-chip-active': isReasonSelected(item.key) }"
|
||||
@tap="toggleReason(item.key)"
|
||||
>
|
||||
<text class="reason-chip-text">{{ item.label }}</text>
|
||||
<view v-if="type === 'smoke'" class="section-card level-section-quick">
|
||||
<view class="level-header">
|
||||
<text class="section-title">烟瘾等级</text>
|
||||
<view class="level-badge">Level {{ formData.level }}</view>
|
||||
</view>
|
||||
<slider
|
||||
class="level-slider"
|
||||
:value="formData.level"
|
||||
:min="1"
|
||||
:max="5"
|
||||
:step="1"
|
||||
activeColor="#22C55E"
|
||||
backgroundColor="#E5E7EB"
|
||||
block-color="#22C55E"
|
||||
:block-size="20"
|
||||
@change="onLevelChange"
|
||||
/>
|
||||
<view class="level-scale">
|
||||
<text class="level-scale-text">无感</text>
|
||||
<text class="level-scale-text">强烈</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="remark-section">
|
||||
<view class="section-heading">
|
||||
<text class="section-title">{{ remarkTitle }}</text>
|
||||
<text class="section-caption">{{ remarkCaption }}</text>
|
||||
<view class="section-card scene-section">
|
||||
<view class="section-heading">
|
||||
<text class="section-title">{{ sceneSectionTitle }}</text>
|
||||
<text class="section-caption">系统预设,可多选</text>
|
||||
</view>
|
||||
<view class="reason-chip-grid">
|
||||
<view
|
||||
v-for="item in quickReasonOptions"
|
||||
:key="item.key"
|
||||
class="reason-chip"
|
||||
:class="{ 'reason-chip-active': isReasonSelected(item.key) }"
|
||||
@tap="toggleReason(item.key)"
|
||||
>
|
||||
<text class="reason-chip-text">{{ item.label }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="remark-card">
|
||||
<textarea
|
||||
class="form-textarea"
|
||||
v-model="formData.remark"
|
||||
:placeholder="remarkPlaceholder"
|
||||
maxlength="200"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="quickModeActive" class="advanced-toggle" @tap="showAdvanced = !showAdvanced">
|
||||
<view>
|
||||
<text class="advanced-toggle-title">{{ showAdvanced ? '收起高级设置' : '展开高级设置' }}</text>
|
||||
<text class="advanced-toggle-desc">修改时间和数量</text>
|
||||
<view v-if="showCustomReasonInput" class="remark-section">
|
||||
<view class="section-heading">
|
||||
<text class="section-title">其他场景</text>
|
||||
<text class="section-caption">自填</text>
|
||||
</view>
|
||||
<view class="remark-card">
|
||||
<textarea
|
||||
class="form-textarea form-textarea-compact"
|
||||
v-model="formData.custom_reason"
|
||||
:placeholder="customReasonPlaceholder"
|
||||
maxlength="120"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<text class="advanced-toggle-arrow">{{ showAdvanced ? '⌃' : '⌄' }}</text>
|
||||
</view>
|
||||
|
||||
<view v-if="showAdvanced || !quickModeActive" class="advanced-fields">
|
||||
<view class="advanced-toggle" @tap="showAdvanced = !showAdvanced">
|
||||
<view>
|
||||
<text class="advanced-toggle-title">{{ showAdvanced ? '收起高级设置' : '展开高级设置' }}</text>
|
||||
<text class="advanced-toggle-desc">修改时间和数量</text>
|
||||
</view>
|
||||
<text class="advanced-toggle-arrow">{{ showAdvanced ? '⌃' : '⌄' }}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<view v-if="showAdvanced || !quickModeActive" class="advanced-fields detail-top-fields">
|
||||
<view class="form-row">
|
||||
<picker class="picker-card" mode="date" :value="formData.smoke_time" @change="onDateChange">
|
||||
<view class="input-card">
|
||||
@@ -121,7 +123,7 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="!quickModeActive" class="section-card">
|
||||
<view class="section-card">
|
||||
<view class="level-header">
|
||||
<text class="section-title">{{ type === 'smoke' ? '烟瘾程度' : '忍住强度' }}</text>
|
||||
<view class="level-badge">Level {{ formData.level }}</view>
|
||||
@@ -144,8 +146,57 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<template v-if="!quickModeActive">
|
||||
<view class="section-card scene-section">
|
||||
<view class="section-heading">
|
||||
<text class="section-title">{{ sceneSectionTitle }}</text>
|
||||
<text class="section-caption">系统预设,可多选</text>
|
||||
</view>
|
||||
<view class="reason-chip-grid">
|
||||
<view
|
||||
v-for="item in quickReasonOptions"
|
||||
:key="item.key"
|
||||
class="reason-chip"
|
||||
:class="{ 'reason-chip-active': isReasonSelected(item.key) }"
|
||||
@tap="toggleReason(item.key)"
|
||||
>
|
||||
<text class="reason-chip-text">{{ item.label }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="showCustomReasonInput" class="remark-section">
|
||||
<view class="section-heading">
|
||||
<text class="section-title">其他场景</text>
|
||||
<text class="section-caption">自填</text>
|
||||
</view>
|
||||
<view class="remark-card">
|
||||
<textarea
|
||||
class="form-textarea form-textarea-compact"
|
||||
v-model="formData.custom_reason"
|
||||
:placeholder="customReasonPlaceholder"
|
||||
maxlength="120"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="remark-section remark-section-bottom">
|
||||
<view class="section-heading">
|
||||
<text class="section-title">原因</text>
|
||||
<text class="section-caption">可选,放在最后补充</text>
|
||||
</view>
|
||||
<view class="remark-card">
|
||||
<textarea
|
||||
class="form-textarea"
|
||||
v-model="formData.remark"
|
||||
:placeholder="remarkPlaceholder"
|
||||
maxlength="200"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
<view class="dialog-footer">
|
||||
<view class="dialog-btn-primary" @tap="submit">
|
||||
<view class="btn-icon"></view>
|
||||
@@ -188,6 +239,7 @@ export default {
|
||||
smoke_time_only: '',
|
||||
smoke_at: '',
|
||||
remark: '',
|
||||
custom_reason: '',
|
||||
reason_tags: [],
|
||||
level: 2,
|
||||
num: 1
|
||||
@@ -212,9 +264,20 @@ export default {
|
||||
quickReasonOptions() {
|
||||
return getReasonOptions(this.type)
|
||||
},
|
||||
sceneSectionTitle() {
|
||||
return this.type === 'smoke' ? '选择抽烟场景' : '选择忍住场景'
|
||||
},
|
||||
reasonSectionTitle() {
|
||||
return this.type === 'smoke' ? '这次为什么会抽?' : '这次是怎么扛住的?'
|
||||
},
|
||||
showCustomReasonInput() {
|
||||
return this.formData.reason_tags.includes('other')
|
||||
},
|
||||
customReasonPlaceholder() {
|
||||
return this.type === 'smoke'
|
||||
? '写下系统场景里没有覆盖的触发点...'
|
||||
: '写下这次具体是怎么撑过去的...'
|
||||
},
|
||||
remarkTitle() {
|
||||
return this.formData.reason_tags.includes('other') ? '补充说明' : '补充备注'
|
||||
},
|
||||
@@ -253,6 +316,7 @@ export default {
|
||||
smoke_time_only: this.initialData.smoke_time_only || '',
|
||||
smoke_at: this.initialData.smoke_at || '',
|
||||
remark: this.initialData.remark || '',
|
||||
custom_reason: '',
|
||||
reason_tags: normalizeReasonTags(this.initialData.reason_tags),
|
||||
level: this.initialData.level ?? 2,
|
||||
num: this.resolveInitialNum(this.initialData)
|
||||
@@ -273,6 +337,7 @@ export default {
|
||||
smoke_time_only: timeStr,
|
||||
smoke_at: datetimeStr,
|
||||
remark: '',
|
||||
custom_reason: '',
|
||||
reason_tags: [],
|
||||
level: 2,
|
||||
num: this.type === 'smoke' ? 1 : 0
|
||||
@@ -350,14 +415,16 @@ export default {
|
||||
},
|
||||
buildRemark() {
|
||||
const customRemark = (this.formData.remark || '').trim()
|
||||
const customReason = (this.formData.custom_reason || '').trim()
|
||||
const reasonLabels = getReasonLabels(this.formData.reason_tags, this.type).filter(label => label !== '其他')
|
||||
if (!reasonLabels.length) {
|
||||
return customRemark
|
||||
const parts = [...reasonLabels]
|
||||
if (customReason) {
|
||||
parts.push(customReason)
|
||||
}
|
||||
if (!customRemark) {
|
||||
return reasonLabels.join('、')
|
||||
if (customRemark) {
|
||||
parts.push(customRemark)
|
||||
}
|
||||
return `${reasonLabels.join('、')};${customRemark}`
|
||||
return parts.join(';')
|
||||
},
|
||||
submit() {
|
||||
if (!this.isTimeValid()) {
|
||||
@@ -546,6 +613,11 @@ export default {
|
||||
box-shadow: 0 10rpx 18rpx rgba(26, 163, 122, 0.12);
|
||||
}
|
||||
|
||||
.scene-section {
|
||||
background:
|
||||
linear-gradient(135deg, rgba(255, 255, 255, 0.86), rgba(240, 249, 255, 0.72));
|
||||
}
|
||||
|
||||
.reason-chip-text {
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
@@ -576,6 +648,14 @@ export default {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-textarea-compact {
|
||||
min-height: 112rpx;
|
||||
}
|
||||
|
||||
.remark-section-bottom {
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.advanced-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
const ENV = {
|
||||
development: {
|
||||
BASE_URL: 'http://localhost:8080/api/v1',
|
||||
BASE_URL: 'http://192.168.31.73:9003/api/v1',
|
||||
MINI_PROGRAM_ID: 2
|
||||
},
|
||||
production: {
|
||||
|
||||
+2
-2
@@ -7,13 +7,13 @@
|
||||
},
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/mode-select/index",
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"path": "pages/mode-select/index",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
|
||||
+1264
-266
File diff suppressed because it is too large
Load Diff
+157
-33
@@ -115,8 +115,13 @@
|
||||
|
||||
<!-- 成就风格 -->
|
||||
<view v-if="achievementThemes.length > 0" class="form-section">
|
||||
<text class="section-label">成就称号风格</text>
|
||||
<text class="section-hint">打卡越久,称号越高</text>
|
||||
<view class="theme-section-head">
|
||||
<view>
|
||||
<text class="section-label">成就称号风格</text>
|
||||
<text class="section-hint">选择一套更能激励你的成长称号</text>
|
||||
</view>
|
||||
<text class="theme-section-badge">可更换</text>
|
||||
</view>
|
||||
<view class="theme-list">
|
||||
<view
|
||||
v-for="theme in achievementThemes"
|
||||
@@ -125,16 +130,25 @@
|
||||
:class="{ 'theme-card-active': formData.achievement_theme_id === theme.id }"
|
||||
@tap="formData.achievement_theme_id = theme.id"
|
||||
>
|
||||
<view class="theme-glow"></view>
|
||||
<view class="theme-header">
|
||||
<text class="theme-icon">{{ theme.icon }}</text>
|
||||
<text class="theme-name">{{ theme.name }}</text>
|
||||
<view class="theme-icon-wrap">
|
||||
<text class="theme-icon">{{ theme.icon }}</text>
|
||||
</view>
|
||||
<view class="theme-title-wrap">
|
||||
<text class="theme-name">{{ theme.name }}</text>
|
||||
<text class="theme-desc">打卡进度会逐步解锁称号</text>
|
||||
</view>
|
||||
<view class="theme-check">
|
||||
<text v-if="formData.achievement_theme_id === theme.id">✓</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="theme-levels">
|
||||
<text
|
||||
v-for="(level, idx) in theme.levels"
|
||||
:key="level.id"
|
||||
class="theme-level"
|
||||
>{{ level.name }}<text v-if="idx < theme.levels.length - 1" class="theme-arrow"> → </text></text>
|
||||
>{{ level.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -263,10 +277,6 @@ async function handleSubmit() {
|
||||
uni.showLoading({ title: '保存中...' })
|
||||
await profileStore.saveProfile(formData.value)
|
||||
uni.hideLoading()
|
||||
if (!formData.value.mode) {
|
||||
uni.redirectTo({ url: '/pages/mode-select/index' })
|
||||
return
|
||||
}
|
||||
uni.switchTab({ url: '/pages/index/index' })
|
||||
} catch (e) {
|
||||
uni.hideLoading()
|
||||
@@ -539,66 +549,180 @@ onShareAppMessage(() => {
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.theme-section-head {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 20rpx;
|
||||
margin-bottom: 18rpx;
|
||||
}
|
||||
|
||||
.theme-section-head .section-hint {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.theme-section-badge {
|
||||
flex-shrink: 0;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(110, 231, 183, 0.16);
|
||||
border: 1rpx solid rgba(16, 185, 129, 0.16);
|
||||
font-size: 20rpx;
|
||||
font-weight: 700;
|
||||
color: #0F766E;
|
||||
}
|
||||
|
||||
.theme-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12rpx;
|
||||
gap: 18rpx;
|
||||
}
|
||||
|
||||
.theme-card {
|
||||
padding: 20rpx;
|
||||
border-radius: 20rpx;
|
||||
background: #F9FBFA;
|
||||
border: 2rpx solid #F0F0F0;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
padding: 24rpx;
|
||||
border-radius: 28rpx;
|
||||
background:
|
||||
linear-gradient(135deg, rgba(255, 255, 255, 0.96), rgba(248, 250, 252, 0.92));
|
||||
border: 2rpx solid rgba(226, 232, 240, 0.9);
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 10rpx 28rpx rgba(15, 23, 42, 0.04);
|
||||
}
|
||||
|
||||
.theme-card-active {
|
||||
background: #E8F5F0;
|
||||
border-color: #10B981;
|
||||
background:
|
||||
radial-gradient(circle at top right, rgba(103, 232, 249, 0.28), transparent 34%),
|
||||
linear-gradient(135deg, rgba(236, 253, 245, 0.98), rgba(240, 249, 255, 0.94));
|
||||
border-color: rgba(16, 185, 129, 0.72);
|
||||
box-shadow: 0 18rpx 42rpx rgba(16, 185, 129, 0.13);
|
||||
}
|
||||
|
||||
.theme-glow {
|
||||
position: absolute;
|
||||
top: -70rpx;
|
||||
right: -70rpx;
|
||||
width: 190rpx;
|
||||
height: 190rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(110, 231, 183, 0.12);
|
||||
}
|
||||
|
||||
.theme-card-active .theme-glow {
|
||||
background: rgba(103, 232, 249, 0.28);
|
||||
}
|
||||
|
||||
.theme-header {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
margin-bottom: 10rpx;
|
||||
gap: 18rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.theme-icon-wrap {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(241, 245, 249, 0.92);
|
||||
border: 1rpx solid rgba(226, 232, 240, 0.9);
|
||||
box-shadow: inset 0 1rpx 0 rgba(255, 255, 255, 0.7);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.theme-card-active .theme-icon-wrap {
|
||||
background: linear-gradient(135deg, #6EE7B7, #67E8F9);
|
||||
border-color: rgba(255, 255, 255, 0.9);
|
||||
box-shadow: 0 12rpx 26rpx rgba(20, 184, 166, 0.18);
|
||||
}
|
||||
|
||||
.theme-icon {
|
||||
font-size: 32rpx;
|
||||
font-size: 36rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.theme-title-wrap {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6rpx;
|
||||
}
|
||||
|
||||
.theme-name {
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
color: #1A1A1A;
|
||||
font-size: 29rpx;
|
||||
line-height: 1.25;
|
||||
font-weight: 800;
|
||||
color: #1E293B;
|
||||
}
|
||||
|
||||
.theme-desc {
|
||||
font-size: 21rpx;
|
||||
line-height: 1.4;
|
||||
color: #64748B;
|
||||
}
|
||||
|
||||
.theme-card-active .theme-name {
|
||||
color: #10B981;
|
||||
color: #0F766E;
|
||||
}
|
||||
|
||||
.theme-check {
|
||||
width: 42rpx;
|
||||
height: 42rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 2rpx solid rgba(148, 163, 184, 0.34);
|
||||
background: rgba(255, 255, 255, 0.78);
|
||||
color: #FFFFFF;
|
||||
font-size: 24rpx;
|
||||
font-weight: 900;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.theme-card-active .theme-check {
|
||||
border-color: transparent;
|
||||
background: linear-gradient(135deg, #10B981, #06B6D4);
|
||||
box-shadow: 0 8rpx 18rpx rgba(16, 185, 129, 0.2);
|
||||
}
|
||||
|
||||
.theme-levels {
|
||||
font-size: 22rpx;
|
||||
color: #999999;
|
||||
line-height: 1.6;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.theme-level {
|
||||
font-size: 22rpx;
|
||||
max-width: 100%;
|
||||
padding: 8rpx 14rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(241, 245, 249, 0.95);
|
||||
border: 1rpx solid rgba(226, 232, 240, 0.9);
|
||||
font-size: 21rpx;
|
||||
line-height: 1.35;
|
||||
font-weight: 700;
|
||||
color: #64748B;
|
||||
}
|
||||
|
||||
.theme-card-active .theme-level {
|
||||
color: #10B981;
|
||||
background: rgba(255, 255, 255, 0.72);
|
||||
border-color: rgba(16, 185, 129, 0.15);
|
||||
color: #0F766E;
|
||||
}
|
||||
|
||||
.theme-card-active .theme-level:first-child {
|
||||
background: rgba(251, 191, 36, 0.18);
|
||||
border-color: rgba(251, 191, 36, 0.22);
|
||||
color: #B45309;
|
||||
}
|
||||
|
||||
.theme-arrow {
|
||||
color: #CCCCCC;
|
||||
}
|
||||
|
||||
.theme-card-active .theme-arrow {
|
||||
color: #6EE7B7;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.bottom-space {
|
||||
|
||||
+349
-105
@@ -1,13 +1,38 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="bg-orb bg-orb-main"></view>
|
||||
<view class="bg-orb bg-orb-soft"></view>
|
||||
|
||||
<view class="header">
|
||||
<text class="title">监督人机制</text>
|
||||
<text class="subtitle">邀请朋友监督你的戒烟旅程,或者你来监督别人</text>
|
||||
<view class="header-copy">
|
||||
<text class="eyebrow">ACCOUNTABILITY</text>
|
||||
<text class="title">监督人机制</text>
|
||||
<text class="subtitle">邀请朋友监督你的戒烟旅程,也可以成为别人的坚持搭子。</text>
|
||||
</view>
|
||||
<view class="hero-panel">
|
||||
<view class="hero-stat">
|
||||
<text class="hero-stat-value">{{ supervisorItems.length }}/3</text>
|
||||
<text class="hero-stat-label">监督我的人</text>
|
||||
</view>
|
||||
<view class="hero-divider"></view>
|
||||
<view class="hero-stat">
|
||||
<text class="hero-stat-value">{{ overviewItems.length }}</text>
|
||||
<text class="hero-stat-label">我监督的人</text>
|
||||
</view>
|
||||
<view class="hero-divider"></view>
|
||||
<view class="hero-stat">
|
||||
<text class="hero-stat-value">{{ reminderEnabled ? 'ON' : 'OFF' }}</text>
|
||||
<text class="hero-stat-label">提醒状态</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<view class="card-head">
|
||||
<text class="card-title">邀请监督人</text>
|
||||
<view class="card-title-wrap">
|
||||
<view class="card-icon">🤝</view>
|
||||
<text class="card-title">邀请监督人</text>
|
||||
</view>
|
||||
<text class="card-meta">已绑定 {{ supervisorItems.length }}/3</text>
|
||||
</view>
|
||||
|
||||
@@ -36,11 +61,15 @@
|
||||
|
||||
<view class="card">
|
||||
<view class="card-head">
|
||||
<text class="card-title">我监督的人</text>
|
||||
<view class="card-title-wrap">
|
||||
<view class="card-icon card-icon-blue">👀</view>
|
||||
<text class="card-title">我监督的人</text>
|
||||
</view>
|
||||
<text class="card-meta">{{ overviewItems.length }} 人</text>
|
||||
</view>
|
||||
|
||||
<view v-if="overviewItems.length === 0" class="empty">
|
||||
<text class="empty-icon">🫶</text>
|
||||
<text class="empty-text">还没有绑定监督关系</text>
|
||||
<text class="empty-hint">收到口令后可去“绑定监督”页面完成绑定</text>
|
||||
<button class="btn btn-ghost" @tap="gotoBindPage">去绑定监督</button>
|
||||
@@ -69,10 +98,14 @@
|
||||
|
||||
<view class="card">
|
||||
<view class="card-head">
|
||||
<text class="card-title">监督我的人</text>
|
||||
<view class="card-title-wrap">
|
||||
<view class="card-icon card-icon-orange">🛡️</view>
|
||||
<text class="card-title">监督我的人</text>
|
||||
</view>
|
||||
<text class="card-meta">{{ supervisorItems.length }} 人</text>
|
||||
</view>
|
||||
<view v-if="supervisorItems.length === 0" class="empty">
|
||||
<text class="empty-icon">🌱</text>
|
||||
<text class="empty-text">还没有人监督你</text>
|
||||
<text class="empty-hint">你可以先生成邀请口令发送给朋友</text>
|
||||
</view>
|
||||
@@ -89,7 +122,10 @@
|
||||
|
||||
<view class="card">
|
||||
<view class="card-head">
|
||||
<text class="card-title">提醒设置</text>
|
||||
<view class="card-title-wrap">
|
||||
<view class="card-icon card-icon-purple">🔔</view>
|
||||
<text class="card-title">提醒设置</text>
|
||||
</view>
|
||||
<text class="card-meta">默认关闭</text>
|
||||
</view>
|
||||
|
||||
@@ -136,7 +172,10 @@
|
||||
|
||||
<view class="card">
|
||||
<view class="card-head">
|
||||
<text class="card-title">提醒测试(监督人)</text>
|
||||
<view class="card-title-wrap">
|
||||
<view class="card-icon card-icon-gray">⚡</view>
|
||||
<text class="card-title">提醒测试(监督人)</text>
|
||||
</view>
|
||||
<text class="card-meta">仅写日志</text>
|
||||
</view>
|
||||
<view class="settings">
|
||||
@@ -417,122 +456,285 @@ onShow(async () => {
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
padding: 28rpx 28rpx 40rpx;
|
||||
padding: 30rpx 28rpx 48rpx;
|
||||
box-sizing: border-box;
|
||||
background: linear-gradient(180deg, #eef7f3 0%, #f7faf8 40%, #fbfdff 100%);
|
||||
overflow: hidden;
|
||||
background:
|
||||
radial-gradient(circle at 16% 0%, rgba(31, 191, 143, 0.18), transparent 34%),
|
||||
radial-gradient(circle at 92% 10%, rgba(96, 165, 250, 0.15), transparent 30%),
|
||||
linear-gradient(180deg, #eef7f3 0%, #f7faf8 42%, #fbfdff 100%);
|
||||
}
|
||||
|
||||
.bg-orb {
|
||||
position: absolute;
|
||||
border-radius: 999rpx;
|
||||
pointer-events: none;
|
||||
filter: blur(2rpx);
|
||||
}
|
||||
|
||||
.bg-orb-main {
|
||||
top: 126rpx;
|
||||
right: -86rpx;
|
||||
width: 230rpx;
|
||||
height: 230rpx;
|
||||
background: rgba(26, 163, 122, 0.12);
|
||||
}
|
||||
|
||||
.bg-orb-soft {
|
||||
top: 520rpx;
|
||||
left: -100rpx;
|
||||
width: 260rpx;
|
||||
height: 260rpx;
|
||||
background: rgba(96, 165, 250, 0.1);
|
||||
}
|
||||
|
||||
.header,
|
||||
.card,
|
||||
.footer {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.header {
|
||||
padding: 8rpx 6rpx 18rpx;
|
||||
padding: 10rpx 4rpx 20rpx;
|
||||
}
|
||||
|
||||
.header-copy {
|
||||
padding: 4rpx 2rpx 24rpx;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
align-self: flex-start;
|
||||
padding: 8rpx 18rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(255, 255, 255, 0.74);
|
||||
border: 1rpx solid rgba(26, 163, 122, 0.14);
|
||||
color: #1aa37a;
|
||||
font-size: 20rpx;
|
||||
font-weight: 800;
|
||||
letter-spacing: 1.8rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: block;
|
||||
font-size: 40rpx;
|
||||
font-weight: 800;
|
||||
margin-top: 18rpx;
|
||||
font-size: 48rpx;
|
||||
line-height: 1.15;
|
||||
font-weight: 900;
|
||||
color: #0f172a;
|
||||
letter-spacing: 0.5rpx;
|
||||
letter-spacing: -0.8rpx;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
display: block;
|
||||
margin-top: 10rpx;
|
||||
font-size: 24rpx;
|
||||
line-height: 1.6;
|
||||
margin-top: 12rpx;
|
||||
max-width: 620rpx;
|
||||
font-size: 25rpx;
|
||||
line-height: 1.7;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.hero-panel {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 24rpx 20rpx;
|
||||
border-radius: 30rpx;
|
||||
background: linear-gradient(135deg, rgba(15, 118, 110, 0.94), rgba(26, 163, 122, 0.86));
|
||||
box-shadow: 0 18rpx 44rpx rgba(15, 118, 110, 0.2);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hero-stat {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hero-stat-value {
|
||||
display: block;
|
||||
font-size: 34rpx;
|
||||
line-height: 1.2;
|
||||
font-weight: 900;
|
||||
color: #ffffff;
|
||||
letter-spacing: -0.4rpx;
|
||||
}
|
||||
|
||||
.hero-stat-label {
|
||||
display: block;
|
||||
margin-top: 8rpx;
|
||||
font-size: 20rpx;
|
||||
line-height: 1.35;
|
||||
color: rgba(255, 255, 255, 0.76);
|
||||
}
|
||||
|
||||
.hero-divider {
|
||||
width: 1rpx;
|
||||
height: 54rpx;
|
||||
background: rgba(255, 255, 255, 0.24);
|
||||
}
|
||||
|
||||
.card {
|
||||
margin-top: 18rpx;
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
border-radius: 26rpx;
|
||||
border: 1rpx solid rgba(15, 23, 42, 0.06);
|
||||
padding: 22rpx 22rpx;
|
||||
box-shadow: 0 10rpx 26rpx rgba(15, 23, 42, 0.05);
|
||||
margin-top: 20rpx;
|
||||
padding: 26rpx;
|
||||
border-radius: 32rpx;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.86);
|
||||
box-shadow: 0 18rpx 44rpx rgba(15, 23, 42, 0.07);
|
||||
backdrop-filter: blur(18rpx);
|
||||
}
|
||||
|
||||
.card-head {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.card-title-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.card-icon {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
border-radius: 18rpx;
|
||||
text-align: center;
|
||||
font-size: 25rpx;
|
||||
background: rgba(26, 163, 122, 0.12);
|
||||
}
|
||||
|
||||
.card-icon-blue {
|
||||
background: rgba(96, 165, 250, 0.14);
|
||||
}
|
||||
|
||||
.card-icon-orange {
|
||||
background: rgba(251, 146, 60, 0.15);
|
||||
}
|
||||
|
||||
.card-icon-purple {
|
||||
background: rgba(168, 85, 247, 0.13);
|
||||
}
|
||||
|
||||
.card-icon-gray {
|
||||
background: rgba(100, 116, 139, 0.12);
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 800;
|
||||
font-size: 29rpx;
|
||||
font-weight: 900;
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
.card-meta {
|
||||
font-size: 22rpx;
|
||||
color: #94a3b8;
|
||||
flex-shrink: 0;
|
||||
padding: 6rpx 14rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(241, 245, 249, 0.78);
|
||||
font-size: 21rpx;
|
||||
font-weight: 700;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.invite-box {
|
||||
margin-top: 18rpx;
|
||||
position: relative;
|
||||
margin-top: 22rpx;
|
||||
padding: 26rpx;
|
||||
border-radius: 28rpx;
|
||||
background:
|
||||
linear-gradient(135deg, rgba(236, 253, 245, 0.94), rgba(255, 255, 255, 0.92));
|
||||
border: 1rpx solid rgba(26, 163, 122, 0.14);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.invite-label {
|
||||
display: block;
|
||||
font-size: 22rpx;
|
||||
font-weight: 800;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.invite-token {
|
||||
display: block;
|
||||
margin-top: 10rpx;
|
||||
font-size: 36rpx;
|
||||
margin-top: 12rpx;
|
||||
font-size: 52rpx;
|
||||
line-height: 1.15;
|
||||
font-weight: 900;
|
||||
letter-spacing: 2rpx;
|
||||
letter-spacing: 4rpx;
|
||||
color: #0f766e;
|
||||
font-family: 'DIN Alternate', -apple-system, sans-serif;
|
||||
}
|
||||
|
||||
.invite-hint {
|
||||
display: block;
|
||||
margin-top: 10rpx;
|
||||
font-size: 22rpx;
|
||||
line-height: 1.6;
|
||||
margin-top: 14rpx;
|
||||
font-size: 23rpx;
|
||||
line-height: 1.65;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.invite-actions {
|
||||
display: flex;
|
||||
gap: 14rpx;
|
||||
margin-top: 16rpx;
|
||||
margin-top: 22rpx;
|
||||
}
|
||||
|
||||
.invite-actions .btn {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.invite-expire {
|
||||
display: block;
|
||||
margin-top: 14rpx;
|
||||
font-size: 22rpx;
|
||||
margin-top: 16rpx;
|
||||
font-size: 21rpx;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.invite-empty {
|
||||
margin-top: 18rpx;
|
||||
margin-top: 22rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
gap: 18rpx;
|
||||
padding: 22rpx;
|
||||
border-radius: 26rpx;
|
||||
background: rgba(248, 250, 252, 0.74);
|
||||
border: 1rpx dashed rgba(26, 163, 122, 0.22);
|
||||
}
|
||||
|
||||
.invite-empty-text {
|
||||
font-size: 24rpx;
|
||||
line-height: 1.6;
|
||||
line-height: 1.65;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.empty {
|
||||
margin-top: 18rpx;
|
||||
padding: 16rpx 6rpx 6rpx;
|
||||
margin-top: 22rpx;
|
||||
padding: 34rpx 24rpx;
|
||||
border-radius: 28rpx;
|
||||
text-align: center;
|
||||
background: linear-gradient(180deg, rgba(248, 250, 252, 0.78), rgba(255, 255, 255, 0.76));
|
||||
border: 1rpx dashed rgba(100, 116, 139, 0.18);
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
display: block;
|
||||
font-size: 48rpx;
|
||||
line-height: 1;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
display: block;
|
||||
font-size: 24rpx;
|
||||
font-weight: 700;
|
||||
font-size: 26rpx;
|
||||
font-weight: 900;
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
@@ -544,28 +746,34 @@ onShow(async () => {
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.empty .btn {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.list {
|
||||
margin-top: 18rpx;
|
||||
margin-top: 22rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14rpx;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
gap: 18rpx;
|
||||
align-items: flex-start;
|
||||
padding: 16rpx;
|
||||
border-radius: 20rpx;
|
||||
background: rgba(241, 245, 249, 0.6);
|
||||
border: 1rpx solid rgba(15, 23, 42, 0.04);
|
||||
padding: 20rpx;
|
||||
border-radius: 26rpx;
|
||||
background: linear-gradient(180deg, rgba(248, 250, 252, 0.9), rgba(255, 255, 255, 0.9));
|
||||
border: 1rpx solid rgba(15, 23, 42, 0.05);
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 74rpx;
|
||||
height: 74rpx;
|
||||
width: 82rpx;
|
||||
height: 82rpx;
|
||||
border-radius: 50%;
|
||||
background: #e2e8f0;
|
||||
border: 4rpx solid #ffffff;
|
||||
box-shadow: 0 10rpx 22rpx rgba(15, 23, 42, 0.09);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -577,24 +785,27 @@ onShow(async () => {
|
||||
.name {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
font-weight: 800;
|
||||
line-height: 1.35;
|
||||
font-weight: 900;
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
.meta {
|
||||
margin-top: 10rpx;
|
||||
margin-top: 12rpx;
|
||||
display: flex;
|
||||
gap: 10rpx;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.pill {
|
||||
padding: 8rpx 12rpx;
|
||||
padding: 8rpx 13rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #ffffff;
|
||||
border: 1rpx solid rgba(15, 23, 42, 0.06);
|
||||
font-size: 20rpx;
|
||||
font-weight: 800;
|
||||
color: #334155;
|
||||
box-shadow: 0 6rpx 14rpx rgba(15, 23, 42, 0.04);
|
||||
}
|
||||
|
||||
.pill-muted {
|
||||
@@ -603,74 +814,94 @@ onShow(async () => {
|
||||
|
||||
.pill-up {
|
||||
color: #0f766e;
|
||||
background: rgba(204, 251, 241, 0.6);
|
||||
background: rgba(204, 251, 241, 0.72);
|
||||
border-color: rgba(15, 118, 110, 0.12);
|
||||
}
|
||||
|
||||
.pill-down {
|
||||
color: #b91c1c;
|
||||
background: rgba(254, 226, 226, 0.8);
|
||||
background: rgba(254, 226, 226, 0.86);
|
||||
border-color: rgba(185, 28, 28, 0.1);
|
||||
}
|
||||
|
||||
.status {
|
||||
display: block;
|
||||
margin-top: 10rpx;
|
||||
margin-top: 12rpx;
|
||||
font-size: 22rpx;
|
||||
line-height: 1.55;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.row-actions {
|
||||
margin-top: 12rpx;
|
||||
margin-top: 14rpx;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.mini-btn {
|
||||
height: 56rpx;
|
||||
line-height: 56rpx;
|
||||
padding: 0 18rpx;
|
||||
border-radius: 14rpx;
|
||||
background: #ffffff;
|
||||
border: 1rpx solid rgba(185, 28, 28, 0.28);
|
||||
color: #b91c1c;
|
||||
font-size: 22rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 20rpx;
|
||||
margin-top: 22rpx;
|
||||
padding-bottom: 20rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.btn {
|
||||
height: 76rpx;
|
||||
line-height: 76rpx;
|
||||
padding: 0 22rpx;
|
||||
border-radius: 18rpx;
|
||||
background: linear-gradient(180deg, #1aa37a 0%, #0f766e 100%);
|
||||
color: #ffffff;
|
||||
font-size: 26rpx;
|
||||
font-weight: 700;
|
||||
.btn,
|
||||
.mini-btn {
|
||||
box-sizing: border-box;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.btn[disabled] {
|
||||
opacity: 0.6;
|
||||
.btn::after,
|
||||
.mini-btn::after {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.btn {
|
||||
height: 78rpx;
|
||||
line-height: 78rpx;
|
||||
padding: 0 28rpx;
|
||||
border-radius: 22rpx;
|
||||
background: linear-gradient(135deg, #1aa37a 0%, #0f766e 100%);
|
||||
color: #ffffff;
|
||||
font-size: 26rpx;
|
||||
font-weight: 900;
|
||||
box-shadow: 0 12rpx 24rpx rgba(15, 118, 110, 0.18);
|
||||
}
|
||||
|
||||
.btn[disabled],
|
||||
.mini-btn[disabled] {
|
||||
opacity: 0.55;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.btn-ghost {
|
||||
background: #ffffff;
|
||||
background: rgba(255, 255, 255, 0.82);
|
||||
color: #0f766e;
|
||||
border: 1rpx solid rgba(15, 118, 110, 0.25);
|
||||
border: 1rpx solid rgba(15, 118, 110, 0.18);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.mini-btn {
|
||||
height: 58rpx;
|
||||
line-height: 58rpx;
|
||||
padding: 0 20rpx;
|
||||
border-radius: 18rpx;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
border: 1rpx solid rgba(185, 28, 28, 0.2);
|
||||
color: #b91c1c;
|
||||
font-size: 22rpx;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.mini-btn-neutral {
|
||||
border-color: rgba(15, 23, 42, 0.12);
|
||||
min-width: 144rpx;
|
||||
border-color: rgba(15, 23, 42, 0.1);
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.settings {
|
||||
margin-top: 18rpx;
|
||||
margin-top: 22rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
@@ -678,20 +909,20 @@ onShow(async () => {
|
||||
|
||||
.setting-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 18rpx;
|
||||
padding: 14rpx 12rpx;
|
||||
border-radius: 18rpx;
|
||||
background: rgba(241, 245, 249, 0.45);
|
||||
border: 1rpx solid rgba(15, 23, 42, 0.04);
|
||||
gap: 20rpx;
|
||||
padding: 20rpx;
|
||||
border-radius: 24rpx;
|
||||
background: rgba(248, 250, 252, 0.8);
|
||||
border: 1rpx solid rgba(15, 23, 42, 0.05);
|
||||
}
|
||||
|
||||
.setting-label {
|
||||
font-size: 24rpx;
|
||||
font-weight: 800;
|
||||
flex-shrink: 0;
|
||||
font-size: 25rpx;
|
||||
font-weight: 900;
|
||||
color: #0f172a;
|
||||
padding-top: 6rpx;
|
||||
}
|
||||
|
||||
.setting-control {
|
||||
@@ -704,13 +935,15 @@ onShow(async () => {
|
||||
}
|
||||
|
||||
.num-input {
|
||||
width: 200rpx;
|
||||
height: 64rpx;
|
||||
padding: 0 14rpx;
|
||||
border-radius: 14rpx;
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
width: 190rpx;
|
||||
height: 66rpx;
|
||||
padding: 0 18rpx;
|
||||
border-radius: 18rpx;
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border: 1rpx solid rgba(15, 23, 42, 0.08);
|
||||
font-size: 26rpx;
|
||||
font-size: 27rpx;
|
||||
font-weight: 800;
|
||||
color: #0f172a;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@@ -726,15 +959,26 @@ onShow(async () => {
|
||||
gap: 14rpx;
|
||||
}
|
||||
|
||||
.setting-actions .btn {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.settings-note {
|
||||
padding: 18rpx 20rpx;
|
||||
border-radius: 22rpx;
|
||||
background: rgba(236, 253, 245, 0.7);
|
||||
font-size: 22rpx;
|
||||
line-height: 1.6;
|
||||
line-height: 1.65;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.run-result {
|
||||
padding: 18rpx 20rpx;
|
||||
border-radius: 22rpx;
|
||||
background: rgba(204, 251, 241, 0.64);
|
||||
font-size: 22rpx;
|
||||
line-height: 1.6;
|
||||
color: #0f766e;
|
||||
font-weight: 700;
|
||||
font-weight: 900;
|
||||
}
|
||||
</style>
|
||||
|
||||
+2
-2
@@ -3,8 +3,8 @@
|
||||
* 所有页面自动注入,无需手动 import
|
||||
*/
|
||||
|
||||
@import './styles/variables';
|
||||
@import './styles/mixins';
|
||||
@import '@/styles/_variables.scss';
|
||||
@import '@/styles/_mixins.scss';
|
||||
|
||||
/* 覆盖 uni-app 默认颜色变量 */
|
||||
$uni-color-primary: $color-primary-dark;
|
||||
|
||||
Reference in New Issue
Block a user