feat0806: APP养生科普健康知识功能改造
| | |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.PathVariable; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import java.util.List; |
| | |
| | | |
| | | /** |
| | | * 获取 APP 健康科普列表。 |
| | | * |
| | | * @param contentType 内容类型:1 健康知识、2 养生科普;不传则返回全部。 |
| | | */ |
| | | @GetMapping("/health-popularizations") |
| | | public ApiResponse<List<AppHealthPopularizationListItemVO>> list() { |
| | | return ApiResponse.ok(appHealthPopularizationService.list()); |
| | | public ApiResponse<List<AppHealthPopularizationListItemVO>> list( |
| | | @RequestParam(value = "contentType", required = false) Integer contentType) { |
| | | return ApiResponse.ok(appHealthPopularizationService.list(contentType)); |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | /** |
| | | * 获取 APP 健康科普列表页数据。 |
| | | * |
| | | * @param contentType 内容类型:1 健康知识、2 养生科普;为空则返回全部。 |
| | | */ |
| | | public List<AppHealthPopularizationListItemVO> list() { |
| | | public List<AppHealthPopularizationListItemVO> list(Integer contentType) { |
| | | List<HealthPopularization> items = healthPopularizationMapper.selectList(new LambdaQueryWrapper<HealthPopularization>() |
| | | .eq(HealthPopularization::getDeleted, 0) |
| | | .eq(HealthPopularization::getStatus, STATUS_ENABLED) |
| | | .orderByAsc(HealthPopularization::getSort) |
| | | .eq(contentType != null, HealthPopularization::getContentType, contentType) |
| | | .orderByDesc(HealthPopularization::getSort) |
| | | .orderByDesc(HealthPopularization::getId)); |
| | | if (items == null || items.isEmpty()) { |
| | | return Collections.emptyList(); |
| | |
| | | detailVO.setContent(trimToEmpty(item.getContent())); |
| | | detailVO.setVideoUrl(trimToEmpty(item.getVideoUrl())); |
| | | detailVO.setVideoFileName(trimToEmpty(item.getVideoFileName())); |
| | | detailVO.setVideoDescription(trimToEmpty(item.getVideoDescription())); |
| | | return detailVO; |
| | | } |
| | | |
| | |
| | | private String videoUrl; |
| | | |
| | | private String videoFileName; |
| | | |
| | | private String videoDescription; |
| | | } |
| | |
| | | <rich-text v-if="!isVideoType" :nodes="contentNodes" class="rich-content"></rich-text> |
| | | <view v-if="loading" class="status-text">加载中...</view> |
| | | <view v-else-if="!detail.id" class="status-text">暂无详情内容</view> |
| | | |
| | | <!-- 视频介绍:仅视频类型且有介绍文案时展示 --> |
| | | <view v-if="isVideoType && videoDescription" class="video-intro"> |
| | | <text class="video-intro-text">{{ videoDescription }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </template> |
| | |
| | | content : string |
| | | videoUrl : string |
| | | videoFileName : string |
| | | videoDescription : string |
| | | } |
| | | |
| | | const statusBarHeight = ref(0) |
| | |
| | | content: '', |
| | | videoUrl: '', |
| | | videoFileName: '', |
| | | videoDescription: '', |
| | | } |
| | | } |
| | | |
| | |
| | | const source = detail.value as PopularizationDetail & { summary ?: string; description ?: string; subTitle ?: string } |
| | | return String(source.subtitle || source.subTitle || source.summary || source.description || '').trim() |
| | | }) |
| | | |
| | | /** |
| | | * 视频介绍文案,去除首尾空白后用于详情底部展示。 |
| | | */ |
| | | const videoDescription = computed(() => String(detail.value.videoDescription || '').trim()) |
| | | |
| | | /** |
| | | * 将富文本正文转换为 `rich-text` 可直接消费的节点字符串。 |
| | |
| | | line-height: 40rpx; |
| | | color: #86909C; |
| | | } |
| | | |
| | | .video-intro { |
| | | margin-top: 32rpx; |
| | | padding-top: 24rpx; |
| | | border-top: 1rpx solid #EBEDF0; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .video-intro-text { |
| | | font-size: 28rpx; |
| | | line-height: 1.8; |
| | | color: #5B6475; |
| | | white-space: pre-wrap; |
| | | } |
| | | </style> |
| | |
| | | } |
| | | |
| | | /** |
| | | * 进入复制后的养生科普二级页。 |
| | | * 进入复制后的养生科普二级页(contentType=2 仅视频)。 |
| | | */ |
| | | const goHealthPopularization = () => { |
| | | uni.navigateTo({ |
| | | url: '/pages/healthPopularization/healthPopularization' |
| | | url: '/pages/healthPopularization/healthPopularization?contentType=2' |
| | | }) |
| | | } |
| | | |
| | | /** |
| | | * 进入原健康科普页,作为「健康知识」二级页。 |
| | | * 进入原健康科普页,作为「健康知识」二级页(contentType=1 仅图文)。 |
| | | */ |
| | | const goHealthKnowledge = () => { |
| | | uni.navigateTo({ |
| | | url: '/pages/publish/publish' |
| | | url: '/pages/publish/publish?contentType=1' |
| | | }) |
| | | } |
| | | </script> |
| | |
| | | <view v-if="articleList.length" class="article-list"> |
| | | <view class="article-item" v-for="item in articleList" :key="item.id" @tap="goToDetail(item.id)"> |
| | | <image class="article-img" :src="item.coverImage || defaultCoverImage" mode="aspectFill"></image> |
| | | <view class="article-shadow"> |
| | | <text class="article-text">{{ item.title }}</text> |
| | | </view> |
| | | <text class="article-title">{{ item.title }}</text> |
| | | </view> |
| | | </view> |
| | | <view v-else-if="loading" class="status-text">加载中...</view> |
| | |
| | | |
| | | <script setup lang="ts"> |
| | | import { ref, onMounted } from 'vue'; |
| | | import { onPullDownRefresh } from '@dcloudio/uni-app' |
| | | import { onLoad, onPullDownRefresh } from '@dcloudio/uni-app' |
| | | import { getHealthPopularizationList } from './service' |
| | | |
| | | interface PopularizationListItem { |
| | |
| | | const loading = ref(false) |
| | | const articleList = ref<PopularizationListItem[]>([]) |
| | | const defaultCoverImage = '/static/image/home/zixun.png' |
| | | // 内容类型:2 养生科普,默认按养生科普过滤。 |
| | | const contentType = ref<number>(2) |
| | | |
| | | /** |
| | | * 读取路由参数中的内容类型,用于按类型过滤列表。 |
| | | */ |
| | | onLoad((options) => { |
| | | const raw = Number(options?.contentType) |
| | | if (!Number.isNaN(raw) && raw > 0) { |
| | | contentType.value = raw |
| | | } |
| | | }) |
| | | |
| | | /** |
| | | * 页面加载时初始化状态栏高度并拉取养生科普列表。 |
| | |
| | | async function loadPopularizationList() { |
| | | loading.value = true |
| | | try { |
| | | const response = await getHealthPopularizationList() |
| | | const response = await getHealthPopularizationList(contentType.value) |
| | | if (response?.code !== 0 || !Array.isArray(response.data)) { |
| | | articleList.value = [] |
| | | return |
| | |
| | | |
| | | .article-list { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | flex-wrap: wrap; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .article-item { |
| | | width: 328rpx; |
| | | height: 328rpx; |
| | | border-radius: 16rpx; |
| | | position: relative; |
| | | overflow: hidden; |
| | | margin-bottom: 24rpx; |
| | | } |
| | | |
| | | .article-img { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | |
| | | .article-shadow { |
| | | position: absolute; |
| | | bottom: 0; |
| | | left: 0; |
| | | width: 100%; |
| | | height: 64rpx; |
| | | background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.8) 100%); |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 0 16rpx; |
| | | width: 100%; |
| | | padding: 24rpx 0; |
| | | border-bottom: 1rpx solid #F0F0F0; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .article-text { |
| | | color: #FFFFFF; |
| | | font-size: 24rpx; |
| | | white-space: nowrap; |
| | | .article-img { |
| | | width: 200rpx; |
| | | height: 150rpx; |
| | | border-radius: 12rpx; |
| | | flex-shrink: 0; |
| | | background-color: #F5F6F8; |
| | | } |
| | | |
| | | .article-title { |
| | | flex: 1; |
| | | margin-left: 24rpx; |
| | | font-size: 30rpx; |
| | | line-height: 44rpx; |
| | | color: #333; |
| | | display: -webkit-box; |
| | | -webkit-box-orient: vertical; |
| | | -webkit-line-clamp: 2; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | width: 100%; |
| | | } |
| | | </style> |
| | |
| | | |
| | | /** |
| | | * 获取 APP 养生科普列表(与原健康科普共用接口)。 |
| | | * @param {number} [contentType] 内容类型:1 健康知识、2 养生科普;不传返回全部。 |
| | | */ |
| | | export const getHealthPopularizationList = () => { |
| | | return request.get('/api/app/health-popularizations', {}, false, false) |
| | | export const getHealthPopularizationList = (contentType) => { |
| | | const params = contentType == null ? {} : { contentType } |
| | | return request.get('/api/app/health-popularizations', params, false, false) |
| | | } |
| | |
| | | <view v-if="articleList.length" class="article-list"> |
| | | <view class="article-item" v-for="item in articleList" :key="item.id" @tap="goToDetail(item.id)"> |
| | | <image class="article-img" :src="item.coverImage || defaultCoverImage" mode="aspectFill"></image> |
| | | <view class="article-shadow"> |
| | | <text class="article-text">{{ item.title }}</text> |
| | | </view> |
| | | <text class="article-title">{{ item.title }}</text> |
| | | </view> |
| | | </view> |
| | | <view v-else-if="loading" class="status-text">加载中...</view> |
| | |
| | | |
| | | <script setup lang="ts"> |
| | | import { ref, onMounted } from 'vue'; |
| | | import { onPullDownRefresh } from '@dcloudio/uni-app' |
| | | import { onLoad, onPullDownRefresh } from '@dcloudio/uni-app' |
| | | import { getHealthPopularizationList } from './service' |
| | | |
| | | interface PopularizationListItem { |
| | |
| | | const loading = ref(false) |
| | | const articleList = ref<PopularizationListItem[]>([]) |
| | | const defaultCoverImage = '/static/image/home/zixun.png' |
| | | // 内容类型:1 健康知识,默认按健康知识过滤。 |
| | | const contentType = ref<number>(1) |
| | | |
| | | /** |
| | | * 读取路由参数中的内容类型,用于按类型过滤列表。 |
| | | */ |
| | | onLoad((options) => { |
| | | const raw = Number(options?.contentType) |
| | | if (!Number.isNaN(raw) && raw > 0) { |
| | | contentType.value = raw |
| | | } |
| | | }) |
| | | |
| | | /** |
| | | * 页面加载时初始化状态栏高度并拉取健康知识列表。 |
| | |
| | | async function loadPopularizationList() { |
| | | loading.value = true |
| | | try { |
| | | const response = await getHealthPopularizationList() |
| | | const response = await getHealthPopularizationList(contentType.value) |
| | | if (response?.code !== 0 || !Array.isArray(response.data)) { |
| | | articleList.value = [] |
| | | return |
| | |
| | | |
| | | .article-list { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | flex-wrap: wrap; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .article-item { |
| | | width: 328rpx; |
| | | height: 328rpx; |
| | | border-radius: 16rpx; |
| | | position: relative; |
| | | overflow: hidden; |
| | | margin-bottom: 24rpx; |
| | | } |
| | | |
| | | .article-img { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | |
| | | .article-shadow { |
| | | position: absolute; |
| | | bottom: 0; |
| | | left: 0; |
| | | width: 100%; |
| | | height: 64rpx; |
| | | background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.8) 100%); |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 0 16rpx; |
| | | width: 100%; |
| | | padding: 24rpx 0; |
| | | border-bottom: 1rpx solid #F0F0F0; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .article-text { |
| | | color: #FFFFFF; |
| | | font-size: 24rpx; |
| | | white-space: nowrap; |
| | | .article-img { |
| | | width: 200rpx; |
| | | height: 150rpx; |
| | | border-radius: 12rpx; |
| | | flex-shrink: 0; |
| | | background-color: #F5F6F8; |
| | | } |
| | | |
| | | .article-title { |
| | | flex: 1; |
| | | margin-left: 24rpx; |
| | | font-size: 30rpx; |
| | | line-height: 44rpx; |
| | | color: #333; |
| | | display: -webkit-box; |
| | | -webkit-box-orient: vertical; |
| | | -webkit-line-clamp: 2; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | width: 100%; |
| | | } |
| | | </style> |
| | |
| | | |
| | | /** |
| | | * 获取 APP 健康科普列表。 |
| | | * @param {number} [contentType] 内容类型:1 健康知识、2 养生科普;不传返回全部。 |
| | | */ |
| | | export const getHealthPopularizationList = () => { |
| | | return request.get('/api/app/health-popularizations', {}, false, false) |
| | | export const getHealthPopularizationList = (contentType) => { |
| | | const params = contentType == null ? {} : { contentType } |
| | | return request.get('/api/app/health-popularizations', params, false, false) |
| | | } |