📝 新增全球统计

This commit is contained in:
远野千束 2024-08-05 06:00:07 +08:00
parent d63ba4943a
commit 16930e96aa
13 changed files with 1412 additions and 10 deletions

View File

@ -1,12 +1,23 @@
import {defineClientConfig} from "vuepress/client";
import { defineEChartsConfig } from "vuepress-plugin-md-enhance/client";
import resourceStoreComp from "./components/ResStore.vue";
import pluginStoreComp from "./components/PluginStore.vue";
import dashComp from "./components/Dash.vue";
import homeComp from "./components/Home.vue";
import geoComp from "./components/Geo.vue";
// import ElementPlus from 'element-plus';
import ElementPlus from 'element-plus';
defineEChartsConfig({
options: {
// 全局 ECharts 配置
},
setup: async () => {
// ECharts 设置
// 例如: await import("echarts-wordcloud")
},
});
export default defineClientConfig({
@ -15,6 +26,7 @@ export default defineClientConfig({
app.component("dashComp", dashComp);
app.component("resourceStoreComp", resourceStoreComp);
app.component("pluginStoreComp", pluginStoreComp);
app.use(ElementPlus);
app.component("geoComp", geoComp);
// app.use(ElementPlus);
},
});

View File

@ -0,0 +1,20 @@
<script setup>
</script>
<template>
<div>
<div style="text-align: center">
<h2>地理分布</h2>
<p>数据来源于Liteyuki API</p>
</div>
<div id="main-chart" style="width: 100%; height: 600px;"></div>
</div>
</template>
<style scoped>
#main-chart {
width: 100px;
height: 600px;
}
</style>

View File

@ -0,0 +1,93 @@
echart = require('echarts');
let chart = echarts.init(document.getElementById('main-chart'));
const color = ['#9ae5fc', '#dcbf71']; // 自定义图中要用到的颜色
console.log("加载图标");
// 在地图加载完成后设置所有地区不可选
function setAllRegionsUnselectable(geoModel) {
const regions = geoModel.get('regions');
// 遍历所有地区并设置selected为false
for (let i = 0; i < regions.length; i++) {
const region = regions[i];
region.selected = false;
}
// 更新模型以反映更改
geoModel.set('regions', regions);
// 更新图表以显示更改
chart.setOption({
geo: {
regions: regions
}
});
}
// 获取数据并初始化图表
fetch('https://api.liteyuki.icu/distribution')
.then(response => response.json())
.then(data => {
// 构造 ECharts 需要的数据格式
const locations = data.locations;
const seriesData = locations.map(location => ({
value: [location[1], location[0]] // 直接使用经纬度数组
}));
console.log(seriesData);
// 初始化图表选项
chart.setOption({
backgroundColor: '#454545',
title: {
text: 'LiteyukiBot分布demo',
subtext: 'LiteyukiBot分布',
textStyle: {
color: '#fff',
fontSize: 20
},
top: '10px',
left: '10px'
},
geo: {
map: 'world',
roam: false,
itemStyle: {
normal: {
areaColor: '#000',
borderType: null, // 设置边界线类型为无
borderColor: '#000', // 设置边界线颜色
},
emphasis: {
areaColor: '#000',
borderType: null, // 设置边界线类型为无
borderColor: '#000', // 设置边界线颜色
}
},
regions: [] // 先保留为空
},
series: [{
// 散点效果
type: 'scatter',
coordinateSystem: 'geo', // 表示使用的坐标系为地理坐标系
symbolSize: 5, // 设置散点的大小为20
itemStyle: {
color: '#ffeb3b', // 黄色
},
data: seriesData
}],
textStyle: {
fontSize: 1
}
});
// 在地图加载完成后设置所有地区不可选
chart.on('ready', function () {
const geoModel = chart.getModel().componentModels.geo[0];
setAllRegionsUnselectable(geoModel);
});
// 自适应窗口大小变化
window.addEventListener("resize", function () {
chart.resize();
});
})
.catch(error => console.error('Error fetching data:', error));

File diff suppressed because one or more lines are too long

View File

@ -20,6 +20,11 @@ export default sidebar({
icon: "store",
prefix: "store/",
children: "structure",
},{
text: "其他",
icon: "question-circle",
prefix: "other/",
children: "structure",
}
],
});

View File

@ -62,6 +62,7 @@ export default hopeTheme({
// 此处开启了很多功能用于演示,你应仅保留用到的功能。
mdEnhance: {
echarts: true,
alert: true,
align: true,
attrs: true,

View File

@ -72,7 +72,7 @@ highlights:
bgImageDark: https://theme-hope-assets.vuejs.press/bg/3-dark.svg
highlights:
- title: 安装 Git 及 Python3.10+
- title: 使用 <code>git clone https://github.com/snowykami/LiteyukiBot --depth=1</code> 以克隆项目至本地。
- title: 使用 <code>git clone https://github.com/LiteyukiStudio/LiteyukiBot --depth=1</code> 以克隆项目至本地。
details: 如果无法连接到GitHub可以使用 <code>git clone https://gitee.com/snowykami/LiteyukiBot --depth=1</code>
- title: 使用 <code>cd LiteyukiBot</code> 切换到项目目录。
- title: 使用 <code>pip install -r requirements.txt</code> 安装项目依赖。

View File

@ -30,7 +30,7 @@ python main.py
### **使用Docker构建镜像部署**
1. 安装 [`Docker`](https://docs.docker.com/get-docker/)
2. 克隆项目 `git clone https://github.com/snowykami/LiteyukiBot`
2. 克隆项目 `git clone https://github.com/LiteyukiStudio/LiteyukiBot`
3. 进入轻雪目录 `cd LiteyukiBot`
4. 构建镜像 `docker build -t liteyukibot .`
5. 启动容器 `docker run -p 20216:20216 -v $(pwd):/liteyukibot -v $(pwd)/.cache:/root/.cache liteyukibot`

8
docs/other/README.md Normal file
View File

@ -0,0 +1,8 @@
---
title: 其他
index: false
icon: question-circle
category: 其他
---
<Catalog />

55
docs/other/geo.md Normal file
View File

@ -0,0 +1,55 @@
---
title: 地理分布
icon: globe
order: 1
category: 其他
---
:::echarts Liteyuki Dist
```js
const option = {
backgroundColor: '#454545',
title: {
text: 'LiteyukiBot分布demo',
subtext: 'LiteyukiBot分布',
textStyle: {
color: '#fff',
fontSize: 20
},
top: '10px',
left: '10px'
},
geo: {
map: 'world',
roam: false,
itemStyle: {
normal: {
areaColor: '#000',
borderType: null, // 设置边界线类型为无
borderColor: '#000', // 设置边界线颜色
},
emphasis: {
areaColor: '#000',
borderType: null, // 设置边界线类型为无
borderColor: '#000', // 设置边界线颜色
}
},
regions: [] // 先保留为空
},
series: [{
// 散点效果
type: 'scatter',
coordinateSystem: 'geo', // 表示使用的坐标系为地理坐标系
symbolSize: 5, // 设置散点的大小为20
itemStyle: {
color: '#ffeb3b', // 黄色
},
}],
textStyle: {
fontSize: 1
}
};
```

View File

@ -20,8 +20,10 @@
},
"dependencies": {
"clipboard": "^2.0.11",
"echarts": "^5.5.1",
"element-plus": "^2.7.0",
"element-ui": "^2.15.14",
"vue-echarts": "7.0.0-beta.0",
"vue-router": "^4.4.0"
}
}

View File

@ -8,12 +8,18 @@ dependencies:
clipboard:
specifier: ^2.0.11
version: 2.0.11
echarts:
specifier: ^5.5.1
version: 5.5.1
element-plus:
specifier: ^2.7.0
version: 2.7.0(vue@3.4.21)
element-ui:
specifier: ^2.15.14
version: 2.15.14(vue@3.4.21)
vue-echarts:
specifier: 7.0.0-beta.0
version: 7.0.0-beta.0(echarts@5.5.1)(vue@3.4.21)
vue-router:
specifier: ^4.4.0
version: 4.4.0(vue@3.4.21)
@ -36,7 +42,7 @@ devDependencies:
version: 2.0.0-rc.34(vuepress@2.0.0-rc.9)
vuepress-theme-hope:
specifier: 2.0.0-rc.32
version: 2.0.0-rc.32(@vuepress/plugin-search@2.0.0-rc.24)(markdown-it@14.1.0)(vuepress-plugin-search-pro@2.0.0-rc.34)(vuepress@2.0.0-rc.9)
version: 2.0.0-rc.32(@vuepress/plugin-search@2.0.0-rc.24)(echarts@5.5.1)(markdown-it@14.1.0)(vuepress-plugin-search-pro@2.0.0-rc.34)(vuepress@2.0.0-rc.9)
packages:
@ -719,6 +725,7 @@ packages:
resolution: {integrity: sha512-bur4JOxvYxfrAmocRJIW0SADs3QdEYK6TQ7dTNz6Z4/lySeu3Z1H/+tl0a4qDYv0bCdBpUYM0sYa/X+9ZqgfSQ==}
cpu: [arm64]
os: [linux]
libc: [glibc]
requiresBuild: true
dev: true
optional: true
@ -727,6 +734,7 @@ packages:
resolution: {integrity: sha512-ssp77SjcDIUSoUyj7DU7/5iwM4ZEluY+N8umtCT9nBRs3u045t0KkW02LTyHouHDomnMXaXSZcCSr2bdMK63kA==}
cpu: [arm64]
os: [linux]
libc: [musl]
requiresBuild: true
dev: true
optional: true
@ -735,6 +743,7 @@ packages:
resolution: {integrity: sha512-Jv1DkIvwEPAb+v25/Unrnnq9BO3F5cbFPT821n3S5litkz+O5NuXuNhqtPx5KtcwOTtaqkTsO+IVzJOsxd11aQ==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
requiresBuild: true
dev: true
optional: true
@ -743,6 +752,7 @@ packages:
resolution: {integrity: sha512-U564BrhEfaNChdATQaEODtquCC7Ez+8Hxz1h5MAdMYj0AqD0GA9rHCpElajb/sQcaFL6NXmHc5O+7FXpWMa73Q==}
cpu: [s390x]
os: [linux]
libc: [glibc]
requiresBuild: true
dev: true
optional: true
@ -751,6 +761,7 @@ packages:
resolution: {integrity: sha512-zGRDulLTeDemR8DFYyFIQ8kMP02xpUsX4IBikc7lwL9PrwR3gWmX2NopqiGlI2ZVWMl15qZeUjumTwpv18N7sQ==}
cpu: [x64]
os: [linux]
libc: [glibc]
requiresBuild: true
dev: true
optional: true
@ -759,6 +770,7 @@ packages:
resolution: {integrity: sha512-VTk/MveyPdMFkYJJPCkYBw07KcTkGU2hLEyqYMsU4NjiOfzoaDTW9PWGRsNwiOA3qI0k/JQPjkl/4FCK1smskQ==}
cpu: [x64]
os: [linux]
libc: [musl]
requiresBuild: true
dev: true
optional: true
@ -1721,6 +1733,12 @@ packages:
domhandler: 5.0.3
dev: true
/echarts@5.5.1:
resolution: {integrity: sha512-Fce8upazaAXUVUVsjgV6mBnGuqgO+JNDlcgF79Dksy4+wgGpQB2lmYoO4TSweFg/mZITdpGHomw/cNBJZj1icA==}
dependencies:
tslib: 2.3.0
zrender: 5.6.0
/electron-to-chromium@1.4.719:
resolution: {integrity: sha512-FbWy2Q2YgdFzkFUW/W5jBjE9dj+804+98E4Pup78JBPnbdb3pv6IneY2JCPKdeKLh3AOKHQeYf+KwLr7mxGh6Q==}
dev: true
@ -2658,6 +2676,9 @@ packages:
is-number: 7.0.0
dev: true
/tslib@2.3.0:
resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==}
/uc.micro@2.1.0:
resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
dev: true
@ -2727,6 +2748,21 @@ packages:
fsevents: 2.3.3
dev: true
/vue-demi@0.13.11(vue@3.4.21):
resolution: {integrity: sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
peerDependencies:
'@vue/composition-api': ^1.0.0-rc.1
vue: ^3.0.0-0 || ^2.6.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
dependencies:
vue: 3.4.21
dev: false
/vue-demi@0.14.7(vue@3.4.21):
resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
engines: {node: '>=12'}
@ -2741,6 +2777,23 @@ packages:
dependencies:
vue: 3.4.21
/vue-echarts@7.0.0-beta.0(echarts@5.5.1)(vue@3.4.21):
resolution: {integrity: sha512-DKmPak9+Al/GlIexC5OvvWIDyO39q/AmZm2aqF7+n2fTDyUq7l/dkdmg/9hBeLafZlU6Yf5J7io/BnDzzRK1+g==}
peerDependencies:
'@vue/runtime-core': ^3.0.0
echarts: ^5.5.1
vue: ^2.7.0 || ^3.1.1
peerDependenciesMeta:
'@vue/runtime-core':
optional: true
dependencies:
echarts: 5.5.1
vue: 3.4.21
vue-demi: 0.13.11(vue@3.4.21)
transitivePeerDependencies:
- '@vue/composition-api'
dev: false
/vue-router@4.4.0(vue@3.4.21):
resolution: {integrity: sha512-HB+t2p611aIZraV2aPSRNXf0Z/oLZFrlygJm+sZbdJaW6lcFqEDQwnzUBXn+DApw+/QzDU/I9TeWx9izEjTmsA==}
peerDependencies:
@ -2806,7 +2859,7 @@ packages:
- typescript
dev: true
/vuepress-plugin-md-enhance@2.0.0-rc.32(markdown-it@14.1.0)(vuepress@2.0.0-rc.9):
/vuepress-plugin-md-enhance@2.0.0-rc.32(echarts@5.5.1)(markdown-it@14.1.0)(vuepress@2.0.0-rc.9):
resolution: {integrity: sha512-zZK8aEfbq26J5w8o9xGWXCHHrL3PYk25tloTPcx96nZWYPeD+5fMFAtVpHte0rXBWUf0MBtDQxddSeATteBE7Q==}
engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'}
peerDependencies:
@ -2883,6 +2936,7 @@ packages:
'@vuepress/helper': 2.0.0-rc.21(vuepress@2.0.0-rc.9)
'@vueuse/core': 10.9.0(vue@3.4.21)
balloon-css: 1.2.0
echarts: 5.5.1
js-yaml: 4.1.0
vue: 3.4.21
vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.21)
@ -3000,7 +3054,7 @@ packages:
- typescript
dev: true
/vuepress-theme-hope@2.0.0-rc.32(@vuepress/plugin-search@2.0.0-rc.24)(markdown-it@14.1.0)(vuepress-plugin-search-pro@2.0.0-rc.34)(vuepress@2.0.0-rc.9):
/vuepress-theme-hope@2.0.0-rc.32(@vuepress/plugin-search@2.0.0-rc.24)(echarts@5.5.1)(markdown-it@14.1.0)(vuepress-plugin-search-pro@2.0.0-rc.34)(vuepress@2.0.0-rc.9):
resolution: {integrity: sha512-5S5qg5xa0TErqVjpubhBN5oy0QmROd+ja5EQKfORUCKdXKQvx0soojQZnCPkXsUEXonwiZ12oCLN2+UGO03eng==}
engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'}
peerDependencies:
@ -3060,7 +3114,7 @@ packages:
vue: 3.4.21
vuepress: 2.0.0-rc.9(@vuepress/bundler-vite@2.0.0-rc.9)(vue@3.4.21)
vuepress-plugin-components: 2.0.0-rc.32(vuepress@2.0.0-rc.9)
vuepress-plugin-md-enhance: 2.0.0-rc.32(markdown-it@14.1.0)(vuepress@2.0.0-rc.9)
vuepress-plugin-md-enhance: 2.0.0-rc.32(echarts@5.5.1)(markdown-it@14.1.0)(vuepress@2.0.0-rc.9)
vuepress-plugin-sass-palette: 2.0.0-rc.32(vuepress@2.0.0-rc.9)
vuepress-plugin-search-pro: 2.0.0-rc.34(vuepress@2.0.0-rc.9)
vuepress-shared: 2.0.0-rc.32(vuepress@2.0.0-rc.9)
@ -3179,3 +3233,8 @@ packages:
y18n: 4.0.3
yargs-parser: 18.1.3
dev: true
/zrender@5.6.0:
resolution: {integrity: sha512-uzgraf4njmmHAbEUxMJ8Oxg+P3fT04O+9p7gY+wJRVxo8Ge+KmYv0WJev945EH4wFuc4OY2NLXz46FZrWS9xJg==}
dependencies:
tslib: 2.3.0

View File

@ -32,6 +32,30 @@ class Database:
self.cursor = self.conn.cursor()
self._on_save_callbacks = []
self._is_locked = False
def lock(self):
self.cursor.execute("BEGIN TRANSACTION")
self._is_locked = True
def lock_query(self, query: str, *args):
"""锁定查询"""
self.cursor.execute(query, args).fetchall()
def lock_model(self, model: LiteModel) -> LiteModel | Any | None:
"""锁定行
Args:
model: 数据模型实例
Returns:
"""
pass
def unlock(self):
self.cursor.execute("COMMIT")
self._is_locked = False
def where_one(self, model: LiteModel, condition: str = "", *args: Any, default: Any = None) -> LiteModel | Any | None:
"""查询第一个
@ -129,7 +153,11 @@ class Database:
fields = ', '.join([f'"{field}"' for field in fields])
placeholders = ', '.join('?' for _ in values)
self.cursor.execute(f"INSERT OR REPLACE INTO {table_name}({fields}) VALUES ({placeholders})", tuple(values))
self.conn.commit()
# self.conn.commit()
if self._is_locked:
pass
else:
self.conn.commit()
foreign_id = self.cursor.execute("SELECT last_insert_rowid()").fetchone()[0]
return f"{self.FOREIGN_KEY_PREFIX}{foreign_id}@{table_name}" # -> FOREIGN_KEY_123456@{table_name} id@{table_name}
else:
@ -214,7 +242,10 @@ class Database:
if not condition and not allow_empty:
raise ValueError("删除操作必须提供条件")
self.cursor.execute(f"DELETE FROM {table_name} WHERE {condition}", args)
self.conn.commit()
if self._is_locked:
pass
else:
self.conn.commit()
def auto_migrate(self, *args: LiteModel):