Merge branch 'abp' into digital-collectibles

# Conflicts:
#	Yi.Bbs.Vue3/src/views/home/Index.vue
This commit is contained in:
橙子
2025-02-04 15:28:23 +08:00
10 changed files with 138 additions and 52 deletions

View File

@@ -77,6 +77,56 @@ namespace Yi.Framework.Bbs.Application.Services.Analyses
return output; return output;
} }
/// <summary>
/// 作者主题,返回当前作者最新的主题
/// </summary>
/// <returns></returns>
[HttpGet("analyse/bbs-discuss/author/{userId}")]
public async Task<List<DiscussGetListOutputDto>> GetAuthorDiscussAsync(
[FromRoute] Guid userId,
[FromQuery] PagedResultRequestDto input)
{
var output = await _forumManager._discussRepository._DbQueryable.Where(discuss=>discuss.CreatorId==userId)
.Where(discuss=>discuss.PermissionType== DiscussPermissionTypeEnum.Public)
.LeftJoin<UserAggregateRoot>((discuss, user) => discuss.CreatorId == user.Id)
.LeftJoin<BbsUserExtraInfoEntity>((discuss, user, info) => user.Id == info.UserId)
.OrderByDescending(discuss => discuss.CreationTime)
.Select((discuss, user, info) => new DiscussGetListOutputDto
{
Id = discuss.Id,
User = new BbsUserGetListOutputDto()
{
Id = user.Id,
UserName = user.UserName,
Nick = user.Nick,
Icon = user.Icon,
Level = info.Level,
UserLimit = info.UserLimit
}
}, true)
.ToPageListAsync(input.SkipCount, input.MaxResultCount);
var discussId = output.Select(x => x.Id);
//点赞字典key为主题idy为用户ids
var agreeDic =
(await _agreeRepository._DbQueryable.Where(x => discussId.Contains(x.DiscussId)).ToListAsync())
.GroupBy(x => x.DiscussId)
.ToDictionary(x => x.Key, y => y.Select(y => y.CreatorId).ToList());
//等级、是否点赞赋值
output?.ForEach(x =>
{
if (CurrentUser.Id is not null)
{
//默认fasle
if (agreeDic.TryGetValue(x.Id,out var userIds))
{
x.IsAgree = userIds.Contains(CurrentUser.Id);
}
}
});
return output;
}
} }
} }

View File

@@ -1,5 +1,20 @@
import request from "@/config/axios/service"; import request from "@/config/axios/service";
/**
* 获取作者主题
* @param userId
* @param {*} data
* @returns
*/
export function getAuthorTopic(userId,data) {
return request({
url: `/analyse/bbs-discuss/author/${userId}`,
method: "get",
data,
});
}
/** /**
* 获取推荐主题 * 获取推荐主题
* @param {*} data * @param {*} data

View File

@@ -1,6 +1,7 @@
<template> <template>
<el-badge class="box-card"> <el-badge class="box-card">
<el-card shadow="never" :style="{ 'border-color': discuss.color }"> <el-card shadow="never" :style="{ 'border-color': discuss.color }"
>
<div class="card-header"> <div class="card-header">
<AvatarInfo :userInfo="discuss.user" /> <AvatarInfo :userInfo="discuss.user" />
</div> </div>
@@ -157,8 +158,8 @@ onMounted(() => {
font-size: 14px; font-size: 14px;
margin: 5px 0; margin: 5px 0;
} }
.box-card { .box-card {
position: relative; position: relative;
width: 100%; width: 100%;
/* right: calc(1px + var(--el-badge-size)/ 2) !important; */ /* right: calc(1px + var(--el-badge-size)/ 2) !important; */

View File

@@ -1,7 +1,7 @@
<script setup> <script setup>
import { ref } from "vue"; import { ref } from "vue";
const props = defineProps(["items", "header", "text", "hideDivider", "height"]); const props = defineProps(["items", "header", "text", "hideDivider", "height","isPadding"]);
const emit = defineEmits(['onClickText']) const emit = defineEmits(['onClickText'])
const height = ref(props.height + "px"); const height = ref(props.height + "px");
@@ -11,7 +11,7 @@ const onClickText=()=>{
</script> </script>
<template> <template>
<el-card class="box-card" shadow="never"> <el-card class="box-card" shadow="never" :body-style="{padding: isPadding===false?'0px 20px':'20px 20px'}">
<template #header> <template #header>
<div class="card-header"> <div class="card-header">
<span>{{ props.header }}</span> <span>{{ props.header }}</span>
@@ -50,7 +50,6 @@ const onClickText=()=>{
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
} }
.text { .text {
font-size: 14px; font-size: 14px;
} }

View File

@@ -2,16 +2,16 @@
<el-scrollbar> <el-scrollbar>
<div class="scrollbar-flex-content"> <div class="scrollbar-flex-content">
<div v-for="item in recommendList" :key="item.id" class="scrollbar-item"> <div v-for="item in recommendList" :key="item.id" class="scrollbar-item">
<el-tooltip <!-- <el-tooltip-->
class="box-item" <!-- class="box-item"-->
effect="dark" <!-- effect="dark"-->
:content="item.dictLabel" <!-- :content="item.dictLabel"-->
placement="top" <!-- placement="top"-->
v-if="item.dictLabel.length > 5" <!-- v-if="item.dictLabel.length > 5"-->
> <!-- >-->
{{ item.dictLabel.slice(0, 5) + "..." }} <!-- {{ item.dictLabel.slice(0, 5) + "..." }}-->
</el-tooltip> <!-- </el-tooltip>-->
<span v-else> <span >
{{ item.dictLabel }} {{ item.dictLabel }}
</span> </span>
</div> </div>
@@ -35,12 +35,13 @@ onMounted(async () => {
display: flex; display: flex;
} }
.scrollbar-item { .scrollbar-item {
padding: 0 15px;
cursor: pointer; cursor: pointer;
flex-shrink: 0; flex-shrink: 0;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 4rem; //width: 4rem;
height: 2.6rem; height: 2.6rem;
margin: 0 0.2rem; margin: 0 0.2rem;
text-align: center; text-align: center;

View File

@@ -1,5 +1,6 @@
<template> <template>
<el-tree <el-tree
empty-text="无子文章"
:data="props.data == '' ? [] : props.data" :data="props.data == '' ? [] : props.data"
:props="defaultProps" :props="defaultProps"
@node-click="handleNodeClick" @node-click="handleNodeClick"

View File

@@ -100,7 +100,7 @@ const router = createRouter({
path: "/article/:discussId", path: "/article/:discussId",
component: () => import("../views/Article.vue"), component: () => import("../views/Article.vue"),
meta: { meta: {
title: "主题封面", title: "主题首页",
}, },
}, },
{ {

View File

@@ -9,7 +9,7 @@
<el-button <el-button
style="width: 100%; margin-bottom: 0.8rem" style="width: 100%; margin-bottom: 0.8rem"
@click="loadDiscuss(true)" @click="loadDiscuss(true)"
>主题封面</el-button >主题首页</el-button
> >
<el-button <el-button
v-if="isAddArticle && isArticleUser" v-if="isAddArticle && isArticleUser"
@@ -19,7 +19,7 @@
>添加子文章</el-button >添加子文章</el-button
> >
<!--目录在这里 --> <!--目录在这里 -->
<el-scrollbar height="410px"> <el-scrollbar style="min-height: 410px">
<TreeArticleInfo <TreeArticleInfo
:data="articleData" :data="articleData"
@remove="delArticle" @remove="delArticle"
@@ -34,19 +34,19 @@
</InfoCard> </InfoCard>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<InfoCard :items="items" header="作者分享" text="更多"> <InfoCard :items="authorList" :isPadding="false" header="作者分享" height="410" text="更多">
<template #item="temp"> <template #item="temp">
<AvatarInfo /> <ThemeData :themeData="temp"/>
</template>
</InfoCard>
</el-col>
<el-col :span="24">
<InfoCard :items="items" header="内容推荐" text="更多">
<template #item="temp">
<AvatarInfo />
</template> </template>
</InfoCard> </InfoCard>
</el-col> </el-col>
<!-- <el-col :span="24">-->
<!-- <InfoCard :items="items" header="内容推荐" text="更多">-->
<!-- <template #item="temp">-->
<!-- <AvatarInfo />-->
<!-- </template>-->
<!-- </InfoCard>-->
<!-- </el-col>-->
</el-row> </el-row>
</el-col> </el-col>
@@ -155,19 +155,24 @@
</InfoCard> </InfoCard>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<InfoCard :items="items" header="其他" text="更多"> <InfoCard :items="themeList" :isPadding="false" header="推荐主题" text="更多" height="500">
<template #item="temp"> <template #item="temp">
<AvatarInfo /> <ThemeData :themeData="temp"/>
</template>
</InfoCard>
</el-col>
<el-col :span="24">
<InfoCard :items="items" header="其他" text="更多">
<template #item="temp">
<AvatarInfo />
</template> </template>
</InfoCard> </InfoCard>
<!-- <InfoCard :items="items" header="其他" text="更多">-->
<!-- <template #item="temp">-->
<!-- <AvatarInfo />-->
<!-- </template>-->
<!-- </InfoCard>-->
</el-col> </el-col>
<!-- <el-col :span="24">-->
<!-- <InfoCard :items="items" header="其他" text="更多">-->
<!-- <template #item="temp">-->
<!-- <AvatarInfo />-->
<!-- </template>-->
<!-- </InfoCard>-->
<!-- </el-col>-->
</el-row> </el-row>
</el-col> </el-col>
</el-row> </el-row>
@@ -192,17 +197,20 @@ import {
import Breadcrumb from "@/components/Breadcrumb/index.vue"; import Breadcrumb from "@/components/Breadcrumb/index.vue";
import { getPermission } from "@/utils/auth"; import { getPermission } from "@/utils/auth";
import useUserStore from "@/stores/user.js"; import useUserStore from "@/stores/user.js";
import ThemeData from "@/views/home/components/RecommendTheme/index.vue";
import {getRecommendedTopic,getAuthorTopic} from "@/apis/analyseApi";
//数据定义 //数据定义
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const spacer = h(ElDivider, { direction: "vertical" }); const spacer = h(ElDivider, { direction: "vertical" });
const items = [{ user: "用户1" }, { user: "用户2" }, { user: "用户3" }];
//子文章数据 //子文章数据
const articleData = ref([]); const articleData = ref([]);
//主题内容 //主题内容
const discuss = ref({}); const discuss = ref({});
//推荐主题
const themeList=ref([]);
//作者主题
const authorList=ref([]);
//封面url //封面url
const getUrl = (str) => { const getUrl = (str) => {
return `${import.meta.env.VITE_APP_BASEAPI}/file/${str}`; return `${import.meta.env.VITE_APP_BASEAPI}/file/${str}`;
@@ -369,11 +377,22 @@ const delArticle = (node, data) => {
}); });
}); });
}; };
const loadThemeData =async () => {
const {data: themeData} = await getRecommendedTopic();
themeList.value = themeData;
}
const loadAuthorData=async () => {
const {data: authorData} = await getAuthorTopic(discuss.value.user.id);
authorList.value = authorData;
}
onMounted(async () => { onMounted(async () => {
await loadDiscuss(); await loadDiscuss();
await loadArticleData(); await loadArticleData();
await loadAuthorData();
await loadThemeData();
}); });
watch( watch(
() => currentArticle.value, () => currentArticle.value,
(val) => { (val) => {
@@ -406,7 +425,7 @@ watch(
} }
.article-box { .article-box {
width: 1400px; width: 1500px;
height: 100%; height: 100%;
.comment { .comment {
min-height: 40rem; min-height: 40rem;

View File

@@ -65,7 +65,7 @@
:codeStyle="codeStyle" :codeStyle="codeStyle"
/> />
</el-form-item> </el-form-item>
<el-form-item label="封面" v-if="radio == 'discuss'"> <el-form-item label="首页" v-if="radio == 'discuss'">
<el-image <el-image
v-if="dialogImageUrl" v-if="dialogImageUrl"
@@ -74,7 +74,7 @@
class="avatar" class="avatar"
/> />
<!-- 主题封面选择 --> <!-- 主题首页选择 -->
<el-upload <el-upload
class="avatar-uploader" class="avatar-uploader"
:action="fileUploadUrl" :action="fileUploadUrl"

View File

@@ -108,7 +108,7 @@ margin: 10px auto;">
<el-col v-if="!isIcp" :span="24"> <el-col v-if="!isIcp" :span="24">
<InfoCard header="活动"> <InfoCard header="活动">
<template #content> <template #content>
<div class="top">今天准备好学习了吗~</div> <div class="top">祝各位蛇年大吉~</div>
<el-row class="active"> <el-row class="active">
<el-col style="padding: 5px 0px;" v-for="item in activeList" :span="6" @click="handleToRouter(item.path)"> <el-col style="padding: 5px 0px;" v-for="item in activeList" :span="6" @click="handleToRouter(item.path)">
@@ -161,7 +161,7 @@ margin: 10px auto;">
<el-col v-if="!isIcp" :span="24"> <el-col v-if="!isIcp" :span="24">
<template v-if="isPointFinished"> <template v-if="isPointFinished">
<InfoCard :items="pointList" header="财富排行榜" text="查看我的位置" height="400" <InfoCard :isPadding="false" :items="pointList" header="财富排行榜" text="查看我的位置" height="410"
@onClickText="onClickMoneyTop"> @onClickText="onClickMoneyTop">
<template #item="temp"> <template #item="temp">
<PointsRanking :pointsData="temp"/> <PointsRanking :pointsData="temp"/>
@@ -169,7 +169,7 @@ margin: 10px auto;">
</InfoCard> </InfoCard>
</template> </template>
<template v-else> <template v-else>
<InfoCard header="本月排行" text="更多"> <InfoCard :isPadding="false" header="财富排行" text="查看我的位置">
<template #content> <template #content>
<Skeleton/> <Skeleton/>
</template> </template>
@@ -179,14 +179,14 @@ margin: 10px auto;">
<el-col v-if="!isIcp" :span="24"> <el-col v-if="!isIcp" :span="24">
<template v-if="isFriendFinished"> <template v-if="isFriendFinished">
<InfoCard :items="friendList" header="推荐好友" text="更多" height="400"> <InfoCard :isPadding="false" :items="friendList" header="推荐好友" text="更多" height="400">
<template #item="temp"> <template #item="temp">
<RecommendFriend :friendData="temp"/> <RecommendFriend :friendData="temp"/>
</template> </template>
</InfoCard> </InfoCard>
</template> </template>
<template v-else> <template v-else>
<InfoCard header="推荐好友" text="更多"> <InfoCard :isPadding="false" header="推荐好友" text="更多">
<template #content> <template #content>
<Skeleton/> <Skeleton/>
</template> </template>
@@ -195,14 +195,14 @@ margin: 10px auto;">
</el-col> </el-col>
<el-col v-if="!isIcp" :span="24"> <el-col v-if="!isIcp" :span="24">
<template v-if="isThemeFinished"> <template v-if="isThemeFinished">
<InfoCard :items="themeList" header="推荐主题" text="更多" height="400"> <InfoCard :isPadding="false" :items="themeList" header="推荐主题" text="更多" height="400">
<template #item="temp"> <template #item="temp">
<ThemeData :themeData="temp"/> <ThemeData :themeData="temp"/>
</template> </template>
</InfoCard> </InfoCard>
</template> </template>
<template v-else> <template v-else>
<InfoCard header="推荐主题" text="更多"> <InfoCard :isPadding="false" header="推荐主题" text="更多">
<template #content> <template #content>
<Skeleton/> <Skeleton/>
</template> </template>
@@ -249,6 +249,7 @@ import {onMounted, ref, reactive, computed, nextTick, watch} from "vue";
import {useRouter} from "vue-router"; import {useRouter} from "vue-router";
import DisscussCard from "@/components/DisscussCard.vue"; import DisscussCard from "@/components/DisscussCard.vue";
import InfoCard from "@/components/InfoCard.vue"; import InfoCard from "@/components/InfoCard.vue";
import ThemeData from "@/views/home/components/RecommendTheme/index.vue";
import PlateCard from "@/components/PlateCard.vue"; import PlateCard from "@/components/PlateCard.vue";
import ScrollbarInfo from "@/components/ScrollbarInfo.vue"; import ScrollbarInfo from "@/components/ScrollbarInfo.vue";
import BottomInfo from "@/components/BottomInfo.vue"; import BottomInfo from "@/components/BottomInfo.vue";
@@ -269,7 +270,6 @@ import {
import {getList as getAllDiscussList} from "@/apis/discussApi.js"; import {getList as getAllDiscussList} from "@/apis/discussApi.js";
import PointsRanking from "./components/PointsRanking/index.vue"; import PointsRanking from "./components/PointsRanking/index.vue";
import RecommendFriend from "./components/RecommendFriend/index.vue"; import RecommendFriend from "./components/RecommendFriend/index.vue";
import ThemeData from "./components/RecommendTheme/index.vue";
import Skeleton from "@/components/Skeleton/index.vue"; import Skeleton from "@/components/Skeleton/index.vue";
import useSocketStore from "@/stores/socket"; import useSocketStore from "@/stores/socket";