feat: 新增bbs排行榜功能

This commit is contained in:
橙子
2024-08-09 22:39:27 +08:00
parent b30e2f0cc0
commit 1c7486a7bc
8 changed files with 142 additions and 105 deletions

View File

@@ -5,9 +5,9 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.BbsUser;
public class MoneyTopUserDto public class MoneyTopUserDto
{ {
public string UserName { get; set; } public string UserName { get; set; }
public string? Nice { get; set; } public string? Nick { get; set; }
public decimal Money { get; set; } public decimal Money { get; set; }
public string Order { get; set; } public int Order { get; set; }
public string? Icon { get; set; } public string? Icon { get; set; }
public int Level { get; set; } public int Level { get; set; }
/// <summary> /// <summary>

View File

@@ -19,6 +19,7 @@ namespace Yi.Framework.Bbs.Application.Services.Analyses
{ {
private BbsUserManager _bbsUserManager; private BbsUserManager _bbsUserManager;
private IOnlineService _onlineService; private IOnlineService _onlineService;
public BbsUserAnalyseService(BbsUserManager bbsUserManager, IOnlineService onlineService) public BbsUserAnalyseService(BbsUserManager bbsUserManager, IOnlineService onlineService)
{ {
_bbsUserManager = bbsUserManager; _bbsUserManager = bbsUserManager;
@@ -36,22 +37,24 @@ namespace Yi.Framework.Bbs.Application.Services.Analyses
{ {
RefAsync<int> total = 0; RefAsync<int> total = 0;
var output = await _bbsUserManager._userRepository._DbQueryable var output = await _bbsUserManager._userRepository._DbQueryable
.LeftJoin<BbsUserExtraInfoEntity>((u,info)=>u.Id==info.UserId) .LeftJoin<BbsUserExtraInfoEntity>((u, info) => u.Id == info.UserId)
.OrderByDescending((u,info) => info.Money)
.Select((u, info) => .Select((u, info) =>
new MoneyTopUserDto new MoneyTopUserDto
{ {
UserName = u.UserName, UserName = u.UserName,
Nice = u.Nick, Nick = u.Nick,
Money = info.Money, Money = info.Money,
Icon = u.Icon, Icon = u.Icon,
Level = info.Level, Level = info.Level,
UserLimit = info.UserLimit UserLimit = info.UserLimit,
Order = SqlFunc.RowNumber(u.Id)
} }
) )
.OrderBy(info=>info.Money)
.ToPageListAsync(input.SkipCount, input.MaxResultCount,total);
output.ForEach(x => { x.LevelName = _bbsUserManager._levelCacheDic[x.Level].Name;}); .ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
output.ForEach(x => { x.LevelName = _bbsUserManager._levelCacheDic[x.Level].Name; });
return new PagedResultDto<MoneyTopUserDto> return new PagedResultDto<MoneyTopUserDto>
{ {
Items = output, Items = output,
@@ -71,10 +74,9 @@ namespace Yi.Framework.Bbs.Application.Services.Analyses
using (DataFilter.DisablePermissionHandler()) using (DataFilter.DisablePermissionHandler())
{ {
var randUserIds = await _bbsUserManager._userRepository._DbQueryable var randUserIds = await _bbsUserManager._userRepository._DbQueryable
//.Where(x => x.UserName != UserConst.Admin) //.Where(x => x.UserName != UserConst.Admin)
.OrderBy(x => SqlFunc.GetRandom()) .OrderBy(x => SqlFunc.GetRandom())
.Select(x => x.Id). .Select(x => x.Id).ToPageListAsync(input.SkipCount, input.MaxResultCount);
ToPageListAsync(input.SkipCount, input.MaxResultCount);
var output = await _bbsUserManager.GetBbsUserInfoAsync(randUserIds); var output = await _bbsUserManager.GetBbsUserInfoAsync(randUserIds);
return output.Adapt<List<BbsUserGetListOutputDto>>(); return output.Adapt<List<BbsUserGetListOutputDto>>();
@@ -83,26 +85,6 @@ namespace Yi.Framework.Bbs.Application.Services.Analyses
//这里有数据权限,会根据用户角色进行过滤 //这里有数据权限,会根据用户角色进行过滤
} }
/// <summary>
/// 积分钱钱排行榜
/// </summary>
/// <returns></returns>
[HttpGet("analyse/bbs-user/integral-top")]
public async Task<List<BbsUserGetListOutputDto>> GetIntegralTopUserAsync([FromQuery] PagedResultRequestDto input)
{
using (DataFilter.DisablePermissionHandler())
{
var randUserIds = await _bbsUserManager._userRepository._DbQueryable
// .Where(user => user.UserName != UserConst.Admin)
.LeftJoin<BbsUserExtraInfoEntity>((user, info) => user.Id == info.UserId)
.OrderByDescending((user, info) => info.Money)
.Select((user, info) => user.Id).
ToPageListAsync(input.SkipCount, input.MaxResultCount);
var output = await _bbsUserManager.GetBbsUserInfoAsync(randUserIds);
return output.OrderByDescending(x => x.Money).ToList().Adapt<List<BbsUserGetListOutputDto>>();
}
}
/// <summary> /// <summary>
/// 用户分析 /// 用户分析
/// </summary> /// </summary>
@@ -112,7 +94,7 @@ namespace Yi.Framework.Bbs.Application.Services.Analyses
{ {
using (DataFilter.DisablePermissionHandler()) using (DataFilter.DisablePermissionHandler())
{ {
var sss= DataFilter.IsEnabled<IDataPermission>(); var sss = DataFilter.IsEnabled<IDataPermission>();
var registerUser = await _bbsUserManager._userRepository._DbQueryable.CountAsync(); var registerUser = await _bbsUserManager._userRepository._DbQueryable.CountAsync();
@@ -121,16 +103,15 @@ namespace Yi.Framework.Bbs.Application.Services.Analyses
DateTime startTime = new DateTime(yesterday.Year, yesterday.Month, yesterday.Day, 0, 0, 0); DateTime startTime = new DateTime(yesterday.Year, yesterday.Month, yesterday.Day, 0, 0, 0);
DateTime endTime = startTime.AddHours(24); DateTime endTime = startTime.AddHours(24);
var yesterdayNewUser = await _bbsUserManager._userRepository._DbQueryable var yesterdayNewUser = await _bbsUserManager._userRepository._DbQueryable
.Where(x => x.CreationTime >= startTime && x.CreationTime <= endTime).CountAsync(); .Where(x => x.CreationTime >= startTime && x.CreationTime <= endTime).CountAsync();
var userOnline = (await _onlineService.GetListAsync(new OnlineUserModel { })).TotalCount; var userOnline = (await _onlineService.GetListAsync(new OnlineUserModel { })).TotalCount;
var output = new BbsUserAnalyseGetOutput() { OnlineNumber = userOnline, RegisterNumber = registerUser, YesterdayNewUser = yesterdayNewUser }; var output = new BbsUserAnalyseGetOutput()
{ OnlineNumber = userOnline, RegisterNumber = registerUser, YesterdayNewUser = yesterdayNewUser };
return output; return output;
} }
} }
} }
} }

View File

@@ -33,9 +33,9 @@ export function getRecommendedFriend(data) {
*/ */
export function getRankingPoints(data) { export function getRankingPoints(data) {
return request({ return request({
url: "/analyse/bbs-user/integral-top", url: "/analyse/bbs-user/money-top",
method: "get", method: "get",
data, params: data
}); });
} }

View File

@@ -106,6 +106,15 @@ const router = createRouter({
title: "联系我们", title: "联系我们",
}, },
}, },
{
name:"money",
path:"/money",
component: () => import("../views/money/Index.vue"),
meta: {
title: "钱钱",
},
},
], ],
}, },
{ {

View File

@@ -84,10 +84,10 @@
<el-col v-for="item in activeList" :span="6" @click="handleToRouter(item.path)"> <el-col v-for="item in activeList" :span="6" @click="handleToRouter(item.path)">
<el-icon color="#70aafb" size="30px" > <el-icon color="#70aafb" size="30px">
<component :is="item.icon"></component> <component :is="item.icon"></component>
</el-icon> </el-icon>
<span> {{item.name}}</span> <span> {{ item.name }}</span>
</el-col> </el-col>
</el-row> </el-row>
</template> </template>
@@ -102,7 +102,18 @@
</InfoCard> </InfoCard>
<el-dialog v-model="accessLogDialogVisible" title="全站历史统计" width="1200px" center> <el-dialog v-model="accessLogDialogVisible" title="全站历史统计" width="1200px" center>
<AccessLogChart :option="accessLogOptins" class="accessLogChart" /> <el-tabs v-model="accessLogTab">
<el-tab-pane label="访问统计" name="AccessLogChart" style="display: flex;justify-content: center;">
<AccessLogChart :option="accessLogOptins" style="height: 600px;width: 1200px;" />
</el-tab-pane>
<el-tab-pane label="注册统计" name="RegisterChart" style="display: flex;justify-content: center;">
即将上线敬请期待
</el-tab-pane>
</el-tabs>
</el-dialog> </el-dialog>
</el-col> </el-col>
@@ -118,7 +129,7 @@
<el-col :span="24"> <el-col :span="24">
<template v-if="isPointFinished"> <template v-if="isPointFinished">
<InfoCard :items="pointList" header="财富排行榜" text="关于钱钱" height="400"> <InfoCard :items="pointList" header="财富排行榜" text="查看我的位置" height="400" @onClickText="onClickMoneyTop">
<template #item="temp"> <template #item="temp">
<PointsRanking :pointsData="temp" /> <PointsRanking :pointsData="temp" />
</template> </template>
@@ -176,8 +187,8 @@
</template> </template>
<script setup> <script setup>
import {onMounted, ref, reactive, computed, nextTick, watch} from "vue"; 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 PlateCard from "@/components/PlateCard.vue"; import PlateCard from "@/components/PlateCard.vue";
@@ -185,18 +196,18 @@ import ScrollbarInfo from "@/components/ScrollbarInfo.vue";
import BottomInfo from "@/components/BottomInfo.vue"; import BottomInfo from "@/components/BottomInfo.vue";
import VisitsLineChart from "./components/VisitsLineChart/index.vue"; import VisitsLineChart from "./components/VisitsLineChart/index.vue";
import AccessLogChart from "./components/AccessLogChart/Index.vue" import AccessLogChart from "./components/AccessLogChart/Index.vue"
import {access, getAccessList} from "@/apis/accessApi.js"; import { access, getAccessList } from "@/apis/accessApi.js";
import {getList} from "@/apis/plateApi.js"; import { getList } from "@/apis/plateApi.js";
import {getList as bannerGetList} from "@/apis/bannerApi.js"; import { getList as bannerGetList } from "@/apis/bannerApi.js";
import {getHomeDiscuss} from "@/apis/discussApi.js"; import { getHomeDiscuss } from "@/apis/discussApi.js";
import {getWeek} from "@/apis/accessApi.js"; import { getWeek } from "@/apis/accessApi.js";
import { import {
getRecommendedTopic, getRecommendedTopic,
getRecommendedFriend, getRecommendedFriend,
getRankingPoints, getRankingPoints,
getUserAnalyse, getUserAnalyse,
} from "@/apis/analyseApi.js"; } from "@/apis/analyseApi.js";
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 ThemeData from "./components/RecommendTheme/index.vue";
@@ -223,17 +234,17 @@ const allDiscussList = ref([]);
const isAllDiscussFinished = ref(false); const isAllDiscussFinished = ref(false);
const userAnalyseInfo = ref({}); const userAnalyseInfo = ref({});
const onlineNumber = ref(0); const onlineNumber = ref(0);
const accessLogTab = ref()
const activeList = [ const activeList = [
{name: "签到", path: "/activity/sign", icon: "Present"}, { name: "签到", path: "/activity/sign", icon: "Present" },
{name: "等级", path: "/activity/level", icon: "Ticket"}, { name: "等级", path: "/activity/level", icon: "Ticket" },
{name: "大转盘", path: "/activity/lucky", icon: "Sunny"}, { name: "大转盘", path: "/activity/lucky", icon: "Sunny" },
{name: "银行", path: "/activity/bank", icon: "Money"}, { name: "银行", path: "/activity/bank", icon: "Money" },
{name: "任务", path: "/activity/sign", icon: "Memo"}, { name: "任务", path: "/activity/sign", icon: "Memo" },
{name: "娱乐城", path: "/activity/sign", icon: "Sunrise"}, { name: "娱乐城", path: "/activity/sign", icon: "Sunrise" },
{name: "开始", path: "/start", icon: "Position"}, { name: "开始", path: "/start", icon: "Position" },
{name: "聊天室", path: "/chat", icon: "ChatRound"}, { name: "聊天室", path: "/chat", icon: "ChatRound" },
]; ];
//主题查询参数 //主题查询参数
@@ -246,34 +257,34 @@ const query = reactive({
//初始化 //初始化
onMounted(async () => { onMounted(async () => {
access(); access();
const {data: plateData} = await getList(); const { data: plateData } = await getList();
plateList.value = plateData.items; plateList.value = plateData.items;
const {data: discussData, config: discussConfig} = await getHomeDiscuss(); const { data: discussData, config: discussConfig } = await getHomeDiscuss();
discussList.value = discussData; discussList.value = discussData;
isDiscussFinished.value = discussConfig.isFinish; isDiscussFinished.value = discussConfig.isFinish;
const {data: bannerData} = await bannerGetList(); const { data: bannerData } = await bannerGetList();
bannerList.value = bannerData.items; bannerList.value = bannerData.items;
const {data: weekData} = await getWeek(); const { data: weekData } = await getWeek();
weekList.value = weekData; weekList.value = weekData;
const {data: pointData, config: pointConfig} = await getRankingPoints(); const { data: pointData, config: pointConfig } = await getRankingPoints();
pointList.value = pointData; pointList.value = pointData.items;
isPointFinished.value = pointConfig.isFinish; isPointFinished.value = pointConfig.isFinish;
const {data: friendData, config: friendConfig} = const { data: friendData, config: friendConfig } =
await getRecommendedFriend(); await getRecommendedFriend();
friendList.value = friendData; friendList.value = friendData;
isFriendFinished.value = friendConfig.isFinish; isFriendFinished.value = friendConfig.isFinish;
const {data: themeData, config: themeConfig} = await getRecommendedTopic(); const { data: themeData, config: themeConfig } = await getRecommendedTopic();
themeList.value = themeData; themeList.value = themeData;
isThemeFinished.value = themeConfig.isFinish; isThemeFinished.value = themeConfig.isFinish;
const {data: allDiscussData, config: allDiscussConfig} = const { data: allDiscussData, config: allDiscussConfig } =
await getAllDiscussList({ await getAllDiscussList({
Type: 0, Type: 0,
skipCount: 1, skipCount: 1,
maxResultCount: 30, maxResultCount: 30,
}); });
isAllDiscussFinished.value = allDiscussConfig.isFinish; isAllDiscussFinished.value = allDiscussConfig.isFinish;
allDiscussList.value = allDiscussData.items; allDiscussList.value = allDiscussData.items;
const {data: userAnalyseInfoData} = await getUserAnalyse(); const { data: userAnalyseInfoData } = await getUserAnalyse();
onlineNumber.value = userAnalyseInfoData.onlineNumber; onlineNumber.value = userAnalyseInfoData.onlineNumber;
userAnalyseInfo.value = userAnalyseInfoData; userAnalyseInfo.value = userAnalyseInfoData;
}); });
@@ -312,6 +323,11 @@ const accessLogOptins = computed(() => {
] ]
} }
}); });
const onClickMoneyTop = () => {
router.push("/money");
};
const onClickToChatHub = () => { const onClickToChatHub = () => {
router.push("/chat"); router.push("/chat");
}; };
@@ -323,18 +339,31 @@ const handleToRouter = (path) => {
// 推送的实时人数获取 // 推送的实时人数获取
const currentOnlineNum = computed(() => useSocketStore().getOnlineNum()); const currentOnlineNum = computed(() => useSocketStore().getOnlineNum());
watch( watch(
() => currentOnlineNum.value, () => currentOnlineNum.value,
(val) => { (val) => {
onlineNumber.value = val; onlineNumber.value = val;
}, },
{deep: true} { deep: true }
); );
watch(
() => accessLogTab.value,
async(value) => {
switch (value) {
case "AccessLogChart":
const {data} = await getAccessList();
accessAllList.value = data;
break;
case "RegisterChart":
break;
}
}
)
const onClickAccessLog = async () => { const onClickAccessLog = async () => {
accessLogDialogVisible.value = true; accessLogDialogVisible.value = true;
const {data} = await getAccessList(); accessLogTab.value = "AccessLogChart";
accessAllList.value = data;
} }
</script> </script>
@@ -439,10 +468,12 @@ const onClickAccessLog = async () => {
} }
} }
} }
.top{
text-align: center; .top {
text-align: center;
margin-bottom: 20px; margin-bottom: 20px;
} }
.active { .active {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@@ -457,10 +488,13 @@ const onClickAccessLog = async () => {
cursor: pointer; cursor: pointer;
padding: 10px 0px; padding: 10px 0px;
} }
.el-col:hover { .el-col:hover {
background-color: #cce1ff; /* 悬浮时背景色变化 */ background-color: #cce1ff;
color: #70aafb; /* 悬浮时文字颜色变化 */ /* 悬浮时背景色变化 */
} color: #70aafb;
/* 悬浮时文字颜色变化 */
}
&-btn { &-btn {
cursor: pointer; cursor: pointer;

View File

@@ -10,25 +10,26 @@
> >
<UserLimitTag :userLimit="pointsData.userLimit" /> <!-- <UserLimitTag :userLimit="pointsData.userLimit" /> -->
</div> </div>
<div class="bottom"> <div class="bottom">
<div class="name"> <div class="name">
<el-tooltip <el-tooltip
class="box-item" class="box-item"
effect="dark" effect="dark"
:content="pointsData.userName" :content="pointsData.nick"
placement="top" placement="top"
> >
{{ pointsData.userName }} {{ pointsData.nick }}
</el-tooltip> </el-tooltip>
</div> </div>
</div> </div>
</div> </div>
<div class="right"> <div class="right">
<div class="follow"> <div class="follow">
<el-icon class="el-icon--right"><Plus /></el-icon>
<div class="text">关注</div> <div class="follow-text"> <el-icon class="el-icon--right"><Plus /></el-icon>关注</div>
</div> </div>
</div> </div>
</div> </div>
@@ -111,4 +112,8 @@ const userImageSrc = computed(() => {
} }
} }
} }
.follow-text
{ cursor: pointer;
font-size: small;
}
</style> </style>

View File

@@ -9,27 +9,27 @@
<el-tooltip <el-tooltip
class="box-item" class="box-item"
effect="dark" effect="dark"
:content="friendData.userName" :content="friendData.nick"
placement="top" placement="top"
> >
{{ friendData.userName }} {{ friendData.nick }}
</el-tooltip> </el-tooltip>
</div> </div>
<el-tag effect="light" type="success" <!-- <el-tag effect="light" type="success"
>{{ friendData.level }}-{{friendData.levelName}} 等级</el-tag >{{ friendData.level }}-{{friendData.levelName}} 等级</el-tag
> > -->
<UserLimitTag :userLimit="friendData.userLimit" /> <UserLimitTag :userLimit="friendData.userLimit" />
</div> </div>
</div> </div>
<div class="right"> <div class="right">
<div class="follow"> <div class="follow">
<el-icon class="el-icon--right"><Plus /></el-icon>
<div class="text">关注</div> <div class="follow-text"> <el-icon class="el-icon--right"><Plus /></el-icon>关注</div>
</div> </div>
</div> </div>
</div> </div>
@@ -86,7 +86,7 @@ const userImageSrc = computed(() => {
display: flex; display: flex;
align-items: center; align-items: center;
.name { .name {
width: 50px; width: 100px;
color: #252933; color: #252933;
margin-left: 5px; margin-left: 5px;
white-space: nowrap; white-space: nowrap;
@@ -111,4 +111,9 @@ const userImageSrc = computed(() => {
} }
} }
} }
.follow-text
{
font-size: small;
cursor: pointer;
}
</style> </style>

View File

@@ -1,4 +1,7 @@
export const accessLogEchartsConfig = { export const accessLogEchartsConfig = {
tooltip: {
trigger: 'axis'
},
xAxis: { xAxis: {
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: false,