Commit dacd3221 by lijiabin

【需求 23684】feat: 完善文章推荐和最新展示配置

parent b2cf34ee
......@@ -19,6 +19,9 @@ import type {
SearchMoreVideoItemDto,
SecondCommentItemDto,
UpdateArticleRecommendAndSortDto,
RelatedColumnItemDto,
RelatedColumnParams,
UpdateArticleShowLatestDto,
} from './types'
import type { BackendServicePageResult, PageSearchParams } from '@/utils/request/types'
import { SpecificVideoRewardEnum, BooleanFlag } from '@/constants'
......@@ -396,3 +399,25 @@ export const getAtUserList = (
data,
})
}
/**
* 根据标签获取专栏相关推荐
*/
export const getRelatedColumnList = (data: RelatedColumnParams) => {
return service.request<RelatedColumnItemDto[]>({
url: '/api/cultureArticle/relatedByTag',
method: 'POST',
data,
})
}
/**
* 修改视频是否在首页最新列表展示
*/
export const updateArticleShowLatest = (data: UpdateArticleShowLatestDto) => {
return service.request<boolean>({
url: '/api/cultureArticle/updateShowLatest',
method: 'POST',
data,
})
}
......@@ -125,6 +125,7 @@ export interface AddOrUpdateVideoDto {
mainTagId: string | number
tagList: { tagId: number; sort: number }[] | number[]
relateColumnId?: number
isShowLatest?: BooleanFlag
}
/**
......@@ -212,6 +213,7 @@ export interface ArticleItemDto {
recommendSort: number
isOfficialAccount: BooleanFlag
deptId: string
isShowLatest?: BooleanFlag
}
/**
......@@ -502,3 +504,18 @@ export interface AtUserInfoDto {
userId: number
version: number
}
export interface RelatedColumnParams {
articleId: number
tagId: number
}
export interface RelatedColumnItemDto {
id: number
title: string
}
export interface UpdateArticleShowLatestDto {
articleId: number
isShowLatest: BooleanFlag
}
......@@ -232,13 +232,41 @@
</div>
<!-- 标签 -->
<div class="flex flex-wrap gap-2 mt-6">
<span
v-for="item in articleDetail?.tagNameList"
<button
v-for="(item, index) in articleDetail?.tagNameList"
:key="item"
class="px-3 py-1 text-sm bg-gradient-to-r from-cyan-100 to-blue-100 text-cyan-600 rounded-full hover:shadow-md transition-all cursor-pointer"
type="button"
:disabled="!canLoadRelatedColumns"
:class="[
'px-3 py-1 text-sm bg-gradient-to-r from-cyan-100 to-blue-100 text-cyan-600 rounded-full transition-all',
canLoadRelatedColumns ? 'cursor-pointer hover:shadow-md' : 'cursor-default',
activeKeyword === item ? 'ring-2 ring-cyan-400' : '',
]"
@click="handleTagClick(item, articleDetail.tagIdList[index]!)"
>
#{{ item }}
</span>
</button>
</div>
<div
v-if="canLoadRelatedColumns && activeKeyword"
v-loading="relatedColumnLoading"
class="mt-4 min-h-24 border-t border-gray-100 pt-4"
>
<h2 class="mb-3 text-sm font-semibold text-gray-700">相关推荐</h2>
<ul v-if="relatedColumnList.length" class="space-y-2">
<li v-for="(item, index) in relatedColumnList" :key="item.id">
<button
type="button"
class="flex w-full items-center gap-2 text-left text-sm text-gray-600 hover:text-blue-600 cursor-pointer"
@click="router.push(`/articleDetail/${item.id}`)"
>
<span class="flex-shrink-0 text-gray-400">{{ index + 1 }}.</span>
<span class="truncate">{{ item.title }}</span>
</button>
</li>
</ul>
<p v-else-if="!relatedColumnLoading" class="text-sm text-gray-400">暂无相关推荐</p>
</div>
</div>
</template>
......@@ -258,7 +286,7 @@
<script setup lang="ts">
import dayjs from 'dayjs'
import type { ArticleItemDto } from '@/api'
import { getRelatedColumnList, type ArticleItemDto, type RelatedColumnItemDto } from '@/api'
import { articleTypeListOptions, ArticleTypeEnum, VideoPositionEnum } from '@/constants'
import ActionMore from '@/components/common/ActionMore/index.vue'
import SendMessageDialog from '@/components/common/SendMessageDialog/index.vue'
......@@ -290,6 +318,33 @@ const isReal = computed(() => {
const loading = computed(() => !articleDetail.title)
// 只有专栏才能点击标签 获取相关推送
const canLoadRelatedColumns = computed(
() => articleDetail.type === ArticleTypeEnum.COLUMN && !isAudit,
)
const activeKeyword = ref('')
const relatedColumnLoading = ref(false)
const relatedColumnList = ref<RelatedColumnItemDto[]>([])
const handleTagClick = async (keyword: string, tagId: number) => {
if (!canLoadRelatedColumns.value) return
activeKeyword.value = keyword
relatedColumnList.value = []
relatedColumnLoading.value = true
try {
const { data } = await getRelatedColumnList({
articleId: articleDetail.id,
tagId,
})
relatedColumnList.value = data
} catch {
relatedColumnList.value = []
} finally {
relatedColumnLoading.value = false
}
}
// 是否是作者
const isAuthor = computed(() => {
return articleDetail.createUserId === userInfo.value.userId
......
......@@ -2,7 +2,7 @@
import { Search, Upload } from '@element-plus/icons-vue'
import { usePageSearch, useResetData } from '@/hooks'
import { addOrUpdateColumn } from '@/api/backend'
import { getArticleList, updateArticleRecommendAndSort } from '@/api'
import { getArticleList, updateArticleRecommendAndSort, updateArticleShowLatest } from '@/api'
import type { FormInstance, FormRules } from 'element-plus'
import type { BackendColumnListItemDto, AddOrUpdateColumnDto } from '@/api/backend'
import dayjs from 'dayjs'
......@@ -51,6 +51,15 @@ const handleIsRecommendChange = async (val: BooleanFlag, row: ArticleItemDto) =>
refresh()
}
const handleIsShowLatestChange = async (val: BooleanFlag, row: ArticleItemDto) => {
await updateArticleShowLatest({
articleId: row.id,
isShowLatest: val,
})
push.success('修改成功')
refresh()
}
// 编辑排序
const handleEditSort = async (row: ArticleItemDto) => {
const value = await prompt({
......@@ -155,6 +164,17 @@ const handleSelectionChange = (selection: BackendColumnListItemDto[]) => {
</template>
</el-table-column>
<el-table-column prop="isShowLatest" label="是否在最新出现" min-width="160">
<template #default="{ row }">
<el-switch
:model-value="row.isShowLatest ?? BooleanFlag.YES"
:active-value="BooleanFlag.YES"
:inactive-value="BooleanFlag.NO"
@change="(val) => handleIsShowLatestChange(val as BooleanFlag, row)"
/>
</template>
</el-table-column>
<el-table-column prop="status" label="是否推荐" min-width="200">
<template #header>
<div class="flex items-center gap-2">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment