mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2c3b7e9ee8 | ||
![]() |
b86a28092a | ||
![]() |
d59e5f2133 | ||
![]() |
3fdd187102 | ||
![]() |
3f085fd8ae |
@@ -4,7 +4,7 @@
|
||||
"name": "NapCatQQ",
|
||||
"slug": "NapCat.Framework",
|
||||
"description": "高性能的 OneBot 11 协议实现",
|
||||
"version": "4.2.28",
|
||||
"version": "4.2.29",
|
||||
"icon": "./logo.png",
|
||||
"authors": [
|
||||
{
|
||||
|
@@ -1,5 +1,3 @@
|
||||
import { request } from '@/utils/request.js';
|
||||
|
||||
import { EventSourcePolyfill } from 'event-source-polyfill';
|
||||
type LogListItem = string;
|
||||
type LogListData = LogListItem[];
|
||||
@@ -15,7 +13,7 @@ export class LogManager {
|
||||
}
|
||||
public async GetLogList(): Promise<LogListData> {
|
||||
try {
|
||||
const ConfigResponse = await request(`${this.apiPrefix}/Log/GetLogList`, {
|
||||
const ConfigResponse = await fetch(`${this.apiPrefix}/Log/GetLogList`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.retCredential,
|
||||
@@ -35,7 +33,7 @@ export class LogManager {
|
||||
}
|
||||
public async GetLog(FileName: string): Promise<string> {
|
||||
try {
|
||||
const ConfigResponse = await request(`${this.apiPrefix}/Log/GetLog?id=${FileName}`, {
|
||||
const ConfigResponse = await fetch(`${this.apiPrefix}/Log/GetLog?id=${FileName}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.retCredential,
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import { request } from '@/utils/request.js';
|
||||
import { OneBotConfig } from '../../../src/onebot/config/config';
|
||||
|
||||
import { ResponseCode } from '../../../src/webui/src/const/status';
|
||||
export class QQLoginManager {
|
||||
private retCredential: string;
|
||||
private readonly apiPrefix: string;
|
||||
@@ -14,7 +13,7 @@ export class QQLoginManager {
|
||||
// TODO:
|
||||
public async GetOB11Config(): Promise<OneBotConfig> {
|
||||
try {
|
||||
const ConfigResponse = await request(`${this.apiPrefix}/OB11Config/GetConfig`, {
|
||||
const ConfigResponse = await fetch(`${this.apiPrefix}/OB11Config/GetConfig`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.retCredential,
|
||||
@@ -23,8 +22,8 @@ export class QQLoginManager {
|
||||
});
|
||||
if (ConfigResponse.status == 200) {
|
||||
const ConfigResponseJson = await ConfigResponse.json();
|
||||
if (ConfigResponseJson.code == 0) {
|
||||
return ConfigResponseJson?.data as OneBotConfig;
|
||||
if (ConfigResponseJson.code == ResponseCode.Success) {
|
||||
return ConfigResponseJson;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -35,7 +34,7 @@ export class QQLoginManager {
|
||||
|
||||
public async SetOB11Config(config: OneBotConfig): Promise<boolean> {
|
||||
try {
|
||||
const ConfigResponse = await request(`${this.apiPrefix}/OB11Config/SetConfig`, {
|
||||
const ConfigResponse = await fetch(`${this.apiPrefix}/OB11Config/SetConfig`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.retCredential,
|
||||
@@ -57,7 +56,7 @@ export class QQLoginManager {
|
||||
|
||||
public async checkQQLoginStatus(): Promise<boolean> {
|
||||
try {
|
||||
const QQLoginResponse = await request(`${this.apiPrefix}/QQLogin/CheckLoginStatus`, {
|
||||
const QQLoginResponse = await fetch(`${this.apiPrefix}/QQLogin/CheckLoginStatus`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.retCredential,
|
||||
@@ -77,7 +76,7 @@ export class QQLoginManager {
|
||||
}
|
||||
public async checkQQLoginStatusWithQrcode(): Promise<{ qrcodeurl: string; isLogin: string } | undefined> {
|
||||
try {
|
||||
const QQLoginResponse = await request(`${this.apiPrefix}/QQLogin/CheckLoginStatus`, {
|
||||
const QQLoginResponse = await fetch(`${this.apiPrefix}/QQLogin/CheckLoginStatus`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.retCredential,
|
||||
@@ -98,7 +97,7 @@ export class QQLoginManager {
|
||||
|
||||
public async checkWebUiLogined(): Promise<boolean> {
|
||||
try {
|
||||
const LoginResponse = await request(`${this.apiPrefix}/auth/check`, {
|
||||
const LoginResponse = await fetch(`${this.apiPrefix}/auth/check`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.retCredential,
|
||||
@@ -119,7 +118,7 @@ export class QQLoginManager {
|
||||
|
||||
public async loginWithToken(token: string): Promise<string | null> {
|
||||
try {
|
||||
const loginResponse = await request(`${this.apiPrefix}/auth/login`, {
|
||||
const loginResponse = await fetch(`${this.apiPrefix}/auth/login`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -140,7 +139,7 @@ export class QQLoginManager {
|
||||
|
||||
public async getQQLoginQrcode(): Promise<string> {
|
||||
try {
|
||||
const QQLoginResponse = await request(`${this.apiPrefix}/QQLogin/GetQQLoginQrcode`, {
|
||||
const QQLoginResponse = await fetch(`${this.apiPrefix}/QQLogin/GetQQLoginQrcode`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.retCredential,
|
||||
@@ -161,7 +160,7 @@ export class QQLoginManager {
|
||||
|
||||
public async getQQQuickLoginList(): Promise<string[]> {
|
||||
try {
|
||||
const QQLoginResponse = await request(`${this.apiPrefix}/QQLogin/GetQuickLoginList`, {
|
||||
const QQLoginResponse = await fetch(`${this.apiPrefix}/QQLogin/GetQuickLoginList`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.retCredential,
|
||||
@@ -182,7 +181,7 @@ export class QQLoginManager {
|
||||
|
||||
public async setQuickLogin(uin: string): Promise<{ result: boolean; errMsg: string }> {
|
||||
try {
|
||||
const QQLoginResponse = await request(`${this.apiPrefix}/QQLogin/SetQuickLogin`, {
|
||||
const QQLoginResponse = await fetch(`${this.apiPrefix}/QQLogin/SetQuickLogin`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.retCredential,
|
||||
|
@@ -4,31 +4,17 @@
|
||||
<h2 class="sotheby-font">QQ Login</h2>
|
||||
<div class="login-methods">
|
||||
<t-tooltip content="快速登录">
|
||||
<t-button
|
||||
id="quick-login"
|
||||
class="login-method"
|
||||
:class="{ active: loginMethod === 'quick' }"
|
||||
@click="loginMethod = 'quick'"
|
||||
>Quick Login</t-button
|
||||
>
|
||||
<t-button id="quick-login" class="login-method" :class="{ active: loginMethod === 'quick' }"
|
||||
@click="loginMethod = 'quick'">Quick Login</t-button>
|
||||
</t-tooltip>
|
||||
<t-tooltip content="二维码登录">
|
||||
<t-button
|
||||
id="qrcode-login"
|
||||
class="login-method"
|
||||
:class="{ active: loginMethod === 'qrcode' }"
|
||||
@click="loginMethod = 'qrcode'"
|
||||
>QR Code</t-button
|
||||
>
|
||||
<t-button id="qrcode-login" class="login-method" :class="{ active: loginMethod === 'qrcode' }"
|
||||
@click="loginMethod = 'qrcode'">QR Code</t-button>
|
||||
</t-tooltip>
|
||||
</div>
|
||||
<div v-show="loginMethod === 'quick'" id="quick-login-dropdown" class="login-form">
|
||||
<t-select
|
||||
id="quick-login-select"
|
||||
v-model="selectedAccount"
|
||||
placeholder="Select Account"
|
||||
@change="selectAccount"
|
||||
>
|
||||
<t-select id="quick-login-select" v-model="selectedAccount" placeholder="Select Account"
|
||||
@change="selectAccount">
|
||||
<t-option v-for="account in quickLoginList" :key="account" :value="account">{{ account }}</t-option>
|
||||
</t-select>
|
||||
</div>
|
||||
@@ -41,7 +27,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ref, onMounted, onBeforeUnmount, nextTick, watch } from 'vue';
|
||||
import * as QRCode from 'qrcode';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { MessagePlugin } from 'tdesign-vue-next';
|
||||
@@ -55,6 +41,7 @@ const qrcodeCanvas = ref<HTMLCanvasElement | null>(null);
|
||||
const qqLoginManager = new QQLoginManager(localStorage.getItem('auth') || '');
|
||||
let heartBeatTimer: number | null = null;
|
||||
let qrcodeUrl: string = '';
|
||||
|
||||
const selectAccount = async (accountName: string): Promise<void> => {
|
||||
const { result, errMsg } = await qqLoginManager.setQuickLogin(accountName);
|
||||
if (result) {
|
||||
@@ -88,10 +75,6 @@ const HeartBeat = async (): Promise<void> => {
|
||||
if (heartBeatTimer) {
|
||||
clearInterval(heartBeatTimer);
|
||||
}
|
||||
// //判断是否已经调转
|
||||
// if (router.currentRoute.value.path !== '/dashboard/basic-info') {
|
||||
// return;
|
||||
// }
|
||||
await MessagePlugin.success('登录成功即将跳转');
|
||||
await router.push({ path: '/dashboard/basic-info' });
|
||||
} else if (isLogined?.qrcodeurl && qrcodeUrl !== isLogined.qrcodeurl) {
|
||||
@@ -103,19 +86,38 @@ const HeartBeat = async (): Promise<void> => {
|
||||
const InitPages = async (): Promise<void> => {
|
||||
quickLoginList.value = await qqLoginManager.getQQQuickLoginList();
|
||||
qrcodeUrl = await qqLoginManager.getQQLoginQrcode();
|
||||
await nextTick();
|
||||
generateQrCode(qrcodeUrl, qrcodeCanvas.value);
|
||||
heartBeatTimer = window.setInterval(HeartBeat, 3000);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
InitPages();
|
||||
InitPages().then().catch((err) => {
|
||||
console.error('InitPages Error:', err);
|
||||
});
|
||||
heartBeatTimer = window.setInterval(HeartBeat, 3000);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (heartBeatTimer) {
|
||||
clearInterval(heartBeatTimer);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
watch(loginMethod, async (newMethod) => {
|
||||
if (newMethod === 'qrcode') {
|
||||
await nextTick();
|
||||
generateQrCode(qrcodeUrl, qrcodeCanvas.value);
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.layout {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.login-container {
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
@@ -182,4 +184,4 @@ onMounted(() => {
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
</style>
|
||||
</style>
|
@@ -8,6 +8,7 @@ import QQLogin from '../components/QQLogin.vue';
|
||||
import WebUiLogin from '../components/WebUiLogin.vue';
|
||||
import OtherConfig from '../pages/OtherConfig.vue';
|
||||
import { MessagePlugin } from 'tdesign-vue-next';
|
||||
import { QQLoginManager } from '@/backend/shell';
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{ path: '/', redirect: '/webui' },
|
||||
@@ -32,17 +33,22 @@ const router = createRouter({
|
||||
routes,
|
||||
});
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
const isPublicRoute = ['/webui', '/qqlogin'].includes(to.path);
|
||||
const token = localStorage.getItem('auth');
|
||||
if (!token && to.path !== '/webui' && to.path !== '/qqlogin') {
|
||||
MessagePlugin.error('Token 过期啦, 重新登录吧');
|
||||
localStorage.clear();
|
||||
setTimeout(() => {
|
||||
next('/webui');
|
||||
}, 500);
|
||||
} else {
|
||||
next();
|
||||
|
||||
if (!isPublicRoute) {
|
||||
if (!token) {
|
||||
MessagePlugin.error('请先登录');
|
||||
return next('/webui');
|
||||
}
|
||||
const login = await new QQLoginManager(token).checkWebUiLogined();
|
||||
if (!login) {
|
||||
MessagePlugin.error('请先登录');
|
||||
return next('/webui');
|
||||
}
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
@@ -1,14 +0,0 @@
|
||||
import { MessagePlugin } from 'tdesign-vue-next';
|
||||
import router from '@/router/index.js';
|
||||
|
||||
export const request = async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
const res = await fetch(input, init);
|
||||
const json = await res.json();
|
||||
if (json.message.includes('Unauthorized')) {
|
||||
MessagePlugin.error('Token 过期啦, 重新登录吧');
|
||||
localStorage.clear();
|
||||
router.push('/webui');
|
||||
}
|
||||
res.json = async () => json;
|
||||
return res;
|
||||
};
|
@@ -2,7 +2,7 @@
|
||||
"name": "napcat",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "4.2.28",
|
||||
"version": "4.2.29",
|
||||
"scripts": {
|
||||
"build:universal": "npm run build:webui && vite build --mode universal || exit 1",
|
||||
"build:framework": "npm run build:webui && vite build --mode framework || exit 1",
|
||||
|
@@ -1 +1 @@
|
||||
export const napCatVersion = '4.2.28';
|
||||
export const napCatVersion = '4.2.29';
|
||||
|
@@ -1,5 +1,5 @@
|
||||
//LiteLoader需要提供部分IPC接口,以便于其他插件调用
|
||||
const { ipcMain } = require('electron');
|
||||
const { ipcMain, BrowserWindow } = require('electron');
|
||||
const napcat = require('./napcat.cjs');
|
||||
const { shell } = require('electron');
|
||||
ipcMain.handle('napcat_get_webtoken', async (event, arg) => {
|
||||
@@ -13,4 +13,14 @@ ipcMain.handle('napcat_get_reactweb', async (event, arg) => {
|
||||
let port = url.port;
|
||||
let token = url.searchParams.get('token');
|
||||
return `https://napcat.152710.xyz/web_login?back=http://127.0.0.1:${port}&token=${token}`;
|
||||
});
|
||||
|
||||
ipcMain.on('napcat_open_inner_url', (event, url) => {
|
||||
const win = new BrowserWindow({
|
||||
autoHideMenuBar: true,
|
||||
});
|
||||
win.loadURL(url);
|
||||
win.webContents.setWindowOpenHandler(details => {
|
||||
win.loadURL(details.url)
|
||||
})
|
||||
});
|
@@ -6,6 +6,9 @@ const napcat = {
|
||||
openExternalUrl: async (url) => {
|
||||
ipcRenderer.send('open_external_url', url);
|
||||
},
|
||||
openInnerUrl: async (url) => {
|
||||
ipcRenderer.send('napcat_open_inner_url', url);
|
||||
},
|
||||
getWebUiUrlReact: async () => {
|
||||
return ipcRenderer.invoke('napcat_get_reactweb');
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ export const onSettingWindowCreated = async (view) => {
|
||||
`;
|
||||
|
||||
view.querySelector('.nc_openwebui').addEventListener('click', () => {
|
||||
window.open(webui, '_blank');
|
||||
window.napcat.openInnerUrl(webui);
|
||||
});
|
||||
view.querySelector('.nc_openwebui_ex').addEventListener('click', () => {
|
||||
window.napcat.openExternalUrl(webui);
|
||||
|
@@ -29,13 +29,14 @@ class GetGroupMemberInfo extends OneBotAction<Payload, OB11GroupMember> {
|
||||
async _handle(payload: Payload) {
|
||||
const isNocache = this.parseBoolean(payload.no_cache ?? true);
|
||||
const uid = await this.getUid(payload.user_id);
|
||||
const [member, info] = await Promise.all([
|
||||
const groupMember = this.core.apis.GroupApi.groupMemberCache.get(payload.group_id.toString())?.get(uid);
|
||||
let [member, info] = await Promise.all([
|
||||
this.core.apis.GroupApi.getGroupMemberEx(payload.group_id.toString(), uid, isNocache),
|
||||
this.core.apis.UserApi.getUserDetailInfo(uid),
|
||||
]);
|
||||
if (!member) throw new Error(`群(${payload.group_id})成员${payload.user_id}不存在`);
|
||||
if (!member || !groupMember) throw new Error(`群(${payload.group_id})成员${payload.user_id}不存在`);
|
||||
if (info) {
|
||||
Object.assign(member, info);
|
||||
member = { ...groupMember, ...member, ...info };
|
||||
} else {
|
||||
this.core.context.logger.logDebug(`获取群成员详细信息失败, 只能返回基础信息`);
|
||||
}
|
||||
|
Reference in New Issue
Block a user