|
|
|
@ -7,6 +7,8 @@ module.exports = {
|
|
|
|
|
whitespace: 'condense'
|
|
|
|
|
},
|
|
|
|
|
setup() {
|
|
|
|
|
const bbsUrl = 'https://bbs.isekai.cn';
|
|
|
|
|
|
|
|
|
|
const mounted = Vue.ref(false);
|
|
|
|
|
const loading = Vue.ref(true);
|
|
|
|
|
const feedList = Vue.ref([]);
|
|
|
|
@ -15,69 +17,91 @@ module.exports = {
|
|
|
|
|
let recentData = {
|
|
|
|
|
recentNew: null,
|
|
|
|
|
recentEdit: null,
|
|
|
|
|
recentThread: null,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let requiredData = ['recentNew', 'recentEdit'];
|
|
|
|
|
let externalData = [];
|
|
|
|
|
|
|
|
|
|
const onLoaded = () => {
|
|
|
|
|
if (Array.isArray(recentData.recentNew) && Array.isArray(recentData.recentEdit)) {
|
|
|
|
|
// 混合两个列表
|
|
|
|
|
let recentList = [
|
|
|
|
|
...recentData.recentNew,
|
|
|
|
|
...recentData.recentEdit
|
|
|
|
|
];
|
|
|
|
|
recentList.sort((a, b) => b.orderWeight - a.orderWeight);
|
|
|
|
|
// 去除重复,获取pageid列表
|
|
|
|
|
let pageIdList = [];
|
|
|
|
|
recentList = recentList.filter((item) => {
|
|
|
|
|
if (pageIdList.includes(item.pageid)) {
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
pageIdList.push(item.pageid);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
if (!requiredData.every((key) => Array.isArray(recentData[key]))) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!externalData.every((key) => Array.isArray(recentData[key]))) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取页面详细信息
|
|
|
|
|
api.get({
|
|
|
|
|
"action": "query",
|
|
|
|
|
"prop": "extracts|info",
|
|
|
|
|
"pageids": pageIdList.join('|'),
|
|
|
|
|
"redirects": 1,
|
|
|
|
|
"converttitles": 1,
|
|
|
|
|
"exchars": 100,
|
|
|
|
|
"exintro": 1,
|
|
|
|
|
"explaintext": 1,
|
|
|
|
|
"inprop": "url"
|
|
|
|
|
}).done((data) => {
|
|
|
|
|
if (data.query && data.query.pages) {
|
|
|
|
|
const pageInfoList = data.query.pages;
|
|
|
|
|
recentList = recentList.map((info) => {
|
|
|
|
|
if (info.pageid in pageInfoList) {
|
|
|
|
|
const pageInfo = pageInfoList[info.pageid];
|
|
|
|
|
return {
|
|
|
|
|
pageid: info.pageid,
|
|
|
|
|
title: pageInfo.title,
|
|
|
|
|
description: pageInfo.extract,
|
|
|
|
|
url: pageInfo.fullurl
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return {
|
|
|
|
|
pageid: info.pageid,
|
|
|
|
|
title: info.title,
|
|
|
|
|
description: '',
|
|
|
|
|
url: mw.util.getUrl(info.title)
|
|
|
|
|
}
|
|
|
|
|
// 混合两个列表
|
|
|
|
|
let recentList = [];
|
|
|
|
|
requiredData.forEach((key) => {
|
|
|
|
|
recentList.push(...recentData[key]);
|
|
|
|
|
});
|
|
|
|
|
externalData.forEach((key) => {
|
|
|
|
|
recentList.push(...recentData[key]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
recentList.sort((a, b) => b.orderWeight - a.orderWeight);
|
|
|
|
|
|
|
|
|
|
// 去除重复,获取pageid列表
|
|
|
|
|
let pageIdList = [];
|
|
|
|
|
recentList = recentList.filter((item) => {
|
|
|
|
|
if (item.external) { // 不过滤外部页面
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pageIdList.includes(item.pageid)) {
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
pageIdList.push(item.pageid);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 获取页面详细信息
|
|
|
|
|
api.get({
|
|
|
|
|
"action": "query",
|
|
|
|
|
"prop": "extracts|info",
|
|
|
|
|
"pageids": pageIdList.join('|'),
|
|
|
|
|
"redirects": 1,
|
|
|
|
|
"converttitles": 1,
|
|
|
|
|
"exchars": 100,
|
|
|
|
|
"exintro": 1,
|
|
|
|
|
"explaintext": 1,
|
|
|
|
|
"inprop": "url"
|
|
|
|
|
}).done((data) => {
|
|
|
|
|
if (data.query && data.query.pages) {
|
|
|
|
|
const pageInfoList = data.query.pages;
|
|
|
|
|
recentList = recentList.map((info) => {
|
|
|
|
|
if (info.external) {
|
|
|
|
|
return {
|
|
|
|
|
pageid: -1,
|
|
|
|
|
...info,
|
|
|
|
|
};
|
|
|
|
|
} else if (info.pageid in pageInfoList) {
|
|
|
|
|
const pageInfo = pageInfoList[info.pageid];
|
|
|
|
|
return {
|
|
|
|
|
pageid: info.pageid,
|
|
|
|
|
title: pageInfo.title,
|
|
|
|
|
description: pageInfo.extract,
|
|
|
|
|
url: pageInfo.fullurl
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
// 设置data
|
|
|
|
|
feedList.value = recentList;
|
|
|
|
|
loading.value = false;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return {
|
|
|
|
|
pageid: info.pageid,
|
|
|
|
|
title: info.title,
|
|
|
|
|
description: '',
|
|
|
|
|
url: mw.util.getUrl(info.title)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
// 设置data
|
|
|
|
|
feedList.value = recentList;
|
|
|
|
|
loading.value = false;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Vue.onMounted(() => {
|
|
|
|
|
mounted.value = true;
|
|
|
|
|
const loadData = () => {
|
|
|
|
|
api.get({
|
|
|
|
|
action: 'query',
|
|
|
|
|
list: 'recentchanges',
|
|
|
|
@ -121,6 +145,46 @@ module.exports = {
|
|
|
|
|
onLoaded();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (bbsUrl) {
|
|
|
|
|
externalData.push('recentThread');
|
|
|
|
|
let formatter = document.createElement('div');
|
|
|
|
|
fetch('/api/bbs/recent').then((res) => {
|
|
|
|
|
if (res.ok) {
|
|
|
|
|
return res.json();
|
|
|
|
|
} else {
|
|
|
|
|
throw new Error('Cannot load bbs threads: HTTP ' + res.status + ' ' + res.statusText);
|
|
|
|
|
}
|
|
|
|
|
}).then((data) => {
|
|
|
|
|
recentData.recentThread = [];
|
|
|
|
|
if (data && Array.isArray(data.topics)) {
|
|
|
|
|
data.topics.forEach((topicData) => {
|
|
|
|
|
let data = {
|
|
|
|
|
external: true,
|
|
|
|
|
siteName: '异世界红茶馆',
|
|
|
|
|
title: topicData.title,
|
|
|
|
|
orderWeight: new Date(topicData.timestamp).getTime(),
|
|
|
|
|
url: bbsUrl + '/topic/' + topicData.slug,
|
|
|
|
|
}
|
|
|
|
|
if (topicData.teaser) {
|
|
|
|
|
data.url += '/' + topicData.teaser.index.toString();
|
|
|
|
|
// 去除HTML标签
|
|
|
|
|
formatter.innerHTML = topicData.teaser.content
|
|
|
|
|
data.description = formatter.innerText;
|
|
|
|
|
}
|
|
|
|
|
recentData.recentThread.push(data);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
onLoaded();
|
|
|
|
|
}).catch(console.error);
|
|
|
|
|
} else {
|
|
|
|
|
recentData.recentThread = [];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Vue.onMounted(() => {
|
|
|
|
|
mounted.value = true;
|
|
|
|
|
loadData();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
@ -133,7 +197,7 @@ module.exports = {
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<div class="isekai-feed-list" :class="{ mounted: mounted }">
|
|
|
|
|
<div class="isekai-feed-list isekai-thin-scrollbar" :class="{ mounted: mounted }">
|
|
|
|
|
<div v-if="loading" class="loading">
|
|
|
|
|
<div class="spinner">
|
|
|
|
|
<div class="oo-ui-widget oo-ui-widget-enabled oo-ui-progressBarWidget-indeterminate oo-ui-progressBarWidget"
|
|
|
|
@ -146,7 +210,10 @@ module.exports = {
|
|
|
|
|
<a class="isekai-list-item" v-for="(feedItem, index) in feedList" :key="index" :href="feedItem.url"
|
|
|
|
|
target="_blank">
|
|
|
|
|
<div class="isekai-list-item-content">
|
|
|
|
|
<div class="isekai-list-item-title">{{ feedItem.title }}</div>
|
|
|
|
|
<div class="isekai-list-item-title">
|
|
|
|
|
<div>{{ feedItem.title }}</div>
|
|
|
|
|
<div v-if="feedItem.siteName" class="tag">{{ feedItem.siteName }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="isekai-list-item-text">{{ feedItem.description }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="isekai-list-item-icon">
|
|
|
|
|