♻️ Mys 类型重构,优化目录结构

This commit is contained in:
BTMuli
2023-06-27 21:01:24 +08:00
parent dc51257e6b
commit 99a6f38c5c
45 changed files with 1864 additions and 1902 deletions

View File

@@ -5,7 +5,7 @@
限时祈愿 限时祈愿
</div> </div>
<div v-if="!loading" class="pool-grid"> <div v-if="!loading" class="pool-grid">
<v-card v-for="pool in poolCards" :key="pool.post_id" class="pool-card"> <v-card v-for="pool in poolCards" :key="pool.postId" class="pool-card">
<v-list class="pool-list"> <v-list class="pool-list">
<v-list-item :title="pool.title" :subtitle="pool.subtitle"> <v-list-item :title="pool.title" :subtitle="pool.subtitle">
<!-- todo 点击播放语音 --> <!-- todo 点击播放语音 -->
@@ -33,12 +33,12 @@
</div> </div>
<div class="pool-clock"> <div class="pool-clock">
<v-progress-circular <v-progress-circular
:model-value="poolTimePass[pool.post_id]" :model-value="poolTimePass[pool.postId]"
size="100" size="100"
width="10" width="10"
:color="poolColor[pool.post_id]" :color="poolColor[pool.postId]"
> >
{{ poolTimeGet[pool.post_id] }} {{ poolTimeGet[pool.postId] }}
</v-progress-circular> </v-progress-circular>
</div> </div>
</div> </div>
@@ -64,9 +64,7 @@ import { useHomeStore } from "../../store/modules/home";
// utils // utils
import { createTGWindow } from "../../utils/TGWindow"; import { createTGWindow } from "../../utils/TGWindow";
// plugins // plugins
import MysOper from "../../plugins/Mys"; import Mys from "../../plugins/Mys";
// interface
import { GachaCard, GachaData } from "../../plugins/Mys/interface/gacha";
// vue // vue
const router = useRouter(); const router = useRouter();
@@ -75,18 +73,18 @@ const router = useRouter();
const homeStore = useHomeStore(); const homeStore = useHomeStore();
// loading // loading
const loading = ref(true as boolean); const loading = ref<boolean>(true);
// snackbar // snackbar
const showBar = ref(false as boolean); const showBar = ref<boolean>(false);
const barText = ref(""); const barText = ref<string>("");
const barColor = ref("error" as string); const barColor = ref<string>("error");
// data // data
const poolCards = ref([] as GachaCard[]); const poolCards = ref<TGApp.Plugins.Mys.Gacha.RenderCard[]>([]);
const poolTimeGet = ref({} as Record<number, string>); const poolTimeGet = ref<Record<number, string>>({});
const poolTimePass = ref({} as Record<number, number>); const poolTimePass = ref<Record<number, number>>({});
const poolColor = ref({} as Record<number, string>); const poolColor = ref<Record<number, string>>({});
const timer = ref({} as Record<number, any>); const timer = ref<Record<number, any>>({});
// expose // expose
defineExpose({ defineExpose({
@@ -95,19 +93,19 @@ defineExpose({
}); });
function poolLastInterval(postId: number) { function poolLastInterval(postId: number) {
const pool = poolCards.value.find((pool) => pool.post_id === postId); const pool = poolCards.value.find((pool) => pool.postId === postId);
if (!pool) return; if (!pool) return;
if (poolTimeGet.value[postId] === "未开始") { if (poolTimeGet.value[postId] === "未开始") {
const isStart = pool.time.start_stamp - Date.now(); const isStart = pool.time.startStamp - Date.now();
if (isStart > 0) return; if (isStart > 0) return;
poolTimeGet.value[postId] = getLastPoolTime(pool.time.end_stamp - Date.now()); poolTimeGet.value[postId] = getLastPoolTime(pool.time.endStamp - Date.now());
poolTimePass.value[postId] = pool.time.end_stamp - Date.now(); poolTimePass.value[postId] = pool.time.endStamp - Date.now();
poolColor.value[postId] = "#90caf9"; poolColor.value[postId] = "#90caf9";
} else { } else {
const isEnd = pool.time.end_stamp - Date.now(); const isEnd = pool.time.endStamp - Date.now();
poolTimeGet.value[postId] = getLastPoolTime(isEnd); poolTimeGet.value[postId] = getLastPoolTime(isEnd);
poolTimePass.value[postId] = poolTimePass.value[postId] =
((pool.time.end_stamp - Date.now()) / (pool.time.end_stamp - pool.time.start_stamp)) * 100; ((pool.time.endStamp - Date.now()) / (pool.time.endStamp - pool.time.startStamp)) * 100;
if (isEnd >= 0) return; if (isEnd >= 0) return;
clearInterval(timer.value[postId]); clearInterval(timer.value[postId]);
timer.value[postId] = null; timer.value[postId] = null;
@@ -119,38 +117,38 @@ function poolLastInterval(postId: number) {
} }
onMounted(async () => { onMounted(async () => {
const gachaData = await MysOper.Gacha.get(); const gachaData = await Mys.Gacha.get();
if (!gachaData) { if (!gachaData) {
console.error("获取限时祈愿数据失败"); console.error("获取限时祈愿数据失败");
return; return;
} }
if (!checkCover(gachaData)) { if (!checkCover(gachaData)) {
poolCards.value = await MysOper.Gacha.card(gachaData); poolCards.value = await Mys.Gacha.card(gachaData);
const coverData: Record<number, string> = {}; const coverData: Record<number, string> = {};
poolCards.value.map((pool) => { poolCards.value.map((pool) => {
coverData[pool.post_id] = pool.cover; coverData[pool.postId] = pool.cover;
return pool; return pool;
}); });
homeStore.poolCover = coverData; homeStore.poolCover = coverData;
} else { } else {
poolCards.value = await MysOper.Gacha.card(gachaData, homeStore.poolCover); poolCards.value = await Mys.Gacha.card(gachaData, homeStore.poolCover);
} }
poolCards.value.map((pool) => { poolCards.value.map((pool) => {
poolTimeGet.value[pool.post_id] = getLastPoolTime(pool.time.end_stamp - Date.now()); poolTimeGet.value[pool.postId] = getLastPoolTime(pool.time.endStamp - Date.now());
poolTimePass.value[pool.post_id] = pool.time.end_stamp - Date.now(); poolTimePass.value[pool.postId] = pool.time.endStamp - Date.now();
if (poolTimePass.value[pool.post_id] <= 0) { if (poolTimePass.value[pool.postId] <= 0) {
poolTimeGet.value[pool.post_id] = "已结束"; poolTimeGet.value[pool.postId] = "已结束";
poolTimePass.value[pool.post_id] = 100; poolTimePass.value[pool.postId] = 100;
poolColor.value[pool.post_id] = "#f44336"; poolColor.value[pool.postId] = "#f44336";
} else if (pool.time.start_stamp - Date.now() > 0) { } else if (pool.time.startStamp - Date.now() > 0) {
poolTimeGet.value[pool.post_id] = "未开始"; poolTimeGet.value[pool.postId] = "未开始";
poolTimePass.value[pool.post_id] = 100; poolTimePass.value[pool.postId] = 100;
poolColor.value[pool.post_id] = "#32A9CA"; poolColor.value[pool.postId] = "#32A9CA";
} else { } else {
poolColor.value[pool.post_id] = "#90caf9"; poolColor.value[pool.postId] = "#90caf9";
} }
timer.value[pool.post_id] = setInterval(() => { timer.value[pool.postId] = setInterval(() => {
poolLastInterval(pool.post_id); poolLastInterval(pool.postId);
}, 1000); }, 1000);
return pool; return pool;
}); });
@@ -158,7 +156,7 @@ onMounted(async () => {
}); });
// 检测新卡池 // 检测新卡池
function checkCover(data: GachaData[]) { function checkCover(data: TGApp.Plugins.Mys.Gacha.Data[]) {
// 如果没有缓存 // 如果没有缓存
if (!homeStore.poolCover || Object.keys(homeStore.poolCover).length === 0) { if (!homeStore.poolCover || Object.keys(homeStore.poolCover).length === 0) {
return false; return false;
@@ -199,12 +197,11 @@ function getLastPoolTime(time: number) {
return `${hour}:${minute.toFixed(0).padStart(2, "0")}:${second.toFixed(0).padStart(2, "0")}`; return `${hour}:${minute.toFixed(0).padStart(2, "0")}:${second.toFixed(0).padStart(2, "0")}`;
} }
function toPost(pool: GachaCard) { function toPost(pool: TGApp.Plugins.Mys.Gacha.RenderCard) {
const path = router.resolve({ const path = router.resolve({
name: "帖子详情", name: "帖子详情",
params: { params: {
// eslint-disable-next-line camelcase post_id: pool.postId.toString(),
post_id: pool.post_id.toString(),
}, },
}).href; }).href;
createTGWindow(path, "限时祈愿", pool.title, 960, 720, false, false); createTGWindow(path, "限时祈愿", pool.title, 960, 720, false, false);

View File

@@ -5,7 +5,7 @@
<span>近期活动</span> <span>近期活动</span>
</div> </div>
<div v-if="!loading" class="position-grid"> <div v-if="!loading" class="position-grid">
<v-card v-for="card in positionCards" :key="card.post_id" class="position-card"> <v-card v-for="card in positionCards" :key="card.postId" class="position-card">
<v-list class="position-list"> <v-list class="position-list">
<v-list-item :title="card.title" :subtitle="card.abstract"> <v-list-item :title="card.title" :subtitle="card.abstract">
<template #prepend> <template #prepend>
@@ -28,11 +28,11 @@
<v-icon>mdi-clock-outline</v-icon> <v-icon>mdi-clock-outline</v-icon>
<span>剩余时间</span> <span>剩余时间</span>
<!-- 玉鈫蓝 --> <!-- 玉鈫蓝 -->
<span v-if="positionTimeGet[card.post_id] !== '已结束'" style="color: #126e82">{{ <span v-if="positionTimeGet[card.postId] !== '已结束'" style="color: #126e82">{{
positionTimeGet[card.post_id] positionTimeGet[card.postId]
}}</span> }}</span>
<!-- 粉红 --> <!-- 粉红 -->
<span v-if="positionTimeGet[card.post_id] === '已结束'" style="color: #f2b9b2" <span v-if="positionTimeGet[card.postId] === '已结束'" style="color: #f2b9b2"
>已结束</span >已结束</span
> >
</div> </div>
@@ -48,21 +48,19 @@ import { useRouter } from "vue-router";
// utils // utils
import { createTGWindow } from "../../utils/TGWindow"; import { createTGWindow } from "../../utils/TGWindow";
// plugins // plugins
import MysOper from "../../plugins/Mys"; import Mys from "../../plugins/Mys";
// interface
import { PositionCard } from "../../plugins/Mys/interface/position";
// vue // vue
const router = useRouter(); const router = useRouter();
// loading // loading
const loading = ref(true as boolean); const loading = ref<boolean>(true);
// data // data
const positionCards = ref([] as PositionCard[]); const positionCards = ref<TGApp.Plugins.Mys.Position.RenderCard[]>([]);
const positionTimeGet = ref({} as Record<number, string>); // 剩余时间/已结束/未知 const positionTimeGet = ref<Record<number, string>>({}); // 剩余时间/已结束/未知
const positionTimeEnd = ref({} as Record<number, number>); // 结束时间戳 const positionTimeEnd = ref<Record<number, number>>({}); // 结束时间戳
const positionTimer = ref({} as Record<number, null>); // 定时器 const positionTimer = ref<Record<number, any>>({}); // 定时器
// expose // expose
defineExpose({ defineExpose({
@@ -86,21 +84,21 @@ function positionLastInterval(postId: number) {
} }
onMounted(async () => { onMounted(async () => {
const positionData = await MysOper.Position.get(); const positionData = await Mys.Position.get();
if (!positionData) { if (!positionData) {
console.error("获取近期活动失败"); console.error("获取近期活动失败");
return; return;
} }
positionCards.value = MysOper.Position.card(positionData); positionCards.value = Mys.Position.card(positionData);
positionCards.value.forEach((card) => { positionCards.value.forEach((card) => {
if (card.time.end_stamp === 0) { if (card.time.endStamp === 0) {
positionTimeGet.value[card.post_id] = "未知"; positionTimeGet.value[card.postId] = "未知";
} else { } else {
positionTimeGet.value[card.post_id] = getLastPositionTime(card.time.end_stamp - Date.now()); positionTimeGet.value[card.postId] = getLastPositionTime(card.time.endStamp - Date.now());
} }
positionTimeEnd.value[card.post_id] = card.time.end_stamp; positionTimeEnd.value[card.postId] = card.time.endStamp;
positionTimer.value[card.post_id] = setInterval(() => { positionTimer.value[card.postId] = setInterval(() => {
positionLastInterval(card.post_id); positionLastInterval(card.postId);
}, 1000); }, 1000);
}); });
loading.value = false; loading.value = false;
@@ -116,13 +114,12 @@ function getLastPositionTime(time: number) {
.padStart(2, "0")}:${second.toFixed(0).padStart(2, "0")}`; .padStart(2, "0")}:${second.toFixed(0).padStart(2, "0")}`;
} }
async function toPost(card: PositionCard) { async function toPost(card: TGApp.Plugins.Mys.Position.RenderCard) {
// 获取路由路径 // 获取路由路径
const path = router.resolve({ const path = router.resolve({
name: "帖子详情", name: "帖子详情",
params: { params: {
// eslint-disable-next-line camelcase post_id: card.postId,
post_id: card.post_id,
}, },
}).href; }).href;
// 打开新窗口 // 打开新窗口

View File

@@ -47,8 +47,9 @@ import TOverlay from "../main/t-overlay.vue";
import TibCalendarItem from "../itembox/tib-calendar-item.vue"; import TibCalendarItem from "../itembox/tib-calendar-item.vue";
import TibCalendarMaterial from "../itembox/tib-calendar-material.vue"; import TibCalendarMaterial from "../itembox/tib-calendar-material.vue";
// utils // utils
import { OBC_CONTENT_API } from "../../plugins/Mys/interface/utils";
import { createTGWindow } from "../../utils/TGWindow"; import { createTGWindow } from "../../utils/TGWindow";
//plugins
import Mys from "../../plugins/Mys";
interface ToCalendarProps { interface ToCalendarProps {
modelValue: boolean; modelValue: boolean;
@@ -70,7 +71,7 @@ const visible = computed({
}); });
const itemType = computed(() => props.dataType); const itemType = computed(() => props.dataType);
const itemVal = computed<TGApp.App.Calendar.Item>(() => props.dataVal); const itemVal = computed<TGApp.App.Calendar.Item>(() => props.dataVal);
const snackbar = ref(false); const snackbar = ref<boolean>(false);
const onCancel = () => { const onCancel = () => {
visible.value = false; visible.value = false;
@@ -82,7 +83,7 @@ function toDetail(item: TGApp.App.Calendar.Item) {
snackbar.value = true; snackbar.value = true;
return; return;
} }
const url = OBC_CONTENT_API.replace("{content_id}", item.contentId.toString()); const url = Mys.Api.Obc.replace("{contentId}", item.contentId.toString());
createTGWindow(url, "素材详情", item.name, 1200, 800, true); createTGWindow(url, "素材详情", item.name, 1200, 800, true);
} }
</script> </script>

View File

@@ -14,7 +14,8 @@ import TibWikiAvatar from "../../components/itembox/tib-wiki-avatar.vue";
// utils // utils
import { createTGWindow } from "../../utils/TGWindow"; import { createTGWindow } from "../../utils/TGWindow";
import { AppCharacterData } from "../../data"; import { AppCharacterData } from "../../data";
import { OBC_CONTENT_API } from "../../plugins/Mys/interface/utils"; // plugins
import Mys from "../../plugins/Mys";
// snackbar // snackbar
const snackbar = ref(false); const snackbar = ref(false);
@@ -26,7 +27,7 @@ function toOuter(item: TGApp.App.Character.WikiBriefInfo) {
snackbar.value = true; snackbar.value = true;
return; return;
} }
const url = OBC_CONTENT_API.replace("{content_id}", item.contentId.toString()); const url = Mys.Api.Obc.replace("{contentId}", item.contentId.toString());
createTGWindow(url, "角色详情", item.name, 1200, 800, true); createTGWindow(url, "角色详情", item.name, 1200, 800, true);
} }
</script> </script>

View File

@@ -110,23 +110,23 @@ import TOLoading from "../../components/overlay/to-loading.vue";
// utils // utils
import { createTGWindow } from "../../utils/TGWindow"; import { createTGWindow } from "../../utils/TGWindow";
import { AppGCGData } from "../../data"; import { AppGCGData } from "../../data";
// interface // plugins
import { OBC_CONTENT_API } from "../../plugins/Mys/interface/utils"; import Mys from "../../plugins/Mys";
// loading // loading
const loading = ref(true); const loading = ref<boolean>(true);
const allCards = computed(() => AppGCGData); const allCards = computed(() => AppGCGData);
// snackbar // snackbar
const snackbar = ref(false); const snackbar = ref<boolean>(false);
// search // search
const doSearch = ref(false); const doSearch = ref<boolean>(false);
const search = ref(""); const search = ref<string>("");
// data // data
const tab = ref("character"); const tab = ref<string>("character");
const CardsInfoC = ref([] as TGApp.App.GCG.WikiBriefInfo[]); const CardsInfoC = ref<TGApp.App.GCG.WikiBriefInfo[]>([]);
const CardsInfoA = ref([] as TGApp.App.GCG.WikiBriefInfo[]); const CardsInfoA = ref<TGApp.App.GCG.WikiBriefInfo[]>([]);
const CardsInfoM = ref([] as TGApp.App.GCG.WikiBriefInfo[]); const CardsInfoM = ref<TGApp.App.GCG.WikiBriefInfo[]>([]);
const CardsInfoS = ref([] as TGApp.App.GCG.WikiBriefInfo[]); const CardsInfoS = ref<TGApp.App.GCG.WikiBriefInfo[]>([]);
onMounted(async () => { onMounted(async () => {
await loadData(); await loadData();
@@ -144,7 +144,7 @@ async function loadData() {
} }
function toOuter(cardName: string, cardId: number) { function toOuter(cardName: string, cardId: number) {
const url = OBC_CONTENT_API.replace("{content_id}", cardId.toString()); const url = Mys.Api.Obc.replace("{contentId}", cardId.toString());
createTGWindow(url, "GCG", cardName, 1200, 800, true); createTGWindow(url, "GCG", cardName, 1200, 800, true);
} }

View File

@@ -14,10 +14,11 @@ import TibWikiWeapon from "../../components/itembox/tib-wiki-weapon.vue";
// utils // utils
import { createTGWindow } from "../../utils/TGWindow"; import { createTGWindow } from "../../utils/TGWindow";
import { AppWeaponData } from "../../data"; import { AppWeaponData } from "../../data";
import { OBC_CONTENT_API } from "../../plugins/Mys/interface/utils"; // plugins
import Mys from "../../plugins/Mys";
// snackbar // snackbar
const snackbar = ref(false); const snackbar = ref<boolean>(false);
// data // data
const cardsInfo = computed(() => AppWeaponData); const cardsInfo = computed(() => AppWeaponData);
@@ -26,7 +27,7 @@ function toOuter(item: TGApp.App.Weapon.WikiBriefInfo) {
snackbar.value = true; snackbar.value = true;
return; return;
} }
const url = OBC_CONTENT_API.replace("{content_id}", item.contentId.toString()); const url = Mys.Api.Obc.replace("{contentId}", item.contentId.toString());
createTGWindow(url, "武器详情", item.name, 1200, 800, true); createTGWindow(url, "武器详情", item.name, 1200, 800, true);
} }
</script> </script>

View File

@@ -0,0 +1,20 @@
/**
* @file plugins Mys api index.ts
* @description Mys API
* @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.2.1
*/
const MysApi = {
Obc: "https://bbs.mihoyo.com/ys/obc/content/{contentId}/detail?bbs_presentation_style=no_header",
Gacha: "https://api-takumi.mihoyo.com/common/blackboard/ys_obc/v1/gacha_pool?app_sn=ys_obc",
Lottery: "https://bbs-api.miyoushe.com/painter/wapi/lottery/user/show?id={lotteryId}",
News: "https://bbs-api.mihoyo.com/post/wapi/getNewsList?gids={gid}&page_size={pageSize}&type={newsType}&last_id={lastId}",
Position: "https://api-static.mihoyo.com/common/blackboard/ys_obc/v1/home/position?app_sn=ys_obc",
Post: {
Api: "https://bbs-api.mihoyo.com/post/wapi/getPostFull?post_id={postId}",
Referer: "https://bbs.mihoyo.com/",
},
};
export default MysApi;

View File

@@ -1,30 +1,33 @@
/** /**
* @file plugins Mys index.ts * @file plugins Mys index.ts
* @description Mys plugin index * @description Mys plugin index
* @author BTMuli<bt-muli@outlook.com> * @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.1.2 * @since Alpha v0.2.1
*/ */
// Api
import MysApi from "./api";
// Post // Post
import { getPostData } from "./request/post"; import getPostData from "./request/getPostData";
import { PostParser } from "./utils/parser"; import parsePost from "./utils/parsePost";
// Gacha // Gacha
import { getGachaData } from "./request/gacha"; import getGachaData from "./request/getGachaData";
import { getGachaCard } from "./utils/gacha"; import getGachaCard from "./utils/getGachaCard";
// Position // Position
import { getPositionData } from "./request/position"; import getPositionData from "./request/getPositionData";
import { getPositionCard } from "./utils/position"; import getPositionCard from "./utils/getPositionCard";
// News // News
import { getNoticeList, getActivityList, getNewsList } from "./request/news"; import getNewsList from "./request/getNewsList";
import { getNoticeCard, getActivityCard, getNewsCard } from "./utils/news"; import { getNoticeCard, getActivityCard, getNewsCard } from "./utils/getNewsCard";
// Lottery // Lottery
import { getLotteryData } from "./request/lottery"; import getLotteryData from "./request/getLotteryData";
import { getLotteryCard, getLotteryRewardCard } from "./utils/lottery"; import getLotteryCard from "./utils/getLotteryCard";
const MysOper = { const Mys = {
Api: MysApi,
Post: { Post: {
get: getPostData, get: getPostData,
parser: PostParser, parser: parsePost,
}, },
Gacha: { Gacha: {
get: getGachaData, get: getGachaData,
@@ -35,11 +38,7 @@ const MysOper = {
card: getPositionCard, card: getPositionCard,
}, },
News: { News: {
get: { get: getNewsList,
notice: getNoticeList,
activity: getActivityList,
news: getNewsList,
},
card: { card: {
notice: getNoticeCard, notice: getNoticeCard,
activity: getActivityCard, activity: getActivityCard,
@@ -48,11 +47,8 @@ const MysOper = {
}, },
Lottery: { Lottery: {
get: getLotteryData, get: getLotteryData,
card: { card: getLotteryCard,
lottery: getLotteryCard,
reward: getLotteryRewardCard,
},
}, },
}; };
export default MysOper; export default Mys;

View File

@@ -1,82 +0,0 @@
/**
* @file plugins Mys interface base.ts
* @description Mys 插件基础接口
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.2
*/
/**
* @description Mys Response 统一接口
* @since Alpha
* @interface MysResponse
* @property {number} retcode 状态码
* @property {string} message 状态信息
* @property {any} data 数据
* @returns {MysResponse}
*/
export interface MysResponse {
retcode: number;
message: string;
data: any;
}
/**
* @description Mys obc 返回数据
* @since Alpha v0.1.1
* @interface MysObcResponse
* @extends MysResponse
* @property {MysObc[]} data.list obc 列表
* @returns {MysObcResponse}
*/
export interface MysObcResponse extends MysResponse {
data: {
list: MysObc[];
};
}
/**
* @description Mys obc 层级结构
* @since Alpha v0.1.1
* @interface MysObc
* @property {number} id ID
* @property {string} name 名称
* @property {number} parent_id 父ID
* @property {number} depth 深度
* @property {string} ch_ext 结构化扩展信息
* @property {any[]} children 子节点
* @property {unknown[]} list 列表
* @returns {MysObc}
*/
export interface MysObc {
id: number;
name: string;
parent_id: number;
depth: number;
ch_ext: string;
children: MysObc[];
list: unknown[];
}
/**
* @description Mys GID 对应的数据
* @since Alpha v0.1.2
* @interface MysGid
* @enum {number}
* @property {number} 1 崩坏3
* @property {number} 2 原神
* @property {number} 3 崩坏2
* @property {number} 4 未定事件簿
* @property {number} 5 大别野
* @property {number} 6 崩坏:星穹铁道
* @property {number} 8 绝区零
* @returns {MysGid}
*/
export enum MysGid {
BH3 = 1,
YS = 2,
BH2 = 3,
WD = 4,
DBY = 5,
SR = 6,
ZZZ = 8,
}

View File

@@ -1,97 +0,0 @@
/**
* @file plugins Mys interface gacha.ts
* @description Mys 插件抽卡接口
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha
*/
import { type MysResponse } from "./base";
/**
* @description 获取卡池信息的返回类型
* @since Alpha
* @interface GachaResponse
* @extends MysResponse
* @property {GachaData[]} data.list 卡池数据
* @returns {GachaResponse}
*/
export interface GachaResponse extends MysResponse {
data: {
list: GachaData[];
};
}
/**
* @description 获取卡池信息的返回类型
* @since Alpha
* @interface GachaData
* @property {string} id 卡池ID
* @property {string} title 卡池标题
* @property {string} activity_url 卡池对应帖子
* @property {string} content_before_act 卡池内容
* @property {GachaPool[]} pool 卡池包含的角色
* @property {string} voice_icon 卡池角色语音头像
* @property {string} voice_url 卡池角色语音URL
* @property {string} voice_status 卡池角色语音状态
* @description 如下时间示例2023-03-21 17:59:59
* @property {string} start_time 卡池开始时间
* @property {string} end_time 卡池结束时间
* @returns {GachaData}
*/
export interface GachaData {
id: string;
title: string;
activity_url: string;
content_before_act: string;
pool: GachaPool[];
voice_icon: string;
voice_url: string;
voice_status: string;
start_time: string;
end_time: string;
}
/**
* @description 获取卡池信息的返回类型
* @since Alpha
* @interface GachaPool
* @property {string} icon 卡池角色头像
* @property {string} url 卡池角色URL
* @returns {GachaPool}
*/
export interface GachaPool {
icon: string;
url: string;
}
/**
* @description 用于渲染的卡池数据
* @since Alpha v0.1.1
* @interface GachaCard
* @property {string} title 卡池标题
* @property {string} subtitle 卡池副标题
* @property {string} cover 卡池封面
* @property {number} post_id 卡池对应帖子ID
* @property {GachaPool[]} characters 卡池包含的角色
* @property {GachaPool} voice 卡池角色语音
* @property time 卡池时间
* @property {string} time.start 卡池开始时间
* @property {string} time.start_stamp 卡池开始时间戳
* @property {string} time.end 卡池结束时间
* @property {string} time.end_stamp 卡池结束时间戳
* @returns {GachaCard}
*/
export interface GachaCard {
title: string;
subtitle: string;
cover: string;
post_id: number;
characters: GachaPool[];
voice: GachaPool;
time: {
start: string;
start_stamp: number;
end: string;
end_stamp: number;
};
}

View File

@@ -1,121 +0,0 @@
/**
* @file plugins Mys interface lottery.ts
* @description Mys 插件抽奖接口
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.2
*/
import { type MysResponse } from "./base";
import { type UserInfoPost } from "./user";
/**
* @description 抽奖返回数据
* @since Alpha v0.1.1
* @interface LotteryResponse
* @extends {MysResponse}
* @property {LotteryData} data.show_lottery 抽奖数据
* @returns {LotteryResponse}
*/
export interface LotteryResponse extends MysResponse {
data: {
show_lottery: LotteryData;
};
}
/**
* @description 抽奖数据
* @since Alpha v0.1.1
* @interface LotteryData
* @property {string} id 抽奖 ID
* @property {UserInfoPost} creator 创建者
* @property {string} draw_time 抽奖时间
* @property {string} participant_way 参与方式 // Forward: 转发
* @property {boolean} is_expect_unfocus_user 是否限制未关注用户
* @property {boolean} is_expect_non_real_name_user 是否限制未实名用户
* @property {LotteryReward[]} user_rewards 用户奖励
* @property {string} status 状态 // Settled: 已结算
* @property {boolean} is_blocked 是否被屏蔽
* @property {string} user_status 用户状态 // NotParticipant: 未参与
* @property {boolean} is_upload_address 是否上传地址
* @property {string} lottery_entity_summary 抽奖实体摘要
* @property {string} entity_id 实体 ID // 若为帖子,则为帖子 ID
* @property {string} entity_type 实体类型 // Post: 帖子
* @property {string} now_time 当前时间
* @returns {LotteryData}
*/
export interface LotteryData {
id: string;
creator: UserInfoPost;
draw_time: string;
participant_way: string;
is_expect_unfocus_user: boolean;
is_expect_non_real_name_user: boolean;
user_rewards: LotteryReward[];
status: string;
is_blocked: boolean;
user_status: string;
is_upload_address: boolean;
lottery_entity_summary: string;
entity_id: string;
entity_type: string;
now_time: string;
}
/**
* @description 抽奖奖励
* @since Alpha v0.1.1
* @interface LotteryReward
* @property {string} reward_name 奖励名称
* @property {number} winner_number 获奖人数
* @property {number} scheduled_winner_number 预计获奖人数
* @property {boolean} is_send_by_post 是否通过帖子发放
* @property {User[]} users 用户列表
* @property {string} id 奖励 ID
* @returns {LotteryReward}
*/
export interface LotteryReward {
reward_name: string;
winner_number: number;
scheduled_winner_number: number;
is_send_by_post: boolean;
users: UserInfoPost[];
id: string;
}
/**
* @description 渲染用的抽奖信息
* @since Alpha v0.1.1
* @interface LotteryCard
* @property {string} id 抽奖 ID
* @property {string} participantWay 参与方式
* @property {string} status 状态
* @property {User} creator 创建者
* @property {string} drawTime 开奖时间
* @property {LotteryRewardCard[]} rewards 奖励列表
* @returns {LotteryCard}
*/
export interface LotteryCard {
id: string;
participantWay: string;
status: string;
creator: UserInfoPost;
drawTime: string;
rewards: LotteryRewardCard[];
}
/**
* @description 渲染用的奖励信息
* @since Alpha v0.1.2
* @interface LotteryRewardCard
* @property {string} rewardName 奖励名称
* @property {number} winnerNumber 获奖人数
* @property {number} scheduledWinnerNumber 预计获奖人数
* @property {User[]} users 用户列表
* @returns {LotteryRewardCard}
*/
export interface LotteryRewardCard {
rewardName: string;
winnerNumber: number;
scheduledWinnerNumber: number;
users: UserInfoPost[];
}

View File

@@ -1,135 +0,0 @@
/**
* @file plugins Mys interface news.ts
* @description Mys 插件咨讯接口
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.2
*/
import { type MysResponse } from "./base";
import { type Post, type Forum, type Topic, type PostStat } from "./post";
import { type UserInfoPost, type SelfOperation } from "./user";
import { type ImageData, type HelpSys } from "./utils";
/**
* @description 咨讯返回数据
* @since Alpha
* @interface NewsResponse
* @extends {MysResponse}
* @property {NewsData} data 咨讯数据
* @returns {NewsResponse}
*/
export interface NewsResponse extends MysResponse {
data: NewsData;
}
/**
* @description 咨讯数据
* @since Alpha
* @interface NewsData
* @property {number} last_id 最后一条咨讯 ID
* @property {boolean} is_last 是否最后一页
* @property {NewsItem[]} list 咨讯列表
* @returns {NewsData}
*/
export interface NewsData {
last_id: number;
is_last: boolean;
list: NewsItem[];
}
/**
* @description 咨讯列表项
* @since Alpha v0.1.2
* @interface NewsItem
* @property {Post} post 帖子
* @property {Forum} forum 版块
* @property {Topic[]} topics 话题
* @property {UserInfoPost} user 发帖用户
* @property {SelfOperation} self_operation 用户操作
* @property {PostStat} stat 帖子统计
* @property {HelpSys} help_sys 帮助系统,可能为 null
* @property {ImageData} cover 封面图片 URL
* @property {ImageData[]} image_list 图片列表
* @property {boolean} is_official_master 是否为官方
* @property {boolean} is_user_master 是否用户
* @property {boolean} hot_reply_exist 是否热门回复
* @property {number} vote_count 投票数
* @property {number} last_modify_time 最后修改时间
* @property {string} recommend_type 推荐类型
* @property {unknown} collection 合集, 可能为 null // TODO: 未知
* @property {unknown[]} vod_list 视频列表
* @property {boolean} is_block_on 是否屏蔽
* @property {unknown} forum_rank_info 版块排名信息,可能为 null // TODO: 未知
* @property {unknown[]} link_card_list 链接卡片列表,可能为 null // TODO: 未知
* @property {NewsMeta} news_meta 元数据
* @returns {NewsItem}
*/
export interface NewsItem {
post: Post;
forum: Forum;
topics: Topic[];
user: UserInfoPost;
self_operation: SelfOperation;
stat: PostStat;
help_sys: HelpSys;
cover: ImageData;
image_list: ImageData[];
is_official_master: boolean;
is_user_master: boolean;
hot_reply_exist: boolean;
vote_count: number;
last_modify_time: number;
recommend_type: string;
collection: unknown;
vod_list: unknown[];
is_block_on: boolean;
forum_rank_info: unknown;
link_card_list: unknown[];
news_meta: NewsMeta;
}
/**
* @description 咨讯元数据,只有活动咨讯才有
* @since Alpha
* @interface NewsMeta
* @property {number} activity_status 活动状态 // ActivityStatus
* @property {string} start_at_sec 活动开始时间戳,单位秒
* @property {string} end_at_sec 活动结束时间戳,单位秒
* @returns {NewsMeta}
*/
export interface NewsMeta {
activity_status: number;
start_at_sec: string;
end_at_sec: string;
}
/**
* @description 用于渲染的咨讯卡片
* @since Alpha
* @interface NewsCard
* @property {string} title 标题
* @property {string} cover 封面图片 URL
* @property {number} post_id 帖子 ID
* @property {string} subtitle 副标题
* @property {ActivityStatus} status 活动状态,仅活动咨讯有
* @returns {NewsCard}
*/
export interface NewsCard {
title: string;
cover: string;
post_id: number;
subtitle: string;
status?: ActivityStatus;
}
/**
* @description 活动状态
* @since Alpha
* @property {string} status 活动状态
* @property {string} colorCss 活动状态按钮背景色
* @returns {ActivityStatus}
*/
export interface ActivityStatus {
status: string;
colorCss: string;
}

View File

@@ -1,97 +0,0 @@
/**
* @file plugins Mys interface position.ts
* @description Mys 插件热点追踪接口
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.1
*/
import { type MysObcResponse, type MysObc } from "./base";
/**
* @description 获取热点追踪信息的返回类型
* @since Alpha v0.1.1
* @interface PositionResponse
* @extends MysObcResponse
* @property {PositionObc[]} data.list obc 列表
* @returns {PositionResponse}
*/
export interface PositionResponse extends MysObcResponse {
data: {
list: PositionObc[];
};
}
/**
* @description 热点追踪层级结构
* @since Alpha v0.1.1
* @interface PositionObc
* @extends MysObc
* @property {PositionData[]} list 列表
* @returns {PositionObc}
*/
export interface PositionObc extends MysObc {
list: PositionData[];
}
/**
* @description 热点追踪信息
* @since Alpha v0.1.1
* @interface PositionData
* @property {number} recommend_id 推荐ID
* @property {number} content_id 内容ID
* @property {string} title 标题
* @property {string} ext 扩展信息
* @property {number} type 类型
* @property {string} url 链接
* @property {string} icon 图标
* @property {string} abstract 摘要
* @property {string} article_user_name 作者
* @property {string} avatar_url 头像
* @property {string} article_time 时间
* @property {string} create_time 创建时间 // 2023-03-31 11:16:57
* @property {string} end_time 结束时间 // 1680465599000
* @returns {PositionData}
*/
export interface PositionData {
recommend_id: number;
content_id: number;
title: string;
ext: string;
type: number;
url: string;
icon: string;
abstract: string;
article_user_name: string;
avatar_url: string;
article_time: string;
create_time: string;
end_time: string;
}
/**
* @description 渲染用的热点追踪信息
* @since Alpha v0.1.1
* @interface PositionCard
* @property {string} title 标题
* @property {number} post_id 帖子ID
* @property {string} icon 图标
* @property {string} abstract 摘要
* @property time 时间
* @property {string} time.start 开始时间
* @property {number} time.start_stamp 开始时间戳
* @property {string} time.end 结束时间
* @property {number} time.end_stamp 结束时间戳
* @returns {PositionCard}
*/
export interface PositionCard {
title: string;
post_id: number;
icon: string;
abstract: string;
time: {
start: string;
start_stamp: number;
end: string;
end_stamp: number;
};
}

View File

@@ -1,376 +0,0 @@
/**
* @file plugins Mys interface post.ts
* @description Mys 插件帖子接口
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.2
*/
import { type MysResponse } from "./base";
import { type NewsMeta } from "./news";
import { type UserInfoPost, type SelfOperation } from "./user";
import { type ImageData, type HelpSys } from "./utils";
/**
* @description 帖子返回数据
* @since Alpha
* @interface PostResponse
* @extends {MysResponse}
* @property {PostData} data.post 帖子数据
* @returns {PostResponse}
*/
export interface PostResponse extends MysResponse {
data: {
post: PostData;
};
}
/**
* @description 帖子数据
* @since Alpha
* @interface PostData
* @property {Post} post 帖子信息
* @property {Forum} forum 所属版块
* @property {Topic[]} topics 所属话题
* @property {User} user 发帖人
* @property {SelfOperation} self_operation 当前用户操作
* @property {PostStat} stat 帖子统计
* @property {HelpSys} help_sys 帮助系统,可能为 null
* @property {ImageData} cover 封面图,可能为 null
* @property {ImageData[]} image_list 图片列表
* @property {boolean} is_official_master 是否为官方帖
* @property {boolean} is_user_master 是否为用户帖
* @property {boolean} hot_reply_exist 是否存在热门回复
* @property {number} vot_count 投票数
* @property {number} last_modify_time 最后修改时间
* @property {string} recommend_type 推荐类型
* @property {unknown} collection 合集,可能为 null // TODO: 未知
* @property {unknown[]} vod_list 视频列表,可能为空 // TODO: 未知
* @property {boolean} is_block_on 是否被屏蔽
* @property {unknown} forum_rank_info 版块排行信息,可能为 null // TODO: 未知
* @property {unknown[]} link_card_list 链接卡片列表,可能为空 // TODO: 未知
* @property {NewsMeta} news_meta 咨讯元数据,可能为 null
* @returns {PostData}
*/
export interface PostData {
post: Post;
forum: Forum;
topics: Topic[];
user: UserInfoPost;
self_operation: SelfOperation;
stat: PostStat;
help_sys: HelpSys | null;
cover: ImageData | null;
image_list: ImageData[];
is_official_master: boolean;
is_user_master: boolean;
hot_reply_exist: boolean;
vot_count: number;
last_modify_time: number;
recommend_type: string;
collection: unknown | null;
vod_list: unknown[];
is_block_on: boolean;
forum_rank_info: unknown | null;
link_card_list: unknown[];
news_meta: NewsMeta | null;
}
/**
* @description 帖子信息
* @since Alpha
* @interface Post
* @property {number} game_id 游戏 ID // 2 为原神
* @property {string} post_id 帖子 ID
* @property {number} f_forum_id 所属版块 ID
* @property {string} uid 发帖人 UID
* @property {string} subject 帖子标题
* @property {string} content 帖子内容,为 html 格式
* @property {string} cover 封面图 URL可能为 ""
* @property {number} view_type 浏览类型 // TODO: 未知
* @property {number} created_at 发帖时间
* @property {string[]} images 图片列表,可能为空
* @property post_status 帖子状态
* @property {boolean} post_status.is_top 是否置顶
* @property {boolean} post_status.is_good 是否加精
* @property {boolean} post_status.is_official 是否官方
* @property {number[]} topic_ids 所属话题 ID 列表
* @property {number} view_status 浏览状态
* @property {number} max_floor 最大楼层
* @property {number} is_original 是否原创
* @property {number} republish_authorization 是否授权转载
* @property {string} reply_time 最后回复时间 // "2023-03-05 20:26:54"
* @property {number} is_deleted 是否删除
* @property {boolean} is_interactive 是否互动
* @property {string} structured_content 结构化内容 // 反序列化后为 PostStructuredContent
* @property {string[]} structured_content_rows 结构化内容原始数据
* @property {number} review_id 审核ID
* @property {boolean} is_profit 是否盈利
* @property {boolean} is_in_profit 是否在盈利
* @property {number} updated_at 更新时间
* @property {number} deleted_at 删除时间
* @property {number} pre_pub_status 预发布状态
* @property {number} cate_id 分类ID
* @property {number} profit_post_status 盈利帖子状态 // TODO: 未知
* @property {number} audit_status 审核状态
* @property {string} meta_content 元内容,可能为 "" // TODO: 未知
* @property {boolean} is_missing 是否缺失 // TODO: 未知
* @property {number} block_reply_img 是否屏蔽回复图片 // TODO: 未知
* @property {boolean} is_showing_missing 是否显示缺失 // TODO: 未知
* @property {number} block_latest_reply_time 是否屏蔽最新回复时间 // TODO: 未知
* @property {number} selected_comment 是否选择评论 // TODO: 未知
* @returns {Post}
*/
export interface Post {
game_id: number;
post_id: string;
f_forum_id: number;
uid: string;
subject: string;
content: string;
cover: string;
view_type: number;
created_at: number;
images: string[];
post_status: {
is_top: boolean;
is_good: boolean;
is_official: boolean;
};
topic_ids: number[];
view_status: number;
max_floor: number;
is_original: number;
republish_authorization: number;
reply_time: string;
is_deleted: number;
is_interactive: boolean;
structured_content: string;
structured_content_rows: string[];
review_id: number;
is_profit: boolean;
is_in_profit: boolean;
updated_at: number;
deleted_at: number;
pre_pub_status: number;
cate_id: number;
profit_post_status: number;
audit_status: number;
meta_content: string;
is_missing: boolean;
block_reply_img: number;
is_showing_missing: boolean;
block_latest_reply_time: number;
selected_comment: number;
}
/**
* @description 版块信息
* @since Alpha
* @interface Forum
* @property {number} id 版块 ID
* @property {string} name 版块名称
* @property {string} icon 版块图标 URL
* @property {number} game_id 游戏 ID // 2 为原神
* @property {unknown} forum_cate 版块分类,可能为 null
* @returns {Forum}
*/
export interface Forum {
id: number;
name: string;
icon: string;
game_id: number;
forum_cate: unknown | null;
}
/**
* @description 话题信息
* @since Alpha
* @interface Topic
* @property {number} id 话题 ID
* @property {string} name 话题名称
* @property {string} cover 话题封面图 URL
* @property {boolean} is_top 是否置顶
* @property {boolean} is_good 是否加精
* @property {boolean} is_interactive 是否互动
* @property {number} game_id 游戏 ID
* @property {number} content_type 内容类型
* @returns {Topic}
*/
export interface Topic {
id: number;
name: string;
cover: string;
is_top: boolean;
is_good: boolean;
is_interactive: boolean;
game_id: number;
content_type: number;
}
/**
* @description 帖子状态
* @since Alpha
* @interface PostStat
* @property {number} view_num 浏览数
* @property {number} reply_num 回复数
* @property {number} like_num 点赞数
* @property {number} bookmark_num 收藏数
* @property {number} forward_num 转发数
* @returns {PostStat}
*/
export interface PostStat {
view_num: number;
reply_num: number;
like_num: number;
bookmark_num: number;
forward_num: number;
}
/**
* @description 帖子内容-结构化
* @description 当用户发帖时,解析内容用这个,为 post.content 的反序列化
* @since Alpha v0.1.1
* @interface PostContent
* @property {string} describe 描述
* @property {string[]} imgs 图片 URL
* @returns {PostContent}
*/
export interface PostContent {
describe: string;
imgs?: string[];
}
/**
* @description 帖子结构化内容
* @since Alpha v0.1.2
* @interface PostStructuredContent
* @property {string|object} insert 插入内容
* @property {string} insert.image 图片 URL
* @property {PostStructuredContentVod} insert.vod 视频信息
* @property {string} insert.video 外部视频 URL
* @property {string} insert.backup_text 折叠文本
* @property {object} insert.lottery 抽奖,当 backup_text 为 [抽奖]
* @property {string} insert.lottery.id 抽奖 ID
* @property {string} insert.lottery.toast 抽奖提示
* @property {object} insert.fold 折叠内容
* @property {string} insert.fold.title 折叠标题,反序列化后为 PostStructuredContent[]
* @property {string} insert.fold.content 折叠文本,反序列化后为 PostStructuredContent[]
* @property {PostStructuredContentLinkCard} insert.link_card 链接卡片
* @property {string} insert.divider 分割线
* @property {object} insert.mention 提及
* @property {string} insert.mention.uid 用户 ID
* @property {string} insert.mention.nickname 用户昵称
* @property {object} attributes 属性
* @property {number} attributes.height 高度
* @property {number} attributes.width 宽度
* @property {number} attributes.size 大小
* @property {string} attributes.ext 扩展名
* @property {boolean} attributes.bold 是否加粗
* @property {string} attributes.color 颜色
* @property {string} attributes.link 链接
* @returns {PostStructuredContent}
*/
export interface PostStructuredContent {
insert:
| {
image?: string;
video?: string;
vod?: PostStructuredContentVod;
backup_text?: string;
lottery?: {
id: string;
toast: string;
};
fold?: {
title: string;
content: string;
};
link_card?: PostStructuredContentLinkCard;
divider?: string;
mention?: {
uid: string;
nickname: string;
};
}
| string;
attributes?: {
height?: number;
width?: number;
size?: number;
ext?: string;
bold?: boolean;
color?: string;
link?: string;
};
}
/**
* @description 帖子结构化内容-视频
* @since Alpha v0.1.1
* @interface PostStructuredContentVod
* @property {number} id 视频 ID
* @property {number} duration 时长
* @property {string} cover 封面图 URL
* @property {object[]} resolutions 分辨率
* @property {string} resolutions.url URL
* @property {string} resolutions.definition 清晰度
* @property {number} resolutions.height 高度
* @property {number} resolutions.width 宽度
* @property {number} resolutions.bitrate 比特率
* @property {number} resolutions.size 大小
* @property {string} resolutions.format 格式
* @property {string} resolutions.label 标签
* @property {number} view_num 浏览数
* @property {number} transcode_status 转码状态
* @property {number} review_status 审核状态
* @returns {PostStructuredContentVod}
*/
export interface PostStructuredContentVod {
id: number;
duration: number;
cover: string;
resolutions: Array<{
url: string;
definition: string;
height: number;
width: number;
bitrate: number;
size: number;
format: string;
label: string;
}>;
view_num: number;
transcoding_status: number;
review_status: number;
}
/**
* @description 帖子结构化内容-链接卡片
* @since Alpha v0.1.1
* @interface PostStructuredContentLinkCard
* @property {number} link_type 链接类型 // 1: 帖子2商品 TODO: 未知
* @property {string} origin_url 原始链接
* @property {string} landing_url 落地页链接
* @property {string} cover 封面图 URL
* @property {string} title 标题
* @property {string} card_id 卡片 ID
* @property {number} card_status 卡片状态 // TODO: 未知
* @property {string} market_price 市场价
* @property {string} price 价格
* @property {string} button_text 按钮文本
* @property {number} landing_url_type 落地链接类型 // TODO: 未知
* @returns {PostStructuredContentLinkCard}
*/
export interface PostStructuredContentLinkCard {
link_type: number;
origin_url: string;
landing_url: string;
cover: string;
title: string;
card_id: string;
card_status: number;
market_price: string;
price: string;
button_text: string;
landing_url_type: number;
}

View File

@@ -1,271 +0,0 @@
/**
* @file plugins Mys interface user.ts
* @description Mys 插件用户接口
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.2
*/
import { type MysResponse } from "./base";
/**
* @description 用户信息返回数据-在米游社用户主页中的用户信息
* @since Alpha v0.1.2
* @interface UserResponse
* @extends {MysResponse}
* @property {UserInfoFull} data 用户信息
* @returns {UserResponse}
*/
export interface UserResponse extends MysResponse {
data: UserInfoFull;
}
/**
* @description 用户信息-在米游社用户主页中的用户信息
* @since Alpha v0.1.2
* @interface UserInfoFull
* @property {UserInfo} user_info 用户信息
* @property {unknown} follow_relation 关注关系
* @property {unknown[]} auth_relations 认证关系
* @property {boolean} is_in_blacklist 是否在黑名单中
* @property {boolean} is_has_collection 是否有收藏
* @property {boolean} is_creator 是否是创作者
* @property custom_service 客服信息
* @property {boolean} custom_service.is_customer_service_staff 是否是客服
* @property {number} custom_service.game_id 游戏 ID
* @property audit_info 审核信息
* @property {boolean} audit_info.is_nickname_in_audit 是否在昵称审核中
* @property {string} audit_info.nickname 审核中的昵称
* @property {boolean} audit_info.is_introduce_in_audit 是否在简介审核中
* @property {string} audit_info.introduce 审核中的简介
* @property {number} audit_info.nickname_status 昵称审核状态
* @returns {UserInfoFull}
*/
export interface UserInfoFull {
user_info: UserInfo;
follow_relation: unknown;
auth_relations: unknown[];
is_in_blacklist: boolean;
is_has_collection: boolean;
is_creator: boolean;
custom_service: {
is_customer_service_staff: boolean;
game_id: number;
};
audit_info: {
is_nickname_in_audit: boolean;
nickname: string;
is_introduce_in_audit: boolean;
introduce: string;
nickname_status: number;
};
}
/**
* @description 用户信息-在米游社用户主页中的用户信息
* @since Alpha v0.1.2
* @interface UserInfo
* @property {string} uid 用户 ID
* @property {string} nickname 用户昵称
* @property {string} introduce 用户简介
* @property {string} avatar 用户头像编号
* @property {number} gender 用户性别
* @property {UserCertification} certification 用户认证信息
* @property {UserLevelExp[]} level_exps 用户等级经验
* @property {UserArchive} archive 用户档案
* @property {UserCommunityInfo} community_info 用户社区信息
* @property {string} avatar_url 用户头像链接
* @property {UserCertification[]} certifications 用户认证信息
* @property {UserLevelExp} level_exp 用户等级经验
* @property {string} pendant 用户挂件 URL可能为 ""
* @property {boolean} is_logoff 是否注销
* @property {string} ip_region 用户 IP 地区
* @returns {UserInfo}
*/
export interface UserInfo {
uid: string;
nickname: string;
introduce: string;
avatar: string;
gender: number;
certification: UserCertification;
level_exps: UserLevelExp[];
archive: UserArchive;
community_info: UserCommunityInfo;
avatar_url: string;
certifications: UserCertification[];
level_exp: UserLevelExp;
pendant: string;
is_logoff: boolean;
ip_region: string;
}
/**
* @description 用户认证信息
* @since Alpha v0.1.2
* @interface UserCertification
* @property {number} type 认证类型
* @property {string} label 认证标签
* @returns {UserCertification}
*/
export interface UserCertification {
type: number;
label: string;
}
/**
* @description 用户等级经验
* @since Alpha v0.1.2
* @interface UserLevelExp
* @property {number} level 用户等级
* @property {number} exp 用户经验
* @see MysGid 游戏 ID
* @property {number} game_id 游戏 ID
* @returns {UserLevelExp}
*/
export interface UserLevelExp {
level: number;
exp: number;
game_id: number;
}
/**
* @description 用户档案
* @since Alpha v0.1.2
* @interface UserArchive
* @property {string} like_num 获赞数
* @property {string} post_num 发帖数
* @property {string} replypost_num 回帖数
* @property {string} follow_cnt 关注数
* @property {string} followed_cnt 被关注数
* @property {string} topic_cnt 话题数
* @property {string} new_follower_num 新粉丝数
* @property {string} good_post_num 精华帖数
* @property {string} follow_collection_cnt 收藏数
* @returns {UserArchive}
*/
export interface UserArchive {
like_num: string;
post_num: string;
replypost_num: string;
follow_cnt: string;
followed_cnt: string;
topic_cnt: string;
new_follower_num: string;
good_post_num: string;
follow_collection_cnt: string;
}
/**
* @description 用户社区信息
* @since Alpha v0.1.2
* @interface UserCommunityInfo
* @property {boolean} is_realname 是否实名
* @property {boolean} agree_status 是否同意协议
* @property {number} silent_end_time 禁言结束时间
* @property {number} forbid_end_time 封禁结束时间
* @property {number} info_upd_time 信息更新时间
* @property privacy_invisible 用户隐私设置
* @property {boolean} privacy_invisible.post 是否隐藏发帖
* @property {boolean} privacy_invisible.collect 是否隐藏收藏
* @property {boolean} privacy_invisible.watermark 是否隐藏水印
* @property {boolean} privacy_invisible.reply 是否隐藏回复
* @property {boolean} privacy_invisible.post_and_instant 是否隐藏发帖和即时
* @property notify_disable 用户通知设置
* @property {boolean} notify_disable.reply 是否禁用回复通知
* @property {boolean} notify_disable.upvote 是否禁用点赞通知
* @property {boolean} notify_disable.follow 是否禁用关注通知
* @property {boolean} notify_disable.system 是否禁用系统通知
* @property {boolean} notify_disable.chat 是否禁用聊天通知
* @property {boolean} has_initialized 是否初始化
* @property user_func_status 用户功能状态
* @property {boolean} user_func_status.enable_history_view 是否启用历史记录
* @property {boolean} user_func_status.enable_recommend 是否启用推荐
* @property {boolean} user_func_status.enable_mention 是否启用提及
* @property {number} user_func_status.user_center_view 是否启用用户中心\
* @property {unknown[]} forum_silent_info 论坛禁言信息
* @property {string} last_login_ip 上次登录 IP
* @property {number} last_login_time 上次登录时间
* @property {number} created_at 创建时间
* @returns {UserCommunityInfo}
*/
export interface UserCommunityInfo {
is_realname: boolean;
agree_status: boolean;
silent_end_time: number;
forbid_end_time: number;
info_upd_time: number;
privacy_invisible: {
post: boolean;
collect: boolean;
watermark: boolean;
reply: boolean;
post_and_instant: boolean;
};
notify_disable: {
reply: boolean;
upvote: boolean;
follow: boolean;
system: boolean;
chat: boolean;
};
has_initialized: boolean;
user_func_status: {
enable_history_view: boolean;
enable_recommend: boolean;
enable_mention: boolean;
user_center_view: number;
};
forum_silent_info: unknown[];
last_login_ip: string;
last_login_time: number;
created_at: number;
}
/**
* @description 用户信息-在 post 中的用户信息
* @since Alpha v0.1.2
* @interface UserInfoPost
* @property {string} uid 用户 ID
* @property {string} nickname 用户昵称
* @property {string} introduce 用户简介
* @property {string} avatar 用户头像 // TODO: 转换为图片链接
* @property {number} gender 用户性别 // TODO: 未知
* @property {UserCertification} certification 用户认证信息
* @property level_exp 用户等级经验
* @property {number} level_exp.level 用户等级
* @property {number} level_exp.exp 用户经验
* @property {boolean} is_following 是否关注
* @property {boolean} is_follower 是否被关注
* @property {string} avatar_url 用户头像链接
* @property {string} pendant 用户挂件 URL可能为 ""
* @returns {UserInfoPost}
*/
export interface UserInfoPost {
uid: string;
nickname: string;
introduce: string;
avatar: string;
gender: number;
certification: UserCertification;
level_exp: {
level: number;
exp: number;
};
is_following: boolean;
is_follower: boolean;
avatar_url: string;
pendant: string;
}
/**
* @description 用户操作
* @since Alpha
* @interface SelfOperation
* @property {number} attitude 操作类型 // TODO: 未知
* @property {boolean} is_collected 是否收藏
* @returns {SelfOperation}
*/
export interface SelfOperation {
attitude: number;
is_collected: boolean;
}

View File

@@ -1,77 +0,0 @@
/**
* @file plugins Mys interface utils.ts
* @description Mys 插件工具接口
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha
*/
// 杂项 API
/**
* @description 观测枢 content API
* @since Alpha
* @param {string} content_id 内容 ID
* @returns {string} API
*/
export const OBC_CONTENT_API =
"https://bbs.mihoyo.com/ys/obc/content/{content_id}/detail?bbs_presentation_style=no_header";
// 杂项接口
/**
* @description 图片数据
* @since Alpha
* @interface ImageData
* @property {string} url 图片 URL
* @property {number} height 图片高度
* @property {string} width 图片宽度
* @property {string} format 图片格式 // jpg
* @property {string} size 图片大小 // 281428
* @property crop 图片裁剪信息,可能为 null
* @property {number} crop.x 裁剪 X 轴
* @property {number} crop.y 裁剪 Y 轴
* @property {number} crop.w 裁剪宽度
* @property {number} crop.h 裁剪高度
* @property {string} crop.url 裁剪图片 URL
* @property {boolean} is_user_set_cover 是否为封面
* @property {string} image_id 图片 ID
* @property {string} entity_type 图片类型 // IMG_ENTITY_POST, IMG_ENTITY_UNKOWN
* @property {string} entity_id 图片 ID
* @property {boolean} is_deleted 是否已删除
* @returns {ImageData}
*/
export interface ImageData {
url: string;
height: number;
width: number;
format: string;
size: string;
crop: {
x: number;
y: number;
w: number;
h: number;
url: string;
} | null;
is_user_set_cover: boolean;
image_id: string;
entity_type: string;
entity_id: string;
is_deleted: boolean;
}
/**
* @description help_sys 信息
* @since Alpha
* @todo 用处未知
* @interface HelpSys
* @property {unknown} top_up 置顶, 可能为 null // TODO: 未知
* @property {unknown[]} top_n 置顶, 可能为空
* @property {number} answer_num 回答数
* @returns {HelpSys}
*/
export interface HelpSys {
top_up: unknown | null;
top_n: unknown[];
answer_num: number;
}

View File

@@ -1,31 +0,0 @@
/**
* @file plugins Mys request gacha.ts
* @description Mys抽卡请求
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha
*/
import { http } from "@tauri-apps/api";
import { type GachaResponse, type GachaData } from "../interface/gacha";
// 卡池 API
const GACHA_POOL_API =
"https://api-takumi.mihoyo.com/common/blackboard/ys_obc/v1/gacha_pool?app_sn=ys_obc";
/**
* @description 获取卡池信息
* @since Alpha
* @return {Promise<GachaData[]>}
*/
export async function getGachaData(): Promise<GachaData[]> {
return await http
.fetch<GachaResponse>(GACHA_POOL_API, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then((res) => {
return res.data.data.list;
});
}

View File

@@ -0,0 +1,29 @@
/**
* @file plugins Mys request getGachaData.ts
* @description Mys 抽卡请求
* @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.2.1
*/
import { http } from "@tauri-apps/api";
import MysApi from "../api";
/**
* @description 获取卡池信息
* @since Alpha v0.2.1
* @return {Promise<TGApp.Plugins.Mys.Gacha.Data[]>}
*/
async function getGachaData(): Promise<TGApp.Plugins.Mys.Gacha.Data[]> {
return await http
.fetch<TGApp.Plugins.Mys.Gacha.Response>(MysApi.Gacha, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then((res) => {
return res.data.data.list;
});
}
export default getGachaData;

View File

@@ -0,0 +1,30 @@
/**
* @file plugins Mys interface getLotteryData.ts
* @description Mys 插件抽奖接口
* @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.2.1
*/
import { http } from "@tauri-apps/api";
import MysApi from "../api";
/**
* @description 获取抽奖信息
* @since Alpha v0.2.1
* @param {string} lotteryId 抽奖 ID
* @return {Promise<TGApp.Plugins.Mys.Lottery.FullData>}
*/
async function getLotteryData(lotteryId: string): Promise<TGApp.Plugins.Mys.Lottery.FullData> {
return await http
.fetch<TGApp.Plugins.Mys.Lottery.Response>(MysApi.Lottery.replace("{lotteryId}", lotteryId), {
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then((res) => {
return res.data.data.show_lottery;
});
}
export default getLotteryData;

View File

@@ -0,0 +1,33 @@
/**
* @file plugins Mys request getNewsList.ts
* @description Mys 插件咨讯请求
* @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.2.1
*/
import { http } from "@tauri-apps/api";
import MysApi from "../api";
/**
* @description 获取 News 列表
* @since Alpha v0.2.1
* @param {string} gid GID
* @param {string} newsType 咨讯类型: 1 为公告2 为活动3 为咨讯
* @param {number} pageSize 返回数量
* @param {number} lastId 上一次请求的最后一条数据的 id
* @return {Promise<TGApp.Plugins.Mys.News.FullData>}
*/
async function getNewsList(
gid: string = "2",
newsType: string = "1",
pageSize: number = 20,
lastId: number = 0,
): Promise<TGApp.Plugins.Mys.News.FullData> {
const url = MysApi.News.replace("{pageSize}", pageSize.toString())
.replace("{gid}", gid)
.replace("{newsType}", newsType)
.replace("{lastId}", lastId.toString());
return await http.fetch<TGApp.Plugins.Mys.News.Response>(url).then((res) => res.data.data);
}
export default getNewsList;

View File

@@ -0,0 +1,49 @@
/**
* @file plugins Mys request getPositionData.ts
* @description Mys 插件热点追踪请求
* @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.2.1
*/
import { http } from "@tauri-apps/api";
import MysApi from "../api";
/**
* @description 深度优先遍历
* @since Alpha v0.2.1
* @param {TGApp.Plugins.Mys.Position.ObcItem[]} list 列表
* @returns {TGApp.Plugins.Mys.Position.Data[]} 返回列表
*/
function DfsObc(list: TGApp.Plugins.Mys.Position.ObcItem[]): TGApp.Plugins.Mys.Position.Data[] {
const res: TGApp.Plugins.Mys.Position.Data[] = [];
for (const item of list) {
if (item.name === "近期活动") {
res.push(...item.list);
}
if (item.children) {
res.push(...DfsObc(<TGApp.Plugins.Mys.Position.ObcItem[]>item.children));
}
}
return res;
}
/**
* @description 获取热点追踪信息
* @since Alpha v0.2.1
* @return {Promise<TGApp.Plugins.Mys.Position.Data[]>}
*/
async function getPositionData(): Promise<TGApp.Plugins.Mys.Position.Data[]> {
const res = await http
.fetch<TGApp.Plugins.Mys.Position.Response>(MysApi.Position, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then((res) => {
return res.data.data.list;
});
return DfsObc(res);
}
export default getPositionData;

View File

@@ -0,0 +1,32 @@
/**
* @file plugins Mys request getPostData.ts
* @description Mys帖子请求
* @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.2.1
*/
import { http } from "@tauri-apps/api";
import MysApi from "../api";
/**
* @description 获取帖子信息
* @since Alpha v0.2.1
* @param {number} postId 帖子 ID
* @return {Promise<TGApp.Plugins.Mys.Post.FullData>}
*/
async function getPostData(postId: number): Promise<TGApp.Plugins.Mys.Post.FullData> {
const url = MysApi.Post.Api.replace("{postId}", postId.toString());
return await http
.fetch<TGApp.Plugins.Mys.Post.Response>(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
Referer: MysApi.Post.Referer,
},
})
.then((res) => {
return res.data.data.post;
});
}
export default getPostData;

View File

@@ -1,32 +0,0 @@
/**
* @file plugins Mys interface lottery.ts
* @description Mys 插件抽奖接口
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.2
*/
import { http } from "@tauri-apps/api";
import { type LotteryResponse, type LotteryData } from "../interface/lottery";
// 抽奖 API
const LOTTERY_API =
"https://bbs-api.miyoushe.com/painter/wapi/lottery/user/show?gids=2&id={lottery_id}";
/**
* @description 获取抽奖信息
* @since Alpha v0.1.2
* @param {string} lotteryId 抽奖 ID
* @return {Promise<LotteryData>}
*/
export async function getLotteryData(lotteryId: string): Promise<LotteryData> {
return await http
.fetch<LotteryResponse>(LOTTERY_API.replace("{lottery_id}", lotteryId), {
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then((res) => {
return res.data.data.show_lottery;
});
}

View File

@@ -1,90 +0,0 @@
/**
* @file plugins Mys request news.ts
* @description Mys 插件咨讯请求
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.2
*/
import { http } from "@tauri-apps/api";
import { type NewsData, type NewsResponse } from "../interface/news";
// 咨讯 API
const NEWS_LIST_API =
"https://bbs-api.mihoyo.com/post/wapi/getNewsList?gids={gid}&page_size={page_size}&type={news_type}&last_id={last_id}";
/**
* @description 咨讯类型
* @enum NewsType
* @since Alpha
* @property {string} NOTICE 公告
* @property {string} ACTIVITY 活动
* @property {string} NEWS 咨讯
* @return {NewsType}
*/
enum NewsType {
NOTICE = "1",
ACTIVITY = "2",
NEWS = "3",
}
// todo: 考虑使用泛型
/**
* @description 获取 Notice 列表
* @since Alpha v0.1.2
* @param {string} gid gid: 1 为崩坏3 2 为原神3 为崩坏24 为未定事件簿5 为大别野6 为崩坏星穹铁道8 为绝区零
* @param {number} pageSize 返回数量
* @param {number} lastId 上一次请求的最后一条数据的 id
* @return {Promise<NewsData>}
*/
export async function getNoticeList(
gid: string = "2",
pageSize: number = 20,
lastId: number = 0,
): Promise<NewsData> {
const url = NEWS_LIST_API.replace("{page_size}", pageSize.toString())
.replace("{gid}", gid)
.replace("{news_type}", NewsType.NOTICE)
.replace("{last_id}", lastId.toString());
return await http.fetch<NewsResponse>(url).then((res) => res.data.data);
}
/**
* @description 获取 Activity 列表
* @since Alpha v0.1.2
* @param {string} gid gid: 1 为崩坏3 2 为原神3 为崩坏24 为未定事件簿5 为大别野6 为崩坏星穹铁道8 为绝区零
* @param {number} pageSize 返回数量
* @param {number} lastId 上一次请求的最后一条数据的 id
* @return {Promise<NewsData>}
*/
export async function getActivityList(
gid: string = "2",
pageSize: number = 20,
lastId: number = 0,
): Promise<NewsData> {
const url = NEWS_LIST_API.replace("{page_size}", pageSize.toString())
.replace("{gid}", gid)
.replace("{news_type}", NewsType.ACTIVITY)
.replace("{last_id}", lastId.toString());
return await http.fetch<NewsResponse>(url).then((res) => res.data.data);
}
/**
* @description 获取 News 列表
* @since Alpha v0.1.2
* @param {string} gid gid: 1 为崩坏3 2 为原神3 为崩坏24 为未定事件簿5 为大别野6 为崩坏星穹铁道8 为绝区零
* @param {number} pageSize 返回数量
* @param {number} lastId 上一次请求的最后一条数据的 id
* @return {Promise<NewsData>}
*/
export async function getNewsList(
gid: string = "2",
pageSize: number = 20,
lastId: number = 0,
): Promise<NewsData> {
const url = NEWS_LIST_API.replace("{page_size}", pageSize.toString())
.replace("{gid}", gid)
.replace("{news_type}", NewsType.NEWS)
.replace("{last_id}", lastId.toString());
return await http.fetch<NewsResponse>(url).then((res) => res.data.data);
}

View File

@@ -1,33 +0,0 @@
/**
* @file plugins Mys request position.ts
* @description Mys 插件热点追踪请求
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.2
*/
import { http } from "@tauri-apps/api";
import { type PositionResponse, type PositionData } from "../interface/position";
import { dfs } from "../utils/position";
// 热点追踪 API
const POSITION_API =
"https://api-static.mihoyo.com/common/blackboard/ys_obc/v1/home/position?app_sn=ys_obc";
/**
* @description 获取热点追踪信息
* @since Alpha v0.1.1
* @return {Promise<PositionData[]>}
*/
export async function getPositionData(): Promise<PositionData[]> {
const res = await http
.fetch<PositionResponse>(POSITION_API, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then((res) => {
return res.data.data.list;
});
return dfs(res);
}

View File

@@ -1,33 +0,0 @@
/**
* @file plugins Mys request post.ts
* @description Mys帖子请求
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.2
*/
import { http } from "@tauri-apps/api";
import { type PostResponse, type PostData } from "../interface/post";
// 帖子 API
const POST_API = "https://bbs-api.mihoyo.com/post/wapi/getPostFull?post_id={post_id}";
const POST_REFERER = "https://bbs.mihoyo.com/";
/**
* @description 获取帖子信息
* @since Alpha v0.1.2
* @param {number} postId 帖子 ID
* @return {Promise<PostData>}
*/
export async function getPostData(postId: number): Promise<PostData> {
return await http
.fetch<PostResponse>(POST_API.replace("{post_id}", postId.toString()), {
method: "GET",
headers: {
"Content-Type": "application/json",
Referer: POST_REFERER,
},
})
.then((res) => {
return res.data.data.post;
});
}

30
src/plugins/Mys/types/Base.d.ts vendored Normal file
View File

@@ -0,0 +1,30 @@
/**
* @file plugins Mys types Base.d.ts
* @description Mys 插件基础类型定义文件
* @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.2.1
*/
/**
* @description Mys 插件基础类型
* @since Alpha v0.2.1
* @namespace Base
* @exports TGApp.plugins.Mys.Base
* @return Base
*/
declare namespace TGApp.Plugins.Mys.Base {
/**
* @description Mys Response 统一接口
* @since Alpha v0.2.1
* @interface Response
* @property {number} retcode 状态码
* @property {string} message 状态信息
* @property {any} data 数据
* @return Response
*/
export interface Response {
retcode: number;
message: string;
data: any;
}
}

103
src/plugins/Mys/types/Gacha.d.ts vendored Normal file
View File

@@ -0,0 +1,103 @@
/**
* @file plugins Mys types Gacha.d.ts
* @description Mys 插件卡池类型定义文件
* @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.2.1
*/
/**
* @description Mys 卡池类型定义
* @since Alpha v0.2.1
* @namespace Gacha
* @exports TGAApp.Plugins.Mys.Gacha
* @return Gacha
*/
declare namespace TGApp.Plugins.Mys.Gacha {
/**
* @description 获取卡池信息返回
* @since Alpha v0.2.1
* @interface Response
* @extends TGApp.Plugins.Mys.Base.Response
* @property {Data[]} data.list 卡池数据
* @return Response
*/
export interface Response extends TGApp.Plugins.Mys.Base.Response {
data: {
list: Data[];
};
}
/**
* @description 卡池信息
* @since Alpha v0.2.1
* @interface Data
* @property {string} id 卡池ID
* @property {string} title 卡池标题
* @property {string} activity_url 卡池对应帖子
* @property {string} content_before_act 卡池内容
* @property {MiniItem[]} pool 卡池包含的角色
* @property {string} voice_icon 卡池角色语音头像
* @property {string} voice_url 卡池角色语音URL
* @property {string} voice_status 卡池角色语音状态
* @description 如下时间示例2023-03-21 17:59:59
* @property {string} start_time 卡池开始时间
* @property {string} end_time 卡池结束时间
* @return Data
*/
export interface Data {
id: string;
title: string;
activity_url: string;
content_before_act: string;
pool: MiniItem[];
voice_icon: string;
voice_url: string;
voice_status: string;
start_time: string;
end_time: string;
}
/**
* @description 基本信息
* @since Alpha v0.2.1
* @interface MiniItem
* @property {string} icon 图标
* @property {string} url 链接
* @return MiniItem
*/
export interface MiniItem {
icon: string;
url: string;
}
/**
* @description 用于渲染的卡池数据
* @since Alpha v0.2.1
* @interface RenderCard
* @property {string} title 卡池标题
* @property {string} subtitle 卡池副标题
* @property {string} cover 卡池封面
* @property {number} postId 卡池对应帖子ID
* @property {MiniItem[]} characters 卡池包含的角色
* @property {MiniItem} voice 卡池角色语音
* @property {string} time.start 卡池开始时间
* @property {string} time.startStamp 卡池开始时间戳
* @property {string} time.end 卡池结束时间
* @property {string} time.endStamp 卡池结束时间戳
* @return RenderCard
*/
export interface RenderCard {
title: string;
subtitle: string;
cover: string;
postId: number;
characters: MiniItem[];
voice: MiniItem;
time: {
start: string;
startStamp: number;
end: string;
endStamp: number;
};
}
}

127
src/plugins/Mys/types/Lottery.d.ts vendored Normal file
View File

@@ -0,0 +1,127 @@
/**
* @file plugins Mys types Lottery.d.ts
* @description Mys 插件抽奖类型定义文件
* @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.2.1
*/
/**
* @description Mys 插件抽奖类型
* @since Alpha v0.2.1
* @namespace Lottery
* @exports TGApp.plugins.Mys.Lottery
* @return Lottery
*/
declare namespace TGApp.Plugins.Mys.Lottery {
/**
* @description 抽奖返回数据
* @since Alpha v0.2.1
* @interface Response
* @extends TGApp.Plugins.Mys.Base.Response;
* @property {FullData} data.show_lottery 抽奖数据
* @return Response
*/
export interface Response extends TGApp.Plugins.Mys.Base.Response {
data: {
show_lottery: FullData;
};
}
/**
* @description 抽奖数据
* @since Alpha v0.2.1
* @interface FullData
* @property {string} id 抽奖 ID
* @property {TGApp.Plugins.Mys.User.Post} creator 创建者
* @property {string} draw_time 抽奖时间
* @property {string} participant_way 参与方式 // Forward: 转发
* @property {boolean} is_expect_unfocus_user 是否限制未关注用户
* @property {boolean} is_expect_non_real_name_user 是否限制未实名用户
* @property {Reward[]} user_rewards 用户奖励
* @property {string} status 状态 // Settled: 已结算
* @property {boolean} is_blocked 是否被屏蔽
* @property {string} user_status 用户状态 // NotParticipant: 未参与
* @property {boolean} is_upload_address 是否上传地址
* @property {string} lottery_entity_summary 抽奖实体摘要
* @property {string} entity_id 实体 ID // 若为帖子,则为帖子 ID
* @property {string} entity_type 实体类型 // Post: 帖子
* @property {string} now_time 当前时间
* @return FullData
*/
export interface FullData {
id: string;
creator: TGApp.Plugins.Mys.User.Post;
draw_time: string;
participant_way: string;
is_expect_unfocus_user: boolean;
is_expect_non_real_name_user: boolean;
user_rewards: Reward[];
status: string;
is_blocked: boolean;
user_status: string;
is_upload_address: boolean;
lottery_entity_summary: string;
entity_id: string;
entity_type: string;
now_time: string;
}
/**
* @description 抽奖奖励
* @since Alpha v0.2.1
* @interface Reward
* @property {string} reward_name 奖励名称
* @property {number} winner_number 获奖人数
* @property {number} scheduled_winner_number 预计获奖人数
* @property {boolean} is_send_by_post 是否通过帖子发放
* @property {TGApp.Plugins.Mys.User.Post[]} users 用户列表
* @property {string} id 奖励 ID
* @return Reward
*/
export interface Reward {
reward_name: string;
winner_number: number;
scheduled_winner_number: number;
is_send_by_post: boolean;
users: TGApp.Plugins.Mys.User.Post[];
id: string;
}
/**
* @description 渲染用的抽奖信息
* @since Alpha v0.2.1
* @interface RenderCard
* @property {string} id 抽奖 ID
* @property {string} upWay 参与方式
* @property {string} status 状态
* @property {TGApp.Plugins.Mys.User.Post} creator 创建者
* @property {string} drawTime 开奖时间
* @property {RenderReward[]} rewards 奖励列表
* @return RenderCard
*/
export interface RenderCard {
id: string;
upWay: string;
status: string;
creator: TGApp.Plugins.Mys.User.Post;
drawTime: string;
rewards: RenderReward[];
}
/**
* @description 渲染用的奖励信息
* @since Alpha v0.2.1
* @interface RenderReward
* @property {string} name 奖励名称
* @property {number} win 获奖人数
* @property {number} goal 预计获奖人数
* @property {TGApp.Plugins.Mys.User.Post[]} users 用户列表
* @return RenderReward
*/
export interface RenderReward {
name: string;
win: number;
goal: number;
users: TGApp.Plugins.Mys.User.Post[];
}
}

139
src/plugins/Mys/types/News.d.ts vendored Normal file
View File

@@ -0,0 +1,139 @@
/**
* @file plugins Mys types news.d.ts
* @description Mys 插件咨讯类型定义文件
* @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.2.1
*/
/**
* @description Mys 插件咨讯类型
* @since Alpha v0.2.1
* @namespace News
* @exports TGApp.plugins.Mys.News
* @return News
*/
declare namespace TGApp.Plugins.Mys.News {
/**
* @description 咨讯返回数据
* @since Alpha v0.2.1
* @interface Response
* @extends TGApp.Plugins.Mys.Base.Response
* @property {FullData} data 咨讯数据
* @return Response
*/
export interface Response extends TGApp.Plugins.Mys.Base.Response {
data: FullData;
}
/**
* @description 咨讯数据
* @since Alpha v0.2.1
* @interface FullData
* @property {number} last_id 最后一条咨讯 ID
* @property {boolean} is_last 是否最后一页
* @property {Item[]} list 咨讯列表
* @return FullData
*/
export interface FullData {
last_id: number;
is_last: boolean;
list: Item[];
}
/**
* @description 咨讯列表项
* @since Alpha v0.2.1
* @interface Item
* @property {TGApp.Plugins.Mys.Post.Post} post 帖子
* @property {TGApp.Plugins.Mys.Post.Forum} forum 版块
* @property {TGApp.Plugins.Mys.Post.Topic[]} topics 话题
* @property {TGApp.Plugins.Mys.User.Post} user 发帖用户
* @property {TGApp.Plugins.Mys.User.SelfOperation} self_operation 用户操作
* @property {TGApp.Plugins.Mys.Post.Stat} stat 帖子统计
* @property {TGApp.Plugins.Mys.Post.HelpSys} help_sys 帮助系统,可能为 null
* @property {TGApp.Plugins.Mys.Post.Image} cover 封面图片 URL
* @property {TGApp.Plugins.Mys.Post.Image[]} image_list 图片列表
* @property {boolean} is_official_master 是否为官方
* @property {boolean} is_user_master 是否用户
* @property {boolean} hot_reply_exist 是否热门回复
* @property {number} vote_count 投票数
* @property {number} last_modify_time 最后修改时间
* @property {string} recommend_type 推荐类型
* @property {unknown} collection 合集, 可能为 null // TODO: 未知
* @property {unknown[]} vod_list 视频列表
* @property {boolean} is_block_on 是否屏蔽
* @property {unknown} forum_rank_info 版块排名信息,可能为 null // TODO: 未知
* @property {unknown[]} link_card_list 链接卡片列表,可能为 null // TODO: 未知
* @property {Meta} news_meta 元数据
* @returns Item
*/
export interface Item {
post: TGApp.Plugins.Mys.Post.Post;
forum: TGApp.Plugins.Mys.Post.Forum;
topics: TGApp.Plugins.Mys.Post.Topic[];
user: TGApp.Plugins.Mys.User.Post;
self_operation: TGApp.Plugins.Mys.User.SelfOperation;
stat: TGApp.Plugins.Mys.Post.Stat;
help_sys: TGApp.Plugins.Mys.Post.HelpSys;
cover: TGApp.Plugins.Mys.Post.Image;
image_list: TGApp.Plugins.Mys.Post.Image[];
is_official_master: boolean;
is_user_master: boolean;
hot_reply_exist: boolean;
vote_count: number;
last_modify_time: number;
recommend_type: string;
collection: unknown;
vod_list: unknown[];
is_block_on: boolean;
forum_rank_info: unknown;
link_card_list: unknown[];
news_meta: Meta;
}
/**
* @description 咨讯元数据,只有活动咨讯才有
* @since Alpha v0.2.1
* @interface Meta
* @property {number} activity_status 活动状态 // ActivityStatus
* @property {string} start_at_sec 活动开始时间戳,单位秒
* @property {string} end_at_sec 活动结束时间戳,单位秒
* @return Meta
*/
export interface Meta {
activity_status: number;
start_at_sec: string;
end_at_sec: string;
}
/**
* @description 用于渲染的咨讯卡片
* @since Alpha v0.2.1
* @interface RenderCard
* @property {string} title 标题
* @property {string} cover 封面图片 URL
* @property {number} postId 帖子 ID
* @property {string} subtitle 副标题
* @property {RenderStatus} status 活动状态,仅活动咨讯有
* @return RenderCard
*/
export interface RenderCard {
title: string;
cover: string;
postId: number;
subtitle: string;
status?: RenderStatus;
}
/**
* @description 活动状态
* @since Alpha v0.2.1
* @property {string} status 活动状态
* @property {string} colorCss 活动状态按钮背景色
* @returns RenderStatus
*/
export interface RenderStatus {
status: string;
colorCss: string;
}
}

52
src/plugins/Mys/types/Obc.d.ts vendored Normal file
View File

@@ -0,0 +1,52 @@
/**
* @file plugins Mys types Obc.d.ts
* @description Mys obc 类型定义文件
* @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.2.1
*/
/**
* @description Mys obc 类型
* @since Alpha v0.2.1
* @namespace Obc
* @exports TGApp.plugins.Mys.Obc
* @return Obc
*/
declare namespace TGApp.Plugins.Mys.Obc {
/**
* @description Mys obc 返回数据
* @since Alpha v0.2.1
* @interface Response
* @extends TGApp.Plugins.Mys.Base.Response
* @property {Obc[]} data.list obc 列表
* @return Response
*/
export interface Response extends TGApp.Plugins.Mys.Base.Response {
data: {
list: Obc[];
};
}
/**
* @description Mys obc 层级结构
* @since Alpha v0.2.1
* @interface Data
* @property {number} id ID
* @property {string} name 名称
* @property {number} parent_id 父ID
* @property {number} depth 深度
* @property {string} ch_ext 结构化扩展信息
* @property {Obc[]} children 子节点,可以递归
* @property {unknown[]} list 列表 // todo: 未知类型
* @return Data
*/
export interface Data {
id: number;
name: string;
parent_id: number;
depth: number;
ch_ext: string;
children: Data[];
list: unknown[];
}
}

104
src/plugins/Mys/types/Position.d.ts vendored Normal file
View File

@@ -0,0 +1,104 @@
/**
* @file plugins Mys types Position.d.ts
* @description Mys 插件热点追踪接口
* @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.2.1
*/
/**
* @description Mys 插件热点追踪类型
* @since Alpha v0.2.1
* @namespace Position
* @exports TGApp.plugins.Mys.Position
* @return Position
*/
declare namespace TGApp.Plugins.Mys.Position {
/**
* @description 热点追踪信息的返回类型
* @since Alpha v0.2.1
* @interface Response
* @extends TGApp.Plugins.Mys.Base.Response
* @property {ObcItem[]} data.list obc 列表
* @return Response
*/
export interface Response extends TGApp.Plugins.Mys.Obc.Response {
data: {
list: ObcItem[];
};
}
/**
* @description 热点追踪层级结构
* @since Alpha v0.2.1
* @interface ObcItem
* @extends TGApp.Plugins.Mys.Obc.Data
* @property {Data[]} list 列表
* @return ObcItem
*/
export interface ObcItem extends TGApp.Plugins.Mys.Obc.Data {
list: Data[];
}
/**
* @description 热点追踪信息
* @since Alpha v0.2.1
* @interface Data
* @property {number} recommend_id 推荐ID
* @property {number} content_id 内容ID
* @property {string} title 标题
* @property {string} ext 扩展信息
* @property {number} type 类型
* @property {string} url 链接
* @property {string} icon 图标
* @property {string} abstract 摘要
* @property {string} article_user_name 作者
* @property {string} avatar_url 头像
* @property {string} article_time 时间
* @property {string} create_time 创建时间 // 2023-03-31 11:16:57
* @property {string} end_time 结束时间 // 1680465599000
* @return Data
*/
export interface Data {
recommend_id: number;
content_id: number;
title: string;
ext: string;
type: number;
url: string;
icon: string;
abstract: string;
article_user_name: string;
avatar_url: string;
article_time: string;
create_time: string;
end_time: string;
}
/**
* @description 渲染用的热点追踪信息
* @since Alpha v0.2.1
* @interface RenderCard
* @property {string} title 标题
* @property {number} postId 帖子ID
* @property {string} icon 图标
* @property {string} abstract 摘要
* @property time 时间
* @property {string} time.start 开始时间
* @property {number} time.startStamp 开始时间戳
* @property {string} time.end 结束时间
* @property {number} time.endStamp 结束时间戳
* @return RenderCard
*/
export interface RenderCard {
title: string;
postId: number;
icon: string;
abstract: string;
time: {
start: string;
startStamp: number;
end: string;
endStamp: number;
};
}
}

438
src/plugins/Mys/types/Post.d.ts vendored Normal file
View File

@@ -0,0 +1,438 @@
/**
* @file plugins Mys types post.d.ts
* @description Mys 插件帖子类型定义文件
* @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.2.1
*/
/**
* @description Mys 插件帖子类型
* @since Alpha v0.2.1
* @namespace Post
* @exports TGApp.plugins.Mys.Post
* @return Post
*/
declare namespace TGApp.Plugins.Mys.Post {
/**
* @description 帖子返回数据
* @since Alpha v0.2.1
* @interface Response
* @extends TGApp.Plugins.Mys.Base.Response
* @property {FullData} data.post 帖子数据
* @return Response
*/
export interface Response extends TGApp.Plugins.Mys.Base.Response {
data: {
post: FullData;
};
}
/**
* @description 帖子数据
* @since Alpha v0.2.1
* @interface FullData
* @property {Post} post 帖子信息
* @property {Forum} forum 所属版块
* @property {Topic[]} topics 所属话题
* @property {TGApp.Plugins.Mys.User.Post} user 发帖人
* @property {TGApp.Plugins.Mys.User.SelfOperation} self_operation 当前用户操作
* @property {Stat} stat 帖子统计
* @property {HelpSys} help_sys 帮助系统,可能为 null
* @property {Image} cover 封面图,可能为 null
* @property {Image[]} image_list 图片列表
* @property {boolean} is_official_master 是否为官方帖
* @property {boolean} is_user_master 是否为用户帖
* @property {boolean} hot_reply_exist 是否存在热门回复
* @property {number} vot_count 投票数
* @property {number} last_modify_time 最后修改时间
* @property {string} recommend_type 推荐类型
* @property {unknown} collection 合集,可能为 null // TODO: 未知
* @property {unknown[]} vod_list 视频列表,可能为空 // TODO: 未知
* @property {boolean} is_block_on 是否被屏蔽
* @property {unknown} forum_rank_info 版块排行信息,可能为 null // TODO: 未知
* @property {unknown[]} link_card_list 链接卡片列表,可能为空 // TODO: 未知
* @property {TGApp.Plugins.Mys.News.Meta} news_meta 咨讯元数据,可能为 null
* @return FullData
*/
export interface FullData {
post: Post;
forum: Forum;
topics: Topic[];
user: TGApp.Plugins.Mys.User.Post;
self_operation: TGApp.Plugins.Mys.User.SelfOperation;
stat: Stat;
help_sys: HelpSys | null;
cover: Image | null;
image_list: Image[];
is_official_master: boolean;
is_user_master: boolean;
hot_reply_exist: boolean;
vot_count: number;
last_modify_time: number;
recommend_type: string;
collection: unknown | null;
vod_list: unknown[];
is_block_on: boolean;
forum_rank_info: unknown | null;
link_card_list: unknown[];
news_meta: TGApp.Plugins.Mys.News.Meta | null;
}
/**
* @description 帖子信息
* @since Alpha v0.2.1
* @interface Post
* @property {number} game_id 游戏 ID // 2 为原神
* @property {string} post_id 帖子 ID
* @property {number} f_forum_id 所属版块 ID
* @property {string} uid 发帖人 UID
* @property {string} subject 帖子标题
* @property {string} content 帖子内容,为 html 格式
* @property {string} cover 封面图 URL可能为 ""
* @property {number} view_type 浏览类型 // TODO: 未知
* @property {number} created_at 发帖时间
* @property {string[]} images 图片列表,可能为空
* @property post_status 帖子状态
* @property {boolean} post_status.is_top 是否置顶
* @property {boolean} post_status.is_good 是否加精
* @property {boolean} post_status.is_official 是否官方
* @property {number[]} topic_ids 所属话题 ID 列表
* @property {number} view_status 浏览状态
* @property {number} max_floor 最大楼层
* @property {number} is_original 是否原创
* @property {number} republish_authorization 是否授权转载
* @property {string} reply_time 最后回复时间 // "2023-03-05 20:26:54"
* @property {number} is_deleted 是否删除
* @property {boolean} is_interactive 是否互动
* @property {string} structured_content 结构化内容 // 反序列化后为 PostStructuredContent
* @property {string[]} structured_content_rows 结构化内容原始数据
* @property {number} review_id 审核ID
* @property {boolean} is_profit 是否盈利
* @property {boolean} is_in_profit 是否在盈利
* @property {number} updated_at 更新时间
* @property {number} deleted_at 删除时间
* @property {number} pre_pub_status 预发布状态
* @property {number} cate_id 分类ID
* @property {number} profit_post_status 盈利帖子状态 // TODO: 未知
* @property {number} audit_status 审核状态
* @property {string} meta_content 元内容,可能为 "" // TODO: 未知
* @property {boolean} is_missing 是否缺失 // TODO: 未知
* @property {number} block_reply_img 是否屏蔽回复图片 // TODO: 未知
* @property {boolean} is_showing_missing 是否显示缺失 // TODO: 未知
* @property {number} block_latest_reply_time 是否屏蔽最新回复时间 // TODO: 未知
* @property {number} selected_comment 是否选择评论 // TODO: 未知
* @return Post
*/
export interface Post {
game_id: number;
post_id: string;
f_forum_id: number;
uid: string;
subject: string;
content: string;
cover: string;
view_type: number;
created_at: number;
images: string[];
post_status: {
is_top: boolean;
is_good: boolean;
is_official: boolean;
};
topic_ids: number[];
view_status: number;
max_floor: number;
is_original: number;
republish_authorization: number;
reply_time: string;
is_deleted: number;
is_interactive: boolean;
structured_content: string;
structured_content_rows: string[];
review_id: number;
is_profit: boolean;
is_in_profit: boolean;
updated_at: number;
deleted_at: number;
pre_pub_status: number;
cate_id: number;
profit_post_status: number;
audit_status: number;
meta_content: string;
is_missing: boolean;
block_reply_img: number;
is_showing_missing: boolean;
block_latest_reply_time: number;
selected_comment: number;
}
/**
* @description 版块信息
* @since Alpha v0.2.1
* @interface Forum
* @property {number} id 版块 ID
* @property {string} name 版块名称
* @property {string} icon 版块图标 URL
* @property {number} game_id 游戏 ID // 2 为原神
* @property {unknown} forum_cate 版块分类,可能为 null
* @return Forum
*/
export interface Forum {
id: number;
name: string;
icon: string;
game_id: number;
forum_cate: unknown | null;
}
/**
* @description 话题信息
* @since Alpha v0.2.1
* @interface Topic
* @property {number} id 话题 ID
* @property {string} name 话题名称
* @property {string} cover 话题封面图 URL
* @property {boolean} is_top 是否置顶
* @property {boolean} is_good 是否加精
* @property {boolean} is_interactive 是否互动
* @property {number} game_id 游戏 ID
* @property {number} content_type 内容类型
* @return Topic
*/
export interface Topic {
id: number;
name: string;
cover: string;
is_top: boolean;
is_good: boolean;
is_interactive: boolean;
game_id: number;
content_type: number;
}
/**
* @description 帖子状态
* @since Alpha v0.2.1
* @interface Stat
* @property {number} view_num 浏览数
* @property {number} reply_num 回复数
* @property {number} like_num 点赞数
* @property {number} bookmark_num 收藏数
* @property {number} forward_num 转发数
* @return Stat
*/
export interface Stat {
view_num: number;
reply_num: number;
like_num: number;
bookmark_num: number;
forward_num: number;
}
/**
* @description 图片数据
* @since Alpha v0.2.1
* @interface Image
* @property {string} url 图片 URL
* @property {number} height 图片高度
* @property {string} width 图片宽度
* @property {string} format 图片格式 // jpg
* @property {string} size 图片大小 // 281428
* @property crop 图片裁剪信息,可能为 null
* @property {number} crop.x 裁剪 X 轴
* @property {number} crop.y 裁剪 Y 轴
* @property {number} crop.w 裁剪宽度
* @property {number} crop.h 裁剪高度
* @property {string} crop.url 裁剪图片 URL
* @property {boolean} is_user_set_cover 是否为封面
* @property {string} image_id 图片 ID
* @property {string} entity_type 图片类型 // IMG_ENTITY_POST, IMG_ENTITY_UNKOWN
* @property {string} entity_id 图片 ID
* @property {boolean} is_deleted 是否已删除
* @return Image
*/
export interface Image {
url: string;
height: number;
width: number;
format: string;
size: string;
crop: {
x: number;
y: number;
w: number;
h: number;
url: string;
} | null;
is_user_set_cover: boolean;
image_id: string;
entity_type: string;
entity_id: string;
is_deleted: boolean;
}
/**
* @description help_sys 信息
* @since Alpha v0.2.1
* @todo 用处未知
* @interface HelpSys
* @property {unknown} top_up 置顶, 可能为 null // TODO: 未知
* @property {unknown[]} top_n 置顶, 可能为空
* @property {number} answer_num 回答数
* @return HelpSys
*/
export interface HelpSys {
top_up: unknown | null;
top_n: unknown[];
answer_num: number;
}
/**
* @description 帖子内容-结构化
* @description 当用户发帖时,解析内容用这个,为 post.content 的反序列化
* @since Alpha v0.2.1
* @interface Content
* @property {string} describe 描述
* @property {string[]} images 图片 URL
* @return Content
*/
export interface PostContent {
describe: string;
images?: string[];
}
/**
* @description 帖子结构化内容
* @since Alpha v0.2.1
* @interface StructuredContent
* @property {string|object} insert 插入内容
* @property {string} insert.image 图片 URL
* @property {StructuredVod} insert.vod 视频信息
* @property {string} insert.video 外部视频 URL
* @property {string} insert.backup_text 折叠文本
* @property {object} insert.lottery 抽奖,当 backup_text 为 [抽奖]
* @property {string} insert.lottery.id 抽奖 ID
* @property {string} insert.lottery.toast 抽奖提示
* @property {object} insert.fold 折叠内容
* @property {string} insert.fold.title 折叠标题,反序列化后为 PostStructuredContent[]
* @property {string} insert.fold.content 折叠文本,反序列化后为 PostStructuredContent[]
* @property {StructuredLinkCard} insert.link_card 链接卡片
* @property {string} insert.divider 分割线
* @property {object} insert.mention 提及
* @property {string} insert.mention.uid 用户 ID
* @property {string} insert.mention.nickname 用户昵称
* @property {object} attributes 属性
* @property {number} attributes.height 高度
* @property {number} attributes.width 宽度
* @property {number} attributes.size 大小
* @property {string} attributes.ext 扩展名
* @property {boolean} attributes.bold 是否加粗
* @property {string} attributes.color 颜色
* @property {string} attributes.link 链接
* @return StructuredContent
*/
export interface StructuredContent {
insert:
| {
image?: string;
video?: string;
vod?: StructuredVod;
backup_text?: string;
lottery?: {
id: string;
toast: string;
};
fold?: {
title: string;
content: string;
};
link_card?: StructuredLinkCard;
divider?: string;
mention?: {
uid: string;
nickname: string;
};
}
| string;
attributes?: {
height?: number;
width?: number;
size?: number;
ext?: string;
bold?: boolean;
color?: string;
link?: string;
};
}
/**
* @description 帖子结构化内容-视频
* @since Alpha v0.2.1
* @interface StructuredVod
* @property {number} id 视频 ID
* @property {number} duration 时长
* @property {string} cover 封面图 URL
* @property {object[]} resolutions 分辨率
* @property {string} resolutions.url URL
* @property {string} resolutions.definition 清晰度
* @property {number} resolutions.height 高度
* @property {number} resolutions.width 宽度
* @property {number} resolutions.bitrate 比特率
* @property {number} resolutions.size 大小
* @property {string} resolutions.format 格式
* @property {string} resolutions.label 标签
* @property {number} view_num 浏览数
* @property {number} transcode_status 转码状态
* @property {number} review_status 审核状态
* @return StructuredVod
*/
export interface StructuredVod {
id: number;
duration: number;
cover: string;
resolutions: Array<{
url: string;
definition: string;
height: number;
width: number;
bitrate: number;
size: number;
format: string;
label: string;
}>;
view_num: number;
transcoding_status: number;
review_status: number;
}
/**
* @description 帖子结构化内容-链接卡片
* @since Alpha v0.2.1
* @interface StructuredLinkCard
* @property {number} link_type 链接类型 // 1: 帖子2商品 TODO: 未知
* @property {string} origin_url 原始链接
* @property {string} landing_url 落地页链接
* @property {string} cover 封面图 URL
* @property {string} title 标题
* @property {string} card_id 卡片 ID
* @property {number} card_status 卡片状态 // TODO: 未知
* @property {string} market_price 市场价
* @property {string} price 价格
* @property {string} button_text 按钮文本
* @property {number} landing_url_type 落地链接类型 // TODO: 未知
* @return StructuredLinkCard
*/
export interface StructuredLinkCard {
link_type: number;
origin_url: string;
landing_url: string;
cover: string;
title: string;
card_id: string;
card_status: number;
market_price: string;
price: string;
button_text: string;
landing_url_type: number;
}
}

277
src/plugins/Mys/types/User.d.ts vendored Normal file
View File

@@ -0,0 +1,277 @@
/**
* @file plugins Mys types user.ts
* @description Mys 插件用户类型定义文件
* @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.2.1
*/
/**
* @description Mys 插件用户类型
* @since Alpha v0.2.1
* @namespace User
* @exports TGApp.plugins.Mys.User
* @return User
*/
declare namespace TGApp.Plugins.Mys.User {
/**
* @description 主页用户信息返回
* @since Alpha v0.2.1
* @interface HomeResponse
* @extends TGApp.Plugins.Mys.Base.Response
* @property {Home} data 用户信息
* @return HomeResponse
*/
export interface HomeResponse extends TGApp.Plugins.Mys.Base.Response {
data: Home;
}
/**
* @description 主页用户信息
* @since Alpha v0.2.1
* @interface Home 用户信息
* @property {Info} user_info 用户信息
* @property {unknown} follow_relation 关注关系
* @property {unknown[]} auth_relations 认证关系
* @property {boolean} is_in_blacklist 是否在黑名单中
* @property {boolean} is_has_collection 是否有收藏
* @property {boolean} is_creator 是否是创作者
* @property custom_service 客服信息
* @property {boolean} custom_service.is_customer_service_staff 是否是客服
* @property {number} custom_service.game_id 游戏 ID
* @property audit_info 审核信息
* @property {boolean} audit_info.is_nickname_in_audit 是否在昵称审核中
* @property {string} audit_info.nickname 审核中的昵称
* @property {boolean} audit_info.is_introduce_in_audit 是否在简介审核中
* @property {string} audit_info.introduce 审核中的简介
* @property {number} audit_info.nickname_status 昵称审核状态
* @return Home
*/
export interface Home {
user_info: Info;
follow_relation: unknown;
auth_relations: unknown[];
is_in_blacklist: boolean;
is_has_collection: boolean;
is_creator: boolean;
custom_service: {
is_customer_service_staff: boolean;
game_id: number;
};
audit_info: {
is_nickname_in_audit: boolean;
nickname: string;
is_introduce_in_audit: boolean;
introduce: string;
nickname_status: number;
};
}
/**
* @description 主页用户信息-二级
* @since Alpha v0.2.1
* @interface Info
* @property {string} uid 用户 ID
* @property {string} nickname 用户昵称
* @property {string} introduce 用户简介
* @property {string} avatar 用户头像编号
* @property {number} gender 用户性别
* @property {Certification} certification 用户认证信息
* @property {LevelExp[]} level_exps 用户等级经验
* @property {Archive} archive 用户档案
* @property {Community} community_info 用户社区信息
* @property {string} avatar_url 用户头像链接
* @property {Certification[]} certifications 用户认证信息
* @property {LevelExp} level_exp 用户等级经验
* @property {string} pendant 用户挂件 URL可能为 ""
* @property {boolean} is_logoff 是否注销
* @property {string} ip_region 用户 IP 地区
* @return Info
*/
export interface Info {
uid: string;
nickname: string;
introduce: string;
avatar: string;
gender: number;
certification: Certification;
level_exps: LevelExp[];
archive: Archive;
community_info: Community;
avatar_url: string;
certifications: Certification[];
level_exp: LevelExp;
pendant: string;
is_logoff: boolean;
ip_region: string;
}
/**
* @description 用户认证信息
* @since Alpha v0.2.1
* @interface Certification
* @property {number} type 认证类型
* @property {string} label 认证标签
* @return Certification
*/
export interface Certification {
type: number;
label: string;
}
/**
* @description 用户等级经验
* @since Alpha v0.2.1
* @interface LevelExp
* @property {number} level 用户等级
* @property {number} exp 用户经验
* @property {number} game_id 游戏 ID
* @return LevelExp
*/
export interface LevelExp {
level: number;
exp: number;
game_id: number;
}
/**
* @description 用户档案
* @since Alpha v0.2.1
* @interface Archive
* @property {string} like_num 获赞数
* @property {string} post_num 发帖数
* @property {string} replypost_num 回帖数
* @property {string} follow_cnt 关注数
* @property {string} followed_cnt 被关注数
* @property {string} topic_cnt 话题数
* @property {string} new_follower_num 新粉丝数
* @property {string} good_post_num 精华帖数
* @property {string} follow_collection_cnt 收藏数
* @return Archive
*/
export interface Archive {
like_num: string;
post_num: string;
replypost_num: string;
follow_cnt: string;
followed_cnt: string;
topic_cnt: string;
new_follower_num: string;
good_post_num: string;
follow_collection_cnt: string;
}
/**
* @description 用户社区信息
* @since Alpha v0.2.1
* @interface Community
* @property {boolean} is_realname 是否实名
* @property {boolean} agree_status 是否同意协议
* @property {number} silent_end_time 禁言结束时间
* @property {number} forbid_end_time 封禁结束时间
* @property {number} info_upd_time 信息更新时间
* @property privacy_invisible 用户隐私设置
* @property {boolean} privacy_invisible.post 是否隐藏发帖
* @property {boolean} privacy_invisible.collect 是否隐藏收藏
* @property {boolean} privacy_invisible.watermark 是否隐藏水印
* @property {boolean} privacy_invisible.reply 是否隐藏回复
* @property {boolean} privacy_invisible.post_and_instant 是否隐藏发帖和即时
* @property notify_disable 用户通知设置
* @property {boolean} notify_disable.reply 是否禁用回复通知
* @property {boolean} notify_disable.upvote 是否禁用点赞通知
* @property {boolean} notify_disable.follow 是否禁用关注通知
* @property {boolean} notify_disable.system 是否禁用系统通知
* @property {boolean} notify_disable.chat 是否禁用聊天通知
* @property {boolean} has_initialized 是否初始化
* @property user_func_status 用户功能状态
* @property {boolean} user_func_status.enable_history_view 是否启用历史记录
* @property {boolean} user_func_status.enable_recommend 是否启用推荐
* @property {boolean} user_func_status.enable_mention 是否启用提及
* @property {number} user_func_status.user_center_view 是否启用用户中心\
* @property {unknown[]} forum_silent_info 论坛禁言信息
* @property {string} last_login_ip 上次登录 IP
* @property {number} last_login_time 上次登录时间
* @property {number} created_at 创建时间
* @return Community
*/
export interface Community {
is_realname: boolean;
agree_status: boolean;
silent_end_time: number;
forbid_end_time: number;
info_upd_time: number;
privacy_invisible: {
post: boolean;
collect: boolean;
watermark: boolean;
reply: boolean;
post_and_instant: boolean;
};
notify_disable: {
reply: boolean;
upvote: boolean;
follow: boolean;
system: boolean;
chat: boolean;
};
has_initialized: boolean;
user_func_status: {
enable_history_view: boolean;
enable_recommend: boolean;
enable_mention: boolean;
user_center_view: number;
};
forum_silent_info: unknown[];
last_login_ip: string;
last_login_time: number;
created_at: number;
}
/**
* @description post中的用户信息
* @since Alpha v0.2.1
* @interface Post
* @property {string} uid 用户 ID
* @property {string} nickname 用户昵称
* @property {string} introduce 用户简介
* @property {string} avatar 用户头像 // TODO: 转换为图片链接
* @property {number} gender 用户性别 // TODO: 未知
* @property {Certification} certification 用户认证信息
* @property level_exp 用户等级经验
* @property {number} level_exp.level 用户等级
* @property {number} level_exp.exp 用户经验
* @property {boolean} is_following 是否关注
* @property {boolean} is_follower 是否被关注
* @property {string} avatar_url 用户头像链接
* @property {string} pendant 用户挂件 URL可能为 ""
* @return Post
*/
export interface Post {
uid: string;
nickname: string;
introduce: string;
avatar: string;
gender: number;
certification: Certification;
level_exp: {
level: number;
exp: number;
};
is_following: boolean;
is_follower: boolean;
avatar_url: string;
pendant: string;
}
/**
* @description 用户操作
* @since Alpha v0.2.1
* @interface SelfOperation
* @property {number} attitude 操作类型 // TODO: 未知
* @property {boolean} is_collected 是否收藏
* @returns {SelfOperation}
*/
export interface SelfOperation {
attitude: number;
is_collected: boolean;
}
}

View File

@@ -1,27 +1,26 @@
/** /**
* @file plugins Mys utils gacha.ts * @file plugins Mys utils getGachaCard.ts
* @description Mys * @description Mys
* @author BTMuli<bt-muli@outlook.com> * @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.1.4 * @since Alpha v0.2.1
*/ */
import { getPostData } from "../request/post"; import getPostData from "../request/getPostData";
import { type GachaCard, type GachaData } from "../interface/gacha";
/** /**
* @description * @description
* @since Alpha v0.1.4 * @since Alpha v0.2.1
* @param {GachaData[]} gachaData * @param {TGApp.Plugins.Mys.Gacha.Data[]} gachaData
* @param {Map<string>} poolCover * @param {Record<number, string>} poolCover
* @returns {Promise<GachaCard[]>} * @returns {Promise<TGApp.Plugins.Mys.Gacha.RenderCard[]>}
*/ */
export async function getGachaCard( async function getGachaCard(
gachaData: GachaData[], gachaData: TGApp.Plugins.Mys.Gacha.Data[],
poolCover: Record<number, string> | undefined = undefined, poolCover?: Record<number, string>,
): Promise<GachaCard[]> { ): Promise<TGApp.Plugins.Mys.Gacha.RenderCard[]> {
const gachaCard: GachaCard[] = []; const gachaCard: TGApp.Plugins.Mys.Gacha.RenderCard[] = [];
await Promise.allSettled( await Promise.allSettled(
gachaData.map(async (data: GachaData) => { gachaData.map(async (data: TGApp.Plugins.Mys.Gacha.Data) => {
let cover = "/source/UI/empty.webp"; let cover = "/source/UI/empty.webp";
const postId: number | undefined = Number(data.activity_url.split("/").pop()) || undefined; const postId: number | undefined = Number(data.activity_url.split("/").pop()) || undefined;
if (postId === undefined || isNaN(postId)) { if (postId === undefined || isNaN(postId)) {
@@ -42,8 +41,7 @@ export async function getGachaCard(
title: data.title, title: data.title,
subtitle: data.content_before_act, subtitle: data.content_before_act,
cover, cover,
// eslint-disable-next-line camelcase postId,
post_id: postId,
characters: data.pool.map((character) => ({ characters: data.pool.map((character) => ({
icon: character.icon, icon: character.icon,
url: character.url, url: character.url,
@@ -54,14 +52,14 @@ export async function getGachaCard(
}, },
time: { time: {
start: data.start_time, start: data.start_time,
// eslint-disable-next-line camelcase startStamp: new Date(data.start_time).getTime(),
start_stamp: new Date(data.start_time).getTime(),
end: data.end_time, end: data.end_time,
// eslint-disable-next-line camelcase endStamp: new Date(data.end_time).getTime(),
end_stamp: new Date(data.end_time).getTime(),
}, },
}); });
}), }),
); );
return gachaCard; return gachaCard;
} }
export default getGachaCard;

View File

@@ -0,0 +1,46 @@
/**
* @file plugins Mys utils getLotteryCard.ts
* @description 抽奖工具类
* @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.2.1
*/
/**
* @description 根据抽奖奖励信息转为渲染用的抽奖奖励信息
* @since Alpha v0.2.1
* @param {TGApp.Plugins.Mys.Lottery.Reward} lotteryReward 抽奖奖励信息
* @returns {TGApp.Plugins.Mys.Lottery.RenderReward}
*/
function getLotteryRewardCard(
lotteryReward: TGApp.Plugins.Mys.Lottery.Reward,
): TGApp.Plugins.Mys.Lottery.RenderReward {
return {
name: lotteryReward.reward_name,
win: lotteryReward.winner_number,
goal: lotteryReward.scheduled_winner_number,
users: lotteryReward.users,
};
}
/**
* @description 根据抽奖信息转为渲染用的抽奖信息
* @since Alpha v0.2.1
* @param {TGApp.Plugins.Mys.Lottery.FullData} lotteryData 抽奖信息
* @returns {TGApp.Plugins.Mys.Lottery.RenderCard}
*/
function getLotteryCard(
lotteryData: TGApp.Plugins.Mys.Lottery.FullData,
): TGApp.Plugins.Mys.Lottery.RenderCard {
return {
id: lotteryData.id,
upWay: lotteryData.participant_way,
status: lotteryData.status,
creator: lotteryData.creator,
drawTime: lotteryData.draw_time,
rewards: lotteryData.user_rewards.map((reward) => {
return getLotteryRewardCard(reward);
}),
};
}
export default getLotteryCard;

View File

@@ -1,28 +1,21 @@
/** /**
* @file plugins Mys utils news.ts * @file plugins Mys utils news.ts
* @description Mys * @description Mys
* @author BTMuli<bt-muli@outlook.com> * @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.1.2 * @since Alpha v0.2.1
*/ */
import {
type NewsData,
type NewsItem,
type NewsCard,
type ActivityStatus,
} from "../interface/news";
// 默认封面图 // 默认封面图
const defaultCover = "/source/UI/defaultCover.webp"; const defaultCover = "/source/UI/defaultCover.webp";
/** /**
* @description * @description
* @since Alpha v0.1.1 * @since Alpha v0.2.1
* @enum {ActivityStatus} * @enum {TGApp.Plugins.Mys.News.RenderStatus}
* @property {ActivityStatus} STARTED * @property {TGApp.Plugins.Mys.News.RenderStatus} STARTED
* @property {ActivityStatus} FINISHED * @property {TGApp.Plugins.Mys.News.RenderStatus} FINISHED
* @property {ActivityStatus} SELECTION * @property {TGApp.Plugins.Mys.News.RenderStatus} SELECTION
* @returns {EnumStatus} * @return EnumStatus
*/ */
const EnumStatus = { const EnumStatus = {
STARTED: { STARTED: {
@@ -49,7 +42,7 @@ const EnumStatus = {
* @param {number} status * @param {number} status
* @returns {string} * @returns {string}
*/ */
export function getActivityStatus(status: number): ActivityStatus { export function getActivityStatus(status: number): TGApp.Plugins.Mys.News.RenderStatus {
switch (status) { switch (status) {
case 1: case 1:
return EnumStatus.STARTED; return EnumStatus.STARTED;
@@ -64,17 +57,19 @@ export function getActivityStatus(status: number): ActivityStatus {
/** /**
* @description * @description
* @since Alpha v0.1.2 * @since Alpha v0.2.1
* @param {NewsData} noticeData * @param {TGApp.Plugins.Mys.News.FullData} noticeData
* @returns {NewsCard[]} * @returns {TGApp.Plugins.Mys.News.RenderCard[]}
*/ */
export function getNoticeCard(noticeData: NewsData): NewsCard[] { export function getNoticeCard(
const noticeCard: NewsCard[] = []; noticeData: TGApp.Plugins.Mys.News.FullData,
noticeData.list.map((item: NewsItem) => { ): TGApp.Plugins.Mys.News.RenderCard[] {
const noticeCard: TGApp.Plugins.Mys.News.RenderCard[] = [];
noticeData.list.map((item: TGApp.Plugins.Mys.News.Item) => {
return noticeCard.push({ return noticeCard.push({
title: item.post.subject, title: item.post.subject,
cover: item.cover?.url || item.post.cover || item.post.images[0] || defaultCover, cover: item.cover?.url || item.post.cover || item.post.images[0] || defaultCover,
post_id: Number(item.post.post_id), postId: Number(item.post.post_id),
subtitle: item.post.post_id, subtitle: item.post.post_id,
}); });
}); });
@@ -83,20 +78,22 @@ export function getNoticeCard(noticeData: NewsData): NewsCard[] {
/** /**
* @description * @description
* @since Alpha v0.1.2 * @since Alpha v0.2.1
* @param {NewsData} activityData * @param {TGApp.Plugins.Mys.News.FullData} activityData
* @returns {NewsCard[]} * @returns {TGApp.Plugins.Mys.News.RenderCard[]}
*/ */
export function getActivityCard(activityData: NewsData): NewsCard[] { export function getActivityCard(
const activityCard: NewsCard[] = []; activityData: TGApp.Plugins.Mys.News.FullData,
activityData.list.map((item: NewsItem) => { ): TGApp.Plugins.Mys.News.RenderCard[] {
const activityCard: TGApp.Plugins.Mys.News.RenderCard[] = [];
activityData.list.map((item: TGApp.Plugins.Mys.News.Item) => {
const startTime = new Date(Number(item.news_meta.start_at_sec) * 1000).toLocaleDateString(); const startTime = new Date(Number(item.news_meta.start_at_sec) * 1000).toLocaleDateString();
const endTime = new Date(Number(item.news_meta.end_at_sec) * 1000).toLocaleDateString(); const endTime = new Date(Number(item.news_meta.end_at_sec) * 1000).toLocaleDateString();
const statusInfo = getActivityStatus(item.news_meta.activity_status); const statusInfo = getActivityStatus(item.news_meta.activity_status);
return activityCard.push({ return activityCard.push({
title: item.post.subject, title: item.post.subject,
cover: item.cover?.url || item.post.cover || item.post.images[0] || defaultCover, cover: item.cover?.url || item.post.cover || item.post.images[0] || defaultCover,
post_id: Number(item.post.post_id), postId: Number(item.post.post_id),
subtitle: `${startTime} - ${endTime}`, subtitle: `${startTime} - ${endTime}`,
status: statusInfo, status: statusInfo,
}); });
@@ -106,17 +103,19 @@ export function getActivityCard(activityData: NewsData): NewsCard[] {
/** /**
* @description * @description
* @since Alpha v0.1.2 * @since Alpha v0.2.1
* @param {NewsData} newsData * @param {TGApp.Plugins.Mys.News.FullData} newsData
* @returns {NewsCard[]} * @returns {TGApp.Plugins.Mys.News.RenderCard[]}
*/ */
export function getNewsCard(newsData: NewsData): NewsCard[] { export function getNewsCard(
const newsCard: NewsCard[] = []; newsData: TGApp.Plugins.Mys.News.FullData,
newsData.list.map((item: NewsItem) => { ): TGApp.Plugins.Mys.News.RenderCard[] {
const newsCard: TGApp.Plugins.Mys.News.RenderCard[] = [];
newsData.list.map((item: TGApp.Plugins.Mys.News.Item) => {
return newsCard.push({ return newsCard.push({
title: item.post.subject, title: item.post.subject,
cover: item.cover?.url || item.post.cover || item.post.images[0] || defaultCover, cover: item.cover?.url || item.post.cover || item.post.images[0] || defaultCover,
post_id: Number(item.post.post_id), postId: Number(item.post.post_id),
subtitle: item.post.post_id, subtitle: item.post.post_id,
}); });
}); });

View File

@@ -0,0 +1,41 @@
/**
* @file plugins Mys utils getPositionCard.ts
* @description Mys 插件热点追踪工具
* @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.2.1
*/
/**
* @description 根据热点追踪信息转为渲染用的数据
* @since Alpha v0.1.5
* @param {TGApp.Plugins.Mys.Position.Data[]} positionData 列表
* @returns {TGApp.Plugins.Mys.Position.RenderCard[]} 返回列表
*/
function getPositionCard(
positionData: TGApp.Plugins.Mys.Position.Data[],
): TGApp.Plugins.Mys.Position.RenderCard[] {
const res: TGApp.Plugins.Mys.Position.RenderCard[] = [];
positionData.map((position) => {
let endStr: string;
if (position.end_time === "0") {
endStr = "";
} else {
endStr = new Date(Number(position.end_time)).toLocaleDateString().replace(/\//g, "-");
}
return res.push<TGApp.Plugins.Mys.Position.RenderCard>({
title: position.title,
postId: Number(position.url.split("/").pop()),
icon: position.icon,
abstract: position.abstract,
time: {
start: position.create_time.split(" ")[0].replace(/\//g, "-"),
startStamp: new Date(position.create_time).getTime(),
end: endStr,
endStamp: Number(position.end_time),
},
});
});
return res;
}
export default getPositionCard;

View File

@@ -1,47 +0,0 @@
/**
* @file plugins Mys utils lottery.ts
* @description 抽奖工具类
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.1
*/
import {
type LotteryData,
type LotteryCard,
type LotteryRewardCard,
type LotteryReward,
} from "../interface/lottery";
/**
* @description 根据抽奖信息转为渲染用的抽奖信息
* @since Alpha v0.1.1
* @param {LotteryData} lotteryData 抽奖信息
* @returns {LotteryCard}
*/
export function getLotteryCard(lotteryData: LotteryData): LotteryCard {
return {
id: lotteryData.id,
participantWay: lotteryData.participant_way,
status: lotteryData.status,
creator: lotteryData.creator,
drawTime: lotteryData.draw_time,
rewards: lotteryData.user_rewards.map((reward) => {
return getLotteryRewardCard(reward);
}),
};
}
/**
* @description 根据抽奖奖励信息转为渲染用的抽奖奖励信息
* @since Alpha v0.1.1
* @param {LotteryReward} lotteryReward 抽奖奖励信息
* @returns {LotteryRewardCard}
*/
export function getLotteryRewardCard(lotteryReward: LotteryReward): LotteryRewardCard {
return {
rewardName: lotteryReward.reward_name,
winnerNumber: lotteryReward.winner_number,
scheduledWinnerNumber: lotteryReward.scheduled_winner_number,
users: lotteryReward.users,
};
}

View File

@@ -1,16 +1,15 @@
/** /**
* @file plugins Mys utils PostParser.ts * @file plugins Mys utils parsePost.ts
* @description Mys数据的工具 * @description Mys数据的工具
* @author BTMuli<bt-muli@outlook.com> * @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.1.3 * @since Alpha v0.2.1
*/ */
import { type PostData, type PostStructuredContent } from "../interface/post";
/** /**
* @description 16 RGB * @description 16 RGB
* @since Alpha v0.1.3 * @since Alpha v0.1.3
* @param {string} hex 16 * @param {string} hex 16
* @returns {object} RGB * @returns {{ r: number; g: number; b: number }} RGB
*/ */
function hexToRgb(hex: string): { r: number; g: number; b: number } { function hexToRgb(hex: string): { r: number; g: number; b: number } {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
@@ -54,10 +53,10 @@ function isColorSimilar(colorBg: string, colorFg: string): boolean {
* @param {string} url * @param {string} url
* @returns {boolean} * @returns {boolean}
*/ */
export function IsMysPost(url: string): boolean { function isMysPost(url: string): boolean {
const regBBS = /^https:\/\/bbs\.mihoyo\.com\/\w+\/article\/\d+$/; const regBBS = /^https:\/\/bbs\.mihoyo\.com\/\w+\/article\/\d+$/;
const regMYS = /^https:\/\/www\.miyoushe\.com\/\w+\/article\/\d+$/; const regMys = /^https:\/\/www\.miyoushe\.com\/\w+\/article\/\d+$/;
return regBBS.test(url) || regMYS.test(url); return regBBS.test(url) || regMys.test(url);
} }
/** /**
@@ -66,7 +65,7 @@ export function IsMysPost(url: string): boolean {
* @param {string} url * @param {string} url
* @returns {string} id * @returns {string} id
*/ */
export function getPostId(url: string): string { function getPostId(url: string): string {
const postId: string | undefined = url.split("/").pop(); const postId: string | undefined = url.split("/").pop();
if (postId === undefined) { if (postId === undefined) {
throw new Error("无法获取帖子 id"); throw new Error("无法获取帖子 id");
@@ -75,15 +74,15 @@ export function getPostId(url: string): string {
} }
/** /**
* @description PostStructContent * @description StructContent
* @since Alpha v0.1.2 * @since Alpha v0.1.2
* @see PostContent * @see PostContent
* @param {string} content * @param {string} content
* @returns {string} * @returns {string}
*/ */
export function contentParser(content: string): string { function parseContent(content: string): string {
const data = JSON.parse(content); const data = JSON.parse(content);
const result: PostStructuredContent[] = []; const result: TGApp.Plugins.Mys.Post.StructuredContent[] = [];
// 遍历 data 属性,值 // 遍历 data 属性,值
Object.keys(data).forEach((key) => { Object.keys(data).forEach((key) => {
switch (key) { switch (key) {
@@ -114,26 +113,26 @@ export function contentParser(content: string): string {
/** /**
* @description Mys数据 * @description Mys数据
* @since Alpha v0.1.2 * @since Alpha v0.1.2
* @param {PostData} post Mys数据 * @param {TGApp.Plugins.Mys.Post.FullData} post Mys数据
* @description * @description
* @returns {string} HTML v-html 使 * @returns {string} HTML v-html 使
*/ */
export function PostParser(post: PostData): string { function parsePost(post: TGApp.Plugins.Mys.Post.FullData): string {
const postContent = post.post.content; const postContent = post.post.content;
let parserData; let parserData;
if (postContent.startsWith("<")) { if (postContent.startsWith("<")) {
parserData = post.post.structured_content; parserData = post.post.structured_content;
} else { } else {
try { try {
parserData = contentParser(post.post.content); parserData = parseContent(post.post.content);
} catch (error) { } catch (error) {
parserData = post.post.structured_content; parserData = post.post.structured_content;
} }
} }
const jsonData: PostStructuredContent[] = JSON.parse(parserData); const jsonData: TGApp.Plugins.Mys.Post.StructuredContent[] = JSON.parse(parserData);
const doc = document.createElement("div"); const doc = document.createElement("div");
jsonData.forEach((item: any) => { jsonData.forEach((item: any) => {
const parsed = ParserTransfer(item); const parsed = transferParser(item);
doc.appendChild(parsed); doc.appendChild(parsed);
}); });
return doc.innerHTML; return doc.innerHTML;
@@ -142,38 +141,40 @@ export function PostParser(post: PostData): string {
/** /**
* @description * @description
* @since Alpha v0.1.2 * @since Alpha v0.1.2
* @param {PostStructuredContent} data Mys数据 * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据
* @returns {HTMLDivElement | HTMLSpanElement} * @returns {HTMLDivElement | HTMLSpanElement}
*/ */
function ParserTransfer(data: PostStructuredContent): HTMLDivElement | HTMLSpanElement { function transferParser(
data: TGApp.Plugins.Mys.Post.StructuredContent,
): HTMLDivElement | HTMLSpanElement {
if (typeof data.insert === "string") { if (typeof data.insert === "string") {
return TextParser(data); return parseText(data);
} else if (data.insert.image) { } else if (data.insert.image) {
return ImageParser(data); return parseImage(data);
} else if (data.insert.vod != null) { } else if (data.insert.vod != null) {
return VideoParser(data); return parseVideo(data);
} else if (data.insert.video) { } else if (data.insert.video) {
return VideoParser(data); return parseVideo(data);
} else if (data.insert.backup_text) { } else if (data.insert.backup_text) {
return BackupTextParser(data); return parseBackup(data);
} else if (data.insert.link_card != null) { } else if (data.insert.link_card != null) {
return LinkCardParser(data); return parseLinkCard(data);
} else if (data.insert.divider) { } else if (data.insert.divider) {
return DividerParser(data); return parseDivider(data);
} else if (data.insert.mention != null) { } else if (data.insert.mention != null) {
return MentionParser(data); return parseMention(data);
} else { } else {
return UnknownParser(data); return parseUnknown(data);
} }
} }
/** /**
* @description * @description
* @since Alpha v0.1.1 * @since Alpha v0.1.1
* @param {PostStructuredContent} data Mys数据 * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据
* @returns {HTMLDivElement} * @returns {HTMLDivElement}
*/ */
function UnknownParser(data: PostStructuredContent): HTMLDivElement { function parseUnknown(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivElement {
// 创建 div // 创建 div
const div = document.createElement("div"); const div = document.createElement("div");
div.classList.add("mys-post-unknown"); div.classList.add("mys-post-unknown");
@@ -189,10 +190,10 @@ function UnknownParser(data: PostStructuredContent): HTMLDivElement {
/** /**
* @description * @description
* @since Alpha v0.1.3 * @since Alpha v0.1.3
* @param {PostStructuredContent} data Mys数据 * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据
* @returns {HTMLSpanElement} * @returns {HTMLSpanElement}
*/ */
function TextParser(data: PostStructuredContent): HTMLSpanElement { function parseText(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLSpanElement {
// 检查数据 // 检查数据
if (typeof data.insert !== "string") { if (typeof data.insert !== "string") {
throw new Error("data.insert is not a string"); throw new Error("data.insert is not a string");
@@ -225,10 +226,10 @@ function TextParser(data: PostStructuredContent): HTMLSpanElement {
/** /**
* @description * @description
* @since Alpha v0.1.2 * @since Alpha v0.1.2
* @param {PostStructuredContent} data Mys数据 * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据
* @returns {HTMLSpanElement} * @returns {HTMLSpanElement}
*/ */
function LinkTextParser(data: PostStructuredContent): HTMLSpanElement { function LinkTextParser(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLSpanElement {
// 检查数据 // 检查数据
if (typeof data.insert !== "string") { if (typeof data.insert !== "string") {
throw new Error("data.insert is not a string"); throw new Error("data.insert is not a string");
@@ -246,7 +247,7 @@ function LinkTextParser(data: PostStructuredContent): HTMLSpanElement {
const link = document.createElement("a"); const link = document.createElement("a");
const linkUrl = data.attributes.link; const linkUrl = data.attributes.link;
link.classList.add("mys-post-link"); link.classList.add("mys-post-link");
if (IsMysPost(linkUrl)) { if (isMysPost(linkUrl)) {
const postId = getPostId(linkUrl); const postId = getPostId(linkUrl);
link.href = `/post_detail/${postId}`; link.href = `/post_detail/${postId}`;
link.target = "_self"; link.target = "_self";
@@ -264,10 +265,10 @@ function LinkTextParser(data: PostStructuredContent): HTMLSpanElement {
/** /**
* @description 线 * @description 线
* @since Alpha v0.1.1 * @since Alpha v0.1.1
* @param {PostStructuredContent} data Mys数据 * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据
* @returns {HTMLDivElement} 线 * @returns {HTMLDivElement} 线
*/ */
function DividerParser(data: PostStructuredContent): HTMLDivElement { function parseDivider(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivElement {
// 数据检查 // 数据检查
if (typeof data.insert === "string") { if (typeof data.insert === "string") {
throw new Error("data.insert is a string"); throw new Error("data.insert is a string");
@@ -294,7 +295,7 @@ function DividerParser(data: PostStructuredContent): HTMLDivElement {
"https://mihoyo-community-web.oss-cn-shanghai.aliyuncs.com/upload/2022/07/13/line_4.png"; "https://mihoyo-community-web.oss-cn-shanghai.aliyuncs.com/upload/2022/07/13/line_4.png";
} else { } else {
console.error("Unknown divider type", data); console.error("Unknown divider type", data);
return UnknownParser(data); return parseUnknown(data);
} }
// 插入 img // 插入 img
div.appendChild(img); div.appendChild(img);
@@ -305,10 +306,10 @@ function DividerParser(data: PostStructuredContent): HTMLDivElement {
/** /**
* @description * @description
* @since Alpha v0.1.1 * @since Alpha v0.1.1
* @param {PostStructuredContent} data Mys数据 * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据
* @returns {HTMLDivElement} * @returns {HTMLDivElement}
*/ */
function ImageParser(data: PostStructuredContent): HTMLDivElement { function parseImage(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivElement {
// 检查数据 // 检查数据
if (typeof data.insert === "string") { if (typeof data.insert === "string") {
throw new Error("data.insert is a string"); throw new Error("data.insert is a string");
@@ -342,10 +343,10 @@ function ImageParser(data: PostStructuredContent): HTMLDivElement {
/** /**
* @description * @description
* @since Alpha * @since Alpha
* @param {PostStructuredContent} data Mys数据 * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据
* @returns {HTMLDivElement} * @returns {HTMLDivElement}
*/ */
function VideoParser(data: PostStructuredContent): HTMLDivElement { function parseVideo(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivElement {
// 检查数据 // 检查数据
if (typeof data.insert === "string") { if (typeof data.insert === "string") {
throw new Error("data.insert is a string"); throw new Error("data.insert is a string");
@@ -392,10 +393,10 @@ function VideoParser(data: PostStructuredContent): HTMLDivElement {
/** /**
* @description * @description
* @since Alpha v0.1.1 * @since Alpha v0.1.1
* @param {PostStructuredContent} data Mys数据 * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据
* @returns {HTMLDivElement} * @returns {HTMLDivElement}
*/ */
function BackupTextParser(data: PostStructuredContent): HTMLDivElement { function parseBackup(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivElement {
// 检查数据 // 检查数据
if (typeof data.insert === "string") { if (typeof data.insert === "string") {
throw new Error("data.insert is a string"); throw new Error("data.insert is a string");
@@ -407,8 +408,10 @@ function BackupTextParser(data: PostStructuredContent): HTMLDivElement {
throw new Error("data.insert.fold is not defined"); throw new Error("data.insert.fold is not defined");
} }
// 转换 // 转换
const titleJson: PostStructuredContent[] = JSON.parse(data.insert.fold.title); const titleJson: TGApp.Plugins.Mys.Post.StructuredContent[] = JSON.parse(data.insert.fold.title);
const contentJson: PostStructuredContent[] = JSON.parse(data.insert.fold.content); const contentJson: TGApp.Plugins.Mys.Post.StructuredContent[] = JSON.parse(
data.insert.fold.content,
);
// 创建 div // 创建 div
const div = document.createElement("div"); const div = document.createElement("div");
div.classList.add("mys-post-div"); div.classList.add("mys-post-div");
@@ -419,13 +422,13 @@ function BackupTextParser(data: PostStructuredContent): HTMLDivElement {
const title = document.createElement("summary"); const title = document.createElement("summary");
// 解析标题 // 解析标题
titleJson.forEach((item) => { titleJson.forEach((item) => {
const parsed = ParserTransfer(item); const parsed = transferParser(item);
title.appendChild(parsed); title.appendChild(parsed);
}); });
// 创建内容 // 创建内容
const content = document.createElement("div"); const content = document.createElement("div");
contentJson.forEach((item) => { contentJson.forEach((item) => {
const parsed = ParserTransfer(item); const parsed = transferParser(item);
content.appendChild(parsed); content.appendChild(parsed);
}); });
details.appendChild(title); details.appendChild(title);
@@ -438,10 +441,10 @@ function BackupTextParser(data: PostStructuredContent): HTMLDivElement {
/** /**
* @description * @description
* @since Alpha v0.1.1 * @since Alpha v0.1.1
* @param {PostStructuredContent} data Mys数据 * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据
* @returns {HTMLDivElement} * @returns {HTMLDivElement}
*/ */
function LotteryParser(data: PostStructuredContent): HTMLDivElement { function LotteryParser(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivElement {
// 检查数据 // 检查数据
if (typeof data.insert === "string") { if (typeof data.insert === "string") {
throw new Error("data.insert is a string"); throw new Error("data.insert is a string");
@@ -476,10 +479,10 @@ function LotteryParser(data: PostStructuredContent): HTMLDivElement {
/** /**
* @description * @description
* @since Alpha v0.1.2 * @since Alpha v0.1.2
* @param {PostStructuredContent} data Mys数据 * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据
* @returns {HTMLDivElement} * @returns {HTMLDivElement}
*/ */
function LinkCardParser(data: PostStructuredContent): HTMLDivElement { function parseLinkCard(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLDivElement {
// 检查数据 // 检查数据
if (typeof data.insert === "string") { if (typeof data.insert === "string") {
throw new Error("data.insert is a string"); throw new Error("data.insert is a string");
@@ -519,7 +522,7 @@ function LinkCardParser(data: PostStructuredContent): HTMLDivElement {
button.classList.add("mys-post-link-card-btn"); button.classList.add("mys-post-link-card-btn");
button.innerHTML = (data.insert.link_card.button_text || "详情") + " >"; button.innerHTML = (data.insert.link_card.button_text || "详情") + " >";
const linkUrl = data.insert.link_card.origin_url; const linkUrl = data.insert.link_card.origin_url;
if (IsMysPost(linkUrl)) { if (isMysPost(linkUrl)) {
const postId = getPostId(linkUrl); const postId = getPostId(linkUrl);
button.href = `/post_detail/${postId}`; button.href = `/post_detail/${postId}`;
button.target = "_self"; button.target = "_self";
@@ -539,10 +542,10 @@ function LinkCardParser(data: PostStructuredContent): HTMLDivElement {
/** /**
* @description Mention * @description Mention
* @since Alpha v0.1.2 * @since Alpha v0.1.2
* @param {PostStructuredContent} data Mys数据 * @param {TGApp.Plugins.Mys.Post.StructuredContent} data Mys数据
* @returns {HTMLAnchorElement} Mention * @returns {HTMLAnchorElement} Mention
*/ */
function MentionParser(data: PostStructuredContent): HTMLAnchorElement { function parseMention(data: TGApp.Plugins.Mys.Post.StructuredContent): HTMLAnchorElement {
// 检查数据 // 检查数据
if (typeof data.insert === "string") { if (typeof data.insert === "string") {
throw new Error("data.insert is a string"); throw new Error("data.insert is a string");
@@ -563,3 +566,5 @@ function MentionParser(data: PostStructuredContent): HTMLAnchorElement {
link.prepend(icon); link.prepend(icon);
return link; return link;
} }
export default parsePost;

View File

@@ -1,58 +0,0 @@
/**
* @file plugins Mys utils position.ts
* @description Mys 插件热点追踪工具
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.5
*/
import { type PositionObc, type PositionData, type PositionCard } from "../interface/position";
/**
* @description 深度优先遍历
* @since Alpha v0.1.1
* @param {PositionObc[]} list 列表
* @returns {PositionData[]} 返回列表
*/
export function dfs(list: PositionObc[]): PositionData[] {
const res: PositionData[] = [];
for (const item of list) {
if (item.name === "近期活动") {
res.push(...item.list);
}
if (item.children) {
res.push(...dfs(<PositionObc[]>item.children));
}
}
return res;
}
/**
* @description 根据热点追踪信息转为渲染用的数据
* @since Alpha v0.1.5
* @param {PositionData[]} positionData 列表
* @returns {PositionCard[]} 返回列表
*/
export function getPositionCard(positionData: PositionData[]): PositionCard[] {
const res: PositionCard[] = [];
positionData.map((position) => {
let endStr: string;
if (position.end_time === "0") {
endStr = "";
} else {
endStr = new Date(Number(position.end_time)).toLocaleDateString().replace(/\//g, "-");
}
return res.push({
title: position.title,
post_id: Number(position.url.split("/").pop()),
icon: position.icon,
abstract: position.abstract,
time: {
start: position.create_time.split(" ")[0].replace(/\//g, "-"),
start_stamp: new Date(position.create_time).getTime(),
end: endStr,
end_stamp: Number(position.end_time),
},
});
});
return res;
}

View File

@@ -1,6 +1,6 @@
<template> <template>
<TSwitchTheme /> <TSwitchTheme />
<TOLoading v-model="loading" :empty="loadingEmpty" :title="loadingTitle" /> <ToLoading v-model="loading" :empty="loadingEmpty" :title="loadingTitle" />
<div v-if="!loading" class="lottery-box"> <div v-if="!loading" class="lottery-box">
<div class="lottery-title"> <div class="lottery-title">
抽奖详情 抽奖详情
@@ -25,18 +25,16 @@
<div class="reward-title">抽奖 ID{{ lotteryCard.id }}</div> <div class="reward-title">抽奖 ID{{ lotteryCard.id }}</div>
<div class="reward-title"> <div class="reward-title">
奖品详情 奖品详情
<div v-for="reward in lotteryCard.rewards" :key="reward.rewardName" class="reward-subtitle"> <div v-for="reward in lotteryCard.rewards" :key="reward.name" class="reward-subtitle">
{{ reward.rewardName }} {{ reward.scheduledWinnerNumber }} {{ reward.name }} {{ reward.goal }}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div v-if="timeStatus === '已开奖'" class="lottery-box"> <div v-if="timeStatus === '已开奖'" class="lottery-box">
<div class="lottery-title">中奖详情</div> <div class="lottery-title">中奖详情</div>
<div v-for="reward in lotteryCard.rewards" :key="reward.rewardName" class="lottery-list"> <div v-for="reward in lotteryCard.rewards" :key="reward.name" class="lottery-list">
<div class="reward-title"> <div class="reward-title">{{ reward.name }} {{ reward.win }}/{{ reward.goal }}</div>
{{ reward.rewardName }} {{ reward.scheduledWinnerNumber }}/{{ reward.winnerNumber }}
</div>
<div class="lottery-grid"> <div class="lottery-grid">
<div v-for="user in reward.users" :key="user.uid" class="lottery-sub-list"> <div v-for="user in reward.users" :key="user.uid" class="lottery-sub-list">
<div class="lottery-user-avatar"> <div class="lottery-user-avatar">
@@ -58,29 +56,27 @@
import { computed, onMounted, onUpdated, reactive, ref } from "vue"; import { computed, onMounted, onUpdated, reactive, ref } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import JsonViewer from "vue-json-viewer"; import JsonViewer from "vue-json-viewer";
import TOLoading from "../components/overlay/to-loading.vue"; import ToLoading from "../components/overlay/to-loading.vue";
import TSwitchTheme from "../components/main/t-switchTheme.vue"; import TSwitchTheme from "../components/main/t-switchTheme.vue";
// tauri // tauri
import { appWindow } from "@tauri-apps/api/window"; import { appWindow } from "@tauri-apps/api/window";
// store // store
import { useAppStore } from "../store/modules/app"; import { useAppStore } from "../store/modules/app";
// plugins // plugins
import MysOper from "../plugins/Mys"; import Mys from "../plugins/Mys";
// interface
import { LotteryCard, LotteryData } from "../plugins/Mys/interface/lottery";
// loading // loading
const loading = ref(true as boolean); const loading = ref<boolean>(true);
const loadingTitle = ref("正在加载"); const loadingTitle = ref<string>("正在加载");
const loadingEmpty = ref(false as boolean); const loadingEmpty = ref<boolean>(false);
// store // store
const appStore = useAppStore(); const appStore = useAppStore();
const showJson = computed(() => appStore.devMode); const showJson = computed(() => appStore.devMode);
// 定时器 // 定时器
const lotteryTimer = ref(null as any); const lotteryTimer = ref<any>(null);
// 参与方式 // 参与方式
const participationMethod = ref("未知" as string); const participationMethod = ref<string>("未知");
function flushTimeStatus() { function flushTimeStatus() {
const timeNow = new Date().getTime(); const timeNow = new Date().getTime();
@@ -99,9 +95,13 @@ function flushTimeStatus() {
// 数据 // 数据
const lotteryId = useRoute().params.lottery_id as string; const lotteryId = useRoute().params.lottery_id as string;
const lotteryCard = ref({} as LotteryCard); const lotteryCard = ref<TGApp.Plugins.Mys.Lottery.RenderCard>(
let jsonData = reactive({} as LotteryData); {} as TGApp.Plugins.Mys.Lottery.RenderCard,
const timeStatus = ref("未知" as string); );
let jsonData = reactive<TGApp.Plugins.Mys.Lottery.FullData>(
{} as TGApp.Plugins.Mys.Lottery.FullData,
);
const timeStatus = ref<string>("未知");
function backPost() { function backPost() {
window.history.back(); window.history.back();
@@ -117,7 +117,7 @@ onMounted(async () => {
} }
// 获取数据 // 获取数据
loadingTitle.value = "正在获取数据..."; loadingTitle.value = "正在获取数据...";
jsonData = await MysOper.Lottery.get(lotteryId); jsonData = await Mys.Lottery.get(lotteryId);
if (!jsonData) { if (!jsonData) {
loadingEmpty.value = true; loadingEmpty.value = true;
loadingTitle.value = "未找到数据"; loadingTitle.value = "未找到数据";
@@ -125,7 +125,7 @@ onMounted(async () => {
} }
await appWindow.setTitle("抽奖详情 " + jsonData.lottery_entity_summary); await appWindow.setTitle("抽奖详情 " + jsonData.lottery_entity_summary);
loadingTitle.value = "正在渲染数据..."; loadingTitle.value = "正在渲染数据...";
lotteryCard.value = MysOper.Lottery.card.lottery(jsonData); lotteryCard.value = Mys.Lottery.card(jsonData);
if (jsonData.status === "Settled") { if (jsonData.status === "Settled") {
timeStatus.value = "已开奖"; timeStatus.value = "已开奖";
} else { } else {
@@ -133,19 +133,19 @@ onMounted(async () => {
flushTimeStatus(); flushTimeStatus();
}, 1000); }, 1000);
} }
participationMethod.value = getParticipationMethod(lotteryCard.value.participantWay); participationMethod.value = getUpWay(lotteryCard.value.upWay);
setTimeout(() => { setTimeout(() => {
loading.value = false; loading.value = false;
}, 1000); }, 1000);
}); });
// 获取参与方式 // 获取参与方式
function getParticipationMethod(participantWay: string) { function getUpWay(upWay: string) {
switch (participantWay) { switch (upWay) {
case "Forward": case "Forward":
return "转发"; return "转发";
default: default:
return participantWay; return upWay;
} }
} }

View File

@@ -28,7 +28,7 @@
<v-window v-model="tab"> <v-window v-model="tab">
<v-window-item value="notice"> <v-window-item value="notice">
<div class="news-grid"> <div class="news-grid">
<v-card v-for="item in postData.notice" :key="item.post_id" class="news-card"> <v-card v-for="item in postData.notice" :key="item.postId" class="news-card">
<div class="news-cover" @click="toPost(item)"> <div class="news-cover" @click="toPost(item)">
<img :src="item.cover" alt="cover" /> <img :src="item.cover" alt="cover" />
</div> </div>
@@ -38,7 +38,7 @@
<img src="../assets/icons/circle-check.svg" alt="check" /> <img src="../assets/icons/circle-check.svg" alt="check" />
<span>查看</span> <span>查看</span>
</v-btn> </v-btn>
<v-card-subtitle>id:{{ item.post_id }}</v-card-subtitle> <v-card-subtitle>id:{{ item.postId }}</v-card-subtitle>
<v-btn v-show="appStore.devMode" class="card-dev-btn" @click="toJson(item)"> <v-btn v-show="appStore.devMode" class="card-dev-btn" @click="toJson(item)">
<template #prepend> <template #prepend>
<img src="../assets/icons/arrow-right.svg" alt="right" /> <img src="../assets/icons/arrow-right.svg" alt="right" />
@@ -59,7 +59,7 @@
</v-window-item> </v-window-item>
<v-window-item value="activity"> <v-window-item value="activity">
<div class="news-grid"> <div class="news-grid">
<v-card v-for="item in postData.activity" :key="item.post_id" class="news-card"> <v-card v-for="item in postData.activity" :key="item.postId" class="news-card">
<div class="news-cover" @click="toPost(item)"> <div class="news-cover" @click="toPost(item)">
<img :src="item.cover" alt="cover" /> <img :src="item.cover" alt="cover" />
</div> </div>
@@ -72,7 +72,7 @@
<span>查看</span> <span>查看</span>
</template> </template>
</v-btn> </v-btn>
<v-card-subtitle>id:{{ item.post_id }}</v-card-subtitle> <v-card-subtitle>id:{{ item.postId }}</v-card-subtitle>
<div v-show="!appStore.devMode"> <div v-show="!appStore.devMode">
<v-btn <v-btn
:style="{ :style="{
@@ -103,7 +103,7 @@
</v-window-item> </v-window-item>
<v-window-item v-if="showNews" value="news"> <v-window-item v-if="showNews" value="news">
<div class="news-grid"> <div class="news-grid">
<v-card v-for="item in postData.news" :key="item.post_id" class="news-card"> <v-card v-for="item in postData.news" :key="item.postId" class="news-card">
<div class="news-cover" @click="toPost(item)"> <div class="news-cover" @click="toPost(item)">
<img :src="item.cover" alt="cover" /> <img :src="item.cover" alt="cover" />
</div> </div>
@@ -115,7 +115,7 @@
<span>查看</span> <span>查看</span>
</template> </template>
</v-btn> </v-btn>
<v-card-subtitle>id:{{ item.post_id }}</v-card-subtitle> <v-card-subtitle>id:{{ item.postId }}</v-card-subtitle>
<v-btn v-show="appStore.devMode" class="card-dev-btn" @click="toJson(item)"> <v-btn v-show="appStore.devMode" class="card-dev-btn" @click="toJson(item)">
<template #prepend> <template #prepend>
<img src="../assets/icons/arrow-right.svg" alt="right" /> <img src="../assets/icons/arrow-right.svg" alt="right" />
@@ -150,39 +150,37 @@ import ToChannel from "../components/overlay/to-channel.vue";
// store // store
import { useAppStore } from "../store/modules/app"; import { useAppStore } from "../store/modules/app";
// plugin // plugin
import MysOper from "../plugins/Mys"; import Mys from "../plugins/Mys";
// utils // utils
import { createTGWindow } from "../utils/TGWindow"; import { createTGWindow } from "../utils/TGWindow";
// interface
import { NewsCard } from "../plugins/Mys/interface/news";
// 路由 // 路由
const router = useRouter(); const router = useRouter();
const gid = useRoute().params.gid as string; const gid = useRoute().params.gid;
const showNews = ref((gid !== "5") as boolean); const showNews = ref<boolean>(gid !== "5");
// Store // Store
const appStore = useAppStore(); const appStore = useAppStore();
// loading // loading
const loading = ref(true as boolean); const loading = ref<boolean>(true);
const loadingTitle = ref("正在加载" as string); const loadingTitle = ref<string>("正在加载");
const loadingSub = ref(false as boolean); const loadingSub = ref<boolean>(false);
// snackbar // snackbar
const snackbar = ref(false as boolean); const snackbar = ref<boolean>(false);
const snackbarText = ref("" as string); const snackbarText = ref<string>("");
const snackbarColor = ref("success" as string); const snackbarColor = ref<string>("success");
// search // search
const search = ref("" as string); const search = ref<string>("");
// 数据 // 数据
const tab = ref("" as string); const tab = ref<string>("");
const showList = ref(false as boolean); const showList = ref<boolean>(false);
const postData = ref({ const postData = ref({
notice: [] as NewsCard[], notice: [] as TGApp.Plugins.Mys.News.RenderCard[],
activity: [] as NewsCard[], activity: [] as TGApp.Plugins.Mys.News.RenderCard[],
news: [] as NewsCard[], news: [] as TGApp.Plugins.Mys.News.RenderCard[],
}); });
const rawData = ref({ const rawData = ref({
notice: { notice: {
@@ -204,10 +202,10 @@ const rawData = ref({
onMounted(async () => { onMounted(async () => {
loadingTitle.value = "正在获取公告数据"; loadingTitle.value = "正在获取公告数据";
const noticeData = await MysOper.News.get.notice(gid); const noticeData = await Mys.News.get(gid);
rawData.value.notice.isLast = noticeData.is_last; rawData.value.notice.isLast = noticeData.is_last;
rawData.value.notice.lastId = noticeData.list.length; rawData.value.notice.lastId = noticeData.list.length;
postData.value.notice = MysOper.News.card.notice(noticeData); postData.value.notice = Mys.News.card.notice(noticeData);
tab.value = "notice"; tab.value = "notice";
setTimeout(() => { setTimeout(() => {
loading.value = false; loading.value = false;
@@ -221,18 +219,18 @@ async function firstLoad(data: string) {
if (data === "activity" && rawData.value.activity.lastId === 0) { if (data === "activity" && rawData.value.activity.lastId === 0) {
loadingTitle.value = "正在获取活动数据..."; loadingTitle.value = "正在获取活动数据...";
loading.value = true; loading.value = true;
const activityData = await MysOper.News.get.activity(gid); const activityData = await Mys.News.get(gid, "2");
rawData.value.activity.isLast = activityData.is_last; rawData.value.activity.isLast = activityData.is_last;
rawData.value.activity.lastId = activityData.list.length; rawData.value.activity.lastId = activityData.list.length;
postData.value.activity = MysOper.News.card.activity(activityData); postData.value.activity = Mys.News.card.activity(activityData);
} }
if (data === "news" && rawData.value.news.lastId === 0) { if (data === "news" && rawData.value.news.lastId === 0) {
loadingTitle.value = "正在获取咨讯数据..."; loadingTitle.value = "正在获取咨讯数据...";
loading.value = true; loading.value = true;
const newsData = await MysOper.News.get.news(gid); const newsData = await Mys.News.get(gid, "3");
rawData.value.news.isLast = newsData.is_last; rawData.value.news.isLast = newsData.is_last;
rawData.value.news.lastId = newsData.list.length; rawData.value.news.lastId = newsData.list.length;
postData.value.news = MysOper.News.card.news(newsData); postData.value.news = Mys.News.card.news(newsData);
} }
setTimeout(() => { setTimeout(() => {
loading.value = false; loading.value = false;
@@ -244,7 +242,7 @@ async function switchAnno() {
} }
// 加载更多 // 加载更多
async function loadMore(data: string) { async function loadMore(data: "notice" | "activity" | "news"): Promise<void> {
loadingSub.value = true; loadingSub.value = true;
if (rawData.value[data].isLast) { if (rawData.value[data].isLast) {
snackbarText.value = "已经是最后一页了"; snackbarText.value = "已经是最后一页了";
@@ -255,10 +253,12 @@ async function loadMore(data: string) {
} }
loadingTitle.value = `正在获取${rawData.value[data].name}数据...`; loadingTitle.value = `正在获取${rawData.value[data].name}数据...`;
loading.value = true; loading.value = true;
const getData = await MysOper.News.get[data](gid, 20, rawData.value[data].lastId); const dataList = ["notice", "activity", "news"];
const dataIndex = (dataList.indexOf(data) + 1).toString();
const getData = await Mys.News.get(gid, dataIndex, 20, rawData.value[data].lastId);
rawData.value[data].lastId = rawData.value[data].lastId + getData.list.length; rawData.value[data].lastId = rawData.value[data].lastId + getData.list.length;
rawData.value[data].isLast = getData.is_last; rawData.value[data].isLast = getData.is_last;
const getCard = MysOper.News.card[data](getData); const getCard = Mys.News.card[data](getData);
postData.value[data] = postData.value[data].concat(getCard); postData.value[data] = postData.value[data].concat(getCard);
if (rawData.value[data].isLast) { if (rawData.value[data].isLast) {
snackbarText.value = "已经是最后一页了"; snackbarText.value = "已经是最后一页了";
@@ -274,30 +274,28 @@ async function loadMore(data: string) {
}, 1500); }, 1500);
} }
async function toPost(item: NewsCard | string) { async function toPost(item: TGApp.Plugins.Mys.News.RenderCard | string) {
console.log(item); if (typeof item === "string") {
// if (typeof item === "string") { const path = router.resolve({
// const path = router.resolve({ name: "帖子详情",
// name: "帖子详情", params: {
// params: { // eslint-disable-next-line camelcase
// // eslint-disable-next-line camelcase post_id: item,
// post_id: item, },
// }, }).href;
// }).href; createTGWindow(path, "帖子-Dev", item, 960, 720, false, false);
// createTGWindow(path, "帖子-Dev", item, 960, 720, false, false); } else {
// } else { const path = router.resolve({
// const path = router.resolve({ name: "帖子详情",
// name: "帖子详情", params: {
// params: { post_id: item.postId.toString(),
// // eslint-disable-next-line camelcase },
// post_id: item.post_id.toString(), }).href;
// }, createTGWindow(path, "帖子", item.title, 960, 720, false, false);
// }).href; }
// createTGWindow(path, "帖子", item.title, 960, 720, false, false);
// }
} }
async function toJson(item: NewsCard | string) { async function toJson(item: TGApp.Plugins.Mys.News.RenderCard | string) {
if (typeof item === "string") { if (typeof item === "string") {
const path = router.resolve({ const path = router.resolve({
name: "帖子详情JSON", name: "帖子详情JSON",
@@ -311,8 +309,7 @@ async function toJson(item: NewsCard | string) {
const path = router.resolve({ const path = router.resolve({
name: "帖子详情JSON", name: "帖子详情JSON",
params: { params: {
// eslint-disable-next-line camelcase post_id: item.postId.toString(),
post_id: item.post_id.toString(),
}, },
}).href; }).href;
createTGWindow(path, "帖子-JSON", `${item.title}-JSON`, 960, 720, false, false); createTGWindow(path, "帖子-JSON", `${item.title}-JSON`, 960, 720, false, false);

View File

@@ -1,6 +1,6 @@
<template> <template>
<TSwitchTheme /> <TSwitchTheme />
<TOLoading v-model="loading" :empty="loadingEmpty" :title="loadingTitle" /> <ToLoading v-model="loading" :empty="loadingEmpty" :title="loadingTitle" />
<div class="post-json"> <div class="post-json">
<div class="post-title">帖子返回内容 JSON</div> <div class="post-title">帖子返回内容 JSON</div>
<JsonViewer :value="jsonData" copyable boxed /> <JsonViewer :value="jsonData" copyable boxed />
@@ -11,17 +11,17 @@
import { ref, onMounted, reactive } from "vue"; import { ref, onMounted, reactive } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import JsonViewer from "vue-json-viewer"; import JsonViewer from "vue-json-viewer";
import TOLoading from "../components/overlay/to-loading.vue"; import ToLoading from "../components/overlay/to-loading.vue";
import TSwitchTheme from "../components/main/t-switchTheme.vue"; import TSwitchTheme from "../components/main/t-switchTheme.vue";
// tauri // tauri
import { appWindow } from "@tauri-apps/api/window"; import { appWindow } from "@tauri-apps/api/window";
// plugins // plugins
import MysOper from "../plugins/Mys"; import Mys from "../plugins/Mys";
// loading // loading
const loading = ref(true as boolean); const loading = ref<boolean>(true);
const loadingTitle = ref("正在加载"); const loadingTitle = ref<string>("正在加载");
const loadingEmpty = ref(false as boolean); const loadingEmpty = ref<boolean>(false);
// 数据 // 数据
const postId = Number(useRoute().params.post_id); const postId = Number(useRoute().params.post_id);
@@ -38,7 +38,7 @@ onMounted(async () => {
// 获取数据 // 获取数据
loadingTitle.value = "正在获取数据..."; loadingTitle.value = "正在获取数据...";
try { try {
jsonData = await MysOper.Post.get(postId); jsonData = await Mys.Post.get(postId);
loading.value = false; loading.value = false;
} catch (e) { } catch (e) {
loadingTitle.value = "帖子不存在或解析失败"; loadingTitle.value = "帖子不存在或解析失败";

View File

@@ -2,7 +2,7 @@
<template> <template>
<TSwitchTheme /> <TSwitchTheme />
<TShareBtn v-show="!loadingEmpty" v-model="postRef" :title="shareTitle" /> <TShareBtn v-show="!loadingEmpty" v-model="postRef" :title="shareTitle" />
<TOLoading v-model="loading" :empty="loadingEmpty" :title="loadingTitle" /> <ToLoading v-model="loading" :empty="loadingEmpty" :title="loadingTitle" />
<div class="mys-post-body"> <div class="mys-post-body">
<div class="mys-post-title"> <div class="mys-post-title">
{{ postRender.title }} {{ postRender.title }}
@@ -18,26 +18,26 @@
// vue // vue
import { ref, onMounted } from "vue"; import { ref, onMounted } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import TOLoading from "../components/overlay/to-loading.vue"; import ToLoading from "../components/overlay/to-loading.vue";
import TSwitchTheme from "../components/main/t-switchTheme.vue"; import TSwitchTheme from "../components/main/t-switchTheme.vue";
import TShareBtn from "../components/main/t-shareBtn.vue"; import TShareBtn from "../components/main/t-shareBtn.vue";
// tauri // tauri
import { appWindow } from "@tauri-apps/api/window"; import { appWindow } from "@tauri-apps/api/window";
// plugins // plugins
import MysOper from "../plugins/Mys"; import Mys from "../plugins/Mys";
// loading // loading
const loading = ref(true as boolean); const loading = ref<boolean>(true);
const loadingTitle = ref("正在加载"); const loadingTitle = ref<string>("正在加载");
const loadingEmpty = ref(false as boolean); const loadingEmpty = ref<boolean>(false);
// share // share
const postRef = ref({} as HTMLElement); const postRef = ref<HTMLElement>({} as HTMLElement);
const shareTitle = ref(""); const shareTitle = ref<string>("");
// 数据 // 数据
const postId = Number(useRoute().params.post_id); const postId = Number(useRoute().params.post_id);
const postHtml = ref(""); const postHtml = ref<string>("");
const postRender = ref({ const postRender = ref({
title: "", title: "",
created: "", created: "",
@@ -56,9 +56,9 @@ onMounted(async () => {
// 获取数据 // 获取数据
loadingTitle.value = "正在获取数据..."; loadingTitle.value = "正在获取数据...";
try { try {
const postData = await MysOper.Post.get(postId); const postData = await Mys.Post.get(postId);
loadingTitle.value = "正在渲染数据..."; loadingTitle.value = "正在渲染数据...";
postHtml.value = MysOper.Post.parser(postData); postHtml.value = Mys.Post.parser(postData);
postRender.value = { postRender.value = {
title: postData.post.subject, title: postData.post.subject,
created: new Date(postData.post.created_at * 1000).toLocaleString().replace(/\//g, "-"), created: new Date(postData.post.created_at * 1000).toLocaleString().replace(/\//g, "-"),