You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

235 lines
8.9 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<script>
const { ref, onMounted } = require('vue');
module.exports = {
compatConfig: {
MODE: 3
},
compilerOptions: {
whitespace: 'condense'
},
setup() {
const bbsUrl = 'https://bbs.isekai.cn';
const mounted = ref(false);
const loading = ref(true);
const feedList = ref([]);
const api = new mw.Api();
let recentData = {
recentNew: null,
recentEdit: null,
recentThread: null,
};
let requiredData = ['recentNew', 'recentEdit'];
let externalData = [];
const onLoaded = () => {
if (!requiredData.every((key) => Array.isArray(recentData[key]))) {
return false;
}
if (!externalData.every((key) => Array.isArray(recentData[key]))) {
return false;
}
// 混合两个列表
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
}
} else {
return {
pageid: info.pageid,
title: info.title,
description: '',
url: mw.util.getUrl(info.title)
}
}
});
// 设置data
feedList.value = recentList;
loading.value = false;
}
});
};
const loadData = () => {
api.get({
action: 'query',
list: 'recentchanges',
rctype: 'edit',
rcnamespace: 0,
rclimit: 20,
}).done((data) => {
recentData.recentEdit = [];
if (data.query && Array.isArray(data.query.recentchanges)) { //有成功取到数据
data.query.recentchanges.forEach((one) => {
if (one.timestamp) {
one.timestamp = new Date(one.timestamp).getTime();
one.orderWeight = one.timestamp;
} else {
one.orderWeight = 0;
}
recentData.recentEdit.push(one);
});
onLoaded();
}
});
api.get({
action: 'query',
list: 'recentchanges',
rctype: 'new',
rcnamespace: 0,
rclimit: 20,
}).done((data) => {
recentData.recentNew = [];
if (data.query && Array.isArray(data.query.recentchanges)) { // 成功取到数据
data.query.recentchanges.forEach((one) => {
if (one.timestamp) {
one.timestamp = new Date(one.timestamp).getTime();
one.orderWeight = one.timestamp + (86400 * 1000); // 新页面保护权重比页面更新高7天
} else {
one.orderWeight = 0;
}
recentData.recentNew.push(one);
});
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((err) => {
console.error(err);
// 加载论坛帖子失败不阻塞
recentData.recentThread = [];
onLoaded();
});
} else {
recentData.recentThread = [];
}
}
onMounted(() => {
mounted.value = true;
loadData();
});
return {
mounted,
loading,
feedList
}
}
}
</script>
<template>
<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"
aria-disabled="false" role="progressbar" aria-valuemin="0" aria-valuemax="100">
<div class="oo-ui-progressBarWidget-bar"></div>
</div>
</div>
</div>
<ul v-else class="isekai-list">
<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">
<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">
<span
class="oo-ui-widget oo-ui-widget-enabled oo-ui-iconElement oo-ui-iconElement-icon oo-ui-image-progressive oo-ui-icon-next oo-ui-labelElement-invisible oo-ui-iconWidget"
aria-disabled="false"></span>
</div>
</a>
</ul>
</div>
</template>