定时任务修正
This commit is contained in:
@@ -59,11 +59,12 @@
|
||||
<div class="stat-views">浏览量</div>
|
||||
<div class="stat-likes">点赞数</div>
|
||||
<div class="stat-time">发布时间</div>
|
||||
<div class="stat-actions">操作</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-for="(article, index) in hotArticles"
|
||||
:key="article.resourceID"
|
||||
:key="article.resource?.resourceID"
|
||||
class="hot-article-row"
|
||||
:class="{ 'top-three': index < 3 }"
|
||||
>
|
||||
@@ -73,28 +74,50 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-title">
|
||||
<span class="article-title" :title="article.title">{{ article.title }}</span>
|
||||
<span class="article-title" :title="article.resource?.title">{{ article.resource?.title }}</span>
|
||||
</div>
|
||||
<div class="stat-tag">
|
||||
<span v-if="article.tagID" class="tag-name">{{ getTagName(article.tagID) }}</span>
|
||||
<span v-if="article.resource?.tagID" class="tag-name">{{ getTagName(article.resource.tagID) }}</span>
|
||||
<span v-else class="tag-empty">-</span>
|
||||
</div>
|
||||
<div class="stat-author">
|
||||
<span>{{ article.author || '-' }}</span>
|
||||
<span>{{ article.resource?.author || '-' }}</span>
|
||||
</div>
|
||||
<div class="stat-views">
|
||||
<div class="stat-number hot">
|
||||
<img src="@/assets/imgs/hot.svg" alt="浏览" class="stat-icon" />
|
||||
{{ formatNumber(article.viewCount) }}
|
||||
{{ formatNumber(article.resource?.viewCount) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-likes">
|
||||
<div class="stat-number">
|
||||
{{ formatNumber(article.likeCount) }}
|
||||
{{ formatNumber(article.resource?.likeCount) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-time">
|
||||
<span class="time-text">{{ formatDate(article.publishTime) }}</span>
|
||||
<span class="time-text">{{ formatDate(article.resource?.publishTime) }}</span>
|
||||
</div>
|
||||
<div class="stat-actions">
|
||||
<button
|
||||
v-if="article.resource?.resourceID && !article.isTopRecommend"
|
||||
class="add-to-top-btn"
|
||||
@click="addToTopRecommends(article.resource.resourceID)"
|
||||
:disabled="!!article.resource?.resourceID && addingToTop.has(article.resource.resourceID)"
|
||||
>
|
||||
{{ article.resource?.resourceID && addingToTop.has(article.resource.resourceID) ? '添加中...' : '添加至TOP' }}
|
||||
</button>
|
||||
<span v-else-if="article.isTopRecommend" class="already-top">已在TOP</span>
|
||||
|
||||
<!-- 添加至思政 -->
|
||||
<button
|
||||
v-if="article.resource?.resourceID && !article.isIdeologicalRecommend"
|
||||
class="add-to-ideological-btn"
|
||||
@click="addToIdeologicalRecommends(article.resource.resourceID)"
|
||||
:disabled="!!article.resource?.resourceID && addingToIdeological.has(article.resource.resourceID)"
|
||||
>
|
||||
{{ article.resource?.resourceID && addingToIdeological.has(article.resource.resourceID) ? '添加中...' : '添加至思政' }}
|
||||
</button>
|
||||
<span v-else-if="article.isIdeologicalRecommend" class="already-ideological">已在思政</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -338,7 +361,7 @@ import { ElDialog, ElInput, ElButton, ElCheckbox, ElIcon, ElForm, ElFormItem, El
|
||||
import { Search } from '@element-plus/icons-vue';
|
||||
import { AdminLayout } from '@/views/admin';
|
||||
import { resourceRecommendApi, resourceApi, resourceTagApi } from '@/apis/resource';
|
||||
import type { ResourceRecommendVO, Resource, Tag } from '@/types';
|
||||
import type { ResourceRecommendVO, Resource, ResourceVO, Tag } from '@/types';
|
||||
|
||||
defineOptions({
|
||||
name: 'ColumnManagementView'
|
||||
@@ -356,9 +379,15 @@ const topRecommends = ref<ResourceRecommendVO[]>([]);
|
||||
const ideologicalRecommends = ref<ResourceRecommendVO[]>([]);
|
||||
|
||||
// 热门文章列表
|
||||
const hotArticles = ref<Resource[]>([]);
|
||||
const hotArticles = ref<ResourceVO[]>([]);
|
||||
const hotArticleLimit = ref<number>(20);
|
||||
|
||||
// 添加至TOP的加载状态
|
||||
const addingToTop = ref<Set<string>>(new Set());
|
||||
|
||||
// 添加至思政的加载状态
|
||||
const addingToIdeological = ref<Set<string>>(new Set());
|
||||
|
||||
// 标签列表
|
||||
const tags = ref<Tag[]>([]);
|
||||
|
||||
@@ -381,7 +410,7 @@ const editForm = ref({
|
||||
orderNum: 1
|
||||
});
|
||||
|
||||
// 挂载时加载标签和当前tab的数据
|
||||
// 挂载时加载标签数据和默认tab的数据
|
||||
onMounted(() => {
|
||||
loadTags();
|
||||
loadTabData(activeTab.value);
|
||||
@@ -445,7 +474,7 @@ async function loadHotArticles() {
|
||||
loading.value = true;
|
||||
try {
|
||||
// 获取已发布的文章,按浏览量排序
|
||||
const result = await resourceApi.getResourcePage(
|
||||
const result = await resourceApi.getResourcePageOrderByViewCount(
|
||||
{
|
||||
pageNumber: 1,
|
||||
pageSize: hotArticleLimit.value
|
||||
@@ -458,7 +487,7 @@ async function loadHotArticles() {
|
||||
if (result.success && result.pageDomain?.dataList) {
|
||||
// 按浏览量降序排序
|
||||
hotArticles.value = result.pageDomain.dataList
|
||||
.sort((a, b) => (b.viewCount || 0) - (a.viewCount || 0));
|
||||
.sort((a, b) => (b.resource?.viewCount || 0) - (a.resource?.viewCount || 0));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载热门文章失败:', error);
|
||||
@@ -510,7 +539,7 @@ async function showAddResourceDialog(recommendType: 1 | 2) {
|
||||
async function searchResources() {
|
||||
searchLoading.value = true;
|
||||
try {
|
||||
const result = await resourceApi.getResourcePage(
|
||||
const result = await resourceApi.getResourcePageOrderByViewCount(
|
||||
{ pageNumber: 1, pageSize: 50 },
|
||||
{
|
||||
keyword: searchKeyword.value,
|
||||
@@ -524,9 +553,9 @@ async function searchResources() {
|
||||
? topRecommends.value.map(r => r.resourceID)
|
||||
: ideologicalRecommends.value.map(r => r.resourceID);
|
||||
|
||||
availableResources.value = result.pageDomain.dataList.filter(
|
||||
r => !existingIds.includes(r.resourceID)
|
||||
);
|
||||
availableResources.value = result.pageDomain.dataList
|
||||
.map(vo => vo.resource)
|
||||
.filter(r => r && !existingIds.includes(r.resourceID)) as Resource[];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('搜索资源失败:', error);
|
||||
@@ -655,6 +684,79 @@ async function deleteRecommend(item: ResourceRecommendVO) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查资源是否已在TOP推荐中
|
||||
function isInTopRecommends(resourceID?: string): boolean {
|
||||
if (!resourceID) return false;
|
||||
return topRecommends.value.some(r => r.resourceID === resourceID);
|
||||
}
|
||||
|
||||
// 检查资源是否已在思政推荐中
|
||||
function isInIdeologicalRecommends(resourceID?: string): boolean {
|
||||
if (!resourceID) return false;
|
||||
return ideologicalRecommends.value.some(r => r.resourceID === resourceID);
|
||||
}
|
||||
|
||||
// 根据ResourceVO获取resourceID
|
||||
function getResourceID(articleVO: ResourceVO): string | undefined {
|
||||
return articleVO.resource?.resourceID;
|
||||
}
|
||||
|
||||
// 添加至TOP推荐
|
||||
async function addToTopRecommends(resourceID?: string) {
|
||||
if (!resourceID) return;
|
||||
|
||||
addingToTop.value.add(resourceID);
|
||||
|
||||
try {
|
||||
await resourceRecommendApi.batchAddRecommends([resourceID], 1);
|
||||
ElMessage.success('添加至TOP推荐成功');
|
||||
|
||||
// 重新加载TOP推荐列表
|
||||
loadedTabs.value.delete('top-resources');
|
||||
const topResult = await resourceRecommendApi.getRecommendsByType(1);
|
||||
if (topResult.success && topResult.dataList) {
|
||||
topRecommends.value = topResult.dataList.sort((a, b) => (a.orderNum || 0) - (b.orderNum || 0));
|
||||
}
|
||||
|
||||
// 重新加载热门文章统计以更新按钮状态
|
||||
loadedTabs.value.delete('hot-articles');
|
||||
await loadHotArticles();
|
||||
} catch (error) {
|
||||
console.error('添加至TOP推荐失败:', error);
|
||||
ElMessage.error('添加至TOP推荐失败');
|
||||
} finally {
|
||||
addingToTop.value.delete(resourceID);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加至思政推荐
|
||||
async function addToIdeologicalRecommends(resourceID?: string) {
|
||||
if (!resourceID) return;
|
||||
|
||||
addingToIdeological.value.add(resourceID);
|
||||
|
||||
try {
|
||||
await resourceRecommendApi.batchAddRecommends([resourceID], 2);
|
||||
ElMessage.success('添加至思政推荐成功');
|
||||
|
||||
// 重新加载思政推荐列表
|
||||
loadedTabs.value.delete('ideological');
|
||||
const ideologicalResult = await resourceRecommendApi.getRecommendsByType(2);
|
||||
if (ideologicalResult.success && ideologicalResult.dataList) {
|
||||
ideologicalRecommends.value = ideologicalResult.dataList.sort((a, b) => (a.orderNum || 0) - (b.orderNum || 0));
|
||||
}
|
||||
|
||||
// 重新加载热门文章统计以更新按钮状态
|
||||
loadedTabs.value.delete('hot-articles');
|
||||
await loadHotArticles();
|
||||
} catch (error) {
|
||||
console.error('添加至思政推荐失败:', error);
|
||||
ElMessage.error('添加至思政推荐失败');
|
||||
} finally {
|
||||
addingToIdeological.value.delete(resourceID);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -906,6 +1008,7 @@ async function deleteRecommend(item: ResourceRecommendVO) {
|
||||
.filter-controls {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
// 热门文章列表
|
||||
@@ -918,7 +1021,7 @@ async function deleteRecommend(item: ResourceRecommendVO) {
|
||||
|
||||
.statistics-header {
|
||||
display: grid;
|
||||
grid-template-columns: 80px 1fr 120px 120px 120px 100px 120px;
|
||||
grid-template-columns: 80px 1fr 120px 120px 120px 100px 120px 150px;
|
||||
gap: 16px;
|
||||
padding: 12px 16px;
|
||||
background: #F9FAFB;
|
||||
@@ -931,7 +1034,7 @@ async function deleteRecommend(item: ResourceRecommendVO) {
|
||||
|
||||
.hot-article-row {
|
||||
display: grid;
|
||||
grid-template-columns: 80px 1fr 120px 120px 120px 100px 120px;
|
||||
grid-template-columns: 80px 1fr 120px 120px 120px 100px 120px 150px;
|
||||
gap: 16px;
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||
@@ -952,6 +1055,13 @@ async function deleteRecommend(item: ResourceRecommendVO) {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.stat-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.rank-badge {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -1035,6 +1145,62 @@ async function deleteRecommend(item: ResourceRecommendVO) {
|
||||
font-size: 13px;
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
.add-to-top-btn {
|
||||
padding: 6px 12px;
|
||||
background: #E7000B;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
color: #FFFFFF;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
background: #c00009;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.already-top {
|
||||
font-size: 13px;
|
||||
color: #10B981;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.add-to-ideological-btn {
|
||||
padding: 6px 12px;
|
||||
background: #E7000B;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
color: #FFFFFF;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
background: #c00009;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.already-ideological {
|
||||
font-size: 13px;
|
||||
color: #10B981;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
// 对话框样式
|
||||
|
||||
Reference in New Issue
Block a user