Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
fa1bbf6098 | ||
![]() |
f5188c1ec6 | ||
![]() |
6b71f1c345 | ||
![]() |
538acbf7ea | ||
![]() |
d7f97a6fa0 | ||
![]() |
4b6cde786e | ||
![]() |
b3c1eff137 |
@@ -15,10 +15,7 @@ charset = utf-8
|
||||
# 2 space indentation
|
||||
[*.{cjs,mjs,js,jsx,ts,tsx,css,scss,sass,html,json}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.bat]
|
||||
charset = latin1
|
||||
indent_size = 2
|
||||
|
||||
# Unfortunately, EditorConfig doesn't support space configuration inside import braces directly.
|
||||
# You'll need to rely on your linter/formatter like ESLint or Prettier for that.
|
||||
|
1
.env.development
Normal file
@@ -0,0 +1 @@
|
||||
VITE_BUILD_TYPE = Development
|
@@ -1,2 +0,0 @@
|
||||
VITE_BUILD_TYPE = Production
|
||||
VITE_BUILD_PLATFORM = Framework
|
@@ -1,2 +1 @@
|
||||
VITE_BUILD_TYPE = Production
|
||||
VITE_BUILD_PLATFORM = Shell
|
68
.eslintrc.cjs
Normal file
@@ -0,0 +1,68 @@
|
||||
module.exports = {
|
||||
'env': {
|
||||
'browser': true,
|
||||
'es2021': true,
|
||||
'node': true
|
||||
},
|
||||
'ignorePatterns': ['src/core/', 'src/core.lib/','src/proto/'],
|
||||
'extends': [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended'
|
||||
],
|
||||
'overrides': [
|
||||
{
|
||||
'env': {
|
||||
'node': true
|
||||
},
|
||||
'files': [
|
||||
'.eslintrc.{js,cjs}'
|
||||
],
|
||||
'parserOptions': {
|
||||
'sourceType': 'script'
|
||||
}
|
||||
}
|
||||
],
|
||||
'parser': '@typescript-eslint/parser',
|
||||
'parserOptions': {
|
||||
'ecmaVersion': 'latest',
|
||||
'sourceType': 'module'
|
||||
},
|
||||
'plugins': [
|
||||
'@typescript-eslint',
|
||||
'import'
|
||||
],
|
||||
'settings': {
|
||||
'import/parsers': {
|
||||
'@typescript-eslint/parser': ['.ts']
|
||||
},
|
||||
'import/resolver': {
|
||||
'typescript': {
|
||||
'alwaysTryTypes': true
|
||||
}
|
||||
}
|
||||
},
|
||||
'rules': {
|
||||
'indent': [
|
||||
'error',
|
||||
2
|
||||
],
|
||||
'linebreak-style': [
|
||||
'error',
|
||||
'unix'
|
||||
],
|
||||
'quotes': [
|
||||
'error',
|
||||
'single'
|
||||
],
|
||||
'semi': [
|
||||
'error',
|
||||
'always'
|
||||
],
|
||||
'no-unused-vars': 'off',
|
||||
'no-async-promise-executor': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'off',
|
||||
'object-curly-spacing': ['error', 'always'],
|
||||
}
|
||||
};
|
1
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -10,7 +10,6 @@ body:
|
||||
在提交新的 Bug 反馈前,请确保您:
|
||||
* 已经搜索了现有的 issues,并且没有找到可以解决您问题的方法
|
||||
* 不与现有的某一 issue 重复
|
||||
* 不涉及[已经停止维护的特性](https://github.com/NapNeko/NapCatQQ?tab=readme-ov-file#挥别昨日),例如 CQ 码
|
||||
- type: input
|
||||
id: system-version
|
||||
attributes:
|
||||
|
55
.github/workflows/build.yml
vendored
@@ -1,47 +1,74 @@
|
||||
name: "Build Action"
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions: write-all
|
||||
|
||||
jobs:
|
||||
Build-LiteLoader:
|
||||
build-linux:
|
||||
if: ${{ startsWith(github.event.head_commit.message, 'build:') }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target_platform: [linux]
|
||||
target_arch: [x64, arm64]
|
||||
steps:
|
||||
- name: Clone Main Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'NapNeko/NapCatQQ'
|
||||
submodules: true
|
||||
ref: main
|
||||
token: ${{ secrets.NAPCAT_BUILD }}
|
||||
- name: Use Node.js 20.X
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.x
|
||||
- name: Build NapCat.Framework
|
||||
- name: Build NuCat Linux
|
||||
run: |
|
||||
npm i && cd napcat.webui && npm i && cd .. || exit 1
|
||||
npm run build:framework && npm run depend || exit 1
|
||||
rm package-lock.json
|
||||
npm i --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
npm run build:prod
|
||||
cd dist
|
||||
npm i --omit=dev --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
cd ..
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: NapCat.Framework
|
||||
name: NapCat.${{ matrix.target_platform }}.${{ matrix.target_arch }}
|
||||
path: dist
|
||||
Build-Shell:
|
||||
build-win32:
|
||||
if: ${{ startsWith(github.event.head_commit.message, 'build:') }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target_platform: [win32]
|
||||
target_arch: [x64,ia32]
|
||||
steps:
|
||||
- name: Clone Main Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'NapNeko/NapCatQQ'
|
||||
submodules: true
|
||||
ref: main
|
||||
token: ${{ secrets.NAPCAT_BUILD }}
|
||||
- name: Use Node.js 20.X
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.x
|
||||
- name: Build NapCat.Shell
|
||||
- name: Build NuCat Linux
|
||||
run: |
|
||||
npm i && cd napcat.webui && npm i && cd .. || exit 1
|
||||
npm run build:shell && npm run depend || exit 1
|
||||
rm package-lock.json
|
||||
npm i --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
npm run build:prod
|
||||
cd dist
|
||||
npm i --omit=dev --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
cd ..
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: NapCat.Shell
|
||||
name: NapCat.${{ matrix.target_platform }}.${{ matrix.target_arch }}
|
||||
path: dist
|
||||
|
87
.github/workflows/release.yml
vendored
@@ -30,9 +30,14 @@ jobs:
|
||||
ls
|
||||
node ./script/checkVersion.cjs
|
||||
sh ./checkVersion.sh
|
||||
Build-LiteLoader:
|
||||
build-linux:
|
||||
needs: [check-version]
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target_platform: [linux]
|
||||
target_arch: [x64, arm64]
|
||||
steps:
|
||||
- name: Clone Main Repository
|
||||
uses: actions/checkout@v4
|
||||
@@ -46,24 +51,28 @@ jobs:
|
||||
with:
|
||||
node-version: 20.x
|
||||
|
||||
- name: Build NuCat Framework
|
||||
- name: Build NuCat Linux
|
||||
run: |
|
||||
npm i
|
||||
cd napcat.webui
|
||||
npm i
|
||||
cd ..
|
||||
npm run build:framework
|
||||
export NAPCAT_BUILDSYS=${{ matrix.target_platform }}
|
||||
export NAPCAT_BUILDARCH=${{ matrix.target_arch }}
|
||||
npm i --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
npm run build:prod
|
||||
cd dist
|
||||
npm i --omit=dev
|
||||
npm i --omit=dev --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
cd ..
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: NapCat.Framework
|
||||
name: NapCat.${{ matrix.target_platform }}.${{ matrix.target_arch }}
|
||||
path: dist
|
||||
Build-Shell:
|
||||
build-win32:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [check-version]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target_platform: [win32]
|
||||
target_arch: [x64,ia32]
|
||||
steps:
|
||||
- name: Clone Main Repository
|
||||
uses: actions/checkout@v4
|
||||
@@ -78,61 +87,36 @@ jobs:
|
||||
with:
|
||||
node-version: 20.x
|
||||
|
||||
- name: Build NuCat Shell
|
||||
- name: Build NuCat Linux
|
||||
run: |
|
||||
npm i
|
||||
cd napcat.webui
|
||||
npm i
|
||||
cd ..
|
||||
npm run build:shell
|
||||
export NAPCAT_BUILDSYS=${{ matrix.target_platform }}
|
||||
export NAPCAT_BUILDARCH=${{ matrix.target_arch }}
|
||||
npm i --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
npm run build:prod
|
||||
cd dist
|
||||
npm i --omit=dev
|
||||
npm i --omit=dev --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
cd ..
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: NapCat.Shell
|
||||
name: NapCat.${{ matrix.target_platform }}.${{ matrix.target_arch }}
|
||||
path: dist
|
||||
|
||||
release-napcat:
|
||||
needs: [Build-LiteLoader,Build-Shell]
|
||||
needs: [build-win32,build-linux]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Clone Main Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'NapNeko/NapCatQQ'
|
||||
submodules: true
|
||||
ref: main
|
||||
token: ${{ secrets.NAPCAT_BUILD }}
|
||||
|
||||
- name: Download All Artifact
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: Compress subdirectories
|
||||
run: |
|
||||
cd ./NapCat.Shell/
|
||||
zip -q -r NapCat.Shell.zip *
|
||||
cd ..
|
||||
cd ./NapCat.Framework/
|
||||
zip -q -r NapCat.Framework.zip *
|
||||
cd ..
|
||||
rm ./NapCat.Shell.zip -rf
|
||||
rm ./NapCat.Framework.zip -rf
|
||||
mv ./NapCat.Shell/NapCat.Shell.zip ./
|
||||
mv ./NapCat.Framework/NapCat.Framework.zip ./
|
||||
for dir in */; do
|
||||
base=$(basename "$dir")
|
||||
zip -r "${base}.zip" "$dir"
|
||||
done
|
||||
|
||||
mkdir ./NapCat.Framework.Windows.Once
|
||||
unzip -q ./external/LiteLoaderWrapper.zip -d ./NapCat.Framework.Windows.Once
|
||||
cd ./NapCat.Framework.Windows.Once
|
||||
ls
|
||||
mkdir -p ./LL/plugins/NapCatQQ
|
||||
unzip -q ../NapCat.Framework.zip -d ./LL/plugins/NapCatQQ
|
||||
zip -q -r NapCat.Framework.Windows.Once.zip *
|
||||
cd ..
|
||||
mv ./NapCat.Framework.Windows.Once/NapCat.Framework.Windows.Once.zip ./
|
||||
- name: Extract version from tag
|
||||
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
|
||||
|
||||
@@ -146,7 +130,10 @@ jobs:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
body_path: CHANGELOG.md
|
||||
files: |
|
||||
NapCat.Framework.zip
|
||||
NapCat.Shell.zip
|
||||
NapCat.Framework.Windows.Once.zip
|
||||
NapCat.win32.ia32.zip
|
||||
NapCat.win32.x64.zip
|
||||
NapCat.linux.x64.zip
|
||||
NapCat.linux.arm64.zip
|
||||
# NapCat.darwin.x64.zip
|
||||
# NapCat.darwin.arm64.zip
|
||||
draft: true
|
||||
|
69
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
name: "Build Test"
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: write-all
|
||||
|
||||
jobs:
|
||||
build-linux:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target_platform: [linux]
|
||||
target_arch: [x64, arm64]
|
||||
steps:
|
||||
- name: Clone Main Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'NapNeko/NapCatQQ'
|
||||
submodules: true
|
||||
ref: main
|
||||
token: ${{ secrets.NAPCAT_BUILD }}
|
||||
- name: Use Node.js 20.X
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.x
|
||||
- name: Build NuCat Linux
|
||||
run: |
|
||||
npm i --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
npm run build:prod
|
||||
cd dist
|
||||
npm i --omit=dev --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
cd ..
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: NapCat.${{ matrix.target_platform }}.${{ matrix.target_arch }}
|
||||
path: dist
|
||||
build-win32:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target_platform: [win32]
|
||||
target_arch: [x64,ia32]
|
||||
steps:
|
||||
- name: Clone Main Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'NapNeko/NapCatQQ'
|
||||
submodules: true
|
||||
ref: main
|
||||
token: ${{ secrets.NAPCAT_BUILD }}
|
||||
- name: Use Node.js 20.X
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.x
|
||||
- name: Build NuCat Linux
|
||||
run: |
|
||||
npm i --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
npm run build:prod
|
||||
cd dist
|
||||
npm i --omit=dev --arch=${{ matrix.target_arch }} --platform=${{ matrix.target_platform }}
|
||||
cd ..
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: NapCat.${{ matrix.target_platform }}.${{ matrix.target_arch }}
|
||||
path: dist
|
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 4,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "always",
|
||||
"printWidth": 120,
|
||||
"endOfLine": "auto"
|
||||
}
|
380
LICENSE
@@ -1,19 +1,373 @@
|
||||
Limited Redistribution License for NapCat
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
Copyright © 2024 Mlikiowa
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1. Usage and Reproduction:
|
||||
- Unauthorized use, reproduction, modification, or distribution of this code is prohibited without explicit permission from the main author of the NapCat repository.
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
2. Redistribution:
|
||||
- Redistribution of this code is permitted, provided that the full text of this license is included, and the source and copyright information is clearly stated.
|
||||
- Minor modifications and extensions are allowed for redistribution purposes, but the modified code must not be publicly released.
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
3. Non-Commercial Use:
|
||||
- This code is not to be used for any commercial purposes.
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
4. Additional Permissions:
|
||||
- Any rights not explicitly addressed in this license must be requested from and granted by the main author of the NapCat repository.
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
5. Disclaimer:
|
||||
- This code is provided "as is," without any express or implied warranties, including but not limited to the implied warranties of merchantability and fitness for a particular purpose. In no event shall the author be liable for any damages or other liability arising from, out of, or in connection with the use or distribution of this code.
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
|
54
README.md
@@ -1,53 +1,33 @@
|
||||
<div align="center">
|
||||
|
||||

|
||||
|
||||
<img src="https://socialify.git.ci/NapNeko/NapCatQQ/image?description=1&language=1&logo=https%3A%2F%2Fraw.githubusercontent.com%2FNapNeko%2FNapCatQQ%2Fmain%2Flogo.png&name=1&stargazers=1&theme=Auto" alt="NapCatQQ" width="640" height="320" />
|
||||
</div>
|
||||
|
||||
---
|
||||
## 欢迎回家
|
||||
NapCatQQ 是现代化的基于 NTQQ 的 Bot 协议端实现
|
||||
## 项目介绍
|
||||
|
||||
## 特性介绍
|
||||
- [x] **安装简单**:就算是笨蛋也能使用
|
||||
- [x] **性能友好**:就算是低内存也能使用
|
||||
- [x] **接口丰富**:就算是没有也能使用
|
||||
- [x] **稳定好用**:就算是被捉也能使用
|
||||
NapCatQQ 是基于 PC NTQQ 本体实现一套无头 Bot 框架。
|
||||
|
||||
## 使用框架
|
||||
名字寓意 瞌睡猫QQ,像睡着了一样在后台低占用运行的无需GUI界面的NTQQ。
|
||||
|
||||
## 如何使用
|
||||
|
||||
可前往 [Release](https://github.com/NapNeko/NapCatQQ/releases/) 页面下载最新版本
|
||||
|
||||
**首次使用**请务必查看如下文档看使用教程
|
||||
|
||||
### 文档地址
|
||||
|
||||
[Cloudflare.Worker](https://doc.napneko.icu/)
|
||||
|
||||
[Cloudflare.HKServer](https://napcat.napneko.icu/)
|
||||
|
||||
[Github.IO](https://napneko.github.io/)
|
||||
|
||||
[Cloudflare.Pages](https://napneko.pages.dev/)
|
||||
|
||||
[Server.Other](https://napcat.cyou/)
|
||||
**首次使用** 请务必前往 [官方文档](https://napneko.github.io/) 查看使用文档与教程
|
||||
|
||||
|
||||
## 回家旅途
|
||||
[QQ Group](https://qm.qq.com/q/NWP25OeV0c)
|
||||
## 项目声明
|
||||
|
||||
## 感谢他们
|
||||
感谢 [Lagrange](https://github.com/LagrangeDev/Lagrange.Core) 对本项目的大力支持 参考部分代码 已获授权
|
||||
* 请不要在无关地方宣传NapCatQQ,本项目只是用于学习 node 相关知识,切勿用于违法用途
|
||||
|
||||
感谢 Tencent Tdesign / Vue3 强力驱动 NapCat.WebUi
|
||||
* NapCat 不会收集用户隐私信息,但是未来可能会为了更好的利于 NapCat 的优化会收集一些设备信息,如 cpu 架构,系统版本等
|
||||
|
||||
不过最最重要的 还是需要感谢屏幕前的你哦~
|
||||
## 相关链接
|
||||
[Telegram Link](https://t.me/+nLZEnpne-pQ1OWFl)
|
||||
|
||||
---
|
||||
## 鸣谢名单
|
||||
|
||||
## 特殊感谢
|
||||
[LLOneBot](https://github.com/LLOneBot/LLOneBot) 相关的开发曾参与本项目
|
||||
[Lagrange](https://github.com/LagrangeDev/Lagrange.Core)
|
||||
|
||||
## 开源附加
|
||||
|
||||
任何使用本仓库代码的地方,都应当严格遵守[本仓库开源许可](./LICENSE)。**此外,禁止任何项目未经仓库主作者授权二次分发或基于 NapCat 代码开发。**
|
||||
<!--
|
||||
QQ群:545402644
|
||||
-->
|
||||
|
12
docs/changelogs/CHANGELOG.v1.8.4.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# v1.8.4
|
||||
|
||||
QQ Version: Windows 9.9.15-26702 / Linux 3.2.12-26702
|
||||
|
||||
## 启动的方式
|
||||
Way03/Way05
|
||||
|
||||
## 新增与调整
|
||||
1. 支持主动临时消息
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
17
docs/changelogs/old/CHANGELOG.v1.3.3.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# v1.3.3
|
||||
|
||||
QQ Version: Windows 9.9.9-23424 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 尝试修复多开崩溃问题
|
||||
* 修复群列表更新问题
|
||||
* 修复兼容性问题支持Win7
|
||||
* 修复下载 http 资源缺少UA
|
||||
* 优化少量消息合并转发速度
|
||||
* 修复加载群通知时出现 getUserDetailInfo timeout 导致程序崩溃
|
||||
|
||||
## 新增与调整
|
||||
* 新增设置群公告 Api: /_send_group_notice
|
||||
* 新增重启实现 包括重启快速登录/普通重启 副作用: 原进程 无法清理
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
18
docs/changelogs/old/CHANGELOG.v1.3.5.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# v1.3.5
|
||||
|
||||
QQ Version: Windows 9.9.9-23424 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 优化启动脚本
|
||||
* 修复非管理时群成员减少事件上报 **无法获取操作者与操作类型**
|
||||
* 修复快速重启进程清理问题
|
||||
* 优化配置文件格式 支持自动更新配置 但仍然建议 **备份配置**
|
||||
* 修复正向反向ws多个客户端周期多次心跳问题
|
||||
|
||||
## 新增与调整
|
||||
* 支持WebUi热重载
|
||||
* 新增启动输出WEBUI秘钥
|
||||
* 新增群荣誉信息 /get_group_honor_info
|
||||
* 支持获取群系统消息 /get_group_system_msg
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.3.6.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# v1.3.6
|
||||
|
||||
QQ Version: Windows 9.9.9-23424 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 修复戳一戳多次上报问题
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
15
docs/changelogs/old/CHANGELOG.v1.3.8.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# v1.3.8
|
||||
|
||||
QQ Version: Windows 9.9.9-23873 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 优化打包后体积问题
|
||||
* 修复QQ等级获取
|
||||
* 兼容 9.7.x 版本换行符 统一为 \n
|
||||
* 修复处理加群请求 字段异常情况
|
||||
* 修复退群通知问题
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.3.9.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# v1.3.9
|
||||
|
||||
QQ Version: Windows 9.9.10-23873 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 修复QQ等级获取与兼容性问题
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
12
docs/changelogs/old/CHANGELOG.v1.4.0.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# v1.4.0
|
||||
|
||||
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
|
||||
## 新增与调整
|
||||
* 支持空间Cookies获取
|
||||
* 支持获取在线设备 API /get_online_clients
|
||||
* 支持图片OCR API: /.ocr_image /ocr_image
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
14
docs/changelogs/old/CHANGELOG.v1.4.1.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# v1.4.1
|
||||
|
||||
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 提高部分Api兼容性
|
||||
* 优化日志膨胀问题
|
||||
* 在线状态刷新问题修复
|
||||
## 新增与调整
|
||||
* 支持非管理群 本地记录时间数据 (建议 **备份配置 清空配置 重新配置**)
|
||||
* 新增英译中接口 Api: /translate_en2zh
|
||||
* 新增群文件管理相关扩展接口 Api: /get_group_file_count /get_group_file_list /set_group_file_folder /del_group_file /del_group_file_folder
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
12
docs/changelogs/old/CHANGELOG.v1.4.2.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# v1.4.2
|
||||
|
||||
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 修复获取群文件列表Api
|
||||
* 修复退群通知问题
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.4.3.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# v1.4.3
|
||||
|
||||
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 修复名片通知
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
10
docs/changelogs/old/CHANGELOG.v1.4.4.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# v1.4.4
|
||||
|
||||
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||
|
||||
## 更新
|
||||
* **重大更新:**更新了版本号
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
||||
|
12
docs/changelogs/old/CHANGELOG.v1.4.5.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# v1.4.5
|
||||
|
||||
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 紧急修复二维扫码问题
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
||||
|
12
docs/changelogs/old/CHANGELOG.v1.4.6.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# v1.4.6
|
||||
|
||||
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 优化整体稳定性
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
||||
|
11
docs/changelogs/old/CHANGELOG.v1.4.7.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# v1.4.7
|
||||
|
||||
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 临时扩展 Api: GoCQHTTPUploadGroupFile folder_id字段 用于选择文件夹
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
12
docs/changelogs/old/CHANGELOG.v1.4.8.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# v1.4.8
|
||||
|
||||
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 优化Guid的生成方式
|
||||
* 支持临时消息获取群来源
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.4.9.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# v1.4.9
|
||||
|
||||
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 修复接口调用问题 接口标准化 API:set_group_add_request
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.5.0.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# v1.5.0
|
||||
|
||||
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 修正各Api默认值
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
12
docs/changelogs/old/CHANGELOG.v1.5.1.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# v1.5.1
|
||||
|
||||
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 支持 新Api: set_self_profile 可设置个性签名
|
||||
* 修复 Api: get_group_system_msg
|
||||
* 整理日志、添加颜色、使用统一的日志函数以提高日志可读性
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
13
docs/changelogs/old/CHANGELOG.v1.5.2.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# v1.5.2
|
||||
|
||||
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
|
||||
|
||||
## 修复与优化
|
||||
* 替换Uid/Uin为内部实现
|
||||
* 增加HttpApi调用稳定性
|
||||
* 修复 GetMsg 兼容性
|
||||
|
||||
## 新增与调整
|
||||
* 支持真正意义上的陌生人信息获取 Api: GoCQHTTP_GetStrangerInfo
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
15
docs/changelogs/old/CHANGELOG.v1.5.3.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# v1.5.3
|
||||
|
||||
QQ Version: Windows 9.9.11-24568 / Linux 3.2.9-23568
|
||||
|
||||
## 修复与优化
|
||||
* 修复引用消息id问题
|
||||
* 修复添加好友的通知
|
||||
|
||||
## 新增与调整
|
||||
* 扩展群分享Json生成
|
||||
* 扩展关于收藏的一系列接口
|
||||
* 支持专属群头衔获取
|
||||
* 支持视频获取直链
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.5.4.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# v1.5.4
|
||||
|
||||
QQ Version: Windows 9.9.11-24568 / Linux 3.2.9-23568
|
||||
|
||||
## 修复与优化
|
||||
* 紧急修复视频与文件问题
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.5.5.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# v1.5.5
|
||||
|
||||
QQ Version: Windows 9.9.11-24568 / Linux 3.2.9-23568
|
||||
|
||||
## 修复与优化
|
||||
* 紧急修复一些问题
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.5.6.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# v1.5.6
|
||||
|
||||
QQ Version: Windows 9.9.11-24568 / Linux 3.2.9-24568
|
||||
|
||||
## 修复与优化
|
||||
* 修复一些问题
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.5.7.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# v1.5.7
|
||||
|
||||
QQ Version: Windows 9.9.11-24568 / Linux 3.2.9-24568
|
||||
|
||||
## 修复与优化
|
||||
* 修复一些问题
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
14
docs/changelogs/old/CHANGELOG.v1.5.8.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# v1.5.8
|
||||
|
||||
QQ Version: Windows 9.9.11-24568 / Linux 3.2.9-24568
|
||||
|
||||
## 修复与优化
|
||||
* 修复视频文件残留问题
|
||||
* 重构 getcookies接口 支持大部分常见域
|
||||
|
||||
## 新增与调整
|
||||
* 日志大小限制
|
||||
* 支持 QQ音乐 卡片 无签名支持时 启用内置方法(缺点没有封面 限速1min/条)
|
||||
* 支持Window X86-32机器
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
12
docs/changelogs/old/CHANGELOG.v1.5.9.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# v1.5.9
|
||||
|
||||
QQ Version: Windows 9.9.11-24815 / Linux 3.2.9-24815
|
||||
|
||||
## 修复与优化
|
||||
* 优化缓存问题
|
||||
* 修复poke异常上报
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.6.0.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# v1.6.0
|
||||
|
||||
QQ Version: Windows 9.9.11-24815 / Linux 3.2.9-24815
|
||||
|
||||
## 修复与优化
|
||||
|
||||
|
||||
## 新增与调整
|
||||
* 新增图片subtype属性 区分表情图片与商城图片
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
11
docs/changelogs/old/CHANGELOG.v1.6.1.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# v1.6.1
|
||||
|
||||
QQ Version: Windows 9.9.11-24815 / Linux 3.2.9-24815
|
||||
|
||||
## 修复与优化
|
||||
|
||||
|
||||
## 新增与调整
|
||||
* 修复poke异常事件
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
13
docs/changelogs/old/CHANGELOG.v1.6.2.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# v1.6.2
|
||||
|
||||
QQ Version: Windows 9.9.11-24815 / Linux 3.2.9-24815
|
||||
|
||||
## 修复与优化
|
||||
* 修复获取Cookies异常崩溃问题
|
||||
* 尝试修复成员退群缓存问题
|
||||
* 修复自身退群后群缓存清理问题
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
13
docs/changelogs/old/CHANGELOG.v1.6.3.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# v1.6.3
|
||||
|
||||
QQ Version: Windows 9.9.11-24815 / Linux 3.2.9-24815
|
||||
|
||||
## 修复与优化
|
||||
* 修复带有groupid的私聊消息异常发送到群聊消息
|
||||
* 尝试修复rws热重载失效问题
|
||||
* 尝试修复进群事件无法正常获取uin
|
||||
|
||||
## 新增与调整
|
||||
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
18
docs/changelogs/old/CHANGELOG.v1.6.4.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# v1.6.4
|
||||
|
||||
QQ Version: Windows 9.9.12-26000 / Linux 3.2.9-26000
|
||||
## 使用前警告
|
||||
1. 在最近版本由于QQ本体大幅变动,为了保证NapCat可用性,NapCat近期启动与安装方式将将大幅变动,请关注文档和社群获取。
|
||||
2. 在Core上完全执行开源,请不要用于违法用途,如此可能造成NapCat完全停止更新。
|
||||
3. 针对原启动方式的围堵,NapCat研发了多种方式,除此其余理论与扩展的分析和思路将部分展示于Docs,以便各位参与开发与维护NapCat。
|
||||
## 其余·备注
|
||||
启动方式: WayBoot.03 (Electron Main进程为Node 直接注入代码 同理项目: LiteLoader)
|
||||
|
||||
## 修复与优化
|
||||
1. 支持Win平台 9.9.12
|
||||
2. 修复部分发送图片下载异常情况
|
||||
|
||||
## 新增与调整
|
||||
没有哦
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
18
docs/changelogs/old/CHANGELOG.v1.6.5.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# v1.6.5
|
||||
|
||||
QQ Version: Windows 9.9.12-26000 / Linux 3.2.9-26000
|
||||
## 使用前警告
|
||||
1. 在最近版本由于QQ本体大幅变动,为了保证NapCat可用性,NapCat近期启动与安装方式将将大幅变动,请关注文档和社群获取。
|
||||
2. 在Core上完全执行开源,请不要用于违法用途,如此可能造成NapCat完全停止更新。
|
||||
3. 针对原启动方式的围堵,NapCat研发了多种方式,除此其余理论与扩展的分析和思路将部分展示于Docs,以便各位参与开发与维护NapCat。
|
||||
## 其余·备注
|
||||
启动方式: WayBoot.03 (Electron Main进程为Node 直接注入代码 同理项目: LiteLoader)
|
||||
|
||||
## 修复与优化
|
||||
1. 优化了WrapperNative载入代码
|
||||
2. 优化缓存
|
||||
|
||||
## 新增与调整
|
||||
没有哦
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
17
docs/changelogs/old/CHANGELOG.v1.6.6.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# v1.6.6
|
||||
|
||||
QQ Version: Windows 9.9.12-26000 / Linux 3.2.9-26000
|
||||
## 使用前警告
|
||||
1. 在最近版本由于QQ本体大幅变动,为了保证NapCat可用性,NapCat近期启动与安装方式将将大幅变动,请关注文档和社群获取。
|
||||
2. 在Core上完全执行开源,请不要用于违法用途,如此可能造成NapCat完全停止更新。
|
||||
3. 针对原启动方式的围堵,NapCat研发了多种方式,除此其余理论与扩展的分析和思路将部分展示于Docs,以便各位参与开发与维护NapCat。
|
||||
## 其余·备注
|
||||
启动方式: WayBoot.03 (Electron Main进程为Node 直接注入代码 同理项目: LiteLoader)
|
||||
|
||||
## 修复与优化
|
||||
1. 修复了一些问题
|
||||
|
||||
## 新增与调整
|
||||
没有哦
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
49
docs/develop/Image.NTAndroid.md
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
public static final int C2C_PIC_DOWNLOAD = 1004;
|
||||
public static final String C2C_PIC_DOWNLOAD_DOMAIN = "c2cpicdw.qpic.cn";
|
||||
public static final String C2C_PIC_DOWNLOAD_QUIC_DOMAIN = "c2cpicdw.quic.qpic.cn";
|
||||
public static final int FLAG_NOT_UPLOAD = 3;
|
||||
public static final int FLAG_UPLOADINFO_ERROR = 4;
|
||||
public static final int GROUP_PIC_DOWNLOAD = 1000;
|
||||
public static final String GROUP_PIC_DOWNLOAD_DOMAIN = "gchat.qpic.cn";
|
||||
public static final String GROUP_PIC_DOWNLOAD_QUIC_DOMAIN = "gchat.quic.qpic.cn";
|
||||
public static final String GUILD_PIC_DOWNLOAD_DOMAIN = "gchat.qpic.cn/qmeetpic";
|
||||
public static final boolean NEW_STORE_FLAG = true;
|
||||
public static final String PTT_VIDEO_DOWNLOAD_DOMAIN = "grouptalk.c2c.qq.com";
|
||||
|
||||
protected static final int AVIF_DECODE_EXCEPTION = 4;
|
||||
protected static final int AVIF_DECODE_FAIL = 1;
|
||||
protected static final int AVIF_DECODE_FAIL_SO_FAIL = 2;
|
||||
protected static final int AVIF_DECODE_FAIL_UNKNOWN = 6;
|
||||
protected static final int AVIF_DECODE_FILETYPE_ERROR = 5;
|
||||
protected static final int AVIF_DECODE_OOM = 3;
|
||||
protected static final int AVIF_DECODE_RENAME_FAIL = 7;
|
||||
protected static final int AVIF_DECODE_SUC = 0;
|
||||
public static final String AVIF_FILE_SUFFIX = ".avif";
|
||||
public static final int AVIF_REQ_APPRUNTIME_NULL = 12;
|
||||
public static final int AVIF_REQ_CODEC_UNSURPPORT = 5;
|
||||
protected static final int AVIF_REQ_DENSITY_UNSURPPORT = 10;
|
||||
protected static final int AVIF_REQ_FLASH_PHOTO = 9;
|
||||
protected static final int AVIF_REQ_HAS_TMP_AVIF = 7;
|
||||
protected static final int AVIF_REQ_INVALID_MSG_RECORD = 2;
|
||||
protected static final int AVIF_REQ_IS_RAW_PHOTO = 3;
|
||||
protected static final int AVIF_REQ_OUTPUTSTREAM_UNSURPPORT = 11;
|
||||
protected static final int AVIF_REQ_OVERSIZE = 6;
|
||||
protected static final int AVIF_REQ_RETRY = 1;
|
||||
public static final int AVIF_REQ_SO_DOWNLOAD_FAILED = 8;
|
||||
protected static final int AVIF_REQ_SUC = 0;
|
||||
public static final int AVIF_REQ_SWITCH_CLOSE = 4;
|
||||
public static final String C2C_PIC_DOWNLOAD_ERROR_CODE = "C2CPicDownloadErrorCode";
|
||||
static final int DOWNLOAD_ST_COMPLETE = 1;
|
||||
static final int DOWNLOAD_ST_HEAD = 2;
|
||||
static final int DOWNLOAD_ST_LEFT = 4;
|
||||
static final int DOWNLOAD_ST_PART = 3;
|
||||
private static final int ENCRYPT_APPID = 1600000226;
|
||||
public static final String GROUP_PIC_DOWNLOAD_ERROR_CODE = "GroupPicDownloadErrorCode";
|
||||
public static final String KEY_PIC_DOWNLOAD_ERROR_CODE = "param_detail_code";
|
||||
protected static final int QUIC_FAIL_IP_LIST_EMPTY = 1;
|
||||
protected static final int QUIC_FAIL_REQUEST_HTTPS = 3;
|
||||
protected static final int QUIC_FAIL_REQUEST_QUIC = 2;
|
||||
protected static final int QUIC_FAIL_SO_LOAD = 4;
|
||||
public static final String REPORT_TAG_DIRECT_DOWNLOAD_FAIL = "report_direct_download_fail";
|
||||
public static final String REQ_PARAM_AVIF = "tp=avif";
|
444
docs/develop/Msg常量NTAndroid.md
Normal file
@@ -0,0 +1,444 @@
|
||||
```java
|
||||
MsgConstant
|
||||
int ARKSTRUCTELEMENTSUBTYPETENCENTDOCFROMMINIAPP = 1;
|
||||
int ARKSTRUCTELEMENTSUBTYPETENCENTDOCFROMPLUSPANEL = 2;
|
||||
int ARKSTRUCTELEMENTSUBTYPEUNKNOWN = 0;
|
||||
int ATTYPEALL = 1;
|
||||
int ATTYPECATEGORY = 512;
|
||||
int ATTYPECHANNEL = 16;
|
||||
int ATTYPEME = 4;
|
||||
int ATTYPEONE = 2;
|
||||
int ATTYPEONLINE = 64;
|
||||
int ATTYPEROLE = 8;
|
||||
int ATTYPESUMMON = 32;
|
||||
int ATTYPESUMMONONLINE = 128;
|
||||
int ATTYPESUMMONROLE = 256;
|
||||
int ATTYPEUNKNOWN = 0;
|
||||
int CALENDARELEMSUBTYPECOMMON = 3;
|
||||
int CALENDARELEMSUBTYPESTRONG = 1;
|
||||
int CALENDARELEMSUBTYPEUNKNOWN = 0;
|
||||
int CALENDARELEMSUBTYPEWEAK = 2;
|
||||
int FACEBUBBLEELEMSUBTYPENORMAL = 1;
|
||||
int FACEBUBBLEELEMSUBTYPEUNKNOWN = 0;
|
||||
int FETCHLONGMSGERRCODEMSGEXPIRED = 196;
|
||||
int FILEELEMENTSUBTYPEAI = 16;
|
||||
int FILEELEMENTSUBTYPEAPP = 11;
|
||||
int FILEELEMENTSUBTYPEAUDIO = 3;
|
||||
int FILEELEMENTSUBTYPEDOC = 4;
|
||||
int FILEELEMENTSUBTYPEEMOTICON = 15;
|
||||
int FILEELEMENTSUBTYPEEXCEL = 6;
|
||||
int FILEELEMENTSUBTYPEFOLDER = 13;
|
||||
int FILEELEMENTSUBTYPEHTML = 10;
|
||||
int FILEELEMENTSUBTYPEIPA = 14;
|
||||
int FILEELEMENTSUBTYPENORMAL = 0;
|
||||
int FILEELEMENTSUBTYPEPDF = 7;
|
||||
int FILEELEMENTSUBTYPEPIC = 1;
|
||||
int FILEELEMENTSUBTYPEPPT = 5;
|
||||
int FILEELEMENTSUBTYPEPSD = 12;
|
||||
int FILEELEMENTSUBTYPETXT = 8;
|
||||
int FILEELEMENTSUBTYPEVIDEO = 2;
|
||||
int FILEELEMENTSUBTYPEZIP = 9;
|
||||
int GRAYTIPELEMENTSUBTYPEAIOOP = 15;
|
||||
int GRAYTIPELEMENTSUBTYPEBLOCK = 14;
|
||||
int GRAYTIPELEMENTSUBTYPEBUDDY = 5;
|
||||
int GRAYTIPELEMENTSUBTYPEBUDDYNOTIFY = 9;
|
||||
int GRAYTIPELEMENTSUBTYPEEMOJIREPLY = 3;
|
||||
int GRAYTIPELEMENTSUBTYPEESSENCE = 7;
|
||||
int GRAYTIPELEMENTSUBTYPEFEED = 6;
|
||||
int GRAYTIPELEMENTSUBTYPEFEEDCHANNELMSG = 11;
|
||||
int GRAYTIPELEMENTSUBTYPEFILE = 10;
|
||||
int GRAYTIPELEMENTSUBTYPEGROUP = 4;
|
||||
int GRAYTIPELEMENTSUBTYPEGROUPNOTIFY = 8;
|
||||
int GRAYTIPELEMENTSUBTYPEJSON = 17;
|
||||
int GRAYTIPELEMENTSUBTYPELOCALMSG = 13;
|
||||
int GRAYTIPELEMENTSUBTYPEPROCLAMATION = 2;
|
||||
int GRAYTIPELEMENTSUBTYPEREVOKE = 1;
|
||||
int GRAYTIPELEMENTSUBTYPEUNKNOWN = 0;
|
||||
int GRAYTIPELEMENTSUBTYPEWALLET = 16;
|
||||
int GRAYTIPELEMENTSUBTYPEXMLMSG = 12;
|
||||
int INLINEKEYBOARDBUTTONRENDERSTYLEBLUEBLACKGROUND = 4;
|
||||
int INLINEKEYBOARDBUTTONRENDERSTYLEBLUEBORDER = 1;
|
||||
int INLINEKEYBOARDBUTTONRENDERSTYLEGRAYBORDER = 0;
|
||||
int INLINEKEYBOARDBUTTONRENDERSTYLENOBORDER = 2;
|
||||
int INLINEKEYBOARDBUTTONRENDERSTYLEREDCHARACTER = 3;
|
||||
int INPUTSTATUSTYPECANCEL = 2;
|
||||
int INPUTSTATUSTYPESPEAK = 3;
|
||||
int INPUTSTATUSTYPETEXT = 1;
|
||||
int KACTIVITYMSG = 22;
|
||||
int KADDLOCALMSGEXTINFOTYPEPROLOGUEMSG = 1;
|
||||
int KANONYMOUSATMEMSGTYPEINMSGBOX = 1001;
|
||||
int KANONYMOUSFLAGFROMOTHERPEOPLE = 1;
|
||||
int KANONYMOUSFLAGFROMOWN = 2;
|
||||
int KANONYMOUSFLAGINVALID = 0;
|
||||
int KAPPCHANNELMSG = 16;
|
||||
int KATALLMSGTYPEINMSGBOX = 2000;
|
||||
int KATMEMSGTYPEINMSGBOX = 1000;
|
||||
int KATTRIBUTETYPEADELIEMSG = 16;
|
||||
int KATTRIBUTETYPEEXTENDBUSINESS = 13;
|
||||
int KATTRIBUTETYPEFEEDBACKSTATE = 17;
|
||||
int KATTRIBUTETYPEGROUPHONOR = 2;
|
||||
int KATTRIBUTETYPEKINGHONOR = 3;
|
||||
int KATTRIBUTETYPELONGMSG = 8;
|
||||
int KATTRIBUTETYPEMEMORYSTATEMSGINFO = 18;
|
||||
int KATTRIBUTETYPEMSG = 0;
|
||||
int KATTRIBUTETYPEMSGBOXEVENTTYPE = 14;
|
||||
int KATTRIBUTETYPEPERSONAL = 1;
|
||||
int KATTRIBUTETYPEPUBLICACCOUNT = 4;
|
||||
int KATTRIBUTETYPEQQCONNECT = 12;
|
||||
int KATTRIBUTETYPESENDMSGRSPTRANSSVRINFO = 15;
|
||||
int KATTRIBUTETYPESHAREDMSGINFO = 5;
|
||||
int KATTRIBUTETYPETEMPCHATGAMESESSION = 6;
|
||||
int KATTRIBUTETYPETOROBOTMSG = 9;
|
||||
int KATTRIBUTETYPEUININFO = 7;
|
||||
int KATTRIBUTETYPEZPLAN = 11;
|
||||
int KAUTOREPLYTEXTNONEINDEX = -1;
|
||||
int KAVRECORDMSG = 19;
|
||||
int KBUSINESSTYPGUILD = 1;
|
||||
int KBUSINESSTYPNT = 0;
|
||||
int KCHATTYPEADELIE = 42;
|
||||
int KCHATTYPEBUDDYNOTIFY = 5;
|
||||
int KCHATTYPEC2C = 1;
|
||||
int KCHATTYPECIRCLE = 113;
|
||||
int KCHATTYPEDATALINE = 8;
|
||||
int KCHATTYPEDATALINEMQQ = 134;
|
||||
int KCHATTYPEDISC = 3;
|
||||
int KCHATTYPEFAV = 41;
|
||||
int KCHATTYPEGAMEMESSAGE = 105;
|
||||
int KCHATTYPEGAMEMESSAGEFOLDER = 116;
|
||||
int KCHATTYPEGROUP = 2;
|
||||
int KCHATTYPEGROUPBLESS = 133;
|
||||
int KCHATTYPEGROUPGUILD = 9;
|
||||
int KCHATTYPEGROUPHELPER = 7;
|
||||
int KCHATTYPEGROUPNOTIFY = 6;
|
||||
int KCHATTYPEGUILD = 4;
|
||||
int KCHATTYPEGUILDMETA = 16;
|
||||
int KCHATTYPEMATCHFRIEND = 104;
|
||||
int KCHATTYPEMATCHFRIENDFOLDER = 109;
|
||||
int KCHATTYPENEARBY = 106;
|
||||
int KCHATTYPENEARBYASSISTANT = 107;
|
||||
int KCHATTYPENEARBYFOLDER = 110;
|
||||
int KCHATTYPENEARBYHELLOFOLDER = 112;
|
||||
int KCHATTYPENEARBYINTERACT = 108;
|
||||
int KCHATTYPEQQNOTIFY = 132;
|
||||
int KCHATTYPERELATEACCOUNT = 131;
|
||||
int KCHATTYPESERVICEASSISTANT = 118;
|
||||
int KCHATTYPESERVICEASSISTANTSUB = 201;
|
||||
int KCHATTYPESQUAREPUBLIC = 115;
|
||||
int KCHATTYPESUBSCRIBEFOLDER = 30;
|
||||
int KCHATTYPETEMPADDRESSBOOK = 111;
|
||||
int KCHATTYPETEMPBUSSINESSCRM = 102;
|
||||
int KCHATTYPETEMPC2CFROMGROUP = 100;
|
||||
int KCHATTYPETEMPC2CFROMUNKNOWN = 99;
|
||||
int KCHATTYPETEMPFRIENDVERIFY = 101;
|
||||
int KCHATTYPETEMPNEARBYPRO = 119;
|
||||
int KCHATTYPETEMPPUBLICACCOUNT = 103;
|
||||
int KCHATTYPETEMPWPA = 117;
|
||||
int KCHATTYPEUNKNOWN = 0;
|
||||
int KCHATTYPEWEIYUN = 40;
|
||||
int KCOMMONREDENVELOPEMSGTYPEINMSGBOX = 1007;
|
||||
int KDOWNSOURCETYPEAIOINNER = 1;
|
||||
int KDOWNSOURCETYPEBIGSCREEN = 2;
|
||||
int KDOWNSOURCETYPEHISTORY = 3;
|
||||
int KDOWNSOURCETYPEUNKNOWN = 0;
|
||||
int KELEMTYPEACTIVITY = 25;
|
||||
int KELEMTYPEACTIVITYSTATE = 41;
|
||||
int KELEMTYPEACTIVITYSUBTYPECREATEMOBATEAM = 12;
|
||||
int KELEMTYPEACTIVITYSUBTYPEDISBANDMOBATEAM = 11;
|
||||
int KELEMTYPEACTIVITYSUBTYPEFEEDSQUARE = 10001;
|
||||
int KELEMTYPEACTIVITYSUBTYPEFINISHGAME = 16;
|
||||
int KELEMTYPEACTIVITYSUBTYPEFINISHMATCHTEAM = 14;
|
||||
int KELEMTYPEACTIVITYSUBTYPEHOTCHAT = 10000;
|
||||
int KELEMTYPEACTIVITYSUBTYPEMINIGAME = 18;
|
||||
int KELEMTYPEACTIVITYSUBTYPEMUSICPLAY = 17;
|
||||
int KELEMTYPEACTIVITYSUBTYPENEWSMOBA = 9;
|
||||
int KELEMTYPEACTIVITYSUBTYPENOLIVE = 2;
|
||||
int KELEMTYPEACTIVITYSUBTYPENOSCREENSHARE = 7;
|
||||
int KELEMTYPEACTIVITYSUBTYPENOVOICE = 3;
|
||||
int KELEMTYPEACTIVITYSUBTYPEONLIVE = 1;
|
||||
int KELEMTYPEACTIVITYSUBTYPEONSCREENSHARE = 6;
|
||||
int KELEMTYPEACTIVITYSUBTYPEONVOICE = 4;
|
||||
int KELEMTYPEACTIVITYSUBTYPESTARTMATCHTEAM = 13;
|
||||
int KELEMTYPEACTIVITYSUBTYPETARTGAME = 15;
|
||||
int KELEMTYPEACTIVITYSUBTYPEUNKNOWN = 0;
|
||||
int KELEMTYPEADELIEACTIONBAR = 44;
|
||||
int KELEMTYPEADELIERECOMMENDEDMSG = 43;
|
||||
int KELEMTYPEARKSTRUCT = 10;
|
||||
int KELEMTYPEAVRECORD = 21;
|
||||
int KELEMTYPECALENDAR = 19;
|
||||
int KELEMTYPEFACE = 6;
|
||||
int KELEMTYPEFACEBUBBLE = 27;
|
||||
int KELEMTYPEFEED = 22;
|
||||
int KELEMTYPEFILE = 3;
|
||||
int KELEMTYPEGIPHY = 15;
|
||||
int KELEMTYPEGRAYTIP = 8;
|
||||
int KELEMTYPEINLINEKEYBOARD = 17;
|
||||
int KELEMTYPEINTEXTGIFT = 18;
|
||||
int KELEMTYPELIVEGIFT = 12;
|
||||
int KELEMTYPEMARKDOWN = 14;
|
||||
int KELEMTYPEMARKETFACE = 11;
|
||||
int KELEMTYPEMULTIFORWARD = 16;
|
||||
int KELEMTYPEONLINEFILE = 23;
|
||||
int KELEMTYPEPIC = 2;
|
||||
int KELEMTYPEPROLOGUE = 46;
|
||||
int KELEMTYPEPTT = 4;
|
||||
int KELEMTYPEREPLY = 7;
|
||||
int KELEMTYPESHARELOCATION = 28;
|
||||
int KELEMTYPESTRUCTLONGMSG = 13;
|
||||
int KELEMTYPETASKTOPMSG = 29;
|
||||
int KELEMTYPETEXT = 1;
|
||||
int KELEMTYPETOFU = 26;
|
||||
int KELEMTYPEUNKNOWN = 0;
|
||||
int KELEMTYPEVIDEO = 5;
|
||||
int KELEMTYPEWALLET = 9;
|
||||
int KELEMTYPEYOLOGAMERESULT = 20;
|
||||
int KENTERAIO = 1;
|
||||
int KEXITAIO = 2;
|
||||
int KFEEDBACKBUTTONTYPEDISLIKE = 2;
|
||||
int KFEEDBACKBUTTONTYPELIKE = 1;
|
||||
int KFEEDBACKBUTTONTYPEPROMPTCLICK = 5;
|
||||
int KFEEDBACKBUTTONTYPEREGENERATE = 4;
|
||||
int KFEEDBACKBUTTONTYPEUNKNOWN = 0;
|
||||
int KFEEDBACKOPTLIKE = 1;
|
||||
int KFEEDBACKOPTUNKNOWN = 0;
|
||||
int KFEEDBACKOPTUNLIKE = 2;
|
||||
int KFRIENDNEWADDEDMSGTYPEINMSGBOX = 1008;
|
||||
int KGAMEBOXNEWMSGTYPEINMSGBOX = 3000;
|
||||
int KGIFTATMEMSGTYPEINMSGBOX = 1005;
|
||||
int KGROUPFILEATALLMSGTYPEINMSGBOX = 2001;
|
||||
int KGROUPHOMEWORK = 20000;
|
||||
int KGROUPHOMEWORKTASK = 20001;
|
||||
int KGROUPKEYWORDMSGTYPEINMSGBOX = 2006;
|
||||
int KGROUPMANNOUNCEATALLMSGTYPEINMSGBOX = 2004;
|
||||
int KGROUPTASKATALLMSGTYPEINMSGBOX = 2003;
|
||||
int KGROUPUNREADTYPEINMSGBOX = 2007;
|
||||
int KGUILDCHANNELLIST = 10;
|
||||
int KHIGHLIGHTWORDINTEMPCHATTYPEINMSGBOX = 1009;
|
||||
int KHOMEWORKREMINDER = 10000;
|
||||
int KLIKEORDISLIKESTATEDISLIKE = 2;
|
||||
int KLIKEORDISLIKESTATELIKE = 1;
|
||||
int KLIKEORDISLIKESTATENONESELECTED = 0;
|
||||
int KMARKETFACE = 17;
|
||||
int KMEMORYSTATEMSGTYPEADELIEWELCOME = 1;
|
||||
int KMEMORYSTATEMSGTYPEUNKNOWN = 0;
|
||||
int KMINIPROGRAMNOTICE = 114;
|
||||
int KMSGSUBTYPEARKGROUPANNOUNCE = 3;
|
||||
int KMSGSUBTYPEARKGROUPANNOUNCECONFIRMREQUIRED = 4;
|
||||
int KMSGSUBTYPEARKGROUPGIFTATME = 5;
|
||||
int KMSGSUBTYPEARKGROUPTASKATALL = 6;
|
||||
int KMSGSUBTYPEARKMULTIMSG = 7;
|
||||
int KMSGSUBTYPEARKNORMAL = 0;
|
||||
int KMSGSUBTYPEARKTENCENTDOCFROMMINIAPP = 1;
|
||||
int KMSGSUBTYPEARKTENCENTDOCFROMPLUSPANEL = 2;
|
||||
int KMSGSUBTYPEEMOTICON = 15;
|
||||
int KMSGSUBTYPEFILEAPP = 11;
|
||||
int KMSGSUBTYPEFILEAUDIO = 3;
|
||||
int KMSGSUBTYPEFILEDOC = 4;
|
||||
int KMSGSUBTYPEFILEEXCEL = 6;
|
||||
int KMSGSUBTYPEFILEFOLDER = 13;
|
||||
int KMSGSUBTYPEFILEHTML = 10;
|
||||
int KMSGSUBTYPEFILEIPA = 14;
|
||||
int KMSGSUBTYPEFILENORMAL = 0;
|
||||
int KMSGSUBTYPEFILEPDF = 7;
|
||||
int KMSGSUBTYPEFILEPIC = 1;
|
||||
int KMSGSUBTYPEFILEPPT = 5;
|
||||
int KMSGSUBTYPEFILEPSD = 12;
|
||||
int KMSGSUBTYPEFILETXT = 8;
|
||||
int KMSGSUBTYPEFILEVIDEO = 2;
|
||||
int KMSGSUBTYPEFILEZIP = 9;
|
||||
int KMSGSUBTYPELINK = 5;
|
||||
int KMSGSUBTYPEMARKETFACE = 1;
|
||||
int KMSGSUBTYPEMIXEMOTICON = 7;
|
||||
int KMSGSUBTYPEMIXFACE = 3;
|
||||
int KMSGSUBTYPEMIXMARKETFACE = 2;
|
||||
int KMSGSUBTYPEMIXPIC = 1;
|
||||
int KMSGSUBTYPEMIXREPLY = 4;
|
||||
int KMSGSUBTYPEMIXTEXT = 0;
|
||||
int KMSGSUBTYPETENCENTDOC = 6;
|
||||
int KMSGTYPEARKSTRUCT = 11;
|
||||
int KMSGTYPEFACEBUBBLE = 24;
|
||||
int KMSGTYPEFILE = 3;
|
||||
int KMSGTYPEGIFT = 14;
|
||||
int KMSGTYPEGIPHY = 13;
|
||||
int KMSGTYPEGRAYTIPS = 5;
|
||||
int KMSGTYPEMIX = 2;
|
||||
int KMSGTYPEMULTIMSGFORWARD = 8;
|
||||
int KMSGTYPENULL = 1;
|
||||
int KMSGTYPEONLINEFILE = 21;
|
||||
int KMSGTYPEONLINEFOLDER = 27;
|
||||
int KMSGTYPEPROLOGUE = 29;
|
||||
int KMSGTYPEPTT = 6;
|
||||
int KMSGTYPEREPLY = 9;
|
||||
int KMSGTYPESHARELOCATION = 25;
|
||||
int KMSGTYPESTRUCT = 4;
|
||||
int KMSGTYPESTRUCTLONGMSG = 12;
|
||||
int KMSGTYPETEXTGIFT = 15;
|
||||
int KMSGTYPEUNKNOWN = 0;
|
||||
int KMSGTYPEVIDEO = 7;
|
||||
int KMSGTYPEWALLET = 10;
|
||||
int KNEEDCONFIRMGROUPMANNOUNCEATALLMSGTYPEINMSGBOX = 2005;
|
||||
int KNOTPASSTHROUGHEVENTTYPEUPPERBOUNDARY = 9999;
|
||||
int KPTTFORMATTYPEAMR = 0;
|
||||
int KPTTFORMATTYPESILK = 1;
|
||||
int KPTTTRANSLATESTATUSFAIL = 3;
|
||||
int KPTTTRANSLATESTATUSSUC = 2;
|
||||
int KPTTTRANSLATESTATUSTRANSLATING = 1;
|
||||
int KPTTTRANSLATESTATUSUNKNOWN = 0;
|
||||
int KPTTVIPLEVELTYPENONE = 0;
|
||||
int KPTTVIPLEVELTYPEQQVIP = 0;
|
||||
int KPTTVIPLEVELTYPESVIP = 0;
|
||||
int KPTTVOICECHANGETYPEBEASTMACHINE = 7;
|
||||
int KPTTVOICECHANGETYPEBOY = 2;
|
||||
int KPTTVOICECHANGETYPECATCHCOLD = 13;
|
||||
int KPTTVOICECHANGETYPEECHO = 5;
|
||||
int KPTTVOICECHANGETYPEFATGUY = 16;
|
||||
int KPTTVOICECHANGETYPEFLASHING = 9;
|
||||
int KPTTVOICECHANGETYPEGIRL = 1;
|
||||
int KPTTVOICECHANGETYPEHORRIBLE = 3;
|
||||
int KPTTVOICECHANGETYPEKINDERGARTEN = 6;
|
||||
int KPTTVOICECHANGETYPEMEDAROT = 15;
|
||||
int KPTTVOICECHANGETYPENONE = 0;
|
||||
int KPTTVOICECHANGETYPEOPTIMUSPRIME = 8;
|
||||
int KPTTVOICECHANGETYPEOUTOFDATE = 14;
|
||||
int KPTTVOICECHANGETYPEPAPI = 11;
|
||||
int KPTTVOICECHANGETYPEQUICK = 4;
|
||||
int KPTTVOICECHANGETYPESTUTTER = 10;
|
||||
int KPTTVOICECHANGETYPETRAPPEDBEAST = 12;
|
||||
int KPTTVOICETYPEINTERCOM = 1;
|
||||
int KPTTVOICETYPESOUNDRECORD = 2;
|
||||
int KPTTVOICETYPEUNKNOW = 0;
|
||||
int KPTTVOICETYPEVOICECHANGE = 3;
|
||||
int KPUBLICACCOUNTTIANSHUHIGHLIGHTWORDTYPEINMSGBOX = 1010;
|
||||
int KREPLYABSELEMTYPEFACE = 2;
|
||||
int KREPLYABSELEMTYPEPIC = 3;
|
||||
int KREPLYABSELEMTYPETEXT = 1;
|
||||
int KREPLYABSELEMTYPEUNKNOWN = 0;
|
||||
int KREPLYATMEMSGTYPEINMSGBOX = 1002;
|
||||
int KRMDOWNTYPEORIG = 1;
|
||||
int KRMDOWNTYPETHUMB = 2;
|
||||
int KRMDOWNTYPEUNKNOWN = 0;
|
||||
int KRMFILETHUMBSIZE128 = 128;
|
||||
int KRMFILETHUMBSIZE320 = 320;
|
||||
int KRMFILETHUMBSIZE384 = 384;
|
||||
int KRMFILETHUMBSIZE750 = 750;
|
||||
int KRMPICAIOTHUMBSIZE = 0;
|
||||
int KRMPICTHUMBSIZE198 = 198;
|
||||
int KRMPICTHUMBSIZE720 = 720;
|
||||
int KRMPICTYPEBMP = 3;
|
||||
int KRMPICTYPECHECKOTHER = 900;
|
||||
int KRMPICTYPEGIF = 2;
|
||||
int KRMPICTYPEJPG = 0;
|
||||
int KRMPICTYPENEWPICAPNG = 2001;
|
||||
int KRMPICTYPENEWPICBMP = 1005;
|
||||
int KRMPICTYPENEWPICGIF = 2000;
|
||||
int KRMPICTYPENEWPICJPEG = 1000;
|
||||
int KRMPICTYPENEWPICPNG = 1001;
|
||||
int KRMPICTYPENEWPICPROGERSSIVJPEG = 1003;
|
||||
int KRMPICTYPENEWPICSHARPP = 1004;
|
||||
int KRMPICTYPENEWPICWEBP = 1002;
|
||||
int KRMPICTYPEPNG = 1;
|
||||
int KRMPICTYPEUNKOWN = 0;
|
||||
int KRMTHUMBSIZEZERO = 0;
|
||||
int KRMTRNASFERSTATUSDOWNLOADING = 3;
|
||||
int KRMTRNASFERSTATUSFAIL = 5;
|
||||
int KRMTRNASFERSTATUSINIT = 1;
|
||||
int KRMTRNASFERSTATUSSUC = 4;
|
||||
int KRMTRNASFERSTATUSUNKOW = 0;
|
||||
int KRMTRNASFERSTATUSUPLOADING = 2;
|
||||
int KRMTRNASFERSTATUSUSERCANCEL = 6;
|
||||
int KSEEKINGPARTNERFLAGSEEKING = 1;
|
||||
int KSEEKINGPARTNERFLAGUNKNOWN = 0;
|
||||
int KSENDSTATUSFAILED = 0;
|
||||
int KSENDSTATUSSENDING = 1;
|
||||
int KSENDSTATUSSUCCESS = 2;
|
||||
int KSENDSTATUSSUCCESSNOSEQ = 3;
|
||||
int KSENDTYPEDROPPED = 6;
|
||||
int KSENDTYPELOCAL = 3;
|
||||
int KSENDTYPEOTHERDEVICE = 2;
|
||||
int KSENDTYPERECV = 0;
|
||||
int KSENDTYPESELF = 1;
|
||||
int KSENDTYPESELFFORWARD = 4;
|
||||
int KSENDTYPESELFMULTIFORWARD = 5;
|
||||
int KSESSIONTYPEADDRESSBOOK = 5;
|
||||
int KSESSIONTYPEC2C = 1;
|
||||
int KSESSIONTYPEDISC = 3;
|
||||
int KSESSIONTYPEFAV = 41;
|
||||
int KSESSIONTYPEGROUP = 2;
|
||||
int KSESSIONTYPEGROUPBLESS = 52;
|
||||
int KSESSIONTYPEGUILD = 4;
|
||||
int KSESSIONTYPEGUILDMETA = 16;
|
||||
int KSESSIONTYPENEARBYPRO = 54;
|
||||
int KSESSIONTYPEQQNOTIFY = 51;
|
||||
int KSESSIONTYPERELATEACCOUNT = 50;
|
||||
int KSESSIONTYPESERVICEASSISTANT = 19;
|
||||
int KSESSIONTYPESUBSCRIBEFOLDER = 30;
|
||||
int KSESSIONTYPETYPEBUDDYNOTIFY = 7;
|
||||
int KSESSIONTYPETYPEGROUPHELPER = 9;
|
||||
int KSESSIONTYPETYPEGROUPNOTIFY = 8;
|
||||
int KSESSIONTYPEUNKNOWN = 0;
|
||||
int KSESSIONTYPEWEIYUN = 40;
|
||||
int KSPECIALCAREMSGTYPEINMSGBOX = 1006;
|
||||
int KSPECIFIEDREDENVELOPEATMEMSGTYPEINMSGBOX = 1004;
|
||||
int KSPECIFIEDREDENVELOPEATONEMSGTYPEINMSGBOX = 1003;
|
||||
int KTENCENTDOCTYPEADDON = 110;
|
||||
int KTENCENTDOCTYPEDOC = 0;
|
||||
int KTENCENTDOCTYPEDRAWING = 89;
|
||||
int KTENCENTDOCTYPEDRIVE = 101;
|
||||
int KTENCENTDOCTYPEFILE = 100;
|
||||
int KTENCENTDOCTYPEFLOWCHART = 91;
|
||||
int KTENCENTDOCTYPEFOLDER = 3;
|
||||
int KTENCENTDOCTYPEFORM = 2;
|
||||
int KTENCENTDOCTYPEMIND = 90;
|
||||
int KTENCENTDOCTYPENOTES = 5;
|
||||
int KTENCENTDOCTYPEPDF = 6;
|
||||
int KTENCENTDOCTYPEPROGRAM = 7;
|
||||
int KTENCENTDOCTYPESHEET = 1;
|
||||
int KTENCENTDOCTYPESLIDE = 4;
|
||||
int KTENCENTDOCTYPESMARTCANVAS = 8;
|
||||
int KTENCENTDOCTYPESMARTSHEET = 9;
|
||||
int KTENCENTDOCTYPESPEECH = 102;
|
||||
int KTENCENTDOCTYPEUNKNOWN = 10;
|
||||
int KTOFURECORDMSG = 23;
|
||||
int KTOPMSGTYPETASK = 1;
|
||||
int KTOPMSGTYPEUNKNOWN = 0;
|
||||
int KTRIGGERTYPEAUTO = 1;
|
||||
int KTRIGGERTYPEMANUAL = 0;
|
||||
int KUNKNOWN = 0;
|
||||
int KUNKNOWNTYPEINMSGBOX = 0;
|
||||
int KUNREADCNTUPTYPEALLDIRECTSESSION = 4;
|
||||
int KUNREADCNTUPTYPEALLFEEDSINGUILD = 6;
|
||||
int KUNREADCNTUPTYPEALLGUILD = 3;
|
||||
int KUNREADCNTUPTYPECATEGORY = 5;
|
||||
int KUNREADCNTUPTYPECHANNEL = 1;
|
||||
int KUNREADCNTUPTYPECONTACT = 0;
|
||||
int KUNREADCNTUPTYPEGUILD = 2;
|
||||
int KUNREADCNTUPTYPEGUILDGROUP = 7;
|
||||
int KUNREADSHOWTTYPEGRAYPOINT = 2;
|
||||
int KUNREADSHOWTYPEREDPOINT = 1;
|
||||
int KUNREADSHOWTYPESMALLGRAYPOINT = 4;
|
||||
int KUNREADSHOWTYPESMALLREDPOINT = 3;
|
||||
int KUNREADSHOWTYPEUNKNOWN = 0;
|
||||
int KVASGIFTCOINTYPECOIN = 0;
|
||||
int KVASGIFTCOINTYPEMARKETCOIN = 1;
|
||||
int KYOLOGAMERESULTMSG = 18;
|
||||
int PIC_800_RECOMMENDED = 7;
|
||||
int PIC_AIGC_EMOJI = 14;
|
||||
int PIC_ALBUM_GIF = 11;
|
||||
int PIC_COMMERCIAL_ADVERTISING = 9;
|
||||
int PIC_FIND = 10;
|
||||
int PIC_HOT = 2;
|
||||
int PIC_HOT_EMOJI = 13;
|
||||
int PIC_NORMAL = 0;
|
||||
int PIC_PK = 3;
|
||||
int PIC_QQZONE = 5;
|
||||
int PIC_SELFIE_GIF = 8;
|
||||
int PIC_SEND_FROM_TAB_SEARCH_BOX = 12;
|
||||
int PIC_USER = 1;
|
||||
int PIC_WISDOM_FIGURE = 4;
|
||||
int REPLYORIGINALMSGSTATEHASRECALL = 1;
|
||||
int REPLYORIGINALMSGSTATEUNKNOWN = 0;
|
||||
int SHARELOCATIONELEMSUBTYPENORMAL = 1;
|
||||
int SHARELOCATIONELEMSUBTYPEUNKNOWN = 0;
|
||||
int TEXTELEMENTSUBTYPELINK = 1;
|
||||
int TEXTELEMENTSUBTYPETENCENTDOC = 2;
|
||||
int TEXTELEMENTSUBTYPEUNKNOWN = 0;
|
||||
```
|
16
docs/develop/NC 1.6.X的计划.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# 开发方向
|
||||
方向一 NativeCall/Hook:
|
||||
1. 崩溃检测机制的实现
|
||||
2. Api_Caller 的Hook 可以拿到Event/Handler 进一步提升NC 即时的拦截与处理一些事件比如ReCall拦截
|
||||
3. Node包装层 进一步分析,拿到脱离自带Listener/Adapter,可以拿到一些更加底层的数据变动 或许包括更多二进制数据
|
||||
|
||||
方向二 全新的无头启动 Way01
|
||||
1. 基于Node启动原理,借助导出符号获取函数地址 再次还原NodeMain
|
||||
|
||||
方向三 发包与收包
|
||||
1. 参考 方向一/3 大概可以收包
|
||||
2. 发包 (暂时没有计划)
|
||||
|
||||
方向四 版本控制
|
||||
1. 根据不同版本进行逻辑控制
|
||||
2. 某些参数的自动提取
|
8
docs/develop/碎碎的研究记录.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# Api方向
|
||||
## getMsgUniqueId √ 已应用
|
||||
getMsgUniqueId 传入时间 产出一个唯一ID 发送消息作为一个参数
|
||||
|
||||
# Native方向
|
||||
## magic_load
|
||||
## api_caller
|
||||
## NodeMain
|
@@ -1,70 +0,0 @@
|
||||
import typescriptEslint from "@typescript-eslint/eslint-plugin";
|
||||
import _import from "eslint-plugin-import";
|
||||
import { fixupPluginRules } from "@eslint/compat";
|
||||
import globals from "globals";
|
||||
import tsParser from "@typescript-eslint/parser";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import js from "@eslint/js";
|
||||
import { FlatCompat } from "@eslint/eslintrc";
|
||||
|
||||
const filename = fileURLToPath(import.meta.url);
|
||||
const dirname = path.dirname(filename);
|
||||
const compat = new FlatCompat({
|
||||
baseDirectory: dirname,
|
||||
recommendedConfig: js.configs.recommended,
|
||||
allConfig: js.configs.all
|
||||
});
|
||||
|
||||
export default [{
|
||||
ignores: ["src/core/proto/"],
|
||||
}, ...compat.extends("eslint:recommended", "plugin:@typescript-eslint/recommended"), {
|
||||
plugins: {
|
||||
"@typescript-eslint": typescriptEslint,
|
||||
import: fixupPluginRules(_import),
|
||||
},
|
||||
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.node,
|
||||
},
|
||||
|
||||
parser: tsParser,
|
||||
ecmaVersion: "latest",
|
||||
sourceType: "module",
|
||||
},
|
||||
|
||||
settings: {
|
||||
"import/parsers": {
|
||||
"@typescript-eslint/parser": [".ts"],
|
||||
},
|
||||
|
||||
"import/resolver": {
|
||||
typescript: {
|
||||
alwaysTryTypes: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
rules: {
|
||||
indent: ["error", 4],
|
||||
semi: ["error", "always"],
|
||||
"no-unused-vars": "off",
|
||||
"no-async-promise-executor": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-unused-vars": "off",
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
"object-curly-spacing": ["error", "always"],
|
||||
},
|
||||
}, {
|
||||
files: ["**/.eslintrc.{js,cjs}"],
|
||||
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
},
|
||||
ecmaVersion: 5,
|
||||
sourceType: "commonjs",
|
||||
},
|
||||
}];
|
BIN
external/LiteLoaderWrapper.zip
vendored
@@ -1,32 +0,0 @@
|
||||
@echo off
|
||||
chcp 65001
|
||||
set NAPCAT_PATCH_PACKAGE=%cd%\qqnt.json
|
||||
set NAPCAT_LOAD_PATH=%cd%\loadNapCat.js
|
||||
set NAPCAT_INJECT_PATH=%cd%\NapCatWinBootHook.dll
|
||||
set NAPCAT_LAUNCHER_PATH=%cd%\NapCatWinBootMain.exe
|
||||
set NAPCAT_MAIN_PATH=%cd%\napcat.mjs
|
||||
:loop_read
|
||||
for /f "tokens=2*" %%a in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ" /v "UninstallString"') do (
|
||||
set RetString=%%b
|
||||
goto :napcat_boot
|
||||
)
|
||||
|
||||
:napcat_boot
|
||||
for %%a in ("%RetString%") do (
|
||||
set "pathWithoutUninstall=%%~dpa"
|
||||
)
|
||||
|
||||
SET QQPath=%pathWithoutUninstall%QQ.exe
|
||||
|
||||
if not exist "%QQpath%" (
|
||||
echo provided QQ path is invalid: %QQpath%
|
||||
pause
|
||||
exit /b
|
||||
)
|
||||
|
||||
set NAPCAT_MAIN_PATH=%NAPCAT_MAIN_PATH:\=/%
|
||||
echo (async () =^> {await import("file:///%NAPCAT_MAIN_PATH%")})() > "%NAPCAT_LOAD_PATH%"
|
||||
|
||||
"%NAPCAT_LAUNCHER_PATH%" "%QQPath%" "%NAPCAT_INJECT_PATH%" %1
|
||||
|
||||
pause
|
@@ -1,33 +0,0 @@
|
||||
@echo off
|
||||
chcp 65001
|
||||
set NAPCAT_PATCH_PACKAGE=%cd%\qqnt.json
|
||||
set NAPCAT_LOAD_PATH=%cd%\loadNapCat.js
|
||||
set NAPCAT_INJECT_PATH=%cd%\NapCatWinBootHook.dll
|
||||
set NAPCAT_LAUNCHER_PATH=%cd%\NapCatWinBootMain.exe
|
||||
set NAPCAT_MAIN_PATH=%cd%\napcat.mjs
|
||||
:loop_read
|
||||
for /f "tokens=2*" %%a in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ" /v "UninstallString"') do (
|
||||
set RetString=%%b
|
||||
goto :napcat_boot
|
||||
)
|
||||
|
||||
:napcat_boot
|
||||
for %%a in ("%RetString%") do (
|
||||
set "pathWithoutUninstall=%%~dpa"
|
||||
)
|
||||
|
||||
SET QQPath=%pathWithoutUninstall%QQ.exe
|
||||
|
||||
if not exist "%QQpath%" (
|
||||
echo provided QQ path is invalid: %QQpath%
|
||||
pause
|
||||
exit /b
|
||||
)
|
||||
set NAPCAT_MAIN_PATH=%NAPCAT_MAIN_PATH:\=/%
|
||||
echo (async () =^> {await import("file:///%NAPCAT_MAIN_PATH%")})() > "%NAPCAT_LOAD_PATH%"
|
||||
|
||||
"%NAPCAT_LAUNCHER_PATH%" "%QQPath%" "%NAPCAT_INJECT_PATH%" %1
|
||||
|
||||
REM "%NAPCAT_LAUNCHER_PATH%" "%QQPath%" "%NAPCAT_INJECT_PATH%" 123456
|
||||
|
||||
pause
|
@@ -1,40 +0,0 @@
|
||||
@echo off
|
||||
chcp 65001
|
||||
net session >nul 2>&1
|
||||
if %errorLevel% == 0 (
|
||||
echo Administrator mode detected.
|
||||
) else (
|
||||
echo Please run this script in administrator mode.
|
||||
powershell -Command "Start-Process 'cmd.exe' -ArgumentList '/c cd /d \"%cd%\" && \"%~f0\" %1' -Verb runAs"
|
||||
exit
|
||||
)
|
||||
|
||||
set NAPCAT_PATCH_PACKAGE=%cd%\qqnt.json
|
||||
set NAPCAT_LOAD_PATH=%cd%\loadNapCat.js
|
||||
set NAPCAT_INJECT_PATH=%cd%\NapCatWinBootHook.dll
|
||||
set NAPCAT_LAUNCHER_PATH=%cd%\NapCatWinBootMain.exe
|
||||
set NAPCAT_MAIN_PATH=%cd%\napcat.mjs
|
||||
:loop_read
|
||||
for /f "tokens=2*" %%a in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ" /v "UninstallString"') do (
|
||||
set RetString=%%b
|
||||
goto :napcat_boot
|
||||
)
|
||||
|
||||
:napcat_boot
|
||||
for %%a in ("%RetString%") do (
|
||||
set "pathWithoutUninstall=%%~dpa"
|
||||
)
|
||||
|
||||
SET QQPath=%pathWithoutUninstall%QQ.exe
|
||||
|
||||
if not exist "%QQpath%" (
|
||||
echo provided QQ path is invalid: %QQpath%
|
||||
pause
|
||||
exit /b
|
||||
)
|
||||
set NAPCAT_MAIN_PATH=%NAPCAT_MAIN_PATH:\=/%
|
||||
echo (async () =^> {await import("file:///%NAPCAT_MAIN_PATH%")})() > "%NAPCAT_LOAD_PATH%"
|
||||
|
||||
"%NAPCAT_LAUNCHER_PATH%" "%QQPath%" "%NAPCAT_INJECT_PATH%" %1
|
||||
|
||||
REM "%NAPCAT_LAUNCHER_PATH%" "%QQPath%" "%NAPCAT_INJECT_PATH%" 123456
|
@@ -1,39 +0,0 @@
|
||||
@echo off
|
||||
chcp 65001
|
||||
net session >nul 2>&1
|
||||
if %errorLevel% == 0 (
|
||||
echo Administrator mode detected.
|
||||
) else (
|
||||
echo Please run this script in administrator mode.
|
||||
powershell -Command "Start-Process 'wt.exe' -ArgumentList 'cmd /c cd /d \"%cd%\" && \"%~f0\" %1' -Verb runAs"
|
||||
exit
|
||||
)
|
||||
|
||||
set NAPCAT_PATCH_PACKAGE=%cd%\qqnt.json
|
||||
set NAPCAT_LOAD_PATH=%cd%\loadNapCat.js
|
||||
set NAPCAT_INJECT_PATH=%cd%\NapCatWinBootHook.dll
|
||||
set NAPCAT_LAUNCHER_PATH=%cd%\NapCatWinBootMain.exe
|
||||
set NAPCAT_MAIN_PATH=%cd%\napcat.mjs
|
||||
:loop_read
|
||||
for /f "tokens=2*" %%a in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ" /v "UninstallString"') do (
|
||||
set RetString=%%b
|
||||
goto :napcat_boot
|
||||
)
|
||||
|
||||
:napcat_boot
|
||||
for %%a in ("%RetString%") do (
|
||||
set "pathWithoutUninstall=%%~dpa"
|
||||
)
|
||||
|
||||
SET QQPath=%pathWithoutUninstall%QQ.exe
|
||||
|
||||
if not exist "%QQpath%" (
|
||||
echo provided QQ path is invalid: %QQpath%
|
||||
pause
|
||||
exit /b
|
||||
)
|
||||
|
||||
set NAPCAT_MAIN_PATH=%NAPCAT_MAIN_PATH:\=/%
|
||||
echo (async () =^> {await import("file:///%NAPCAT_MAIN_PATH%")})() > "%NAPCAT_LOAD_PATH%"
|
||||
|
||||
"%NAPCAT_LAUNCHER_PATH%" "%QQPath%" "%NAPCAT_INJECT_PATH%" %1
|
@@ -1,5 +0,0 @@
|
||||
const path = require('path');
|
||||
const CurrentPath = path.dirname(__filename);
|
||||
(async () => {
|
||||
await import("file://" + path.join(CurrentPath, './napcat/napcat.mjs'));
|
||||
})();
|
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"name": "qq-chat",
|
||||
"version": "9.9.16-29456",
|
||||
"verHash": "dd395162",
|
||||
"linuxVersion": "3.2.13-29456",
|
||||
"linuxVerHash": "e379390a",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"description": "QQ",
|
||||
"productName": "QQ",
|
||||
"author": {
|
||||
"name": "Tencent",
|
||||
"email": "QQ-Team@tencent.com"
|
||||
},
|
||||
"homepage": "https://im.qq.com",
|
||||
"sideEffects": true,
|
||||
"bin": {
|
||||
"qd": "externals/devtools/cli/index.js"
|
||||
},
|
||||
"main": "./loadNapCat.js",
|
||||
"buildVersion": "29456",
|
||||
"isPureShell": true,
|
||||
"isByteCodeShell": true,
|
||||
"platform": "win32",
|
||||
"eleArch": "x64"
|
||||
}
|
@@ -1,4 +0,0 @@
|
||||
@echo off
|
||||
REM ./launcher.bat 123456
|
||||
REM ./launcher-win10.bat 123456
|
||||
REM 带有REM的为注释 删掉你需要的系统的那行REM这三个单词 修改QQ本脚本启动即可
|
BIN
logo.png
Before Width: | Height: | Size: 335 KiB After Width: | Height: | Size: 208 KiB |
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"manifest_version": 4,
|
||||
"type": "extension",
|
||||
"name": "NapCatQQ",
|
||||
"slug": "NapCat.Framework",
|
||||
"description": "高性能的 OneBot 11 协议实现",
|
||||
"version": "4.2.0",
|
||||
"icon": "./logo.png",
|
||||
"authors": [
|
||||
{
|
||||
"name": "MliKiowa",
|
||||
"link": "https://github.com/MliKiowa"
|
||||
},
|
||||
{
|
||||
"name": "Young",
|
||||
"link": "https://github.com/Wesley-Young"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"repo": "NapNeko/NapCatQQ",
|
||||
"branch": "main"
|
||||
},
|
||||
"platform": [
|
||||
"win32",
|
||||
"linux",
|
||||
"darwin"
|
||||
],
|
||||
"injects": {
|
||||
"renderer": "./renderer.js",
|
||||
"main": "./liteloader.cjs",
|
||||
"preload": "./preload.cjs"
|
||||
}
|
||||
}
|
24
napcat.webui/.gitignore
vendored
@@ -1,24 +0,0 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
3
napcat.webui/.vscode/extensions.json
vendored
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"recommendations": ["Vue.volar"]
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
# Vue 3 + TypeScript + Vite
|
||||
|
||||
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||
|
||||
Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
|
@@ -1,52 +0,0 @@
|
||||
import globals from 'globals';
|
||||
import ts from 'typescript-eslint';
|
||||
import vue from 'eslint-plugin-vue';
|
||||
import prettier from 'eslint-plugin-prettier/recommended';
|
||||
|
||||
export default [
|
||||
{
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.node,
|
||||
},
|
||||
},
|
||||
},
|
||||
...ts.configs.recommended,
|
||||
{
|
||||
rules: {
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
'@typescript-eslint/no-var-requires': 'warn',
|
||||
},
|
||||
},
|
||||
...vue.configs['flat/base'],
|
||||
{
|
||||
files: ['*.vue', '**/*.vue'],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
parser: ts.parser,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
rules: {
|
||||
indent: ['error', 4],
|
||||
semi: ['error', 'always'],
|
||||
'no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
'@typescript-eslint/no-unused-vars': 'warn',
|
||||
'@typescript-eslint/no-var-requires': 'warn',
|
||||
'object-curly-spacing': ['error', 'always'],
|
||||
'vue/v-for-delimiter-style': ['error', 'in'],
|
||||
'vue/require-name-property': 'warn',
|
||||
'vue/prefer-true-attribute-shorthand': 'warn',
|
||||
'prefer-arrow-callback': 'warn',
|
||||
},
|
||||
},
|
||||
prettier,
|
||||
{
|
||||
rules: {
|
||||
'prettier/prettier': 'warn',
|
||||
},
|
||||
},
|
||||
];
|
@@ -1,13 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="./logo_webui.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>NapCat WebUI</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="./src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"name": "napcat.webui",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"webui:lint": "eslint --fix src/**/*.{js,ts,vue}",
|
||||
"webui:dev": "vite",
|
||||
"webui:build": "vite build",
|
||||
"webui:preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"qrcode": "^1.5.4",
|
||||
"tdesign-icons-vue-next": "^0.3.3",
|
||||
"tdesign-vue-next": "^1.10.3",
|
||||
"vue": "^3.5.13",
|
||||
"vue-router": "^4.4.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.1.0",
|
||||
"@eslint/js": "^9.14.0",
|
||||
"@types/qrcode": "^1.5.5",
|
||||
"@vitejs/plugin-legacy": "^5.4.3",
|
||||
"@vitejs/plugin-vue": "^5.1.4",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-vue": "^9.31.0",
|
||||
"globals": "^15.12.0",
|
||||
"terser": "^5.36.0",
|
||||
"typescript": "~5.6.2",
|
||||
"vite": "^5.4.10",
|
||||
"vue-tsc": "^2.1.8"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 335 KiB |
Before Width: | Height: | Size: 201 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,112 +0,0 @@
|
||||
<template>
|
||||
<div id="app" theme-mode="dark">
|
||||
<router-view />
|
||||
</div>
|
||||
<div v-if="show">
|
||||
<t-sticky-tool shape="round" placement="right-bottom" :offset="[-50, 10]" @click="changeTheme">
|
||||
<t-sticky-item label="浅色" popup="切换浅色模式">
|
||||
<template #icon><sunny-icon /></template>
|
||||
</t-sticky-item>
|
||||
<t-sticky-item label="深色" popup="切换深色模式">
|
||||
<template #icon><mode-dark-icon /></template>
|
||||
</t-sticky-item>
|
||||
<t-sticky-item label="自动" popup="跟随系统">
|
||||
<template #icon><control-platform-icon /></template>
|
||||
</t-sticky-item>
|
||||
</t-sticky-tool>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onBeforeUnmount, onMounted, onUnmounted, ref } from 'vue';
|
||||
import { ControlPlatformIcon, ModeDarkIcon, SunnyIcon } from 'tdesign-icons-vue-next';
|
||||
const smallScreen = window.matchMedia('(max-width: 768px)');
|
||||
interface Item {
|
||||
label: string;
|
||||
popup: string;
|
||||
}
|
||||
|
||||
interface Context {
|
||||
item: Item;
|
||||
}
|
||||
enum ThemeMode {
|
||||
Dark = 'dark',
|
||||
Light = 'light',
|
||||
Auto = 'auto',
|
||||
}
|
||||
const themeLabelMap: Record<string, ThemeMode> = {
|
||||
"浅色": ThemeMode.Light,
|
||||
"深色": ThemeMode.Dark,
|
||||
"自动": ThemeMode.Auto,
|
||||
};
|
||||
const show = ref<boolean>(true);
|
||||
const createSetThemeAttributeFunction = () => {
|
||||
let mediaQueryForAutoTheme: MediaQueryList | null = null;
|
||||
return (mode: ThemeMode | null) => {
|
||||
const element = document.documentElement;
|
||||
if (mode === ThemeMode.Dark) {
|
||||
element.setAttribute('theme-mode', ThemeMode.Dark);
|
||||
} else if (mode === ThemeMode.Light) {
|
||||
element.removeAttribute('theme-mode');
|
||||
} else if (mode === ThemeMode.Auto) {
|
||||
mediaQueryForAutoTheme = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
const handleMediaChange = (e: MediaQueryListEvent) => {
|
||||
if (e.matches) {
|
||||
element.setAttribute('theme-mode', ThemeMode.Dark);
|
||||
} else {
|
||||
element.removeAttribute('theme-mode');
|
||||
}
|
||||
};
|
||||
mediaQueryForAutoTheme.addEventListener('change', handleMediaChange);
|
||||
const event = new Event('change');
|
||||
Object.defineProperty(event, 'matches', {
|
||||
value: mediaQueryForAutoTheme.matches,
|
||||
writable: false,
|
||||
});
|
||||
mediaQueryForAutoTheme.dispatchEvent(event);
|
||||
onBeforeUnmount(() => {
|
||||
if (mediaQueryForAutoTheme) {
|
||||
mediaQueryForAutoTheme.removeEventListener('change', handleMediaChange);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const setThemeAttribute = createSetThemeAttributeFunction();
|
||||
|
||||
const getStoredTheme = (): ThemeMode | null => {
|
||||
return localStorage.getItem('theme') as ThemeMode | null;
|
||||
};
|
||||
|
||||
const initTheme = () => {
|
||||
const storedTheme = getStoredTheme();
|
||||
if (storedTheme === null) {
|
||||
setThemeAttribute(ThemeMode.Auto);
|
||||
} else {
|
||||
setThemeAttribute(storedTheme);
|
||||
}
|
||||
};
|
||||
|
||||
const changeTheme = (context: Context) => {
|
||||
const themeLabel = themeLabelMap[context.item.label] as ThemeMode;
|
||||
console.log(themeLabel);
|
||||
setThemeAttribute(themeLabel);
|
||||
localStorage.setItem('theme', themeLabel);
|
||||
};
|
||||
const haddingFbars = () => {
|
||||
show.value = !smallScreen.matches;
|
||||
if (smallScreen.matches) {
|
||||
localStorage.setItem('theme', 'auto');
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
initTheme();
|
||||
haddingFbars();
|
||||
window.addEventListener('resize', haddingFbars);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', haddingFbars);
|
||||
});
|
||||
</script>
|
||||
<style scoped></style>
|
Before Width: | Height: | Size: 335 KiB |
Before Width: | Height: | Size: 201 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
Before Width: | Height: | Size: 496 B |
@@ -1,205 +0,0 @@
|
||||
import { OneBotConfig } from '../../../src/onebot/config/config';
|
||||
|
||||
export class QQLoginManager {
|
||||
private retCredential: string;
|
||||
private readonly apiPrefix: string;
|
||||
|
||||
//调试时http://127.0.0.1:6099/api 打包时 ../api
|
||||
constructor(retCredential: string, apiPrefix: string = '../api') {
|
||||
this.retCredential = retCredential;
|
||||
this.apiPrefix = apiPrefix;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
public async GetOB11Config(): Promise<OneBotConfig> {
|
||||
try {
|
||||
const ConfigResponse = await fetch(`${this.apiPrefix}/OB11Config/GetConfig`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.retCredential,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
if (ConfigResponse.status == 200) {
|
||||
const ConfigResponseJson = await ConfigResponse.json();
|
||||
if (ConfigResponseJson.code == 0) {
|
||||
return ConfigResponseJson?.data as OneBotConfig;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error getting OB11 config:', error);
|
||||
}
|
||||
return {} as OneBotConfig;
|
||||
}
|
||||
|
||||
public async SetOB11Config(config: OneBotConfig): Promise<boolean> {
|
||||
try {
|
||||
const ConfigResponse = await fetch(`${this.apiPrefix}/OB11Config/SetConfig`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.retCredential,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ config: JSON.stringify(config) }),
|
||||
});
|
||||
if (ConfigResponse.status == 200) {
|
||||
const ConfigResponseJson = await ConfigResponse.json();
|
||||
if (ConfigResponseJson.code == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error setting OB11 config:', error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public async checkQQLoginStatus(): Promise<boolean> {
|
||||
try {
|
||||
const QQLoginResponse = await fetch(`${this.apiPrefix}/QQLogin/CheckLoginStatus`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.retCredential,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
if (QQLoginResponse.status == 200) {
|
||||
const QQLoginResponseJson = await QQLoginResponse.json();
|
||||
if (QQLoginResponseJson.code == 0) {
|
||||
return QQLoginResponseJson.data.isLogin;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error checking QQ login status:', error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public async checkQQLoginStatusWithQrcode(): Promise<{ qrcodeurl: string; isLogin: string } | undefined> {
|
||||
try {
|
||||
const QQLoginResponse = await fetch(`${this.apiPrefix}/QQLogin/CheckLoginStatus`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.retCredential,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
if (QQLoginResponse.status == 200) {
|
||||
const QQLoginResponseJson = await QQLoginResponse.json();
|
||||
if (QQLoginResponseJson.code == 0) {
|
||||
return QQLoginResponseJson.data;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error checking QQ login status:', error);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public async checkWebUiLogined(): Promise<boolean> {
|
||||
try {
|
||||
const LoginResponse = await fetch(`${this.apiPrefix}/auth/check`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.retCredential,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
if (LoginResponse.status == 200) {
|
||||
const LoginResponseJson = await LoginResponse.json();
|
||||
if (LoginResponseJson.code == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error checking web UI login status:', error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public async loginWithToken(token: string): Promise<string | null> {
|
||||
try {
|
||||
const loginResponse = await fetch(`${this.apiPrefix}/auth/login`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ token: token }),
|
||||
});
|
||||
const loginResponseJson = await loginResponse.json();
|
||||
const retCode = loginResponseJson.code;
|
||||
if (retCode === 0) {
|
||||
this.retCredential = loginResponseJson.data.Credential;
|
||||
return this.retCredential;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error logging in with token:', error);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public async getQQLoginQrcode(): Promise<string> {
|
||||
try {
|
||||
const QQLoginResponse = await fetch(`${this.apiPrefix}/QQLogin/GetQQLoginQrcode`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.retCredential,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
if (QQLoginResponse.status == 200) {
|
||||
const QQLoginResponseJson = await QQLoginResponse.json();
|
||||
if (QQLoginResponseJson.code == 0) {
|
||||
return QQLoginResponseJson.data.qrcode || '';
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error getting QQ login QR code:', error);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public async getQQQuickLoginList(): Promise<string[]> {
|
||||
try {
|
||||
const QQLoginResponse = await fetch(`${this.apiPrefix}/QQLogin/GetQuickLoginList`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.retCredential,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
if (QQLoginResponse.status == 200) {
|
||||
const QQLoginResponseJson = await QQLoginResponse.json();
|
||||
if (QQLoginResponseJson.code == 0) {
|
||||
return QQLoginResponseJson.data || [];
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error getting QQ quick login list:', error);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
public async setQuickLogin(uin: string): Promise<{ result: boolean; errMsg: string }> {
|
||||
try {
|
||||
const QQLoginResponse = await fetch(`${this.apiPrefix}/QQLogin/SetQuickLogin`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.retCredential,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ uin: uin }),
|
||||
});
|
||||
if (QQLoginResponse.status == 200) {
|
||||
const QQLoginResponseJson = await QQLoginResponse.json();
|
||||
if (QQLoginResponseJson.code == 0) {
|
||||
return { result: true, errMsg: '' };
|
||||
} else {
|
||||
return { result: false, errMsg: QQLoginResponseJson.message };
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error setting quick login:', error);
|
||||
}
|
||||
return { result: false, errMsg: '接口异常' };
|
||||
}
|
||||
}
|
@@ -1,58 +0,0 @@
|
||||
<template>
|
||||
<t-layout class="dashboard-container">
|
||||
<div ref="menuRef">
|
||||
<SidebarMenu :menu-items="menuItems" class="sidebar-menu" />
|
||||
</div>
|
||||
<t-layout>
|
||||
<router-view />
|
||||
</t-layout>
|
||||
</t-layout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue';
|
||||
import SidebarMenu from './webui/Nav.vue';
|
||||
import emitter from '@/ts/event-bus';
|
||||
interface MenuItem {
|
||||
value: string;
|
||||
icon: string;
|
||||
label: string;
|
||||
route: string;
|
||||
}
|
||||
|
||||
const menuItems = ref<MenuItem[]>([
|
||||
{ value: 'item1', icon: 'dashboard', label: '基础信息', route: '/dashboard/basic-info' },
|
||||
{ value: 'item3', icon: 'wifi-1', label: '网络配置', route: '/dashboard/network-config' },
|
||||
{ value: 'item4', icon: 'setting', label: '其余配置', route: '/dashboard/other-config' },
|
||||
{ value: 'item5', icon: 'system-log', label: '日志查看', route: '/dashboard/log-view' },
|
||||
{ value: 'item6', icon: 'info-circle', label: '关于我们', route: '/dashboard/about-us' },
|
||||
]);
|
||||
const menuRef = ref<HTMLDivElement | null>(null);
|
||||
emitter.on('sendMenu', (event) => {
|
||||
emitter.emit('sendWidth', menuRef.value?.offsetWidth);
|
||||
localStorage.setItem('menuWidth', menuRef.value?.offsetWidth?.toString() || '0');
|
||||
});
|
||||
onMounted(() => {
|
||||
localStorage.setItem('menuWidth', menuRef.value?.offsetWidth?.toString() || '0');
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.dashboard-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sidebar-menu {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.content {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -1,185 +0,0 @@
|
||||
<template>
|
||||
<t-card class="layout">
|
||||
<div class="login-container">
|
||||
<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-tooltip>
|
||||
<t-tooltip content="二维码登录">
|
||||
<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-option v-for="account in quickLoginList" :key="account" :value="account">{{ account }}</t-option>
|
||||
</t-select>
|
||||
</div>
|
||||
<div v-show="loginMethod === 'qrcode'" id="qrcode" class="qrcode">
|
||||
<canvas ref="qrcodeCanvas"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<t-footer class="footer">Power By NapCat.WebUi</t-footer>
|
||||
</t-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import * as QRCode from 'qrcode';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { MessagePlugin } from 'tdesign-vue-next';
|
||||
import { QQLoginManager } from '@/backend/shell';
|
||||
|
||||
const router = useRouter();
|
||||
const loginMethod = ref<'quick' | 'qrcode'>('quick');
|
||||
const quickLoginList = ref<string[]>([]);
|
||||
const selectedAccount = ref<string>('');
|
||||
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) {
|
||||
if (heartBeatTimer) {
|
||||
clearInterval(heartBeatTimer);
|
||||
}
|
||||
await MessagePlugin.success('登录成功即将跳转');
|
||||
await router.push({ path: '/dashboard/basic-info' });
|
||||
} else {
|
||||
await MessagePlugin.error('登录失败,' + errMsg);
|
||||
}
|
||||
};
|
||||
|
||||
const generateQrCode = (data: string, canvas: HTMLCanvasElement | null): void => {
|
||||
if (!canvas) {
|
||||
console.error('Canvas element not found');
|
||||
return;
|
||||
}
|
||||
QRCode.toCanvas(canvas, data, function (error: Error | null | undefined) {
|
||||
if (error) {
|
||||
console.error('Error generating QR Code:', error);
|
||||
} else {
|
||||
console.log('QR Code generated!');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const HeartBeat = async (): Promise<void> => {
|
||||
const isLogined = await qqLoginManager.checkQQLoginStatusWithQrcode();
|
||||
if (isLogined?.isLogin) {
|
||||
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) {
|
||||
qrcodeUrl = isLogined.qrcodeurl;
|
||||
generateQrCode(qrcodeUrl, qrcodeCanvas.value);
|
||||
}
|
||||
};
|
||||
|
||||
const InitPages = async (): Promise<void> => {
|
||||
quickLoginList.value = await qqLoginManager.getQQQuickLoginList();
|
||||
qrcodeUrl = await qqLoginManager.getQQLoginQrcode();
|
||||
generateQrCode(qrcodeUrl, qrcodeCanvas.value);
|
||||
heartBeatTimer = window.setInterval(HeartBeat, 3000);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
InitPages();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.layout {
|
||||
height: 100vh;
|
||||
}
|
||||
.login-container {
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
max-width: 400px;
|
||||
min-width: 300px;
|
||||
position: relative;
|
||||
margin: 50px auto;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.login-container {
|
||||
width: 90%;
|
||||
min-width: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.login-methods {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.login-method {
|
||||
padding: 10px 15px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.login-method.active {
|
||||
background-color: #e6f0ff;
|
||||
color: #007bff;
|
||||
}
|
||||
|
||||
.login-form,
|
||||
.qrcode {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.qrcode {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.sotheby-font {
|
||||
font-family: Sotheby, Helvetica, monospace;
|
||||
font-size: 3.125rem;
|
||||
line-height: 1.2;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.footer {
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
font-size: 0.875rem;
|
||||
color: #888;
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
</style>
|
@@ -1,153 +0,0 @@
|
||||
<template>
|
||||
<t-card class="layout">
|
||||
<div class="login-container">
|
||||
<h2 class="sotheby-font">WebUi Login</h2>
|
||||
<t-form ref="form" :data="formData" colon :label-width="0" @submit="onSubmit">
|
||||
<t-form-item name="password">
|
||||
<t-input v-model="formData.token" type="password" clearable placeholder="请输入Token">
|
||||
<template #prefix-icon>
|
||||
<lock-on-icon />
|
||||
</template>
|
||||
</t-input>
|
||||
</t-form-item>
|
||||
<t-form-item>
|
||||
<t-button theme="primary" type="submit" block>登录</t-button>
|
||||
</t-form-item>
|
||||
</t-form>
|
||||
</div>
|
||||
<t-footer class="footer">Power By NapCat.WebUi</t-footer>
|
||||
</t-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import '../css/style.css';
|
||||
import '../css/font.css';
|
||||
import { reactive, onMounted } from 'vue';
|
||||
import { MessagePlugin } from 'tdesign-vue-next';
|
||||
import { LockOnIcon } from 'tdesign-icons-vue-next';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { QQLoginManager } from '@/backend/shell';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
interface FormData {
|
||||
token: string;
|
||||
}
|
||||
|
||||
const formData: FormData = reactive({
|
||||
token: '',
|
||||
});
|
||||
|
||||
const handleLoginSuccess = async (credential: string) => {
|
||||
localStorage.setItem('auth', credential);
|
||||
await checkLoginStatus();
|
||||
};
|
||||
|
||||
const handleLoginFailure = (message: string) => {
|
||||
MessagePlugin.error(message);
|
||||
};
|
||||
|
||||
const checkLoginStatus = async () => {
|
||||
const storedCredential = localStorage.getItem('auth');
|
||||
if (!storedCredential) {
|
||||
return;
|
||||
}
|
||||
const loginManager = new QQLoginManager(storedCredential);
|
||||
const isWenUiLoggedIn = await loginManager.checkWebUiLogined();
|
||||
console.log('isWenUiLoggedIn', isWenUiLoggedIn);
|
||||
if (!isWenUiLoggedIn) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isQQLoggedIn = await loginManager.checkQQLoginStatus();
|
||||
if (isQQLoggedIn) {
|
||||
await router.push({ path: '/dashboard/basic-info' });
|
||||
} else {
|
||||
await router.push({ path: '/qqlogin' });
|
||||
}
|
||||
};
|
||||
|
||||
const loginWithToken = async (token: string) => {
|
||||
const loginManager = new QQLoginManager('');
|
||||
const credential = await loginManager.loginWithToken(token);
|
||||
if (credential) {
|
||||
await handleLoginSuccess(credential);
|
||||
} else {
|
||||
handleLoginFailure('登录失败,请检查Token');
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
const url = new URL(window.location.href);
|
||||
const token = url.searchParams.get('token');
|
||||
if (token) {
|
||||
loginWithToken(token);
|
||||
}
|
||||
checkLoginStatus();
|
||||
});
|
||||
|
||||
const onSubmit = async ({ validateResult }: { validateResult: boolean }) => {
|
||||
if (validateResult) {
|
||||
await loginWithToken(formData.token);
|
||||
} else {
|
||||
handleLoginFailure('请填写Token');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.layout {
|
||||
height: 100vh;
|
||||
}
|
||||
.login-container {
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
max-width: 400px;
|
||||
min-width: 300px;
|
||||
position: relative;
|
||||
margin: 50px auto;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.login-container {
|
||||
width: 90%;
|
||||
min-width: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.tdesign-demo-block-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 16px;
|
||||
}
|
||||
|
||||
.tdesign-demo-block-column-large {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 32px;
|
||||
}
|
||||
|
||||
.tdesign-demo-block-row {
|
||||
display: flex;
|
||||
column-gap: 16px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sotheby-font {
|
||||
font-family: Sotheby, Helvetica, monospace;
|
||||
font-size: 3.125rem;
|
||||
line-height: 1.2;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.footer {
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
font-size: 0.875rem;
|
||||
color: #888;
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
</style>
|
@@ -1,127 +0,0 @@
|
||||
<template>
|
||||
<t-menu theme="light" default-value="2-1" :collapsed="collapsed" class="sidebar-menu">
|
||||
<template #logo>
|
||||
<div class="logo">
|
||||
<img class="logo-img" :width="collapsed ? 35 : 'auto'" src="@/assets/logo_webui.png" alt="logo" />
|
||||
<div class="logo-textBox">
|
||||
<div class="logo-text">{{ collapsed ? '' : 'NapCat' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<router-link v-for="item in menuItems" :key="item.value" :to="item.route">
|
||||
<t-tooltip :disabled="!collapsed" :content="item.label" placement="right">
|
||||
<t-menu-item :value="item.value" :disabled="item.disabled" class="menu-item">
|
||||
<template #icon>
|
||||
<t-icon :name="item.icon" />
|
||||
</template>
|
||||
{{ item.label }}
|
||||
</t-menu-item>
|
||||
</t-tooltip>
|
||||
</router-link>
|
||||
<template #operations>
|
||||
<t-button
|
||||
:disabled="disBtn"
|
||||
class="t-demo-collapse-btn"
|
||||
variant="text"
|
||||
shape="square"
|
||||
@click="changeCollapsed"
|
||||
>
|
||||
<template #icon><t-icon :name="iconName" /></template>
|
||||
</t-button>
|
||||
</template>
|
||||
</t-menu>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, defineProps, onMounted, watch } from 'vue';
|
||||
import emitter from '@/ts/event-bus';
|
||||
|
||||
type MenuItem = {
|
||||
value: string;
|
||||
label: string;
|
||||
route: string;
|
||||
icon?: string;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
defineProps<{
|
||||
menuItems: MenuItem[];
|
||||
}>();
|
||||
const collapsed = ref<boolean>(localStorage.getItem('sidebar-collapsed') === 'true');
|
||||
const iconName = ref<string>(collapsed.value ? 'menu-unfold' : 'menu-fold');
|
||||
const disBtn = ref<boolean>(false);
|
||||
|
||||
const changeCollapsed = (): void => {
|
||||
collapsed.value = !collapsed.value;
|
||||
iconName.value = collapsed.value ? 'menu-unfold' : 'menu-fold';
|
||||
localStorage.setItem('sidebar-collapsed', collapsed.value.toString());
|
||||
};
|
||||
watch(collapsed, (newValue, oldValue) => {
|
||||
setTimeout(() => {
|
||||
emitter.emit('sendMenu', collapsed.value);
|
||||
}, 300);
|
||||
});
|
||||
onMounted(() => {
|
||||
const mediaQuery = window.matchMedia('(max-width: 800px)');
|
||||
const handleMediaChange = (e: MediaQueryListEvent) => {
|
||||
disBtn.value = e.matches;
|
||||
if (e.matches) {
|
||||
collapsed.value = e.matches;
|
||||
}
|
||||
};
|
||||
mediaQuery.addEventListener('change', handleMediaChange);
|
||||
const event = new Event('change');
|
||||
Object.defineProperty(event, 'matches', {
|
||||
value: mediaQuery.matches,
|
||||
writable: false,
|
||||
});
|
||||
mediaQuery.dispatchEvent(event);
|
||||
return () => {
|
||||
mediaQuery.removeEventListener('change', handleMediaChange);
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.sidebar-menu {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 200px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.sidebar-menu {
|
||||
width: 100px; /* 移动端侧边栏宽度 */
|
||||
}
|
||||
}
|
||||
.logo {
|
||||
display: flex;
|
||||
width: auto;
|
||||
height: 100%;
|
||||
}
|
||||
.logo-img {
|
||||
object-fit: contain;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.logo-textBox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.logo-text {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 22px;
|
||||
font-family: Sotheby, Helvetica, monospace;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
@@ -1,6 +0,0 @@
|
||||
@font-face {
|
||||
font-family: 'Sotheby';
|
||||
src: url('../assets/Sotheby.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
@@ -1,84 +0,0 @@
|
||||
:root {
|
||||
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
place-items: center;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
background-color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #646cff;
|
||||
}
|
||||
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
#app {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
color: #213547;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #747bff;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
}
|
@@ -1,87 +0,0 @@
|
||||
import { createApp } from 'vue';
|
||||
import App from './App.vue';
|
||||
import {
|
||||
Button as TButton,
|
||||
Input as TInput,
|
||||
Form as TForm,
|
||||
FormItem as TFormItem,
|
||||
Select as TSelect,
|
||||
Option as TOption,
|
||||
Menu as TMenu,
|
||||
MenuItem as TMenuItem,
|
||||
Icon as TIcon,
|
||||
Submenu as TSubmenu,
|
||||
Col as TCol,
|
||||
Row as TRow,
|
||||
Card as TCard,
|
||||
Divider as TDivider,
|
||||
Link as TLink,
|
||||
List as TList,
|
||||
Alert as TAlert,
|
||||
Tag as TTag,
|
||||
Descriptions as TDescriptionsProps,
|
||||
DescriptionsItem as TDescriptionsItem,
|
||||
Collapse as TCollapse,
|
||||
CollapsePanel as TCollapsePanel,
|
||||
ListItem as TListItem,
|
||||
Tabs as TTabs,
|
||||
TabPanel as TTabPanel,
|
||||
Space as TSpace,
|
||||
Checkbox as TCheckbox,
|
||||
Popup as TPopup,
|
||||
Dialog as TDialog,
|
||||
Switch as TSwitch,
|
||||
Tooltip as Tooltip,
|
||||
StickyTool as TStickyTool,
|
||||
StickyItem as TStickyItem,
|
||||
Layout as TLayout,
|
||||
Content as TContent,
|
||||
Footer as TFooter,
|
||||
Aside as TAside,
|
||||
Popconfirm as Tpopconfirm,
|
||||
Empty as TEmpty,
|
||||
} from 'tdesign-vue-next';
|
||||
import { router } from './router';
|
||||
import 'tdesign-vue-next/es/style/index.css';
|
||||
const app = createApp(App);
|
||||
app.use(router);
|
||||
app.use(TButton);
|
||||
app.use(TInput);
|
||||
app.use(TForm);
|
||||
app.use(TFormItem);
|
||||
app.use(TSelect);
|
||||
app.use(TOption);
|
||||
app.use(TMenu);
|
||||
app.use(TMenuItem);
|
||||
app.use(TIcon);
|
||||
app.use(TSubmenu);
|
||||
app.use(TCol);
|
||||
app.use(TRow);
|
||||
app.use(TCard);
|
||||
app.use(TDivider);
|
||||
app.use(TLink);
|
||||
app.use(TList);
|
||||
app.use(TAlert);
|
||||
app.use(TTag);
|
||||
app.use(TDescriptionsProps);
|
||||
app.use(TDescriptionsItem);
|
||||
app.use(TCollapse);
|
||||
app.use(TCollapsePanel);
|
||||
app.use(TListItem);
|
||||
app.use(TTabs);
|
||||
app.use(TTabPanel);
|
||||
app.use(TSpace);
|
||||
app.use(TCheckbox);
|
||||
app.use(TPopup);
|
||||
app.use(TDialog);
|
||||
app.use(TSwitch);
|
||||
app.use(Tooltip);
|
||||
app.use(TStickyTool);
|
||||
app.use(TStickyItem);
|
||||
app.use(TLayout);
|
||||
app.use(TContent);
|
||||
app.use(TFooter);
|
||||
app.use(TAside);
|
||||
app.use(Tpopconfirm);
|
||||
app.use(TEmpty);
|
||||
app.mount('#app');
|
@@ -1,66 +0,0 @@
|
||||
<template>
|
||||
<div class="about-us">
|
||||
<div>
|
||||
<t-divider content="面板关于信息" align="left" />
|
||||
<t-alert theme="success" message="NapCat.WebUi is running" />
|
||||
<t-list class="list">
|
||||
<t-list-item class="list-item">
|
||||
<span class="item-label">开发人员:</span>
|
||||
<span class="item-content">
|
||||
<t-link href="mailto:nanaeonn@outlook.com">Mlikiowa</t-link>
|
||||
</span>
|
||||
</t-list-item>
|
||||
<t-list-item class="list-item">
|
||||
<span class="item-label">版本信息:</span>
|
||||
<span class="item-content">
|
||||
<t-tag class="tag-item" theme="success"> WebUi: {{ pkg.version }} </t-tag>
|
||||
<t-tag class="tag-item" theme="success"> NapCat: {{ napCatVersion }} </t-tag>
|
||||
<t-tag class="tag-item" theme="success">
|
||||
TDesign: {{ pkg.dependencies['tdesign-vue-next'] }}
|
||||
</t-tag>
|
||||
</span>
|
||||
</t-list-item>
|
||||
</t-list>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import pkg from '../../package.json';
|
||||
import { napCatVersion } from '../../../src/common/version';
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.about-us {
|
||||
padding: 20px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.list-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item-label {
|
||||
flex: 1;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
flex: 2;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.tag-item {
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
@@ -1,6 +0,0 @@
|
||||
<template>
|
||||
<div class="basic-info">
|
||||
<h1>面板基础信息</h1>
|
||||
<p>这里显示面板的基础信息。</p>
|
||||
</div>
|
||||
</template>
|
@@ -1,6 +0,0 @@
|
||||
<template>
|
||||
<div class="log-view">
|
||||
<h1>面板日志信息</h1>
|
||||
<p>这里显示面板的日志信息。</p>
|
||||
</div>
|
||||
</template>
|
@@ -1,540 +0,0 @@
|
||||
<template>
|
||||
<div ref="headerBox" class="title">
|
||||
<t-divider content="网络配置" align="left" />
|
||||
<t-divider align="right">
|
||||
<t-button @click="addConfig()">
|
||||
<template #icon><add-icon /></template>
|
||||
添加配置</t-button>
|
||||
</t-divider>
|
||||
</div>
|
||||
<div v-if="loadPage" ref="setting" class="setting">
|
||||
<t-tabs ref="tabsRef" :style="{ width: tabsWidth + 'px' }" default-value="all" @change="selectType">
|
||||
<t-tab-panel value="all" label="全部"></t-tab-panel>
|
||||
<t-tab-panel value="httpServers" label="HTTP 服务器"></t-tab-panel>
|
||||
<t-tab-panel value="httpClients" label="HTTP 客户端"></t-tab-panel>
|
||||
<t-tab-panel value="websocketServers" label="WebSocket 服务器"></t-tab-panel>
|
||||
<t-tab-panel value="websocketClients" label="WebSocket 客户端"></t-tab-panel>
|
||||
</t-tabs>
|
||||
</div>
|
||||
<div v-if="loadPage" class="card-box" :style="{ width: tabsWidth + 'px' }">
|
||||
<div class="setting-box" :style="{ maxHeight: cardHeight + 'px' }" v-if="cardConfig.length > 0">
|
||||
<div v-for="(item, index) in cardConfig" :key="index">
|
||||
<t-card :title="item.name" :description="item.type" :style="{ width: cardWidth + 'px' }"
|
||||
:header-bordered="true" class="setting-card">
|
||||
<template #actions>
|
||||
<t-space>
|
||||
<edit2-icon size="20px" @click="editConfig(item)"></edit2-icon>
|
||||
<t-popconfirm theme="danger" content="确认删除" @confirm="delConfig(item)">
|
||||
<delete-icon size="20px"></delete-icon>
|
||||
</t-popconfirm>
|
||||
</t-space>
|
||||
</template>
|
||||
<div class="setting-content">
|
||||
<t-card class="card-address" :style="{
|
||||
borderLeft: '7px solid ' + (item.enable ?
|
||||
'var(--td-success-color)' :
|
||||
'var(--td-error-color)')
|
||||
}">
|
||||
<div class="local-box" v-if="item.host&&item.port">
|
||||
<server-filled-icon class="local-icon" size="20px"></server-filled-icon>
|
||||
<strong class="local">{{ item.host }}:{{ item.port }}</strong>
|
||||
<copy-icon class="copy-icon" size="20px" @click="copyText(item.host + ':' + item.port)"></copy-icon>
|
||||
</div>
|
||||
<div class="local-box" v-if="item.url">
|
||||
<server-filled-icon class="local-icon" size="20px"></server-filled-icon>
|
||||
<strong class="local" >{{ item.url }}</strong>
|
||||
<copy-icon class="copy-icon" size="20px" @click="copyText(item.url)"></copy-icon>
|
||||
</div>
|
||||
</t-card>
|
||||
<t-collapse :default-value="[0]" expand-mutex style="margin-top:10px;" class="info-coll">
|
||||
<t-collapse-panel header="基础信息">
|
||||
<t-descriptions size="small" :layout="infoOneCol ? 'vertical' : 'horizontal'"
|
||||
class="setting-base-info">
|
||||
<t-descriptions-item v-if="item.token" label="连接密钥">
|
||||
<div v-if="mediumScreen.matches||largeScreen.matches" class="token-view">
|
||||
<span>{{ showToken ? item.token : '******' }}</span>
|
||||
<browse-icon class="browse-icon" v-if="showToken" size="18px"
|
||||
@click="showToken = false"></browse-icon>
|
||||
<browse-off-icon class="browse-icon" v-else size="18px"
|
||||
@click="showToken = true"></browse-off-icon>
|
||||
</div>
|
||||
<div v-else>
|
||||
<t-popup :showArrow="true" trigger="click">
|
||||
<t-tag theme="primary">点击查看</t-tag>
|
||||
<template #content>
|
||||
<div @click="copyText(item.token)">{{item.token}}</div>
|
||||
</template>
|
||||
</t-popup>
|
||||
</div>
|
||||
</t-descriptions-item>
|
||||
<t-descriptions-item label="消息格式">{{ item.messagePostFormat }}</t-descriptions-item>
|
||||
</t-descriptions>
|
||||
</t-collapse-panel>
|
||||
<t-collapse-panel header="状态信息">
|
||||
<t-descriptions size="small" :layout="infoOneCol ? 'vertical' : 'horizontal'"
|
||||
class="setting-base-info">
|
||||
<t-descriptions-item v-if="item.hasOwnProperty('debug')" label="调试日志">
|
||||
<t-tag class="tag-item" :theme="item.debug ? 'success' : 'danger'">
|
||||
{{ item.debug ? '开启' : '关闭' }}</t-tag>
|
||||
</t-descriptions-item>
|
||||
<t-descriptions-item v-if="item.hasOwnProperty('enableWebsocket')"
|
||||
label="Websocket 功能">
|
||||
<t-tag class="tag-item" :theme="item.enableWebsocket ? 'success' : 'danger'">
|
||||
{{ item.enableWebsocket ? '启用' : '禁用' }}</t-tag>
|
||||
</t-descriptions-item>
|
||||
<t-descriptions-item v-if="item.hasOwnProperty('enableCors')" label="跨域放行">
|
||||
<t-tag class="tag-item" :theme="item.enableCors ? 'success' : 'danger'">
|
||||
{{ item.enableCors ? '开启' : '关闭' }}</t-tag>
|
||||
</t-descriptions-item>
|
||||
<t-descriptions-item v-if="item.hasOwnProperty('enableForcePushEvent')"
|
||||
label="上报自身消息">
|
||||
<t-tag class="tag-item" :theme="item.reportSelfMessage ? 'success' : 'danger'">
|
||||
{{ item.reportSelfMessage ? '开启' : '关闭' }}</t-tag>
|
||||
</t-descriptions-item>
|
||||
<t-descriptions-item v-if="item.hasOwnProperty('enableForcePushEvent')"
|
||||
label="强制推送事件">
|
||||
<t-tag class="tag-item"
|
||||
:theme="item.enableForcePushEvent ? 'success' : 'danger'">
|
||||
{{ item.enableForcePushEvent ? '开启' : '关闭' }}</t-tag>
|
||||
</t-descriptions-item>
|
||||
</t-descriptions>
|
||||
</t-collapse-panel>
|
||||
</t-collapse>
|
||||
</div>
|
||||
</t-card>
|
||||
</div>
|
||||
<div style="height: 20vh"></div>
|
||||
</div>
|
||||
<t-card v-else>
|
||||
<t-empty class="card-none" title="暂无网络配置"> </t-empty>
|
||||
</t-card>
|
||||
</div>
|
||||
<t-dialog v-model:visible="visibleBody" :header="dialogTitle" :destroy-on-close="true"
|
||||
:show-in-attached-element="true" placement="center" :on-confirm="saveConfig" class=".t-dialog__ctx .t-dialog--defaul">
|
||||
<div slot="body" class="dialog-body" >
|
||||
<t-form ref="form" :data="newTab" labelAlign="left" :model="newTab">
|
||||
<t-form-item style="text-align: left" :rules="[{ required: true, message: '请输入名称', trigger: 'blur' }]"
|
||||
label="名称" name="name">
|
||||
<t-input v-model="newTab.name" />
|
||||
</t-form-item>
|
||||
<t-form-item style="text-align: left" :rules="[{ required: true, message: '请选择类型', trigger: 'change' }]"
|
||||
label="类型" name="type">
|
||||
<t-select v-model="newTab.type" @change="onloadDefault">
|
||||
<t-option value="httpServers">HTTP 服务器</t-option>
|
||||
<t-option value="httpClients">HTTP 客户端</t-option>
|
||||
<t-option value="websocketServers">WebSocket 服务器</t-option>
|
||||
<t-option value="websocketClients">WebSocket 客户端</t-option>
|
||||
</t-select>
|
||||
</t-form-item>
|
||||
<div>
|
||||
<component :is="resolveDynamicComponent(getComponent(newTab.type as ComponentKey))"
|
||||
:config="newTab.data" />
|
||||
</div>
|
||||
</t-form>
|
||||
</div>
|
||||
</t-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { AddIcon, DeleteIcon, Edit2Icon, ServerFilledIcon, CopyIcon, BrowseOffIcon, BrowseIcon } from 'tdesign-icons-vue-next';
|
||||
import { onMounted, onUnmounted, ref, resolveDynamicComponent } from 'vue';
|
||||
import emitter from '@/ts/event-bus';
|
||||
import {
|
||||
mergeNetworkDefaultConfig,
|
||||
mergeOneBotConfigs,
|
||||
NetworkConfig,
|
||||
OneBotConfig,
|
||||
} from '../../../src/onebot/config/config';
|
||||
import HttpServerComponent from '@/pages/network/HttpServerComponent.vue';
|
||||
import HttpClientComponent from '@/pages/network/HttpClientComponent.vue';
|
||||
import WebsocketServerComponent from '@/pages/network/WebsocketServerComponent.vue';
|
||||
import WebsocketClientComponent from '@/pages/network/WebsocketClientComponent.vue';
|
||||
import { MessagePlugin } from 'tdesign-vue-next';
|
||||
import { QQLoginManager } from '@/backend/shell';
|
||||
|
||||
const showToken = ref<boolean>(false);
|
||||
const infoOneCol = ref<boolean>(true);
|
||||
const tabsWidth = ref<number>(0);
|
||||
const menuWidth = ref<number>(0);
|
||||
const cardWidth = ref<number>(0);
|
||||
const cardHeight = ref<number>(0);
|
||||
const mediumScreen = window.matchMedia('(min-width: 768px) and (max-width: 1024px)');
|
||||
const largeScreen = window.matchMedia('(min-width: 1025px)');
|
||||
const headerBox = ref<HTMLDivElement | null>(null);
|
||||
const setting = ref<HTMLDivElement | null>(null);
|
||||
const loadPage = ref<boolean>(false);
|
||||
const visibleBody = ref<boolean>(false);
|
||||
const newTab = ref<{ name: string; data: any; type: string }>({ name: '', data: {}, type: '' });
|
||||
const dialogTitle = ref<string>('');
|
||||
|
||||
type ComponentKey = keyof typeof mergeNetworkDefaultConfig;
|
||||
|
||||
const componentMap: Record<
|
||||
ComponentKey,
|
||||
| typeof HttpServerComponent
|
||||
| typeof HttpClientComponent
|
||||
| typeof WebsocketServerComponent
|
||||
| typeof WebsocketClientComponent
|
||||
> = {
|
||||
httpServers: HttpServerComponent,
|
||||
httpClients: HttpClientComponent,
|
||||
websocketServers: WebsocketServerComponent,
|
||||
websocketClients: WebsocketClientComponent,
|
||||
};
|
||||
|
||||
//操作类型
|
||||
const operateType = ref<string>('');
|
||||
//配置项索引
|
||||
const configIndex = ref<number>(0);
|
||||
//保存时所用数据
|
||||
const networkConfig: NetworkConfig & { [key: string]: any; } = {
|
||||
websocketClients: [],
|
||||
websocketServers: [],
|
||||
httpClients: [],
|
||||
httpServers: [],
|
||||
};
|
||||
|
||||
//挂载的数据
|
||||
const WebConfg = ref(
|
||||
new Map<string, Array<null>>([
|
||||
['all', []],
|
||||
['httpServers', []],
|
||||
['httpClients', []],
|
||||
['websocketServers', []],
|
||||
['websocketClients', []],
|
||||
])
|
||||
);
|
||||
const typeCh: Record<ComponentKey, string> = {
|
||||
httpServers: 'HTTP 服务器',
|
||||
httpClients: 'HTTP 客户端',
|
||||
websocketServers: 'WebSocket 服务器',
|
||||
websocketClients: 'WebSocket 客户端',
|
||||
};
|
||||
const cardConfig = ref<any>([]);
|
||||
const getComponent = (type: ComponentKey) => {
|
||||
return componentMap[type];
|
||||
};
|
||||
const getKeyByValue = (obj: typeof typeCh, value: string): string | undefined => {
|
||||
return Object.entries(obj).find(([_, v]) => v === value)?.[0];
|
||||
};
|
||||
|
||||
const addConfig = () => {
|
||||
dialogTitle.value = '添加配置';
|
||||
newTab.value = { name: '', data: {}, type: '' };
|
||||
operateType.value = 'add';
|
||||
visibleBody.value = true;
|
||||
};
|
||||
|
||||
const editConfig = (item: any) => {
|
||||
dialogTitle.value = '修改配置';
|
||||
const type = getKeyByValue(typeCh, item.type);
|
||||
if (type) {
|
||||
newTab.value = { name: item.name, data: item, type: type };
|
||||
}
|
||||
operateType.value = 'edit';
|
||||
configIndex.value = networkConfig[newTab.value.type].findIndex((obj: any) => obj.name === item.name);
|
||||
visibleBody.value = true;
|
||||
};
|
||||
const delConfig = (item: any) => {
|
||||
const type = getKeyByValue(typeCh, item.type);
|
||||
if (type) {
|
||||
newTab.value = { name: item.name, data: item, type: type };
|
||||
}
|
||||
configIndex.value = configIndex.value = networkConfig[newTab.value.type].findIndex(
|
||||
(obj: any) => obj.name === item.name
|
||||
);
|
||||
operateType.value = 'delete';
|
||||
saveConfig();
|
||||
};
|
||||
|
||||
const selectType = (key: ComponentKey) => {
|
||||
cardConfig.value = WebConfg.value.get(key);
|
||||
};
|
||||
|
||||
const onloadDefault = (key: ComponentKey) => {
|
||||
console.log(key);
|
||||
newTab.value.data = structuredClone(mergeNetworkDefaultConfig[key]);
|
||||
};
|
||||
//检测重名
|
||||
const checkName = (name: string) => {
|
||||
const allConfigs = WebConfg.value.get('all')?.findIndex((obj: any) => obj.name === name);
|
||||
if (newTab.value.name === '' || newTab.value.type === '') {
|
||||
MessagePlugin.error('请填写完整信息');
|
||||
return false;
|
||||
} else if (allConfigs === -1 || newTab.value.data.name === name) {
|
||||
return true;
|
||||
} else {
|
||||
MessagePlugin.error('名称已存在');
|
||||
return false;
|
||||
}
|
||||
};
|
||||
//保存
|
||||
const saveConfig = async () => {
|
||||
if (operateType.value == 'add') {
|
||||
if (!checkName(newTab.value.name)) return;
|
||||
newTab.value.data.name = newTab.value.name;
|
||||
networkConfig[newTab.value.type].push(newTab.value.data);
|
||||
} else if (operateType.value == 'edit') {
|
||||
if (!checkName(newTab.value.name)) return;
|
||||
newTab.value.data.name = newTab.value.name;
|
||||
networkConfig[newTab.value.type][configIndex.value] = newTab.value.data;
|
||||
} else if (operateType.value == 'delete') {
|
||||
networkConfig[newTab.value.type].splice(configIndex.value, 1);
|
||||
}
|
||||
const userConfig = await getOB11Config();
|
||||
if (!userConfig) return;
|
||||
userConfig.network = networkConfig;
|
||||
const success = await setOB11Config(userConfig);
|
||||
if (success) {
|
||||
operateType.value = '';
|
||||
configIndex.value = 0;
|
||||
MessagePlugin.success('配置保存成功');
|
||||
await loadConfig();
|
||||
visibleBody.value = false;
|
||||
} else {
|
||||
MessagePlugin.error('配置保存失败');
|
||||
}
|
||||
};
|
||||
const getOB11Config = async (): Promise<OneBotConfig | undefined> => {
|
||||
const storedCredential = localStorage.getItem('auth');
|
||||
if (!storedCredential) {
|
||||
console.error('No stored credential found');
|
||||
return;
|
||||
}
|
||||
const loginManager = new QQLoginManager(storedCredential);
|
||||
return await loginManager.GetOB11Config();
|
||||
};
|
||||
|
||||
const setOB11Config = async (config: OneBotConfig): Promise<boolean> => {
|
||||
const storedCredential = localStorage.getItem('auth');
|
||||
if (!storedCredential) {
|
||||
console.error('No stored credential found');
|
||||
return false;
|
||||
}
|
||||
const loginManager = new QQLoginManager(storedCredential);
|
||||
return await loginManager.SetOB11Config(config);
|
||||
};
|
||||
|
||||
//获取卡片数据
|
||||
const getAllData = (data: NetworkConfig) => {
|
||||
cardConfig.value = [];
|
||||
WebConfg.value.set('all', []);
|
||||
for (const key in data) {
|
||||
const configs = data[key as keyof NetworkConfig];
|
||||
if (key in mergeNetworkDefaultConfig) {
|
||||
networkConfig[key] = [...configs];
|
||||
const newConfigsArray = configs.map((config: any) => ({
|
||||
...config,
|
||||
type: typeCh[key as ComponentKey],
|
||||
}));
|
||||
WebConfg.value.set(key, newConfigsArray);
|
||||
const allConfigs = WebConfg.value.get('all');
|
||||
if (allConfigs) {
|
||||
const newAllConfigs = [...allConfigs, ...newConfigsArray];
|
||||
WebConfg.value.set('all', newAllConfigs);
|
||||
}
|
||||
cardConfig.value = WebConfg.value.get('all');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const loadConfig = async () => {
|
||||
try {
|
||||
const userConfig = await getOB11Config();
|
||||
if (!userConfig) return;
|
||||
const mergedConfig = mergeOneBotConfigs(userConfig);
|
||||
getAllData(mergedConfig.network);
|
||||
} catch (error) {
|
||||
console.error('Error loading config:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const copyText = async (text: string) => {
|
||||
const input = document.createElement('input');
|
||||
input.value = text;
|
||||
document.body.appendChild(input);
|
||||
input.select();
|
||||
await navigator.clipboard.writeText(text);
|
||||
document.body.removeChild(input);
|
||||
MessagePlugin.success('复制成功');
|
||||
};
|
||||
|
||||
const handleResize = () => {
|
||||
// 得根据卡片宽度改,懒得改了;先不管了
|
||||
// if(window.innerWidth < 540) {
|
||||
// infoOneCol.value= true
|
||||
// } else {
|
||||
// infoOneCol.value= false
|
||||
// }
|
||||
tabsWidth.value = window.innerWidth - 41 - menuWidth.value;
|
||||
if (mediumScreen.matches) {
|
||||
cardWidth.value = (tabsWidth.value - 20) / 2;
|
||||
} else if (largeScreen.matches) {
|
||||
cardWidth.value = (tabsWidth.value - 40) / 3;
|
||||
} else {
|
||||
cardWidth.value = tabsWidth.value;
|
||||
}
|
||||
loadPage.value = true;
|
||||
setTimeout(() => {
|
||||
cardHeight.value = window.innerHeight - (headerBox.value?.offsetHeight ?? 0) - (setting.value?.offsetHeight ?? 0) - 21;
|
||||
}, 300);
|
||||
};
|
||||
emitter.on('sendWidth', (width) => {
|
||||
if (typeof width === 'number' && !isNaN(width)) {
|
||||
menuWidth.value = width;
|
||||
handleResize();
|
||||
}
|
||||
});
|
||||
onMounted(() => {
|
||||
loadConfig();
|
||||
const cachedWidth = localStorage.getItem('menuWidth');
|
||||
if (cachedWidth) {
|
||||
menuWidth.value = parseInt(cachedWidth);
|
||||
setTimeout(() => {
|
||||
handleResize();
|
||||
}, 300);
|
||||
}
|
||||
window.addEventListener('resize', handleResize);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.title {
|
||||
padding: 20px 20px 0 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.setting {
|
||||
margin: 0 20px;
|
||||
}
|
||||
|
||||
.setting-box {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 20px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.setting-card {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.setting-content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.card-address svg {
|
||||
fill: var(--td-brand-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.local-box {
|
||||
display: flex;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.local-icon{
|
||||
flex: 1;
|
||||
}
|
||||
.local {
|
||||
flex: 6;
|
||||
margin: 0 10px 0 10px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
|
||||
.copy-icon {
|
||||
flex: 1;
|
||||
cursor: pointer;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
|
||||
.token-view {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.token-view span {
|
||||
flex: 5;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.browse-icon{
|
||||
flex: 2;
|
||||
}
|
||||
:global(.t-dialog__ctx .t-dialog--defaul) {
|
||||
margin: 0 20px;
|
||||
}
|
||||
@media (max-width: 1024px) {
|
||||
.setting-box {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 786px) {
|
||||
.setting-box {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.card-box {
|
||||
margin: 10px 20px 0 20px;
|
||||
}
|
||||
|
||||
.card-none {
|
||||
line-height: 400px !important;
|
||||
}
|
||||
|
||||
|
||||
.dialog-body {
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
background: transparent;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.setting-card .t-card__title {
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
.setting-card .t-card__description {
|
||||
margin-bottom: 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.card-address .t-card__body {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.setting-base-info .t-descriptions__header {
|
||||
font-size: 15px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.setting-base-info .t-descriptions__label {
|
||||
padding: 0 var(--td-comp-paddingLR-l) !important;
|
||||
}
|
||||
|
||||
.setting-base-info tr>td:last-child {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.info-coll .t-collapse-panel__wrapper .t-collapse-panel__content {
|
||||
padding: var(--td-comp-paddingTB-m) var(--td-comp-paddingLR-l);
|
||||
}
|
||||
</style>
|
@@ -1,148 +0,0 @@
|
||||
<template>
|
||||
<div class="title">
|
||||
<t-divider content="其余配置" align="left" />
|
||||
</div>
|
||||
<t-card class="card">
|
||||
<div class="other-config-container">
|
||||
<div class="other-config">
|
||||
<t-form ref="form" :model="otherConfig" :label-align="labelAlign" label-width="auto" colon>
|
||||
<t-form-item label="音乐签名地址" name="musicSignUrl" class="form-item">
|
||||
<t-input v-model="otherConfig.musicSignUrl" />
|
||||
</t-form-item>
|
||||
<t-form-item label="启用本地文件到URL" name="enableLocalFile2Url" class="form-item">
|
||||
<t-switch v-model="otherConfig.enableLocalFile2Url" />
|
||||
</t-form-item>
|
||||
<t-form-item label="启用上报解析合并消息" name="parseMultMsg" class="form-item">
|
||||
<t-switch v-model="otherConfig.parseMultMsg" />
|
||||
</t-form-item>
|
||||
</t-form>
|
||||
<div class="button-container">
|
||||
<t-button @click="saveConfig">保存</t-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { MessagePlugin } from 'tdesign-vue-next';
|
||||
import { OneBotConfig } from '../../../src/onebot/config/config';
|
||||
import { QQLoginManager } from '@/backend/shell';
|
||||
|
||||
const otherConfig = ref<Partial<OneBotConfig>>({
|
||||
musicSignUrl: '',
|
||||
enableLocalFile2Url: false,
|
||||
parseMultMsg: true
|
||||
});
|
||||
|
||||
const labelAlign = ref<string>();
|
||||
const getOB11Config = async (): Promise<OneBotConfig | undefined> => {
|
||||
const storedCredential = localStorage.getItem('auth');
|
||||
if (!storedCredential) {
|
||||
console.error('No stored credential found');
|
||||
return;
|
||||
}
|
||||
const loginManager = new QQLoginManager(storedCredential);
|
||||
return await loginManager.GetOB11Config();
|
||||
};
|
||||
|
||||
const setOB11Config = async (config: OneBotConfig): Promise<boolean> => {
|
||||
const storedCredential = localStorage.getItem('auth');
|
||||
if (!storedCredential) {
|
||||
console.error('No stored credential found');
|
||||
return false;
|
||||
}
|
||||
const loginManager = new QQLoginManager(storedCredential);
|
||||
return await loginManager.SetOB11Config(config);
|
||||
};
|
||||
|
||||
const loadConfig = async () => {
|
||||
try {
|
||||
const userConfig = await getOB11Config();
|
||||
if (userConfig) {
|
||||
otherConfig.value.musicSignUrl = userConfig.musicSignUrl;
|
||||
otherConfig.value.enableLocalFile2Url = userConfig.enableLocalFile2Url;
|
||||
otherConfig.value.parseMultMsg = userConfig.parseMultMsg;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading config:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const saveConfig = async () => {
|
||||
try {
|
||||
const userConfig = await getOB11Config();
|
||||
if (userConfig) {
|
||||
userConfig.musicSignUrl = otherConfig.value.musicSignUrl || '';
|
||||
userConfig.enableLocalFile2Url = otherConfig.value.enableLocalFile2Url ?? false;
|
||||
userConfig.parseMultMsg = otherConfig.value.parseMultMsg ?? true;
|
||||
const success = await setOB11Config(userConfig);
|
||||
if (success) {
|
||||
MessagePlugin.success('配置保存成功');
|
||||
} else {
|
||||
MessagePlugin.error('配置保存失败');
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error saving config:', error);
|
||||
MessagePlugin.error('配置保存失败');
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
loadConfig();
|
||||
const mediaQuery = window.matchMedia('(max-width: 768px)');
|
||||
const handleMediaChange = (e: MediaQueryListEvent) => {
|
||||
if (e.matches) {
|
||||
labelAlign.value = 'top';
|
||||
} else {
|
||||
labelAlign.value = 'left';
|
||||
}
|
||||
};
|
||||
mediaQuery.addEventListener('change', handleMediaChange);
|
||||
const event = new Event('change');
|
||||
Object.defineProperty(event, 'matches', {
|
||||
value: mediaQuery.matches,
|
||||
writable: false,
|
||||
});
|
||||
mediaQuery.dispatchEvent(event);
|
||||
return () => {
|
||||
mediaQuery.removeEventListener('change', handleMediaChange);
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.title {
|
||||
padding: 20px 20px 0 20px;
|
||||
}
|
||||
.card {
|
||||
margin: 0 20px;
|
||||
padding-top: 20px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
.other-config-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.other-config {
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 20px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
@@ -1,49 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<t-form labelAlign="left">
|
||||
<t-form-item label="启用">
|
||||
<t-checkbox v-model="config.enable" />
|
||||
</t-form-item>
|
||||
<t-form-item label="URL">
|
||||
<t-input v-model="config.url" />
|
||||
</t-form-item>
|
||||
<t-form-item label="消息格式">
|
||||
<t-select v-model="config.messagePostFormat" :options="messageFormatOptions" />
|
||||
</t-form-item>
|
||||
<t-form-item label="报告自身消息">
|
||||
<t-checkbox v-model="config.reportSelfMessage" />
|
||||
</t-form-item>
|
||||
<t-form-item label="Token">
|
||||
<t-input v-model="config.token" />
|
||||
</t-form-item>
|
||||
<t-form-item label="调试模式">
|
||||
<t-checkbox v-model="config.debug" />
|
||||
</t-form-item>
|
||||
</t-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineProps, ref, watch } from 'vue';
|
||||
import { HttpClientConfig } from '../../../../src/onebot/config/config';
|
||||
|
||||
const props = defineProps<{
|
||||
config: HttpClientConfig;
|
||||
}>();
|
||||
|
||||
const messageFormatOptions = ref([
|
||||
{ label: 'Array', value: 'array' },
|
||||
{ label: 'String', value: 'string' },
|
||||
]);
|
||||
|
||||
watch(
|
||||
() => props.config.messagePostFormat,
|
||||
(newValue) => {
|
||||
if (newValue !== 'array' && newValue !== 'string') {
|
||||
props.config.messagePostFormat = 'array';
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@@ -1,55 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<t-form labelAlign="left">
|
||||
<t-form-item label="启用">
|
||||
<t-checkbox v-model="config.enable" />
|
||||
</t-form-item>
|
||||
<t-form-item label="端口">
|
||||
<t-input v-model.number="config.port" type="number" />
|
||||
</t-form-item>
|
||||
<t-form-item label="主机">
|
||||
<t-input v-model="config.host" type="text" />
|
||||
</t-form-item>
|
||||
<t-form-item label="启用 CORS">
|
||||
<t-checkbox v-model="config.enableCors" />
|
||||
</t-form-item>
|
||||
<t-form-item label="启用 WS">
|
||||
<t-checkbox v-model="config.enableWebsocket" />
|
||||
</t-form-item>
|
||||
<t-form-item label="消息格式">
|
||||
<t-select v-model="config.messagePostFormat" :options="messageFormatOptions" />
|
||||
</t-form-item>
|
||||
<t-form-item label="Token">
|
||||
<t-input v-model="config.token" type="text" />
|
||||
</t-form-item>
|
||||
<t-form-item label="调试模式">
|
||||
<t-checkbox v-model="config.debug" />
|
||||
</t-form-item>
|
||||
</t-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineProps, ref, watch } from 'vue';
|
||||
import { HttpServerConfig } from '../../../../src/onebot/config/config';
|
||||
|
||||
const props = defineProps<{
|
||||
config: HttpServerConfig;
|
||||
}>();
|
||||
|
||||
const messageFormatOptions = ref([
|
||||
{ label: 'Array', value: 'array' },
|
||||
{ label: 'String', value: 'string' },
|
||||
]);
|
||||
|
||||
watch(
|
||||
() => props.config.messagePostFormat,
|
||||
(newValue) => {
|
||||
if (newValue !== 'array' && newValue !== 'string') {
|
||||
props.config.messagePostFormat = 'array';
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@@ -1,52 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<t-form labelAlign="left">
|
||||
<t-form-item label="启用">
|
||||
<t-checkbox v-model="config.enable" />
|
||||
</t-form-item>
|
||||
<t-form-item label="URL">
|
||||
<t-input v-model="config.url" />
|
||||
</t-form-item>
|
||||
<t-form-item label="消息格式">
|
||||
<t-select v-model="config.messagePostFormat" :options="messageFormatOptions" />
|
||||
</t-form-item>
|
||||
<t-form-item label="报告自身消息">
|
||||
<t-checkbox v-model="config.reportSelfMessage" />
|
||||
</t-form-item>
|
||||
<t-form-item label="Token">
|
||||
<t-input v-model="config.token" />
|
||||
</t-form-item>
|
||||
<t-form-item label="调试模式">
|
||||
<t-checkbox v-model="config.debug" />
|
||||
</t-form-item>
|
||||
<t-form-item label="心跳间隔">
|
||||
<t-input v-model.number="config.heartInterval" type="number" />
|
||||
</t-form-item>
|
||||
</t-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineProps, ref, watch } from 'vue';
|
||||
import { WebsocketClientConfig } from '../../../../src/onebot/config/config';
|
||||
|
||||
const props = defineProps<{
|
||||
config: WebsocketClientConfig;
|
||||
}>();
|
||||
|
||||
const messageFormatOptions = ref([
|
||||
{ label: 'Array', value: 'array' },
|
||||
{ label: 'String', value: 'string' },
|
||||
]);
|
||||
|
||||
watch(
|
||||
() => props.config.messagePostFormat,
|
||||
(newValue) => {
|
||||
if (newValue !== 'array' && newValue !== 'string') {
|
||||
props.config.messagePostFormat = 'array';
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@@ -1,58 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<t-form labelAlign="left">
|
||||
<t-form-item label="启用">
|
||||
<t-checkbox v-model="config.enable" />
|
||||
</t-form-item>
|
||||
<t-form-item label="主机">
|
||||
<t-input v-model="config.host" />
|
||||
</t-form-item>
|
||||
<t-form-item label="端口">
|
||||
<t-input v-model.number="config.port" type="number" />
|
||||
</t-form-item>
|
||||
<t-form-item label="消息格式">
|
||||
<t-select v-model="config.messagePostFormat" :options="messageFormatOptions" />
|
||||
</t-form-item>
|
||||
<t-form-item label="上报自身消息">
|
||||
<t-checkbox v-model="config.reportSelfMessage" />
|
||||
</t-form-item>
|
||||
<t-form-item label="Token">
|
||||
<t-input v-model="config.token" />
|
||||
</t-form-item>
|
||||
<t-form-item label="强制推送事件">
|
||||
<t-checkbox v-model="config.enableForcePushEvent" />
|
||||
</t-form-item>
|
||||
<t-form-item label="调试模式">
|
||||
<t-checkbox v-model="config.debug" />
|
||||
</t-form-item>
|
||||
<t-form-item label="心跳间隔">
|
||||
<t-input v-model.number="config.heartInterval" type="number" />
|
||||
</t-form-item>
|
||||
</t-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineProps, ref, watch } from 'vue';
|
||||
import { WebsocketServerConfig } from '../../../../src/onebot/config/config';
|
||||
|
||||
const props = defineProps<{
|
||||
config: WebsocketServerConfig;
|
||||
}>();
|
||||
|
||||
const messageFormatOptions = ref([
|
||||
{ label: 'Array', value: 'array' },
|
||||
{ label: 'String', value: 'string' },
|
||||
]);
|
||||
|
||||
watch(
|
||||
() => props.config.messagePostFormat,
|
||||
(newValue) => {
|
||||
if (newValue !== 'array' && newValue !== 'string') {
|
||||
props.config.messagePostFormat = 'array';
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@@ -1,32 +0,0 @@
|
||||
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
|
||||
import Dashboard from '../components/Dashboard.vue';
|
||||
import BasicInfo from '../pages/BasicInfo.vue';
|
||||
import AboutUs from '../pages/AboutUs.vue';
|
||||
import LogView from '../pages/Log.vue';
|
||||
import NetWork from '../pages/NetWork.vue';
|
||||
import QQLogin from '../components/QQLogin.vue';
|
||||
import WebUiLogin from '../components/WebUiLogin.vue';
|
||||
import OtherConfig from '../pages/OtherConfig.vue';
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{ path: '/', redirect: '/webui' },
|
||||
{ path: '/webui', component: WebUiLogin, name: 'WebUiLogin' },
|
||||
{ path: '/qqlogin', component: QQLogin, name: 'QQLogin' },
|
||||
{
|
||||
path: '/dashboard',
|
||||
component: Dashboard,
|
||||
children: [
|
||||
{ path: '', redirect: 'basic-info' },
|
||||
{ path: 'basic-info', component: BasicInfo, name: 'BasicInfo' },
|
||||
{ path: 'network-config', component: NetWork, name: 'NetWork' },
|
||||
{ path: 'log-view', component: LogView, name: 'LogView' },
|
||||
{ path: 'other-config', component: OtherConfig, name: 'OtherConfig' },
|
||||
{ path: 'about-us', component: AboutUs, name: 'AboutUs' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes,
|
||||
});
|
@@ -1,3 +0,0 @@
|
||||
import mitt from 'mitt';
|
||||
const emitter = mitt();
|
||||
export default emitter;
|
1
napcat.webui/src/vite-env.d.ts
vendored
@@ -1 +0,0 @@
|
||||
/// <reference types="vite/client" />
|
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "vue",
|
||||
"lib": [
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"baseUrl": ".",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
},
|
||||
"resolveJsonModule": true,
|
||||
"types": [
|
||||
"vite/client"
|
||||
],
|
||||
"strict": true,
|
||||
"strictNullChecks": true,
|
||||
"noUnusedLocals": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"isolatedModules": true,
|
||||
"experimentalDecorators": true,
|
||||
"useDefineForClassFields": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules"],
|
||||
"references": [{"path": "./tsconfig.node.json"}]
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strictNullChecks": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
@@ -1,41 +0,0 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import legacy from '@vitejs/plugin-legacy';
|
||||
import path from 'path';
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
legacy({
|
||||
targets: ['defaults', 'not IE 11'],
|
||||
modernPolyfills: ['web.structured-clone'],
|
||||
}),
|
||||
],
|
||||
base: './',
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, 'src'),
|
||||
},
|
||||
},
|
||||
server: {
|
||||
proxy: {
|
||||
'/api': 'http://localhost:6099',
|
||||
},
|
||||
},
|
||||
build: {
|
||||
chunkSizeWarningLimit: 4000,
|
||||
rollupOptions: {
|
||||
output: {
|
||||
chunkFileNames: 'static/js/[name]-[hash].js',
|
||||
entryFileNames: 'static/js/[name]-[hash].js',
|
||||
assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
|
||||
manualChunks(id: string) {
|
||||
if (id.includes('node_modules')) {
|
||||
return id.toString().split('node_modules/')[1].split('/')[0].toString();
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
78
package.json
@@ -2,59 +2,69 @@
|
||||
"name": "napcat",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "4.2.0",
|
||||
"version": "1.8.4",
|
||||
"scripts": {
|
||||
"build:framework": "npm run build:webui && vite build --mode framework || exit 1",
|
||||
"build:shell": "npm run build:webui && vite build --mode shell || exit 1",
|
||||
"build:webui": "cd napcat.webui && vite build",
|
||||
"dev:framework": "vite build --mode framework",
|
||||
"dev:shell": "vite build --mode shell",
|
||||
"dev:webui": "cd napcat.webui && npm run webui:dev",
|
||||
"lint": "eslint --fix src/**/*.{js,ts,vue}",
|
||||
"watch:dev": "vite --mode development",
|
||||
"watch:prod": "vite --mode production",
|
||||
"build:dev": "vite build --mode development",
|
||||
"build:prod": "vite build --mode production",
|
||||
"build": "npm run build:dev",
|
||||
"build:core": "cd ./src/core && npm run build && cd ../.. && node ./script/copy-core.cjs",
|
||||
"build:webui": "cd ./src/webui && vite build",
|
||||
"watch": "npm run watch:dev",
|
||||
"debug-win": "powershell dist/napcat.ps1",
|
||||
"lint": "eslint --fix src/**/*.{js,ts}",
|
||||
"release": "npm run build:prod",
|
||||
"depend": "cd dist && npm install --omit=dev"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.7",
|
||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||
"@babel/plugin-proposal-decorators": "^7.24.7",
|
||||
"@babel/preset-typescript": "^7.24.7",
|
||||
"@eslint/compat": "^1.2.2",
|
||||
"@eslint/eslintrc": "^3.1.0",
|
||||
"@eslint/js": "^9.14.0",
|
||||
"@log4js-node/log4js-api": "^1.0.2",
|
||||
"@napneko/nap-proto-core": "^0.0.4",
|
||||
"@protobuf-ts/plugin": "^2.9.4",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@rollup/plugin-typescript": "^11.1.6",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/figlet": "^1.5.8",
|
||||
"@types/fluent-ffmpeg": "^2.1.24",
|
||||
"@types/node": "^22.0.1",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/node": "^22.0.0",
|
||||
"@types/qrcode-terminal": "^0.12.2",
|
||||
"@types/ws": "^8.5.12",
|
||||
"@typescript-eslint/eslint-plugin": "^8.3.0",
|
||||
"@typescript-eslint/parser": "^8.3.0",
|
||||
"ajv": "^8.13.0",
|
||||
"async-mutex": "^0.5.0",
|
||||
"commander": "^12.1.0",
|
||||
"cors": "^2.8.5",
|
||||
"eslint": "^9.14.0",
|
||||
"@types/ws": "^8.5.10",
|
||||
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
||||
"@typescript-eslint/parser": "^7.4.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-import-resolver-typescript": "^3.6.1",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"fast-xml-parser": "^4.3.6",
|
||||
"file-type": "^19.0.0",
|
||||
"globals": "^15.12.0",
|
||||
"image-size": "^1.1.1",
|
||||
"json-schema-to-ts": "^3.1.1",
|
||||
"i": "^0.3.7",
|
||||
"javascript-obfuscator": "^4.1.0",
|
||||
"rollup": "^4.13.2",
|
||||
"rollup-plugin-dts": "^6.1.0",
|
||||
"rollup-plugin-obfuscator": "^1.1.0",
|
||||
"typescript": "^5.3.3",
|
||||
"typescript-eslint": "^8.13.0",
|
||||
"vite": "^6.0.1",
|
||||
"vite": "^5.2.6",
|
||||
"vite-plugin-babel": "^1.2.0",
|
||||
"vite-plugin-cp": "^4.0.8",
|
||||
"vite-tsconfig-paths": "^5.1.0",
|
||||
"winston": "^3.17.0"
|
||||
"vite-plugin-dts": "^3.8.2",
|
||||
"vite-tsconfig-paths": "^4.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "^5.0.0",
|
||||
"ajv": "^8.13.0",
|
||||
"chalk": "^5.3.0",
|
||||
"commander": "^12.0.0",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^5.0.0-beta.2",
|
||||
"fast-xml-parser": "^4.3.6",
|
||||
"file-type": "^19.0.0",
|
||||
"fluent-ffmpeg": "^2.1.2",
|
||||
"piscina": "^4.7.0",
|
||||
"image-size": "^1.1.1",
|
||||
"json-schema-to-ts": "^3.1.0",
|
||||
"log4js": "^6.9.1",
|
||||
"qrcode-terminal": "^0.12.0",
|
||||
"silk-wasm": "^3.6.1",
|
||||
"ws": "^8.18.0"
|
||||
"ws": "^8.16.0"
|
||||
}
|
||||
}
|
||||
|