- Update Maven compiler plugin to support Lombok annotation processing - Add deploy.conf for automated deployment - Update backend models and controllers - Update frontend pages and API
746 lines
17 KiB
Vue
746 lines
17 KiB
Vue
<template>
|
||
<view class="tool-page">
|
||
<!-- 用户健康卡片 -->
|
||
<view class="user-card">
|
||
<view class="user-card-content">
|
||
<view class="user-avatar" @tap="goToMyProfile">
|
||
<image class="avatar-img" :src='userInfo.avatar' v-if="userInfo.avatar && uid" mode="aspectFill"></image>
|
||
<image v-else class="avatar-img" :src="urlDomain+'crmebimage/perset/staticImg/f.png'" mode="aspectFill"></image>
|
||
</view>
|
||
<view class="user-info">
|
||
<view class="user-name" v-if="userInfo && uid">
|
||
{{userInfo.nickname}}
|
||
<!-- <view class="vip-tag" v-if="userInfo.vip">
|
||
<image :src="userInfo.vipIcon" mode="aspectFit" class="vip-icon"></image>
|
||
<text class="vip-text">{{userInfo.vipName || ''}}</text>
|
||
</view> -->
|
||
</view>
|
||
<view class="user-name" v-else @tap="openAuto">请点击登录</view>
|
||
<view class="user-desc" :class="{ 'completed': userHealthStatus.hasProfile }">
|
||
{{ userHealthStatus.profileStatus || '尚未完成健康档案' }}
|
||
</view>
|
||
</view>
|
||
<view class="checkin-btn" @tap="handleCheckin">
|
||
<text>打卡</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 四大功能入口(根据系统配置 eb_system_config.field01=1 时显示) -->
|
||
<view class="function-grid" v-if="showFunctionEntries">
|
||
<view class="function-item calculator" @tap="goToCalculator">
|
||
<view class="function-content">
|
||
<view class="function-text">
|
||
<view class="function-title">食谱计算器</view>
|
||
<view class="function-desc">个性化营养方案</view>
|
||
</view>
|
||
<view class="function-icon">
|
||
<text class="icon">📊</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="function-item ai-nutritionist" @tap="goToAINutritionist">
|
||
<view class="function-content">
|
||
<view class="function-text">
|
||
<view class="function-title">AI营养师</view>
|
||
<view class="function-desc">智慧知肾健康</view>
|
||
</view>
|
||
<view class="function-icon">
|
||
<text class="icon">💬</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="function-item food-encyclopedia" @tap="goToFoodEncyclopedia">
|
||
<view class="function-content">
|
||
<view class="function-text">
|
||
<view class="function-title">食物百科</view>
|
||
<view class="function-desc">营养成分查询</view>
|
||
</view>
|
||
<view class="function-icon">
|
||
<text class="icon">🔍</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="function-item nutrition-knowledge" @tap="goToNutritionKnowledge">
|
||
<view class="function-content">
|
||
<view class="function-text">
|
||
<view class="function-title">健康知识</view>
|
||
<view class="function-desc">专业营养指导</view>
|
||
</view>
|
||
<view class="function-icon">
|
||
<text class="icon">💡</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 精选食谱 -->
|
||
<view class="section">
|
||
<view class="section-header">
|
||
<text class="section-title">精选食谱</text>
|
||
<view class="section-more" @tap="goToRecipeList">
|
||
<text>›</text>
|
||
</view>
|
||
</view>
|
||
<view class="recipe-list">
|
||
<view class="recipe-item" v-for="(item, index) in recipeList" :key="index" @tap="goToRecipeDetail(item)">
|
||
<view class="recipe-image">
|
||
<image :src="item.coverImage" mode="aspectFill"></image>
|
||
<view class="recipe-tag" :class="item.source === 'calculator' ? 'tag-mine' : 'tag-recommend'">
|
||
{{ item.source === 'calculator' ? '我的配餐' : '推荐' }}
|
||
</view>
|
||
</view>
|
||
<view class="recipe-info">
|
||
<view class="recipe-title">{{ item.name }}</view>
|
||
<view class="recipe-desc">{{ item.description || '' }}</view>
|
||
<view class="recipe-meta">
|
||
<view class="meta-item" v-if="item.totalProtein">
|
||
<text class="meta-icon">🥩</text>
|
||
<text class="meta-text">蛋白质 {{ item.totalProtein }}g</text>
|
||
</view>
|
||
<view class="meta-item" v-if="item.totalEnergy">
|
||
<text class="meta-icon">🔥</text>
|
||
<text class="meta-text">{{ item.totalEnergy }}kcal</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 营养方案领取卡片 -->
|
||
<view class="promotion-card" @tap="goToPromotion">
|
||
<view class="promotion-content">
|
||
<view class="promotion-text">
|
||
<view class="promotion-title">慢生活营养专家</view>
|
||
<view class="promotion-desc">专业个性化营养方案</view>
|
||
</view>
|
||
<view class="promotion-btn">
|
||
<text>立即领取福利</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 健康知识 -->
|
||
<view class="section">
|
||
<view class="section-header">
|
||
<text class="section-title">健康知识</text>
|
||
<view class="section-more" @tap="goToKnowledgeList">
|
||
<text>›</text>
|
||
</view>
|
||
</view>
|
||
<view class="knowledge-list">
|
||
<view class="knowledge-item" v-for="(item, index) in knowledgeList" :key="index" @tap="goToKnowledgeDetail(item)">
|
||
<view class="knowledge-icon">
|
||
<image v-if="item.coverImage" class="knowledge-cover" :src="item.coverImage" mode="aspectFill"></image>
|
||
<text v-else>{{ item.icon || '💡' }}</text>
|
||
</view>
|
||
<view class="knowledge-info">
|
||
<view class="knowledge-title">{{ item.title }}</view>
|
||
<view class="knowledge-desc">{{ item.desc || item.summary || '' }}</view>
|
||
<view class="knowledge-meta">
|
||
<text class="meta-text">{{ item.time || '' }}</text>
|
||
<text class="meta-dot" v-if="item.time && item.views">·</text>
|
||
<text class="meta-text">{{ item.views != null ? item.views : '' }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 底部安全距离 -->
|
||
<view class="safe-bottom"></view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import {
|
||
getRecommendedRecipes,
|
||
getRecommendedKnowledge,
|
||
getUserHealthStatus,
|
||
getHomeDisplayConfig
|
||
} from '@/api/tool.js';
|
||
import { mapGetters } from 'vuex';
|
||
import { toLogin, checkLogin } from '@/libs/login.js';
|
||
import Cache from '@/utils/cache';
|
||
import { BACK_URL } from '@/config/cache';
|
||
|
||
export default {
|
||
name: 'ToolIndex',
|
||
computed: {
|
||
...mapGetters(['userInfo','uid','isLogin'])
|
||
},
|
||
data() {
|
||
return {
|
||
urlDomain: this.$Cache.get("imgHost"),
|
||
recipeList: [],
|
||
knowledgeList: [],
|
||
userHealthStatus: {
|
||
hasProfile: false,
|
||
profileStatus: '尚未完成健康档案'
|
||
},
|
||
showFunctionEntries: false,
|
||
loading: false
|
||
}
|
||
},
|
||
onLoad() {
|
||
this.loadData();
|
||
},
|
||
onPullDownRefresh() {
|
||
this.loadData().finally(() => {
|
||
uni.stopPullDownRefresh();
|
||
});
|
||
},
|
||
methods: {
|
||
// 打开授权
|
||
openAuto() {
|
||
Cache.set(BACK_URL, '')
|
||
toLogin();
|
||
},
|
||
// 加载页面数据
|
||
async loadData() {
|
||
this.loading = true;
|
||
try {
|
||
// 并行加载数据(含首页展示配置:field01=1 时显示四大功能入口)
|
||
const [recipesRes, knowledgeRes, healthRes, displayConfigRes] = await Promise.all([
|
||
getRecommendedRecipes({ limit: 2 }).catch(() => ({ data: [] })),
|
||
getRecommendedKnowledge({ limit: 2 }).catch(() => ({ data: [] })),
|
||
getUserHealthStatus().catch(() => ({ data: { hasProfile: false, profileStatus: '尚未完成健康档案' } })),
|
||
getHomeDisplayConfig().catch(() => ({ data: { showFunctionEntries: false } }))
|
||
]);
|
||
|
||
this.recipeList = recipesRes.data?.list || recipesRes.data || [];
|
||
const rawKnowledge = knowledgeRes.data?.list || knowledgeRes.data || [];
|
||
this.knowledgeList = rawKnowledge.map(item => ({
|
||
...item,
|
||
desc: item.summary ?? item.desc ?? '',
|
||
icon: item.icon || '💡'
|
||
}));
|
||
this.userHealthStatus = healthRes.data || { hasProfile: false, profileStatus: '尚未完成健康档案' };
|
||
this.showFunctionEntries = !!(displayConfigRes.data && displayConfigRes.data.showFunctionEntries);
|
||
} catch (error) {
|
||
console.error('加载数据失败:', error);
|
||
uni.showToast({
|
||
title: '加载失败,请重试',
|
||
icon: 'none'
|
||
});
|
||
} finally {
|
||
this.loading = false;
|
||
}
|
||
},
|
||
// 跳转到我的页面
|
||
goToMyProfile() {
|
||
uni.navigateTo({
|
||
url: '/pages/tool/my-profile'
|
||
})
|
||
},
|
||
// 跳转到打卡页面
|
||
handleCheckin() {
|
||
if (!checkLogin()) {
|
||
uni.showToast({ title: '请先登录', icon: 'none' });
|
||
setTimeout(() => toLogin(), 500);
|
||
return;
|
||
}
|
||
uni.navigateTo({
|
||
url: '/pages/tool/checkin'
|
||
});
|
||
},
|
||
// 跳转到食谱计算器
|
||
goToCalculator() {
|
||
if (!checkLogin()) {
|
||
uni.showToast({ title: '请先登录', icon: 'none' });
|
||
setTimeout(() => toLogin(), 500);
|
||
return;
|
||
}
|
||
uni.navigateTo({
|
||
url: '/pages/tool/calculator'
|
||
})
|
||
},
|
||
// 跳转到AI营养师
|
||
goToAINutritionist() {
|
||
if (!checkLogin()) {
|
||
uni.showToast({ title: '请先登录', icon: 'none' });
|
||
setTimeout(() => toLogin(), 500);
|
||
return;
|
||
}
|
||
uni.navigateTo({
|
||
url: '/pages/tool/ai-nutritionist'
|
||
})
|
||
},
|
||
// 跳转到食物百科
|
||
goToFoodEncyclopedia() {
|
||
uni.navigateTo({
|
||
url: '/pages/tool/food-encyclopedia'
|
||
})
|
||
},
|
||
// 跳转到营养知识
|
||
goToNutritionKnowledge() {
|
||
uni.navigateTo({
|
||
url: '/pages/tool/nutrition-knowledge'
|
||
})
|
||
},
|
||
// 跳转到食谱列表(功能开发中)
|
||
goToRecipeList() {
|
||
uni.showToast({
|
||
title: '食谱列表功能开发中',
|
||
icon: 'none'
|
||
})
|
||
},
|
||
// 跳转到食谱详情
|
||
goToRecipeDetail(item) {
|
||
if (!item) return
|
||
uni.navigateTo({
|
||
url: `/pages/tool/recipe-detail?id=${item.id || 1}`
|
||
})
|
||
},
|
||
// 跳转到会员福利
|
||
goToPromotion() {
|
||
uni.navigateTo({
|
||
url: '/pages/tool/welcome-gift'
|
||
})
|
||
},
|
||
// 跳转到营养知识列表
|
||
goToKnowledgeList() {
|
||
uni.navigateTo({
|
||
url: '/pages/tool/nutrition-knowledge'
|
||
})
|
||
},
|
||
// 跳转到营养知识详情
|
||
goToKnowledgeDetail(item) {
|
||
if (!item) return
|
||
uni.navigateTo({
|
||
url: `/pages/tool/knowledge-detail?id=${item.id || 1}`
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.tool-page {
|
||
min-height: 100vh;
|
||
background-color: #f4f5f7;
|
||
padding-bottom: 20rpx;
|
||
}
|
||
|
||
/* 用户健康卡片 */
|
||
.user-card {
|
||
margin: 32rpx 32rpx 0;
|
||
height: 192rpx;
|
||
border-radius: 24rpx;
|
||
background: linear-gradient(135deg, #ff6b35 0%, #ff7a4a 50%, #d64820 100%);
|
||
box-shadow: 0 16rpx 48rpx rgba(255, 107, 53, 0.25);
|
||
overflow: hidden;
|
||
position: relative;
|
||
|
||
.user-card-content {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 32rpx;
|
||
height: 100%;
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.user-avatar {
|
||
width: 128rpx;
|
||
height: 128rpx;
|
||
border-radius: 50%;
|
||
background: #ffffff;
|
||
border: 5rpx solid #ffffff;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-right: 24rpx;
|
||
cursor: pointer;
|
||
overflow: hidden;
|
||
|
||
.avatar-img {
|
||
width: 100%;
|
||
height: 100%;
|
||
border-radius: 50%;
|
||
}
|
||
}
|
||
|
||
.user-info {
|
||
flex: 1;
|
||
|
||
.user-name {
|
||
font-size: 32rpx;
|
||
color: #ffffff;
|
||
font-weight: 500;
|
||
margin-bottom: 4rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12rpx;
|
||
}
|
||
|
||
.vip-tag {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 4rpx 16rpx;
|
||
background: rgba(0, 0, 0, 0.2);
|
||
border-radius: 20rpx;
|
||
|
||
.vip-icon {
|
||
width: 24rpx;
|
||
height: 24rpx;
|
||
margin-right: 6rpx;
|
||
}
|
||
|
||
.vip-text {
|
||
font-size: 20rpx;
|
||
color: #ffe157;
|
||
}
|
||
}
|
||
|
||
.user-desc {
|
||
font-size: 24rpx;
|
||
color: rgba(255, 255, 255, 0.9);
|
||
}
|
||
}
|
||
|
||
.checkin-btn {
|
||
background: rgba(255, 255, 255, 0.95);
|
||
border: 2rpx solid rgba(255, 255, 255, 0.9);
|
||
border-radius: 24rpx;
|
||
padding: 16rpx 32rpx;
|
||
box-shadow: 0 8rpx 40rpx rgba(255, 107, 53, 0.3);
|
||
|
||
text {
|
||
font-size: 24rpx;
|
||
color: #ff6b35;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 四大功能入口 */
|
||
.function-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 24rpx;
|
||
margin: 32rpx 32rpx 0;
|
||
}
|
||
|
||
.function-item {
|
||
height: 168rpx;
|
||
border-radius: 32rpx;
|
||
overflow: hidden;
|
||
position: relative;
|
||
box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.1);
|
||
|
||
.function-content {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 40rpx;
|
||
height: 100%;
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.function-text {
|
||
flex: 1;
|
||
|
||
.function-title {
|
||
font-size: 32rpx;
|
||
color: #ffffff;
|
||
font-weight: 500;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.function-desc {
|
||
font-size: 24rpx;
|
||
color: rgba(255, 255, 255, 0.75);
|
||
}
|
||
}
|
||
|
||
.function-icon {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
background: rgba(255, 255, 255, 0.2);
|
||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||
border-radius: 24rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
.icon {
|
||
font-size: 40rpx;
|
||
line-height: 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
.calculator {
|
||
background: linear-gradient(135deg, #4ecdc4 0%, #44b8b0 100%);
|
||
box-shadow: 0 16rpx 48rpx rgba(78, 205, 196, 0.25);
|
||
}
|
||
|
||
.ai-nutritionist {
|
||
background: linear-gradient(135deg, #5b9bf3 0%, #4a8ae8 100%);
|
||
box-shadow: 0 16rpx 48rpx rgba(91, 155, 243, 0.25);
|
||
}
|
||
|
||
.food-encyclopedia {
|
||
background: linear-gradient(135deg, #ffb84d 0%, #ffa726 100%);
|
||
box-shadow: 0 16rpx 48rpx rgba(255, 184, 77, 0.25);
|
||
}
|
||
|
||
.nutrition-knowledge {
|
||
background: linear-gradient(135deg, #ff6b7a 0%, #ff5252 100%);
|
||
box-shadow: 0 16rpx 48rpx rgba(255, 107, 122, 0.25);
|
||
}
|
||
|
||
/* 通用区块样式 */
|
||
.section {
|
||
margin: 32rpx 32rpx 0;
|
||
|
||
.section-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 32rpx;
|
||
|
||
.section-title {
|
||
font-size: 32rpx;
|
||
color: #2e3e5c;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.section-more {
|
||
font-size: 32rpx;
|
||
color: #9fa5c0;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 精选食谱 */
|
||
.recipe-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 24rpx;
|
||
}
|
||
|
||
.recipe-item {
|
||
background: #ffffff;
|
||
border-radius: 24rpx;
|
||
padding: 24rpx;
|
||
box-shadow: 0 20rpx 30rpx -6rpx rgba(0, 0, 0, 0.1), 0 8rpx 12rpx -4rpx rgba(0, 0, 0, 0.1);
|
||
display: flex;
|
||
gap: 24rpx;
|
||
}
|
||
|
||
.recipe-image {
|
||
width: 192rpx;
|
||
height: 192rpx;
|
||
border-radius: 32rpx;
|
||
overflow: hidden;
|
||
position: relative;
|
||
flex-shrink: 0;
|
||
box-shadow: 0 8rpx 12rpx -2rpx rgba(0, 0, 0, 0.1), 0 4rpx 8rpx -2rpx rgba(0, 0, 0, 0.1);
|
||
|
||
image {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.recipe-tag {
|
||
position: absolute;
|
||
left: 16rpx;
|
||
top: 16rpx;
|
||
border-radius: 16rpx;
|
||
padding: 8rpx 16rpx;
|
||
font-size: 24rpx;
|
||
color: #ffffff;
|
||
box-shadow: 0 20rpx 30rpx -6rpx rgba(0, 0, 0, 0.1), 0 8rpx 12rpx -4rpx rgba(0, 0, 0, 0.1);
|
||
|
||
&.tag-recommend {
|
||
background: linear-gradient(135deg, #ff6b35 0%, #ff8c5a 100%);
|
||
}
|
||
|
||
&.tag-mine {
|
||
background: linear-gradient(135deg, #4ecdc4 0%, #44b8b0 100%);
|
||
}
|
||
}
|
||
}
|
||
|
||
.recipe-info {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
padding: 4rpx 0;
|
||
|
||
.recipe-title {
|
||
font-size: 28rpx;
|
||
color: #2e3e5c;
|
||
font-weight: 500;
|
||
margin-bottom: 12rpx;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.recipe-desc {
|
||
font-size: 24rpx;
|
||
color: #9fa5c0;
|
||
margin-bottom: 16rpx;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.recipe-meta {
|
||
display: flex;
|
||
gap: 32rpx;
|
||
align-items: center;
|
||
|
||
.meta-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8rpx;
|
||
|
||
.meta-icon {
|
||
font-size: 24rpx;
|
||
width: 28rpx;
|
||
height: 28rpx;
|
||
}
|
||
|
||
.meta-text {
|
||
font-size: 24rpx;
|
||
color: #9fa5c0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 营养方案领取卡片 */
|
||
.promotion-card {
|
||
margin: 32rpx 32rpx 0;
|
||
height: 192rpx;
|
||
border-radius: 24rpx;
|
||
background: linear-gradient(135deg, #ff6b35 0%, #ff7a4a 50%, #d64820 100%);
|
||
box-shadow: 0 40rpx 50rpx -10rpx rgba(0, 0, 0, 0.1), 0 16rpx 20rpx -6rpx rgba(0, 0, 0, 0.1);
|
||
overflow: hidden;
|
||
position: relative;
|
||
|
||
.promotion-content {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 32rpx;
|
||
height: 100%;
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.promotion-text {
|
||
.promotion-title {
|
||
font-size: 32rpx;
|
||
color: #ffffff;
|
||
font-weight: 500;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.promotion-desc {
|
||
font-size: 28rpx;
|
||
color: rgba(255, 255, 255, 0.85);
|
||
}
|
||
}
|
||
|
||
.promotion-btn {
|
||
background: #ffffff;
|
||
border: 2rpx solid rgba(255, 107, 53, 0.2);
|
||
border-radius: 24rpx;
|
||
padding: 16rpx 32rpx;
|
||
box-shadow: 0 8rpx 40rpx rgba(255, 107, 53, 0.3);
|
||
|
||
text {
|
||
font-size: 28rpx;
|
||
color: #ff6b35;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 健康知识 */
|
||
.knowledge-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 24rpx;
|
||
}
|
||
|
||
.knowledge-item {
|
||
background: #ffffff;
|
||
border-radius: 24rpx;
|
||
padding: 32rpx;
|
||
box-shadow: 0 20rpx 30rpx -6rpx rgba(0, 0, 0, 0.1), 0 8rpx 12rpx -4rpx rgba(0, 0, 0, 0.1);
|
||
display: flex;
|
||
gap: 32rpx;
|
||
}
|
||
|
||
.knowledge-icon {
|
||
width: 128rpx;
|
||
height: 128rpx;
|
||
border-radius: 32rpx;
|
||
background: #f4f5f7;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
overflow: hidden;
|
||
|
||
.knowledge-cover {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
text {
|
||
font-size: 60rpx;
|
||
}
|
||
}
|
||
|
||
.knowledge-info {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
|
||
.knowledge-title {
|
||
font-size: 28rpx;
|
||
color: #2e3e5c;
|
||
font-weight: 500;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
|
||
.knowledge-desc {
|
||
font-size: 24rpx;
|
||
color: #9fa5c0;
|
||
line-height: 1.6;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.knowledge-meta {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 24rpx;
|
||
|
||
.meta-text {
|
||
font-size: 24rpx;
|
||
color: #9fa5c0;
|
||
}
|
||
|
||
.meta-dot {
|
||
font-size: 24rpx;
|
||
color: #d0dbea;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 底部安全距离 */
|
||
.safe-bottom {
|
||
height: 40rpx;
|
||
}
|
||
</style>
|