Skip to content

Commit

Permalink
✨ 帖子收藏 #100
Browse files Browse the repository at this point in the history
  • Loading branch information
BTMuli committed Mar 19, 2024
1 parent c558721 commit 8996c1b
Show file tree
Hide file tree
Showing 12 changed files with 602 additions and 19 deletions.
103 changes: 103 additions & 0 deletions src/components/app/t-setCollect.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<template>
<div class="collect-box" data-html2canvas-ignore>
<div class="collect-btn" @click="switchCollect()" :title="isCollected ? '取消收藏' : '收藏'">
<v-icon :color="isCollected ? 'yellow' : 'white'">
{{ isCollected ? "mdi-star" : "mdi-star-outline" }}
</v-icon>
</div>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from "vue";
import TGSqlite from "../../plugins/Sqlite";
import showConfirm from "../func/confirm";
import showSnackbar from "../func/snackbar";
const isCollected = ref(false);
const collect = ref<Array<string>>([]);
interface TSetCollectProps {
modelValue: number;
data: TGApp.Plugins.Mys.Post.FullData | undefined;
}
const props = defineProps<TSetCollectProps>();
onMounted(async () => await getCollect());
async function getCollect(): Promise<void> {
const res = await TGSqlite.checkPostCollect(props.modelValue.toString());
if (res !== false) {
isCollected.value = true;
try {
collect.value = JSON.parse(res);
console.warn(collect.value);
} catch (e) {
showSnackbar({
text: `收藏数据解析失败: ${res}`,
color: "error",
});
}
}
}
async function switchCollect(): Promise<void> {
if (isCollected.value === false) {
collect.value = ["default"];
if (props.data === undefined) {
showSnackbar({
text: "获取帖子数据失败",
color: "error",
});
return;
}
await TGSqlite.collectPost(props.data, collect.value);
isCollected.value = true;
showSnackbar({
text: "收藏成功",
color: "success",
});
return;
}
if (collect.value.length > 1) {
const check = await showConfirm({
title: "确定取消收藏?",
text: "该帖子有多个收藏分类,是否全部取消?",
});
if (!check) {
return;
}
}
await TGSqlite.cancelCollect(props.modelValue.toString());
isCollected.value = false;
showSnackbar({
text: "取消收藏成功",
color: "success",
});
}
</script>
<style lang="css" scoped>
.collect-box {
position: absolute;
top: 80px;
right: 20px;
border: 2px solid var(--common-shadow-8);
border-radius: 50%;
cursor: pointer;
}
.collect-box:hover {
opacity: 0.8;
}
.collect-btn {
display: flex;
width: 24px;
height: 24px;
align-items: center;
justify-content: center;
padding-right: 2px;
margin: 5px;
}
</style>
5 changes: 5 additions & 0 deletions src/components/app/t-sidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,11 @@
<img src="/platforms/mhy/mys.webp" alt="酒馆" class="side-icon-menu" />
</template>
</v-list-item>
<v-list-item class="side-item-menu" title="收藏" :link="true" href="/collection">
<template #prepend>
<img src="/source/UI/posts.png" alt="collect" class="side-icon-menu" />
</template>
</v-list-item>
<v-list-item
class="side-item-menu"
title="登录"
Expand Down
255 changes: 255 additions & 0 deletions src/pages/common/PostCollect.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
<template>
<ToLoading v-model="loading" :title="loadingTitle" :subtitle="loadingSub" />
<div class="pc-container">
<div class="pc-top">
<v-select
v-model="curSelect"
class="pc-select"
:items="Array.from(selects)"
variant="outlined"
label="合集"
/>
<v-btn rounded class="pc-btn" prepend-icon="mdi-refresh" @click="freshUser"
>获取用户收藏</v-btn
>
<!-- todo 编辑收藏 -->
<v-pagination class="pc-page" v-model="page" :length="length" />
</div>
<div class="pc-posts">
<div v-for="item in getPageItems()" :key="item.post.post_id">
<TPostCard :model-value="item" />
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { storeToRefs } from "pinia";
import { onMounted, ref, watch } from "vue";
import showSnackbar from "../../components/func/snackbar";
import TPostCard from "../../components/main/t-postcard.vue";
import ToLoading from "../../components/overlay/to-loading.vue";
import TGSqlite from "../../plugins/Sqlite";
import { insertPostCollectData } from "../../plugins/Sqlite/sql/insertData";
import { useUserStore } from "../../store/modules/user";
import TGLogger from "../../utils/TGLogger";
import TGRequest from "../../web/request/TGRequest";
const loading = ref(false);
const loadingTitle = ref("加载中...");
const loadingSub = ref("");
const userStore = storeToRefs(useUserStore());
const collections = ref<TGApp.Sqlite.UserCollection.SingleTable[]>([]);
const selected = ref<TGApp.Sqlite.UserCollection.SingleTable[]>([]);
const selects = ref<Set<string>>(new Set());
const curSelect = ref<string>("default");
const page = ref(1);
const length = ref(5);
onMounted(async () => {
loadingTitle.value = "检测 UserCollection 表...";
loading.value = true;
const check = await TGSqlite.checkTableExist("UserCollection");
if (!check) {
loadingTitle.value = "创建 UserCollection 表...";
await createCollectTable();
}
loadingTitle.value = "获取收藏帖子...";
await getCollect();
filterBySelect();
loading.value = false;
});
async function createCollectTable(): Promise<void> {
const db = await TGSqlite.getDB();
const sql = `
create table if not exists UserCollection
(
postId text not null, -- 帖子ID
title text not null, -- 帖子标题
content text, -- 帖子内容
collect text, -- 合集标题
uid text, -- 用户ID
updated text not null, -- 收藏时间
primary key (postId)
);
`;
await db.execute(sql);
showSnackbar({
text: "创建 UserCollection 表成功",
color: "success",
});
}
// 根据合集筛选
function filterBySelect(): void {
selected.value = collections.value.filter((item) => item.collect.includes(curSelect.value));
length.value = Math.ceil(selected.value.length / 12);
showSnackbar({
text: `筛选合集 ${curSelect.value} 成功,共 ${selected.value.length} 条数据`,
color: "success",
});
}
// 获取当前页的帖子
function getPageItems(): TGApp.Plugins.Mys.Post.FullData[] {
const posts = selected.value.slice((page.value - 1) * 12, page.value * 12);
const card: TGApp.Plugins.Mys.Post.FullData[] = [];
for (const post of posts) {
try {
card.push(JSON.parse(post.content));
} catch (e) {
TGLogger.Error("[PostCollect] getPageItems");
TGLogger.Error(<string>e);
}
}
return card;
}
watch(curSelect, () => {
filterBySelect();
});
async function getCollect(): Promise<void> {
const db = await TGSqlite.getDB();
const sql = "SELECT * FROM UserCollection";
collections.value = await db.select(sql);
for (const item of collections.value) {
try {
const parse: string[] = JSON.parse(item.collect);
for (const p of parse) {
selects.value.add(p);
}
} catch (e) {
await TGLogger.Error("[PostCollect] getCollect");
await TGLogger.Error(<string>e);
}
}
}
async function freshUser(): Promise<void> {
if (!userStore.cookie.value) {
showSnackbar({
text: "请先登录",
color: "error",
});
return;
}
const cookie = {
cookie_token: userStore.cookie.value.cookie_token,
account_id: userStore.cookie.value.account_id,
};
loadingTitle.value = "获取用户收藏...";
loading.value = true;
let res = await TGRequest.User.byCookie.getCollect(cookie);
let is_last = false;
while (!is_last) {
if ("retcode" in res) {
showSnackbar({
text: `[${res.retcode}] ${res.message}`,
color: "error",
});
return;
}
let posts = res.list;
loadingTitle.value = `合并收藏帖子 [offset]${res.next_offset}...`;
await mergePosts(posts);
if (res.is_last) {
is_last = true;
} else {
loadingTitle.value = "获取用户收藏...";
loadingSub.value = `[offset]${res.next_offset} [is_last]${res.is_last}`;
res = await TGRequest.User.byCookie.getCollect(cookie, res.next_offset);
}
}
loading.value = false;
showSnackbar({
text: "获取用户收藏成功",
color: "success",
});
window.location.reload();
}
// 合并收藏帖子
async function mergePosts(posts: TGApp.Plugins.Mys.Post.FullData[]): Promise<void> {
const db = await TGSqlite.getDB();
const collectTitle = `${userStore.briefInfo.value.nickname} 的收藏`;
for (const post of posts) {
loadingSub.value = `合并帖子 ${post.post.post_id} ${post.post.subject}`;
const postId = post.post.post_id;
const collect = await TGSqlite.checkPostCollect(postId.toString());
let collects = new Set<string>();
if (collect !== false) {
try {
const parse: string[] = JSON.parse(collect);
for (const item of parse) {
collects.add(item);
}
} catch (e) {
collects.add("default");
showSnackbar({
text: `收藏数据解析失败: ${collect}`,
color: "error",
});
await new Promise((resolve) => setTimeout(resolve, 1000));
}
collects.add(collectTitle);
}
const sql = insertPostCollectData(post, Array.from(collects), userStore.briefInfo.value.uid);
await db.execute(sql);
}
}
</script>
<style lang="css" scoped>
.pc-container {
position: relative;
display: flex;
height: 100%;
flex-direction: column;
align-items: center;
row-gap: 10px;
}
.pc-top {
position: relative;
display: flex;
width: 100%;
height: 60px;
align-items: center;
justify-content: flex-start;
column-gap: 10px;
}
.pc-select {
max-width: 400px;
max-height: 100%;
}
.pc-page {
margin-left: auto;
}
/* stylelint-disable-next-line selector-class-pattern */
.pc-page > .v-pagination__list {
justify-content: flex-end;
}
.pc-btn {
height: 40px;
background: var(--btn-bg-1);
color: var(--btn-text-1);
font-family: var(--font-title);
}
.dark .pc-btn {
border: 1px solid var(--common-shadow-2);
}
.pc-posts {
display: grid;
font-family: var(--font-title);
grid-gap: 10px;
grid-template-columns: repeat(4, minmax(320px, 1fr));
}
</style>
Loading

0 comments on commit 8996c1b

Please sign in to comment.