mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-12 09:18:14 +08:00
✨ 帖子收藏 #100
This commit is contained in:
103
src/components/app/t-setCollect.vue
Normal file
103
src/components/app/t-setCollect.vue
Normal file
@@ -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>
|
||||
@@ -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="登录"
|
||||
|
||||
255
src/pages/common/PostCollect.vue
Normal file
255
src/pages/common/PostCollect.vue
Normal file
@@ -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>
|
||||
@@ -1,19 +1,19 @@
|
||||
/**
|
||||
* @file plugins/Sqlite/index.ts
|
||||
* @description Sqlite 数据库操作类
|
||||
* @since Beta v0.4.4
|
||||
* @since Beta v0.4.5
|
||||
*/
|
||||
|
||||
import { app } from "@tauri-apps/api";
|
||||
import Database from "tauri-plugin-sql-api";
|
||||
|
||||
import initDataSql from "./sql/initData";
|
||||
import initTableSql from "./sql/initTable";
|
||||
import {
|
||||
importAbyssData,
|
||||
insertAbyssData,
|
||||
insertAppData,
|
||||
insertGameAccountData,
|
||||
insertPostCollectData,
|
||||
insertRecordData,
|
||||
insertRoleData,
|
||||
} from "./sql/insertData";
|
||||
@@ -66,12 +66,12 @@ class Sqlite {
|
||||
|
||||
/**
|
||||
* @description 初始化数据库
|
||||
* @since Beta v0.3.3
|
||||
* @since Beta v0.4.5
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async initDB(): Promise<void> {
|
||||
const db = await this.getDB();
|
||||
const sql = [...initTableSql(), ...(await initDataSql())];
|
||||
const sql = await initDataSql();
|
||||
for (const item of sql) {
|
||||
await db.execute(item);
|
||||
}
|
||||
@@ -181,7 +181,6 @@ class Sqlite {
|
||||
let isVerified = false;
|
||||
const sqlT = "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;";
|
||||
const res: Array<{ name: string }> = await db.select(sqlT);
|
||||
// 只检测已有的表是否具备,不检测总表数目
|
||||
if (this.tables.every((item) => res.map((i) => i.name).includes(item))) {
|
||||
isVerified = true;
|
||||
}
|
||||
@@ -491,6 +490,70 @@ class Sqlite {
|
||||
if (res.length === 0) return undefined;
|
||||
return res[0].id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 检测特定表是否存在
|
||||
* @since Beta v0.4.5
|
||||
* @param {string} table 表名
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async checkTableExist(table: string): Promise<boolean> {
|
||||
const db = await this.getDB();
|
||||
const sql = `SELECT name
|
||||
FROM sqlite_master
|
||||
WHERE type='table'
|
||||
AND name='${table}';`;
|
||||
const res: Array<{ name: string }> = await db.select(sql);
|
||||
return res.length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 检测帖子是否已收藏
|
||||
* @since Beta v0.4.5
|
||||
* @param {string} postId 帖子 id
|
||||
* @returns {Promise<false|string>} 当该帖子被归到多个分类时,返回分类数量
|
||||
*/
|
||||
async checkPostCollect(postId: string): Promise<false | string> {
|
||||
const db = await this.getDB();
|
||||
const sql = `SELECT collect
|
||||
FROM UserCollection
|
||||
WHERE postId = '${postId}';`;
|
||||
const res: Array<{ collect: string }> = await db.select(sql);
|
||||
if (res.length === 0) return false;
|
||||
return res[0].collect;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 收藏单个帖子
|
||||
* @since Beta v0.4.5
|
||||
* @param {TGApp.Plugins.Mys.Post.FullData} post 帖子
|
||||
* @param {Array<string>} collect 分类
|
||||
* @param {string} uid 用户 uid
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async collectPost(
|
||||
post: TGApp.Plugins.Mys.Post.FullData,
|
||||
collect: string[],
|
||||
uid?: string,
|
||||
): Promise<void> {
|
||||
const db = await this.getDB();
|
||||
const sql = insertPostCollectData(post, collect, uid);
|
||||
await db.execute(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 取消收藏
|
||||
* @since Beta v0.4.5
|
||||
* @param {string} postId 帖子 id
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async cancelCollect(postId: string): Promise<void> {
|
||||
const db = await this.getDB();
|
||||
const sql = `DELETE
|
||||
FROM UserCollection
|
||||
WHERE postId = '${postId}';`;
|
||||
await db.execute(sql);
|
||||
}
|
||||
}
|
||||
|
||||
const TGSqlite = new Sqlite();
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
/**
|
||||
* @file plugins Sqlite sql initData.ts
|
||||
* @file plugins/Sqlite/sql/initData.ts
|
||||
* @description Sqlite 初始化数据 sql 语句
|
||||
* @since Alpha v0.2.0
|
||||
* @since Beta v0.4.5
|
||||
*/
|
||||
|
||||
import { app } from "@tauri-apps/api";
|
||||
|
||||
import initTableSql from "./initTable";
|
||||
import {
|
||||
insertAchievementData,
|
||||
insertAchievementSeriesData,
|
||||
@@ -33,12 +34,14 @@ async function initAppData(): Promise<string[]> {
|
||||
sqlRes.push(`
|
||||
INSERT INTO AppData (key, value, updated)
|
||||
VALUES ('appVersion', '${appVersion}', datetime('now', 'localtime'))
|
||||
ON CONFLICT(key) DO UPDATE SET value = '${appVersion}', updated = datetime('now', 'localtime');`);
|
||||
ON CONFLICT(key) DO UPDATE SET value = '${appVersion}',
|
||||
updated = datetime('now', 'localtime');`);
|
||||
// 初始化应用数据更新时间
|
||||
sqlRes.push(`
|
||||
INSERT INTO AppData (key, value, updated)
|
||||
VALUES ('dataUpdated', '${buildTime}', datetime('now', 'localtime'))
|
||||
ON CONFLICT(key) DO UPDATE SET value = '${buildTime}', updated = datetime('now', 'localtime');`);
|
||||
ON CONFLICT(key) DO UPDATE SET value = '${buildTime}',
|
||||
updated = datetime('now', 'localtime');`);
|
||||
// 初始化 cookie
|
||||
sqlRes.push(`
|
||||
INSERT INTO AppData (key, value, updated)
|
||||
@@ -85,11 +88,12 @@ function initCharacterData(): string[] {
|
||||
|
||||
/**
|
||||
* @description 初始化数据
|
||||
* @since Alpha v0.2.0
|
||||
* @since Beta v0.4.5
|
||||
* @returns {Promise<string[]>} sql
|
||||
*/
|
||||
async function initDataSql(): Promise<string[]> {
|
||||
const sqlRes: string[] = [];
|
||||
sqlRes.push(...initTableSql());
|
||||
sqlRes.push(...(await initAppData()));
|
||||
sqlRes.push(...initAchievementSeriesData());
|
||||
sqlRes.push(...initAchievementData());
|
||||
|
||||
@@ -269,3 +269,28 @@ export function insertRoleData(uid: string, data: TGApp.Game.Character.ListItem[
|
||||
});
|
||||
return sql.join("");
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 插入帖子收藏数据
|
||||
* @since Beta v0.4.5
|
||||
* @param {TGApp.Plugins.Mys.Post.FullData} data 帖子数据
|
||||
* @param {Array<string>} collect 合集
|
||||
* @param {string} uid 用户 UID
|
||||
* @returns {string} sql
|
||||
*/
|
||||
export function insertPostCollectData(
|
||||
data: TGApp.Plugins.Mys.Post.FullData,
|
||||
collect: string[],
|
||||
uid?: string,
|
||||
): string {
|
||||
return `
|
||||
INSERT INTO UserCollection (postId, title, content, collect, uid, updated)
|
||||
VALUES (${data.post.post_id}, '${data.post.subject}', '${JSON.stringify(data)}',
|
||||
'${JSON.stringify(collect)}', '${uid}', datetime('now', 'localtime'))
|
||||
ON CONFLICT DO UPDATE
|
||||
SET title = '${data.post.subject}',
|
||||
content = '${JSON.stringify(data)}',
|
||||
collect = '${JSON.stringify(collect)}',
|
||||
updated = datetime('now', 'localtime');
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file router/modules/main.ts
|
||||
* @description 主路由模块
|
||||
* @since Beta v0.4.4
|
||||
* @since Beta v0.4.5
|
||||
*/
|
||||
|
||||
const mainRoutes = [
|
||||
@@ -30,6 +30,11 @@ const mainRoutes = [
|
||||
name: "成就",
|
||||
component: async () => await import("../../pages/common/Achievements.vue"),
|
||||
},
|
||||
{
|
||||
path: "/collection",
|
||||
name: "收藏",
|
||||
component: async () => await import("../../pages/common/PostCollect.vue"),
|
||||
},
|
||||
{
|
||||
path: "/test",
|
||||
name: "测试页",
|
||||
|
||||
40
src/types/BBS/Collection.d.ts
vendored
Normal file
40
src/types/BBS/Collection.d.ts
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* @file types/BBS/Collection.d.ts
|
||||
* @description BBS 收藏相关类型定义文件
|
||||
* @since Beta v0.4.5
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description BBS 收藏命名空间
|
||||
* @since Beta v0.4.5
|
||||
* @namespace TGApp.BBS.Collection
|
||||
* @memberof TGApp.BBS
|
||||
*/
|
||||
declare namespace TGApp.BBS.Collection {
|
||||
/**
|
||||
* @description 用户收藏帖子数据返回
|
||||
* @since Beta v0.4.5
|
||||
* @interface PostResponse
|
||||
* @extends TGApp.BBS.Response.BaseWithData
|
||||
* @property {PostRespData} data - 响应数据
|
||||
* @return PostResponse
|
||||
*/
|
||||
interface PostResponse extends TGApp.BBS.Response.BaseWithData {
|
||||
data: PostRespData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 用户收藏帖子响应数据
|
||||
* @since Beta v0.4.5
|
||||
* @interface PostRespData
|
||||
* @property {boolean} is_last - 是否最后一页
|
||||
* @property {string} next_offset - 下一页偏移量
|
||||
* @property {Array<TGApp.Plugins.Mys.Post.FullData>} list - 帖子列表
|
||||
* @return PostRespData
|
||||
*/
|
||||
interface PostRespData {
|
||||
is_last: boolean;
|
||||
next_offset: string;
|
||||
list: TGApp.Plugins.Mys.Post.FullData[];
|
||||
}
|
||||
}
|
||||
41
src/types/Sqlite/Collection.d.ts
vendored
Normal file
41
src/types/Sqlite/Collection.d.ts
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @file types/Sqlite/Collection.d.ts
|
||||
* @description Sqlite UserCollection 类型定义文件
|
||||
* @since Beta v0.4.5
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description 用户收藏命名空间
|
||||
* @since Beta v0.4.5
|
||||
* @namespace TGApp.Sqlite.UserCollection
|
||||
* @memberof TGApp.Sqlite
|
||||
*/
|
||||
declare namespace TGApp.Sqlite.UserCollection {
|
||||
/**
|
||||
* @description 数据库-用户收藏表
|
||||
* @since Beta v0.4.5
|
||||
* @interface SingleTable
|
||||
* @property {string} postId - 帖子 ID
|
||||
* @property {string} title - 标题
|
||||
* @property {string} content - 内容
|
||||
* @property {string} collect - 合集
|
||||
* @property {string} uid - 用户 UID
|
||||
* @property {string} updated - 更新时间
|
||||
* @return SingleTable
|
||||
*/
|
||||
interface SingleTable {
|
||||
postId: string;
|
||||
title: string;
|
||||
content: string;
|
||||
collect: string;
|
||||
uid: string;
|
||||
updated: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 渲染卡片
|
||||
* @since Beta v0.4.5
|
||||
* @interface RenderCard
|
||||
*/
|
||||
type RenderCard = TGApp.Plugins.Mys.Forum.RenderCard;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<TSwitchTheme />
|
||||
<TSetCollect v-if="collectExist" :model-value="postId" :data="postData" />
|
||||
<TShareBtn
|
||||
v-show="!loadingEmpty"
|
||||
v-model="postRef"
|
||||
@@ -85,6 +86,7 @@ import { appWindow } from "@tauri-apps/api/window";
|
||||
import { nextTick, onMounted, onUnmounted, ref, watch } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
import TSetCollect from "../components/app/t-setCollect.vue";
|
||||
import TSwitchTheme from "../components/app/t-switchTheme.vue";
|
||||
import TShareBtn from "../components/main/t-shareBtn.vue";
|
||||
import ToLoading from "../components/overlay/to-loading.vue";
|
||||
@@ -92,6 +94,7 @@ import TpAvatar from "../components/post/tp-avatar.vue";
|
||||
import TpParser from "../components/post/tp-parser.vue";
|
||||
import TpoCollection from "../components/post/tpo-collection.vue";
|
||||
import Mys from "../plugins/Mys";
|
||||
import TGSqlite from "../plugins/Sqlite";
|
||||
import { useAppStore } from "../store/modules/app";
|
||||
import TGClient from "../utils/TGClient";
|
||||
import TGLogger from "../utils/TGLogger";
|
||||
@@ -119,6 +122,7 @@ const shareTime = ref<number>(Math.floor(Date.now() / 1000));
|
||||
const shareTimeTimer = ref<any>();
|
||||
// 合集
|
||||
const showCollection = ref<boolean>(false);
|
||||
const collectExist = ref<boolean>(false);
|
||||
|
||||
onMounted(async () => {
|
||||
await appWindow.show();
|
||||
@@ -160,6 +164,7 @@ onMounted(async () => {
|
||||
await TGLogger.Info(`[t-post][${postId}][onMounted] 打开 JSON 窗口`);
|
||||
createPostJson(postId);
|
||||
}
|
||||
collectExist.value = await TGSqlite.checkTableExist("UserCollection");
|
||||
await nextTick(() => {
|
||||
shareTimeTimer.value = setInterval(() => {
|
||||
shareTime.value = Math.floor(Date.now() / 1000);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file web/request/TGRequest.ts
|
||||
* @description 应用用到的请求函数
|
||||
* @since Beta v0.4.3
|
||||
* @since Beta v0.4.5
|
||||
*/
|
||||
|
||||
import { genAuthkey, genAuthkey2 } from "./genAuthkey";
|
||||
@@ -20,6 +20,7 @@ import { getStokenByGameToken, getTokenBySToken } from "./getStoken";
|
||||
import getSyncAvatarDetail from "./getSyncAvatarDetail";
|
||||
import getSyncAvatarListAll from "./getSyncAvatarListAll";
|
||||
import { getTokensByLoginTicket } from "./getTokens";
|
||||
import { getUserCollect } from "./getUserCollect";
|
||||
import { getUserInfoByCookie } from "./getUserInfo";
|
||||
import { verifyLToken } from "./verifyLToken";
|
||||
|
||||
@@ -43,6 +44,7 @@ const TGRequest = {
|
||||
getAbyss,
|
||||
getAccounts: getGameAccountsByCookie,
|
||||
getUserInfo: getUserInfoByCookie,
|
||||
getCollect: getUserCollect,
|
||||
},
|
||||
byLToken: {
|
||||
verify: verifyLToken,
|
||||
|
||||
35
src/web/request/getUserCollect.ts
Normal file
35
src/web/request/getUserCollect.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @file web/request/getUserCollect.ts
|
||||
* @description 获取用户收藏请求模块
|
||||
* @since Beta v0.4.5
|
||||
*/
|
||||
|
||||
import { http } from "@tauri-apps/api";
|
||||
|
||||
import TGUtils from "../utils/TGUtils";
|
||||
|
||||
/**
|
||||
* @description 获取用户收藏帖子
|
||||
* @since Beta v0.4.5
|
||||
* @param {Record<string, string>} cookie - 用户 cookie
|
||||
* @param {string} offset - 偏移量
|
||||
* @returns {Promise<TGApp.BBS.Collection.PostRespData|TGApp.BBS.Response.Base>} 用户收藏帖子
|
||||
*/
|
||||
export async function getUserCollect(
|
||||
cookie: Record<string, string>,
|
||||
offset: string = "",
|
||||
): Promise<TGApp.BBS.Collection.PostRespData | TGApp.BBS.Response.Base> {
|
||||
const url = "https://bbs-api.miyoushe.com/post/wapi/userFavouritePost";
|
||||
const params = { size: "20", offset };
|
||||
const header = TGUtils.User.getHeader(cookie, "GET", params, "common");
|
||||
return await http
|
||||
.fetch<TGApp.BBS.Collection.PostResponse | TGApp.BBS.Response.Base>(url, {
|
||||
method: "GET",
|
||||
headers: header,
|
||||
query: params,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data.retcode !== 0) return <TGApp.BBS.Response.Base>res.data;
|
||||
return res.data.data;
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user