mirror of
https://github.com/hi2shark/nazhua.git
synced 2026-01-19 10:40:43 +08:00
Compare commits
No commits in common. "86b45b5f2a1827ee74e7985bf3f8deaf8af72866" and "718b0138b0bf5b05e2edd735a3ca03f911dbda64" have entirely different histories.
86b45b5f2a
...
718b0138b0
@ -66,7 +66,6 @@ module.exports = {
|
|||||||
'no-param-reassign': 'off',
|
'no-param-reassign': 'off',
|
||||||
'no-underscore-dangle': 'off',
|
'no-underscore-dangle': 'off',
|
||||||
'no-unsafe-optional-chaining': 'off',
|
'no-unsafe-optional-chaining': 'off',
|
||||||
'max-classes-per-file': 'off',
|
|
||||||
'max-len': ['warn', 120],
|
'max-len': ['warn', 120],
|
||||||
'vue/max-len': ['warn', 120],
|
'vue/max-len': ['warn', 120],
|
||||||
'object-property-newline': ['error', {
|
'object-property-newline': ['error', {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "nazhua",
|
"name": "nazhua",
|
||||||
"version": "0.5.1",
|
"version": "0.4.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@ -5,15 +5,12 @@ window.$$nazhuaConfig = {
|
|||||||
// buyBtnText: '购买', // 购买按钮文案
|
// buyBtnText: '购买', // 购买按钮文案
|
||||||
// customBackgroundImage: '', // 自定义的背景图片地址
|
// customBackgroundImage: '', // 自定义的背景图片地址
|
||||||
// lightBackground: true, // 启用了浅色系背景图,会强制关闭点点背景
|
// lightBackground: true, // 启用了浅色系背景图,会强制关闭点点背景
|
||||||
// showFireworks: true, // 是否显示烟花,建议开启浅色系背景
|
|
||||||
// showLantern: true, // 是否显示灯笼
|
|
||||||
// listServerItemTypeToggle: true, // 服务器列表项类型切换
|
|
||||||
// listServerItemType: 'row', // 服务器列表项类型 card/row row列表模式移动端自动切换至card
|
// listServerItemType: 'row', // 服务器列表项类型 card/row row列表模式移动端自动切换至card
|
||||||
// listServerStatusType: 'progress', // 服务器状态类型--列表
|
// listServerStatusType: 'progress', // 服务器状态类型--列表
|
||||||
// listServerRealTimeShowLoad: true, // 列表显示服务器实时负载
|
// listServerRealTimeShowLoad: false, // 列表显示服务器实时负载
|
||||||
// detailServerStatusType: 'progress', // 服务器状态类型--详情页
|
// detailServerStatusType: 'progress', // 服务器状态类型--详情页
|
||||||
// serverStatusLinear: true, // 服务器状态渐变线性显示
|
// serverStatusLinear: true, // 服务器状态渐变线性显示
|
||||||
// disableSarasaTermSC: true, // 禁用Sarasa Term SC字体
|
// disableSarasaTermSC: false, // 禁用Sarasa Term SC字体
|
||||||
// hideWorldMap: false, // 隐藏地图
|
// hideWorldMap: false, // 隐藏地图
|
||||||
// hideHomeWorldMap: false, // 隐藏首页地图
|
// hideHomeWorldMap: false, // 隐藏首页地图
|
||||||
// hideDetailWorldMap: false, // 隐藏详情地图
|
// hideDetailWorldMap: false, // 隐藏详情地图
|
||||||
|
|||||||
@ -71,17 +71,12 @@ Nazhua对这个支持大概在90%左右,参与数据处理了的字段如下
|
|||||||
"bandwidth": "30Mbps",
|
"bandwidth": "30Mbps",
|
||||||
"trafficVol": "1TB/月",
|
"trafficVol": "1TB/月",
|
||||||
"trafficType": "1",
|
"trafficType": "1",
|
||||||
"IPv4": "1",
|
|
||||||
"IPv6": "1",
|
|
||||||
"networkRoute": "CN2,GIA",
|
"networkRoute": "CN2,GIA",
|
||||||
"extra": "传家宝,AS9929"
|
"extra": "传家宝,AS9929"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
~~其中IPv4、IPv6暂未参与到处理中,后续可能会支持。~~
|
其中IPv4、IPv6暂未参与到处理中,后续可能会支持。
|
||||||
- 都有显示标签:双栈IP;
|
|
||||||
- 单IPv4显示标签:仅IPv4;
|
|
||||||
- 单IPv6显示标签:仅IPv6;
|
|
||||||
|
|
||||||
## 数据来源
|
## 数据来源
|
||||||
1-0. 公开的全量配置,其中包括“公开备注”(PublicNote),来自探针主页上暴露的服务器节点列表配置信息。此处是根据正则匹配的方式,获取到的节点列表。在主题项目中,默认将访问`/nezha/`的指向此处。
|
1-0. 公开的全量配置,其中包括“公开备注”(PublicNote),来自探针主页上暴露的服务器节点列表配置信息。此处是根据正则匹配的方式,获取到的节点列表。在主题项目中,默认将访问`/nezha/`的指向此处。
|
||||||
|
|||||||
@ -1,158 +0,0 @@
|
|||||||
<template>
|
|
||||||
<canvas
|
|
||||||
ref="canvas"
|
|
||||||
class="fireworks-canvas"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import {
|
|
||||||
ref,
|
|
||||||
onMounted,
|
|
||||||
onUnmounted,
|
|
||||||
} from 'vue';
|
|
||||||
|
|
||||||
const canvas = ref(null);
|
|
||||||
let ctx = null;
|
|
||||||
let particles = [];
|
|
||||||
let rockets = [];
|
|
||||||
let animationFrameId = null;
|
|
||||||
|
|
||||||
class Particle {
|
|
||||||
constructor(x, y, color) {
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.color = color;
|
|
||||||
this.velocity = {
|
|
||||||
x: (Math.random() - 0.5) * 8,
|
|
||||||
y: (Math.random() - 0.5) * 12 - 8,
|
|
||||||
};
|
|
||||||
this.alpha = 1;
|
|
||||||
this.decay = 0.02;
|
|
||||||
}
|
|
||||||
|
|
||||||
draw() {
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.arc(this.x, this.y, 2, 0, Math.PI * 2);
|
|
||||||
ctx.fillStyle = `rgba(${this.color}, ${this.alpha})`;
|
|
||||||
ctx.fill();
|
|
||||||
}
|
|
||||||
|
|
||||||
update() {
|
|
||||||
this.velocity.y += 0.1;
|
|
||||||
this.x += this.velocity.x;
|
|
||||||
this.y += this.velocity.y;
|
|
||||||
this.alpha -= this.decay;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createFirework(x, y) {
|
|
||||||
const colors = [
|
|
||||||
'255, 0, 0',
|
|
||||||
'0, 255, 0',
|
|
||||||
'0, 0, 255',
|
|
||||||
'255, 255, 0',
|
|
||||||
'255, 0, 255',
|
|
||||||
'0, 255, 255',
|
|
||||||
];
|
|
||||||
const color = colors[Math.floor(Math.random() * colors.length)];
|
|
||||||
for (let i = 0; i < 80; i += 1) {
|
|
||||||
particles.push(new Particle(x, y, color));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Rocket {
|
|
||||||
constructor() {
|
|
||||||
this.x = Math.random() * canvas.value.width;
|
|
||||||
this.y = canvas.value.height;
|
|
||||||
this.targetY = canvas.value.height * 0.5;
|
|
||||||
this.speed = 15;
|
|
||||||
this.trail = [];
|
|
||||||
this.maxTrailLength = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
draw() {
|
|
||||||
// 绘制火箭尾迹
|
|
||||||
ctx.beginPath();
|
|
||||||
this.trail.forEach((pos, index) => {
|
|
||||||
ctx.fillStyle = `rgba(255, 200, 0, ${index / this.trail.length})`;
|
|
||||||
ctx.fillRect(pos.x, pos.y, 2, 2);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 绘制火箭本体
|
|
||||||
ctx.fillStyle = 'rgba(255, 220, 0, 1)';
|
|
||||||
ctx.fillRect(this.x, this.y, 3, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
update() {
|
|
||||||
this.trail.push({
|
|
||||||
x: this.x,
|
|
||||||
y: this.y,
|
|
||||||
});
|
|
||||||
if (this.trail.length > this.maxTrailLength) {
|
|
||||||
this.trail.shift();
|
|
||||||
}
|
|
||||||
this.y -= this.speed;
|
|
||||||
if (this.y <= this.targetY) {
|
|
||||||
createFirework(this.x, this.y);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function animate() {
|
|
||||||
ctx.clearRect(0, 0, canvas.value.width, canvas.value.height);
|
|
||||||
|
|
||||||
// 更新和绘制火箭
|
|
||||||
rockets = rockets.filter((rocket) => {
|
|
||||||
rocket.draw();
|
|
||||||
return rocket.update();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 更新和绘制粒子
|
|
||||||
particles = particles.filter((particle) => particle.alpha > 0);
|
|
||||||
particles.forEach((particle) => {
|
|
||||||
particle.draw();
|
|
||||||
particle.update();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 发射新的火箭
|
|
||||||
if (Math.random() < 0.03 && rockets.length < 3) {
|
|
||||||
rockets.push(new Rocket());
|
|
||||||
}
|
|
||||||
|
|
||||||
animationFrameId = requestAnimationFrame(animate);
|
|
||||||
}
|
|
||||||
|
|
||||||
function resizeCanvas() {
|
|
||||||
if (canvas.value) {
|
|
||||||
canvas.value.width = window.innerWidth;
|
|
||||||
canvas.value.height = window.innerHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
ctx = canvas.value.getContext('2d');
|
|
||||||
resizeCanvas();
|
|
||||||
window.addEventListener('resize', resizeCanvas);
|
|
||||||
animate();
|
|
||||||
});
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
window.removeEventListener('resize', resizeCanvas);
|
|
||||||
if (animationFrameId) {
|
|
||||||
cancelAnimationFrame(animationFrameId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.fireworks-canvas {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: 8;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,257 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="lantern-container">
|
|
||||||
<div class="lantern-group right-group">
|
|
||||||
<div class="deng-box">
|
|
||||||
<div class="deng">
|
|
||||||
<div class="xian" />
|
|
||||||
<div class="deng-a">
|
|
||||||
<div class="deng-b">
|
|
||||||
<div class="deng-t">快</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="shui shui-a">
|
|
||||||
<div class="shui-c" />
|
|
||||||
<div class="shui-b" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="deng-box deng-box--2">
|
|
||||||
<div class="deng">
|
|
||||||
<div class="xian" />
|
|
||||||
<div class="deng-a">
|
|
||||||
<div class="deng-b">
|
|
||||||
<div class="deng-t">乐</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="shui shui-a">
|
|
||||||
<div class="shui-c" />
|
|
||||||
<div class="shui-b" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="lantern-group left-group">
|
|
||||||
<div class="deng-box">
|
|
||||||
<div class="deng">
|
|
||||||
<div class="xian" />
|
|
||||||
<div class="deng-a">
|
|
||||||
<div class="deng-b">
|
|
||||||
<div class="deng-t">新</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="shui shui-a">
|
|
||||||
<div class="shui-c" />
|
|
||||||
<div class="shui-b" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="deng-box deng-box--2">
|
|
||||||
<div class="deng">
|
|
||||||
<div class="xian" />
|
|
||||||
<div class="deng-a">
|
|
||||||
<div class="deng-b">
|
|
||||||
<div class="deng-t">年</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="shui shui-a">
|
|
||||||
<div class="shui-c" />
|
|
||||||
<div class="shui-b" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
// 灯笼组件
|
|
||||||
// 由AI生成
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.lantern-container {
|
|
||||||
position: fixed;
|
|
||||||
top: calc(var(--layout-header-height) + 5px);
|
|
||||||
width: 100%;
|
|
||||||
z-index: 50;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lantern-group {
|
|
||||||
position: fixed;
|
|
||||||
top: 70px;
|
|
||||||
animation: swing 3s infinite ease-in-out;
|
|
||||||
transform-origin: 50% -10px;
|
|
||||||
|
|
||||||
&.left-group {
|
|
||||||
left: 40px;
|
|
||||||
animation-delay: -1.5s;
|
|
||||||
|
|
||||||
.deng-box:nth-child(2) {
|
|
||||||
margin-top: -12px;
|
|
||||||
|
|
||||||
.deng {
|
|
||||||
animation: swing-extra 2s infinite ease-in-out;
|
|
||||||
animation-delay: -0.5s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.right-group {
|
|
||||||
right: 30px;
|
|
||||||
animation-delay: -0.5s;
|
|
||||||
|
|
||||||
.deng-box:nth-child(2) {
|
|
||||||
|
|
||||||
.deng {
|
|
||||||
animation: swing-extra 2s infinite ease-in-out;
|
|
||||||
animation-delay: -1s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.deng {
|
|
||||||
animation: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.deng-box {
|
|
||||||
position: relative;
|
|
||||||
top: -40px;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
z-index: 2;
|
|
||||||
.deng {
|
|
||||||
margin-bottom: 23px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:nth-child(2) {
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.deng {
|
|
||||||
position: relative;
|
|
||||||
width: 120px;
|
|
||||||
height: 90px;
|
|
||||||
margin: 50px;
|
|
||||||
background: rgba(216, 0, 15, 0.8);
|
|
||||||
border-radius: 50% 50%;
|
|
||||||
transform-origin: 50% -100px;
|
|
||||||
animation: swing 3s infinite ease-in-out;
|
|
||||||
box-shadow: -5px 5px 50px 4px rgba(250, 108, 0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.deng-a {
|
|
||||||
width: 100px;
|
|
||||||
height: 90px;
|
|
||||||
background: rgba(216, 0, 15, 0.1);
|
|
||||||
margin: 12px 8px 8px 10px;
|
|
||||||
border-radius: 50% 50%;
|
|
||||||
border: 2px solid #dc8f03;
|
|
||||||
}
|
|
||||||
|
|
||||||
.deng-b {
|
|
||||||
width: 45px;
|
|
||||||
height: 90px;
|
|
||||||
background: rgba(216, 0, 15, 0.1);
|
|
||||||
margin: -4px 8px 8px 26px;
|
|
||||||
border-radius: 50% 50%;
|
|
||||||
border: 2px solid #dc8f03;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xian {
|
|
||||||
position: absolute;
|
|
||||||
top: -20px;
|
|
||||||
left: 60px;
|
|
||||||
width: 2px;
|
|
||||||
height: 20px;
|
|
||||||
background: #dc8f03;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shui-a {
|
|
||||||
position: relative;
|
|
||||||
width: 5px;
|
|
||||||
height: 20px;
|
|
||||||
margin: -5px 0 0 59px;
|
|
||||||
transform-origin: 50% -45px;
|
|
||||||
background: #ffa500;
|
|
||||||
border-radius: 0 0 5px 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shui-b {
|
|
||||||
position: absolute;
|
|
||||||
top: 14px;
|
|
||||||
left: -2px;
|
|
||||||
width: 10px;
|
|
||||||
height: 10px;
|
|
||||||
background: #dc8f03;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shui-c {
|
|
||||||
position: absolute;
|
|
||||||
top: 18px;
|
|
||||||
left: -2px;
|
|
||||||
width: 10px;
|
|
||||||
height: 35px;
|
|
||||||
background: #ffa500;
|
|
||||||
border-radius: 0 0 0 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.deng:before {
|
|
||||||
position: absolute;
|
|
||||||
top: -7px;
|
|
||||||
left: 29px;
|
|
||||||
height: 12px;
|
|
||||||
width: 60px;
|
|
||||||
content: " ";
|
|
||||||
display: block;
|
|
||||||
z-index: 999;
|
|
||||||
border-radius: 5px 5px 0 0;
|
|
||||||
border: solid 1px #dc8f03;
|
|
||||||
background: linear-gradient(to right, #dc8f03, #ffa500, #dc8f03, #ffa500, #dc8f03);
|
|
||||||
}
|
|
||||||
|
|
||||||
.deng:after {
|
|
||||||
position: absolute;
|
|
||||||
bottom: -7px;
|
|
||||||
left: 10px;
|
|
||||||
height: 12px;
|
|
||||||
width: 60px;
|
|
||||||
content: " ";
|
|
||||||
display: block;
|
|
||||||
margin-left: 20px;
|
|
||||||
border-radius: 0 0 5px 5px;
|
|
||||||
border: solid 1px #dc8f03;
|
|
||||||
background: linear-gradient(to right, #dc8f03, #ffa500, #dc8f03, #ffa500, #dc8f03);
|
|
||||||
}
|
|
||||||
|
|
||||||
.deng-t {
|
|
||||||
font-family: 华文行楷, Arial, Lucida Grande, Tahoma, sans-serif;
|
|
||||||
font-size: 3.2rem;
|
|
||||||
color: #ffd000;
|
|
||||||
line-height: 85px;
|
|
||||||
text-align: center;
|
|
||||||
margin-left: -5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes swing {
|
|
||||||
0% { transform: rotate(-6deg) }
|
|
||||||
50% { transform: rotate(6deg) }
|
|
||||||
100% { transform: rotate(-6deg) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes swing-extra {
|
|
||||||
0% { transform: rotate(-3deg) }
|
|
||||||
50% { transform: rotate(3deg) }
|
|
||||||
100% { transform: rotate(-3deg) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 1024px) {
|
|
||||||
.lantern-container {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -46,9 +46,6 @@ const store = useStore();
|
|||||||
const dynamicContentRef = ref();
|
const dynamicContentRef = ref();
|
||||||
|
|
||||||
const dynamicContent = computed(() => {
|
const dynamicContent = computed(() => {
|
||||||
if (store.state.setting?.config?.custom_code) {
|
|
||||||
return store.state.setting.config.custom_code;
|
|
||||||
}
|
|
||||||
if (store.state.setting?.custom_code) {
|
if (store.state.setting?.custom_code) {
|
||||||
return store.state.setting.custom_code;
|
return store.state.setting.custom_code;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -335,10 +335,6 @@ const dashboardUrl = computed(() => config.nazhua.v1DashboardUrl || '/dashboard'
|
|||||||
color: #ddd;
|
color: #ddd;
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
|
|
||||||
.value {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.server-count--total {
|
&.server-count--total {
|
||||||
.value {
|
.value {
|
||||||
color: #70f3ff;
|
color: #70f3ff;
|
||||||
|
|||||||
@ -12,12 +12,6 @@
|
|||||||
<slot />
|
<slot />
|
||||||
<layout-footer />
|
<layout-footer />
|
||||||
</div>
|
</div>
|
||||||
<template v-if="config.nazhua.showFireworks">
|
|
||||||
<fireworks />
|
|
||||||
</template>
|
|
||||||
<template v-if="config.nazhua.showLantern">
|
|
||||||
<lantern />
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -27,8 +21,6 @@
|
|||||||
*/
|
*/
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import Fireworks from '@/components/fireworks.vue';
|
|
||||||
import Lantern from '@/components/lantern.vue';
|
|
||||||
import LayoutHeader from './components/header.vue';
|
import LayoutHeader from './components/header.vue';
|
||||||
import LayoutFooter from './components/footer.vue';
|
import LayoutFooter from './components/footer.vue';
|
||||||
|
|
||||||
|
|||||||
@ -118,7 +118,7 @@ const store = createStore({
|
|||||||
commit('SET_SETTING', res);
|
commit('SET_SETTING', res);
|
||||||
// 如果自定义配置没有设置title,使用站点名称
|
// 如果自定义配置没有设置title,使用站点名称
|
||||||
if (!window.$$nazhuaConfig.title) {
|
if (!window.$$nazhuaConfig.title) {
|
||||||
config.nazhua.title = res.config?.site_name || res.site_name;
|
config.nazhua.title = res.site_name;
|
||||||
if (route?.name === 'Home' || !route) {
|
if (route?.name === 'Home' || !route) {
|
||||||
document.title = config.nazhua.title;
|
document.title = config.nazhua.title;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -212,13 +212,8 @@ export function getPlatformLogoIconClassName(platform) {
|
|||||||
/**
|
/**
|
||||||
* 获取系统发行版本
|
* 获取系统发行版本
|
||||||
*/
|
*/
|
||||||
export function getSystemOSLabel(platform, short = false) {
|
export function getSystemOSLabel(platform) {
|
||||||
const platformStr = (platform || '').toLowerCase();
|
switch (platform) {
|
||||||
// 匹配一些超长系统发行版本
|
|
||||||
if (short && platformStr.includes('windows')) {
|
|
||||||
return 'Windows';
|
|
||||||
}
|
|
||||||
switch (platformStr) {
|
|
||||||
case 'windows':
|
case 'windows':
|
||||||
return 'Windows';
|
return 'Windows';
|
||||||
case 'linux':
|
case 'linux':
|
||||||
|
|||||||
@ -26,8 +26,7 @@ export const loadServerGroup = async () => request({
|
|||||||
/**
|
/**
|
||||||
* 加载网站配置
|
* 加载网站配置
|
||||||
*
|
*
|
||||||
* 暂时只使用site_name\custom_code
|
* 暂时只使用site_name
|
||||||
* 哪吒v1.4.9之后,上面的参数调整至data.config
|
|
||||||
*/
|
*/
|
||||||
export const loadSetting = async () => request({
|
export const loadSetting = async () => request({
|
||||||
url: config.nazhua.v1ApiSettingPath,
|
url: config.nazhua.v1ApiSettingPath,
|
||||||
|
|||||||
@ -212,9 +212,6 @@
|
|||||||
v-for="(tag, index) in tagList"
|
v-for="(tag, index) in tagList"
|
||||||
:key="`${tag}_${index}`"
|
:key="`${tag}_${index}`"
|
||||||
class="server-info-tag-item"
|
class="server-info-tag-item"
|
||||||
:class="{
|
|
||||||
'has-sarasa-term': $hasSarasaTerm && config.nazhua.disableSarasaTermSC !== true,
|
|
||||||
}"
|
|
||||||
>
|
>
|
||||||
{{ tag }}
|
{{ tag }}
|
||||||
</span>
|
</span>
|
||||||
@ -418,24 +415,11 @@ const billPlanData = computed(() => ['billing', 'remainingTime', 'bandwidth', 't
|
|||||||
|
|
||||||
const tagList = computed(() => {
|
const tagList = computed(() => {
|
||||||
const list = [];
|
const list = [];
|
||||||
const {
|
if (props?.info?.PublicNote?.planDataMod?.networkRoute) {
|
||||||
networkRoute,
|
list.push(...props.info.PublicNote.planDataMod.networkRoute.split(','));
|
||||||
extra,
|
|
||||||
IPv4,
|
|
||||||
IPv6,
|
|
||||||
} = props?.info?.PublicNote?.planDataMod || {};
|
|
||||||
if (networkRoute) {
|
|
||||||
list.push(...networkRoute?.split?.(','));
|
|
||||||
}
|
}
|
||||||
if (extra) {
|
if (props?.info?.PublicNote?.planDataMod?.extra) {
|
||||||
list.push(...extra?.split?.(','));
|
list.push(...props.info.PublicNote.planDataMod.extra.split(','));
|
||||||
}
|
|
||||||
if (IPv4 === '1' && IPv6 === '1') {
|
|
||||||
list.push('双栈IP');
|
|
||||||
} else if (IPv4 === '1') {
|
|
||||||
list.push('仅IPv4');
|
|
||||||
} else if (IPv6 === '1') {
|
|
||||||
list.push('仅IPv6');
|
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
});
|
});
|
||||||
@ -608,16 +592,12 @@ const processCount = computed(() => props.info?.State?.ProcessCount);
|
|||||||
.server-info-tag-item {
|
.server-info-tag-item {
|
||||||
height: 18px;
|
height: 18px;
|
||||||
padding: 0 5px 0 6px;
|
padding: 0 5px 0 6px;
|
||||||
line-height: 18px;
|
line-height: 20px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--public-note-tag-color);
|
color: var(--public-note-tag-color);
|
||||||
background: var(--public-note-tag-bg);
|
background: var(--public-note-tag-bg);
|
||||||
text-shadow: 1px 1px 2px rgba(#000, 0.2);
|
text-shadow: 1px 1px 2px rgba(#000, 0.2);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|
||||||
&.has-sarasa-term {
|
|
||||||
line-height: 20px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
:key="`${tagItem}_${index}`"
|
:key="`${tagItem}_${index}`"
|
||||||
class="tag-item"
|
class="tag-item"
|
||||||
:class="{
|
:class="{
|
||||||
'has-sarasa-term': $hasSarasaTerm && config.nazhua.disableSarasaTermSC !== true,
|
'has-sarasa-term': $hasSarasaTerm,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
{{ tagItem }}
|
{{ tagItem }}
|
||||||
@ -106,24 +106,11 @@ function toBuy() {
|
|||||||
|
|
||||||
const tagList = computed(() => {
|
const tagList = computed(() => {
|
||||||
const list = [];
|
const list = [];
|
||||||
const {
|
if (props?.info?.PublicNote?.planDataMod?.networkRoute) {
|
||||||
networkRoute,
|
list.push(...props.info.PublicNote.planDataMod.networkRoute.split(','));
|
||||||
extra,
|
|
||||||
IPv4,
|
|
||||||
IPv6,
|
|
||||||
} = props?.info?.PublicNote?.planDataMod || {};
|
|
||||||
if (networkRoute) {
|
|
||||||
list.push(...networkRoute.split(','));
|
|
||||||
}
|
}
|
||||||
if (extra) {
|
if (props?.info?.PublicNote?.planDataMod?.extra) {
|
||||||
list.push(...extra.split(','));
|
list.push(...props.info.PublicNote.planDataMod.extra.split(','));
|
||||||
}
|
|
||||||
if (IPv4 === '1' && IPv6 === '1') {
|
|
||||||
list.push('双栈IP');
|
|
||||||
} else if (IPv4 === '1') {
|
|
||||||
list.push('仅IPv4');
|
|
||||||
} else if (IPv6 === '1') {
|
|
||||||
list.push('仅IPv6');
|
|
||||||
}
|
}
|
||||||
// 列表最多显示5个标签
|
// 列表最多显示5个标签
|
||||||
return list.slice(0, 5);
|
return list.slice(0, 5);
|
||||||
|
|||||||
@ -92,7 +92,7 @@ const { cpuAndMemAndDisk } = handleServerInfo({
|
|||||||
props,
|
props,
|
||||||
});
|
});
|
||||||
|
|
||||||
const platformSystemLabel = computed(() => hostUtils.getSystemOSLabel(props.info?.Host?.Platform, true));
|
const platformSystemLabel = computed(() => hostUtils.getSystemOSLabel(props.info?.Host?.Platform));
|
||||||
|
|
||||||
function openDetail() {
|
function openDetail() {
|
||||||
router.push({
|
router.push({
|
||||||
@ -156,7 +156,6 @@ function openDetail() {
|
|||||||
height: 32px;
|
height: 32px;
|
||||||
line-height: 34px;
|
line-height: 34px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|||||||
@ -1,113 +0,0 @@
|
|||||||
<template>
|
|
||||||
<transition-group
|
|
||||||
v-if="showTransition"
|
|
||||||
name="list"
|
|
||||||
tag="div"
|
|
||||||
class="server-list-container"
|
|
||||||
:class="{
|
|
||||||
'server-list--row': showListRow,
|
|
||||||
'server-list--card': showListCard,
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<slot />
|
|
||||||
</transition-group>
|
|
||||||
<div
|
|
||||||
v-else
|
|
||||||
class="server-list-container"
|
|
||||||
:class="{
|
|
||||||
'server-list--row': showListRow,
|
|
||||||
'server-list--card': showListCard,
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
/**
|
|
||||||
* 服务器列表
|
|
||||||
*/
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
showTransition: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
showListRow: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
showListCard: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.server-list-container.server-list--card {
|
|
||||||
--list-padding: 20px;
|
|
||||||
--list-gap-size: 20px;
|
|
||||||
--list-item-num: 3;
|
|
||||||
--list-item-width: calc(
|
|
||||||
(
|
|
||||||
var(--list-container-width)
|
|
||||||
- (var(--list-padding) * 2)
|
|
||||||
- (
|
|
||||||
var(--list-gap-size)
|
|
||||||
* (var(--list-item-num) - 1)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
/ var(--list-item-num)
|
|
||||||
);
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: var(--list-gap-size);
|
|
||||||
padding: 0 var(--list-padding);
|
|
||||||
width: var(--list-container-width);
|
|
||||||
margin: auto;
|
|
||||||
|
|
||||||
// 针对1440px以下的屏幕
|
|
||||||
@media screen and (max-width: 1440px) {
|
|
||||||
--list-gap-size: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 1024px) {
|
|
||||||
--list-item-num: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 680px) {
|
|
||||||
--list-item-num: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.server-list-container.server-list--row {
|
|
||||||
--list-padding: 20px;
|
|
||||||
--list-gap-size: 12px;
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: var(--list-gap-size);
|
|
||||||
width: var(--list-container-width);
|
|
||||||
padding: 0 var(--list-padding);
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-move,
|
|
||||||
.list-enter-active,
|
|
||||||
.list-leave-active {
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
.list-enter-from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-30px);
|
|
||||||
}
|
|
||||||
.list-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(30px);
|
|
||||||
}
|
|
||||||
.list-leave-active {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -10,22 +10,12 @@
|
|||||||
:key="item.key"
|
:key="item.key"
|
||||||
class="server-option-item"
|
class="server-option-item"
|
||||||
:class="{
|
:class="{
|
||||||
'has-icon': item.icon,
|
|
||||||
active: activeValue === item.value,
|
active: activeValue === item.value,
|
||||||
}"
|
}"
|
||||||
:title="item?.title || false"
|
:title="item?.title || false"
|
||||||
@click="toggleModelValue(item)"
|
@click="toggleModelValue(item)"
|
||||||
>
|
>
|
||||||
<i
|
<span class="option-label">{{ item.label }}</span>
|
||||||
v-if="item.icon"
|
|
||||||
class="option-icon"
|
|
||||||
:class="item.icon"
|
|
||||||
:title="item.label"
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
v-else
|
|
||||||
class="option-label"
|
|
||||||
>{{ item.label }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -95,27 +85,13 @@ function toggleModelValue(item) {
|
|||||||
background: rgba(#000, 0.3);
|
background: rgba(#000, 0.3);
|
||||||
transition: all 0.3s linear;
|
transition: all 0.3s linear;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&.has-icon {
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
@media screen and (max-width: 768px) {
|
||||||
height: 30px;
|
|
||||||
padding: 0 10px;
|
|
||||||
border-radius: 3px;
|
|
||||||
background-color: rgba(#000, 0.8);
|
background-color: rgba(#000, 0.8);
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.option-icon {
|
|
||||||
line-height: 1;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.option-label {
|
.option-label {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-weight: bold;
|
|
||||||
transition: all 0.3s linear;
|
transition: all 0.3s linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,10 +120,6 @@ function toggleModelValue(item) {
|
|||||||
&:hover {
|
&:hover {
|
||||||
background: rgba(#000, 0.8);
|
background: rgba(#000, 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
|
||||||
background: rgba(#ff7500, 0.75);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,36 +31,34 @@
|
|||||||
v-model="filterFormData.online"
|
v-model="filterFormData.online"
|
||||||
:options="onlineOptions"
|
:options="onlineOptions"
|
||||||
/>
|
/>
|
||||||
<server-option-box
|
|
||||||
v-if="config.nazhua.listServerItemTypeToggle"
|
|
||||||
v-model="listType"
|
|
||||||
:options="listTypeOptions"
|
|
||||||
:accpet-empty="false"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<server-list-warp
|
<transition-group
|
||||||
v-if="showListRow"
|
v-if="showListRow"
|
||||||
:show-transition="showTransition"
|
name="list"
|
||||||
:show-list-row="showListRow"
|
tag="div"
|
||||||
|
class="server-list-container"
|
||||||
|
:class="`server-list--row`"
|
||||||
>
|
>
|
||||||
<server-row-item
|
<server-row-item
|
||||||
v-for="item in filterServerList.list"
|
v-for="item in filterServerList.list"
|
||||||
:key="item.ID"
|
:key="item.ID"
|
||||||
:info="item"
|
:info="item"
|
||||||
/>
|
/>
|
||||||
</server-list-warp>
|
</transition-group>
|
||||||
<server-list-warp
|
<transition-group
|
||||||
v-if="showListCard"
|
v-if="showListCard"
|
||||||
:show-transition="showTransition"
|
name="list"
|
||||||
:show-list-card="showListCard"
|
tag="div"
|
||||||
|
class="server-list-container"
|
||||||
|
:class="`server-list--card`"
|
||||||
>
|
>
|
||||||
<server-card-item
|
<server-card-item
|
||||||
v-for="item in filterServerList.list"
|
v-for="item in filterServerList.list"
|
||||||
:key="item.ID"
|
:key="item.ID"
|
||||||
:info="item"
|
:info="item"
|
||||||
/>
|
/>
|
||||||
</server-list-warp>
|
</transition-group>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -95,7 +93,6 @@ import validate from '@/utils/validate';
|
|||||||
|
|
||||||
import WorldMap from '@/components/world-map/world-map.vue';
|
import WorldMap from '@/components/world-map/world-map.vue';
|
||||||
import ServerOptionBox from './components/server-list/server-option-box.vue';
|
import ServerOptionBox from './components/server-list/server-option-box.vue';
|
||||||
import ServerListWarp from './components/server-list/server-list-warp.vue';
|
|
||||||
import ServerCardItem from './components/server-list/card/server-list-item.vue';
|
import ServerCardItem from './components/server-list/card/server-list-item.vue';
|
||||||
import ServerRowItem from './components/server-list/row/server-list-item.vue';
|
import ServerRowItem from './components/server-list/row/server-list-item.vue';
|
||||||
|
|
||||||
@ -103,30 +100,14 @@ const store = useStore();
|
|||||||
const worldMapWidth = ref();
|
const worldMapWidth = ref();
|
||||||
const windowWidth = ref(window.innerWidth);
|
const windowWidth = ref(window.innerWidth);
|
||||||
|
|
||||||
const listType = ref(config.nazhua.listServerItemType || 'card');
|
|
||||||
|
|
||||||
const showTransition = computed(() => {
|
|
||||||
// 强制开启
|
|
||||||
if (config.nazhua.forceTransition) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// 服务器数量小于7时,不开启
|
|
||||||
return store.state.serverList.length < 7;
|
|
||||||
});
|
|
||||||
const showListRow = computed(() => {
|
const showListRow = computed(() => {
|
||||||
if (windowWidth.value > 1024) {
|
if (windowWidth.value > 1024) {
|
||||||
if (config.nazhua.listServerItemTypeToggle) {
|
|
||||||
return listType.value === 'row';
|
|
||||||
}
|
|
||||||
return config.nazhua.listServerItemType === 'row';
|
return config.nazhua.listServerItemType === 'row';
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
const showListCard = computed(() => {
|
const showListCard = computed(() => {
|
||||||
if (windowWidth.value > 1024) {
|
if (windowWidth.value > 1024) {
|
||||||
if (config.nazhua.listServerItemTypeToggle) {
|
|
||||||
return listType.value !== 'row';
|
|
||||||
}
|
|
||||||
return config.nazhua.listServerItemType !== 'row';
|
return config.nazhua.listServerItemType !== 'row';
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -178,18 +159,6 @@ const onlineOptions = computed(() => {
|
|||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
|
|
||||||
const listTypeOptions = computed(() => [{
|
|
||||||
key: 'card',
|
|
||||||
label: '卡片',
|
|
||||||
value: 'card',
|
|
||||||
icon: 'ri-gallery-view-2',
|
|
||||||
}, {
|
|
||||||
key: 'row',
|
|
||||||
label: '列表',
|
|
||||||
value: 'row',
|
|
||||||
icon: 'ri-list-view',
|
|
||||||
}]);
|
|
||||||
|
|
||||||
const filterServerList = computed(() => {
|
const filterServerList = computed(() => {
|
||||||
const fields = {};
|
const fields = {};
|
||||||
const locationMap = {};
|
const locationMap = {};
|
||||||
@ -360,19 +329,75 @@ onActivated(() => {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 10px 20px;
|
gap: 10px 20px;
|
||||||
width: var(--list-container-width);
|
width: var(--list-container-width);
|
||||||
padding: 0 20px;
|
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
|
||||||
.left-box {
|
&.list-is-card {
|
||||||
display: flex;
|
padding: 0 20px;
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.right-box {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.server-list-container.server-list--card {
|
||||||
|
--list-padding: 20px;
|
||||||
|
--list-gap-size: 20px;
|
||||||
|
--list-item-num: 3;
|
||||||
|
--list-item-width: calc(
|
||||||
|
(
|
||||||
|
var(--list-container-width)
|
||||||
|
- (var(--list-padding) * 2)
|
||||||
|
- (
|
||||||
|
var(--list-gap-size)
|
||||||
|
* (var(--list-item-num) - 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
/ var(--list-item-num)
|
||||||
|
);
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--list-gap-size);
|
||||||
|
padding: 0 var(--list-padding);
|
||||||
|
width: var(--list-container-width);
|
||||||
|
margin: auto;
|
||||||
|
|
||||||
|
// 针对1440px以下的屏幕
|
||||||
|
@media screen and (max-width: 1440px) {
|
||||||
|
--list-gap-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 1024px) {
|
||||||
|
--list-item-num: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 680px) {
|
||||||
|
--list-item-num: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.server-list-container.server-list--row {
|
||||||
|
--list-padding: 20px;
|
||||||
|
--list-gap-size: 12px;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--list-gap-size);
|
||||||
|
width: var(--list-container-width);
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-move,
|
||||||
|
.list-enter-active,
|
||||||
|
.list-leave-active {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
.list-enter-from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-30px);
|
||||||
|
}
|
||||||
|
.list-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(30px);
|
||||||
|
}
|
||||||
|
.list-leave-active {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user