Merge branch 'abp' of https://gitee.com/ccnetcore/Yi into abp
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-badge :value="props.badge ?? ''" class="box-card">
|
||||
<el-badge class="box-card">
|
||||
<el-card shadow="never" :style="{ 'border-color': discuss.color }">
|
||||
<el-row>
|
||||
<!-- 头部 -->
|
||||
@@ -69,6 +69,12 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
<div class="pinned" v-if="props.badge">
|
||||
<div class="icon">
|
||||
<el-icon><Upload /></el-icon>
|
||||
</div>
|
||||
<div class="text">{{ props.badge ?? "" }}</div>
|
||||
</div>
|
||||
</el-badge>
|
||||
</template>
|
||||
<script setup>
|
||||
@@ -170,10 +176,28 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.box-card {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 15rem;
|
||||
/* right: calc(1px + var(--el-badge-size)/ 2) !important; */
|
||||
/* top: 0 !important; */
|
||||
.pinned {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
padding: 5px 15px;
|
||||
border-radius: 5px;
|
||||
color: rgb(8, 119, 229);
|
||||
background-color: #ecf5ff;
|
||||
font-size: 14px;
|
||||
.icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-title {
|
||||
|
||||
@@ -51,12 +51,12 @@ service.interceptors.response.use(
|
||||
// 对响应错误做点什么
|
||||
if (error.message.indexOf("timeout") != -1) {
|
||||
ElMessage({
|
||||
type: "danger",
|
||||
type: "error",
|
||||
message: "网络超时",
|
||||
});
|
||||
} else if (error.message == "Network Error") {
|
||||
ElMessage({
|
||||
type: "danger",
|
||||
type: "error",
|
||||
message: "网络连接错误",
|
||||
});
|
||||
} else {
|
||||
@@ -77,7 +77,7 @@ service.interceptors.response.use(
|
||||
if (status !== 200) {
|
||||
if (status >= 500) {
|
||||
ElMessage({
|
||||
type: "danger",
|
||||
type: "error",
|
||||
message: "网络开小差了,请稍后再试",
|
||||
});
|
||||
return Promise.reject(new Error(message));
|
||||
@@ -85,7 +85,7 @@ service.interceptors.response.use(
|
||||
// 避开找不到后端接口的提醒
|
||||
if (status !== 404) {
|
||||
ElMessage({
|
||||
type: "danger",
|
||||
type: "error",
|
||||
message,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ import useUserStore from "@/stores/user.js";
|
||||
import useConfigStore from "@/stores/config";
|
||||
import useAuths from "@/hooks/useAuths";
|
||||
import { Session } from "@/utils/storage";
|
||||
import signalR from "@/utils/signalR";
|
||||
|
||||
const { getToken, clearStorage } = useAuths();
|
||||
const configStore = useConfigStore();
|
||||
@@ -103,6 +104,7 @@ const logout = async () => {
|
||||
}).then(async () => {
|
||||
//异步
|
||||
await userStore.logOut();
|
||||
await signalR.close();
|
||||
//删除成功后,跳转到主页
|
||||
router.push("/login");
|
||||
ElMessage({
|
||||
|
||||
@@ -63,7 +63,7 @@ const router = createRouter({
|
||||
{
|
||||
name: "discuss",
|
||||
path: "/discuss/:plateId?/:isPublish?",
|
||||
component: () => import("../views/Discuss.vue"),
|
||||
component: () => import("../views/discuss/index.vue"),
|
||||
meta: {
|
||||
title: "板块",
|
||||
},
|
||||
|
||||
@@ -14,10 +14,6 @@ const socketStore = defineStore("socket", {
|
||||
this.onlineNum = value;
|
||||
},
|
||||
},
|
||||
persist: {
|
||||
key: "onlineInfo",
|
||||
storage: window.sessionStorage,
|
||||
},
|
||||
});
|
||||
|
||||
export default socketStore;
|
||||
|
||||
@@ -327,8 +327,8 @@ const typeOptions = [
|
||||
label: "默认",
|
||||
},
|
||||
{
|
||||
value: "Vuepress",
|
||||
label: "Vuepress",
|
||||
value: "VuePress",
|
||||
label: "VuePress",
|
||||
},
|
||||
];
|
||||
const getFile = async (e) => {
|
||||
|
||||
84
Yi.Bbs.Vue3/src/views/discuss/components/tabs.vue
Normal file
84
Yi.Bbs.Vue3/src/views/discuss/components/tabs.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<div class="tabs">
|
||||
<div class="left">
|
||||
<div
|
||||
class="items"
|
||||
v-for="item in leftList"
|
||||
@click="handleClick(item)"
|
||||
:class="[modelValue === item.name ? 'active-tab' : '']"
|
||||
>
|
||||
{{ item.label }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="center"></div>
|
||||
<div class="right">
|
||||
<template v-for="(item, index) in rightList">
|
||||
<div
|
||||
class="items"
|
||||
@click="handleClick(item)"
|
||||
:class="[modelValue === item.name ? 'active-tab' : '']"
|
||||
>
|
||||
{{ item.label }}
|
||||
</div>
|
||||
<div class="line" v-if="index < rightList.length - 1">|</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, defineProps, defineEmits } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
tabList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:modelValue"], ["tab-change"]);
|
||||
|
||||
const leftList = computed(() =>
|
||||
props.tabList.filter((item) => item.position === "left")
|
||||
);
|
||||
const rightList = computed(() =>
|
||||
props.tabList.filter((item) => item.position === "right")
|
||||
);
|
||||
const handleClick = (item) => {
|
||||
emit("update:modelValue", item.name);
|
||||
emit("tab-change", item);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.tabs {
|
||||
display: flex;
|
||||
background-color: #fff;
|
||||
padding: 1rem;
|
||||
margin: 1rem 0rem;
|
||||
color: #8c8c8c;
|
||||
.left {
|
||||
width: 100px;
|
||||
}
|
||||
.center {
|
||||
flex: 3;
|
||||
}
|
||||
.right {
|
||||
width: 200px;
|
||||
display: flex;
|
||||
.line {
|
||||
margin: 0 10px;
|
||||
}
|
||||
}
|
||||
.items {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.active-tab {
|
||||
color: #409eff;
|
||||
}
|
||||
</style>
|
||||
@@ -47,28 +47,10 @@
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<el-tabs v-model="activeName" @tab-change="handleClick">
|
||||
<el-tab-pane label="最新" name="new"> </el-tab-pane>
|
||||
<el-tab-pane label="推荐" name="suggest"> </el-tab-pane>
|
||||
<el-tab-pane label="最热" name="host"> </el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<el-collapse class="collapse-list" style="background-color: #f0f2f5">
|
||||
<el-collapse-item>
|
||||
<template #title>
|
||||
<div class="collapse-top">
|
||||
已置顶主题<el-icon class="header-icon">
|
||||
<info-filled />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<div class="div-item" v-for="i in topDiscussList">
|
||||
<DisscussCard :discuss="i" badge="置顶" />
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
<el-divider v-show="topDiscussList.length > 0" />
|
||||
<Tabs v-model="activeName" :tabList="tabList" @tab-change="handleClick" />
|
||||
<div class="div-item" v-for="i in topDiscussList">
|
||||
<DisscussCard :discuss="i" badge="置顶" />
|
||||
</div>
|
||||
<template v-if="isDiscussFinished">
|
||||
<div class="div-item" v-for="i in discussList">
|
||||
<DisscussCard :discuss="i" />
|
||||
@@ -77,6 +59,9 @@
|
||||
<template v-else>
|
||||
<Skeleton :isBorder="true" />
|
||||
</template>
|
||||
<div class="div-item" v-for="i in discussList">
|
||||
<DisscussCard :discuss="i" />
|
||||
</div>
|
||||
<div>
|
||||
<el-pagination
|
||||
v-model:current-page="query.skipCount"
|
||||
@@ -113,12 +98,13 @@ import { getPermission } from "@/utils/auth";
|
||||
import useAuths from "@/hooks/useAuths";
|
||||
import { Session } from "@/utils/storage";
|
||||
import Skeleton from "@/components/Skeleton/index.vue";
|
||||
import Tabs from "./components/tabs.vue";
|
||||
|
||||
const { getToken, clearStorage } = useAuths();
|
||||
//数据定义
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const activeName = ref("new");
|
||||
const activeName = ref("suggest");
|
||||
//主题内容
|
||||
const discussList = ref([]);
|
||||
const isDiscussFinished = ref(false);
|
||||
@@ -133,7 +119,7 @@ const query = reactive({
|
||||
type: activeName.value,
|
||||
});
|
||||
|
||||
const handleClick = async (tab, event) => {
|
||||
const handleClick = async (item) => {
|
||||
query.type = activeName.value;
|
||||
await loadDiscussList();
|
||||
};
|
||||
@@ -212,6 +198,12 @@ watch(
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
const tabList = ref([
|
||||
{ label: "全部文章", name: "suggest", position: "left" },
|
||||
{ label: "最新", name: "new", position: "right" },
|
||||
{ label: "最热", name: "host", position: "right" },
|
||||
]);
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.discuss-box {
|
||||
@@ -235,6 +227,10 @@ watch(
|
||||
padding: 1rem;
|
||||
margin: 1rem 0rem;
|
||||
}
|
||||
|
||||
.header-tab {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.collapse-top {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
@@ -278,6 +274,7 @@ watch(
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 禁用状态下的样式 */
|
||||
.el-button.el-button--disabled {
|
||||
opacity: 0.6;
|
||||
@@ -62,7 +62,7 @@
|
||||
<div class="content">
|
||||
<div class="name"></div>
|
||||
<div class="content-box top">
|
||||
<div class="count">{{ userAnalyseInfo.onlineNumber }}</div>
|
||||
<div class="count">{{ onlineNumber }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -199,6 +199,7 @@ import RecommendFriend from "./components/RecommendFriend/index.vue";
|
||||
import ThemeData from "./components/RecommendTheme/index.vue";
|
||||
import Skeleton from "@/components/Skeleton/index.vue";
|
||||
import useUserStore from "@/stores/user";
|
||||
import useSocketStore from "@/stores/socket";
|
||||
import { storeToRefs } from "pinia";
|
||||
import signalR from "@/utils/signalR";
|
||||
|
||||
@@ -218,6 +219,7 @@ const isThemeFinished = ref([]);
|
||||
const allDiscussList = ref([]);
|
||||
const isAllDiscussFinished = ref(false);
|
||||
const userAnalyseInfo = ref({});
|
||||
const onlineNumber = ref(0);
|
||||
|
||||
const items = [{ user: "用户1" }, { user: "用户2" }, { user: "用户3" }];
|
||||
//主题查询参数
|
||||
@@ -258,21 +260,19 @@ onMounted(async () => {
|
||||
isAllDiscussFinished.value = allDiscussConfig.isFinish;
|
||||
allDiscussList.value = allDiscussData.items;
|
||||
const { data: userAnalyseInfoData } = await getUserAnalyse();
|
||||
onlineNumber.value = userAnalyseInfoData.onlineNumber;
|
||||
userAnalyseInfo.value = userAnalyseInfoData;
|
||||
// 实时人数
|
||||
// await signalR.init(`main`);
|
||||
// nextTick(() => {
|
||||
// // 初始化主题样式
|
||||
// handleThemeStyle(useSettingsStore().theme);
|
||||
// });
|
||||
await signalR.init(`main`);
|
||||
});
|
||||
|
||||
//这里还需要监视token的变化,重新进行signalr连接
|
||||
watch();
|
||||
// () => token.value,
|
||||
// async (newValue, oldValue) => {
|
||||
// await signalR.init(`main`);
|
||||
// }
|
||||
watch(
|
||||
() => token.value,
|
||||
async (newValue, oldValue) => {
|
||||
await signalR.init(`main`);
|
||||
}
|
||||
);
|
||||
|
||||
const weekXAxis = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"];
|
||||
// 访问统计
|
||||
@@ -290,6 +290,15 @@ const statisOptions = computed(() => {
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
// 推送的实时人数获取
|
||||
const currentOnlineNum = computed(() => useSocketStore().getOnlineNum());
|
||||
watch(
|
||||
() => currentOnlineNum.value,
|
||||
(val) => {
|
||||
onlineNumber.value = val;
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.home-box {
|
||||
@@ -375,7 +384,6 @@ const statisOptions = computed(() => {
|
||||
.text {
|
||||
width: 60px;
|
||||
position: absolute;
|
||||
padding: 0 5px;
|
||||
top: -10px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
|
||||
Reference in New Issue
Block a user