mirror of
https://github.com/hi2shark/nazhua.git
synced 2026-01-19 18:49:36 +08:00
Compare commits
7 Commits
d85eeb9a44
...
0606ba918d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0606ba918d | ||
|
|
249a1463b3 | ||
|
|
7d424ffa78 | ||
|
|
057e0f5f11 | ||
|
|
247115c3c3 | ||
|
|
bd6b3c8b44 | ||
|
|
a23fbe4546 |
2
.github/workflows/docker-build.yml
vendored
2
.github/workflows/docker-build.yml
vendored
@ -12,7 +12,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
|
|||||||
33
.github/workflows/release.yml
vendored
33
.github/workflows/release.yml
vendored
@ -12,22 +12,19 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-release:
|
build-and-release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 10
|
fetch-depth: 20
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '20'
|
node-version: '20'
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm install
|
|
||||||
|
|
||||||
- name: Get version from package.json
|
- name: Get version from package.json
|
||||||
id: get_version
|
id: get_version
|
||||||
run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
|
run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
|
||||||
@ -41,6 +38,16 @@ jobs:
|
|||||||
echo "version=${{ steps.get_version.outputs.version }}" >> $GITHUB_OUTPUT
|
echo "version=${{ steps.get_version.outputs.version }}" >> $GITHUB_OUTPUT
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
- name: Generate release notes
|
||||||
|
id: release_notes
|
||||||
|
run: |
|
||||||
|
echo "#### Changes" > release_notes.md
|
||||||
|
git log -20 --pretty=format:"- %s" >> release_notes.md
|
||||||
|
echo -e "\n-----------\n哪吒V1请下载dist.zip\n哪吒V0请下载v0-dist.zip\n哪吒V0/nazhua/子目录需求请下载v0-nazhua.zip\nv${{ steps.determine_version.outputs.version }}-all.zip是全量包\nv${{ steps.determine_version.outputs.version }}-cdn-jsdelivr.zip是jsdelivr引用版\nv${{ steps.determine_version.outputs.version }}-cdn-loli.zip是cdnjs的loli.net引用版" >> release_notes.md
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm install
|
||||||
|
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
id: create_release
|
id: create_release
|
||||||
uses: actions/create-release@v1
|
uses: actions/create-release@v1
|
||||||
@ -49,7 +56,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
tag_name: v${{ steps.determine_version.outputs.version }}
|
tag_name: v${{ steps.determine_version.outputs.version }}
|
||||||
release_name: Release v${{ steps.determine_version.outputs.version }}
|
release_name: Release v${{ steps.determine_version.outputs.version }}
|
||||||
draft: false
|
draft: true
|
||||||
prerelease: false
|
prerelease: false
|
||||||
|
|
||||||
- name: 构建自动版 - 完整引用版本
|
- name: 构建自动版 - 完整引用版本
|
||||||
@ -174,19 +181,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Add release notes
|
- name: Add release notes
|
||||||
run: |
|
run: |
|
||||||
# 获取最近一次提交的变更内容
|
|
||||||
git log $(git describe --tags --abbrev=0)..HEAD --pretty=format:"%s%n%b" > change.txt
|
|
||||||
|
|
||||||
# 获取现有的发布说明
|
|
||||||
gh release view v${{ steps.determine_version.outputs.version }} --json body -q .body > body.txt
|
|
||||||
|
|
||||||
# 添加最近一次提交的变更内容
|
|
||||||
echo -e "\n## 变更内容\n$(cat change.txt)" >> body.txt
|
|
||||||
|
|
||||||
# 添加其他发布说明
|
|
||||||
echo -e "\n哪吒V1请下载dist.zip\n哪吒V0请下载v0-dist.zip\n哪吒V0/nazhua/子目录需求请下载v0-nazhua.zip\nv${{ steps.determine_version.outputs.version }}-all.zip是全量包\nv${{ steps.determine_version.outputs.version }}-cdn-jsdelivr.zip是jsdelivr引用版\nv${{ steps.determine_version.outputs.version }}-cdn-loli.zip是cdnjs的loli.net引用版" >> body.txt
|
|
||||||
|
|
||||||
# 更新发布说明
|
# 更新发布说明
|
||||||
gh release edit v${{ steps.determine_version.outputs.version }} --notes-file body.txt
|
gh release edit v${{ steps.determine_version.outputs.version }} --notes-file release_notes.md
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "nazhua",
|
"name": "nazhua",
|
||||||
"version": "0.4.13",
|
"version": "0.4.14",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@ -19,7 +19,6 @@ window.$$nazhuaConfig = {
|
|||||||
// hideTag: false, // 隐藏标签
|
// hideTag: false, // 隐藏标签
|
||||||
// hideDotBG: true, // 隐藏框框里面的点点背景
|
// hideDotBG: true, // 隐藏框框里面的点点背景
|
||||||
// monitorRefreshTime: 10, // 监控刷新时间间隔,单位s(秒), 0为不刷新,为保证不频繁请求源站,最低生效值为10s
|
// monitorRefreshTime: 10, // 监控刷新时间间隔,单位s(秒), 0为不刷新,为保证不频繁请求源站,最低生效值为10s
|
||||||
// filterWeirdGPU: true, // 过滤奇怪的GPU
|
|
||||||
// filterGPUKeywords: ['Virtual Display'], // 如果GPU名称中包含这些关键字,则过滤掉
|
// filterGPUKeywords: ['Virtual Display'], // 如果GPU名称中包含这些关键字,则过滤掉
|
||||||
// customCodeMap: {}, // 自定义的地图点信息
|
// customCodeMap: {}, // 自定义的地图点信息
|
||||||
// nezhaVersion: 'v1', // 哪吒版本
|
// nezhaVersion: 'v1', // 哪吒版本
|
||||||
|
|||||||
12
readme.md
12
readme.md
@ -84,7 +84,9 @@ Nazhua对这个支持大概在90%左右,参与数据处理了的字段如下
|
|||||||
4-1. 分组数据,v1来自公开的api接口,`/api/v1/server-group`。
|
4-1. 分组数据,v1来自公开的api接口,`/api/v1/server-group`。
|
||||||
|
|
||||||
## 部署
|
## 部署
|
||||||
Nazhua主题是一个纯前端项目,可以部署在纯静态服务器上,但需要解决`/api/v1/monitor/${id}`监控数据、`/ws`WS服务和`/`主页的跨域访问。
|
Nazhua主题是一个纯前端项目,可以部署在纯静态服务器上;
|
||||||
|
v0需要解决`/api/v1/monitor/${id}`监控数据、`/ws`WS服务和`/`主页的跨域访问。
|
||||||
|
v1需要解决`/api/xxx`等数据接口、`/api/v1/ws/server`WS服务的跨域访问。
|
||||||
通常来说,你需要一个nginx或者caddy反代请求解决跨域问题。
|
通常来说,你需要一个nginx或者caddy反代请求解决跨域问题。
|
||||||
|
|
||||||
### Docker Compose + Cloudflare Tunnels部署
|
### Docker Compose + Cloudflare Tunnels部署
|
||||||
@ -118,8 +120,8 @@ services:
|
|||||||
### Nginx配置示例
|
### Nginx配置示例
|
||||||
```nginx
|
```nginx
|
||||||
map $http_upgrade $connection_upgrade {
|
map $http_upgrade $connection_upgrade {
|
||||||
default upgrade;
|
default upgrade;
|
||||||
'' close;
|
'' close;
|
||||||
}
|
}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
@ -172,7 +174,6 @@ server {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## 自定义配置
|
## 自定义配置
|
||||||
可以通过修改根目录下的`config.js`文件来自定义配置
|
可以通过修改根目录下的`config.js`文件来自定义配置
|
||||||
例如:(*参考内容在文档上不一定是最新,具体参考public/config.js或者[Nazhua配置生成器](https://hi2shark.github.io/nazhua-generator/)*)
|
例如:(*参考内容在文档上不一定是最新,具体参考public/config.js或者[Nazhua配置生成器](https://hi2shark.github.io/nazhua-generator/)*)
|
||||||
@ -183,6 +184,7 @@ window.$$nazhuaConfig = {
|
|||||||
infinityCycle: '无限', // 无限周期名称
|
infinityCycle: '无限', // 无限周期名称
|
||||||
buyBtnText: '购买', // 购买按钮文案
|
buyBtnText: '购买', // 购买按钮文案
|
||||||
listServerStatusType: 'progress', // 服务器状态类型--列表
|
listServerStatusType: 'progress', // 服务器状态类型--列表
|
||||||
|
listServerRealTimeShowLoad: false, // 列表显示服务器实时负载
|
||||||
detailServerStatusType: 'progress', // 服务器状态类型--详情页
|
detailServerStatusType: 'progress', // 服务器状态类型--详情页
|
||||||
disableSarasaTermSC: false, // 禁用Sarasa Term SC字体
|
disableSarasaTermSC: false, // 禁用Sarasa Term SC字体
|
||||||
hideWorldMap: false, // 隐藏地图
|
hideWorldMap: false, // 隐藏地图
|
||||||
@ -196,6 +198,8 @@ window.$$nazhuaConfig = {
|
|||||||
hideFilter: false, // 隐藏筛选
|
hideFilter: false, // 隐藏筛选
|
||||||
hideTag: false, // 隐藏标签
|
hideTag: false, // 隐藏标签
|
||||||
hideDotBG: false, // 隐藏框框里面的点点背景
|
hideDotBG: false, // 隐藏框框里面的点点背景
|
||||||
|
monitorRefreshTime: 10, // 监控刷新时间间隔,单位s(秒), 0为不刷新,为保证不频繁请求源站,最低生效值为10s
|
||||||
|
filterGPUKeywords: ['Virtual Display'], // 如果GPU名称中包含这些关键字,则过滤掉
|
||||||
customCodeMap: {}, // 自定义的地图点信息
|
customCodeMap: {}, // 自定义的地图点信息
|
||||||
nezhaVersion: 'v1', // 哪吒版本
|
nezhaVersion: 'v1', // 哪吒版本
|
||||||
apiMonitorPath: '/api/v1/monitor/{id}',
|
apiMonitorPath: '/api/v1/monitor/{id}',
|
||||||
|
|||||||
@ -11,6 +11,21 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="right-box">
|
<div class="right-box">
|
||||||
|
<div
|
||||||
|
class="refresh-data-group"
|
||||||
|
title="是否自动刷新"
|
||||||
|
@click="switchRefresh"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="switch-box"
|
||||||
|
:class="{
|
||||||
|
active: refreshData,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<span class="switch-dot" />
|
||||||
|
</div>
|
||||||
|
<span class="label-text">刷新</span>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
class="peak-shaving-group"
|
class="peak-shaving-group"
|
||||||
title="过滤太高或太低的数据"
|
title="过滤太高或太低的数据"
|
||||||
@ -62,16 +77,37 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const refreshData = ref(true);
|
||||||
const peakShaving = ref(false);
|
const peakShaving = ref(false);
|
||||||
|
|
||||||
const monitorData = ref([]);
|
const monitorData = ref([]);
|
||||||
|
|
||||||
const monitorChartData = computed(() => {
|
const monitorChartData = computed(() => {
|
||||||
|
/**
|
||||||
|
* 处理监控数据以生成分类的平均延迟随时间变化的列表。
|
||||||
|
*
|
||||||
|
* @returns {Object} 返回一个对象,包含:
|
||||||
|
* - cateList {Array}: 唯一监控名称的列表。
|
||||||
|
* - dateList {Array}: 排序后的唯一时间戳列表。
|
||||||
|
* - valueList {Array}: 包含以下内容的对象列表:
|
||||||
|
* - name {String}: 监控名称。
|
||||||
|
* - data {Array}: [时间戳, 平均延迟] 对的数组。
|
||||||
|
*
|
||||||
|
* 该函数执行以下步骤:
|
||||||
|
* 1. 遍历监控数据以分类和过滤平均延迟。
|
||||||
|
* 2. 如果启用了削峰,则应用削峰以过滤异常值。
|
||||||
|
* 3. 构建监控名称到其各自时间戳和平均延迟的映射。
|
||||||
|
* 4. 将映射转换为监控名称、时间戳和平均延迟数据的列表。
|
||||||
|
* 5. 删除重复的时间戳并对其进行排序。
|
||||||
|
*/
|
||||||
const cateMap = {};
|
const cateMap = {};
|
||||||
const dateMap = {};
|
|
||||||
monitorData.value.forEach((i) => {
|
monitorData.value.forEach((i) => {
|
||||||
|
const dateMap = {};
|
||||||
if (!cateMap[i.monitor_name]) {
|
if (!cateMap[i.monitor_name]) {
|
||||||
cateMap[i.monitor_name] = [];
|
cateMap[i.monitor_name] = {
|
||||||
|
dateMap,
|
||||||
|
avgs: [],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
const {
|
const {
|
||||||
threshold,
|
threshold,
|
||||||
@ -80,49 +116,47 @@ const monitorChartData = computed(() => {
|
|||||||
min,
|
min,
|
||||||
} = peakShaving.value ? getThreshold(i.avg_delay, 2) : {};
|
} = peakShaving.value ? getThreshold(i.avg_delay, 2) : {};
|
||||||
i.created_at.forEach((o, index) => {
|
i.created_at.forEach((o, index) => {
|
||||||
if (!dateMap[o]) {
|
if (dateMap[o]) {
|
||||||
dateMap[o] = [];
|
return;
|
||||||
}
|
}
|
||||||
const avgDelay = i.avg_delay[index];
|
const avgDelay = i.avg_delay[index];
|
||||||
if (peakShaving.value) {
|
if (peakShaving.value) {
|
||||||
if (Math.abs(avgDelay - mean) > threshold && max / min > 2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (avgDelay === 0) {
|
if (avgDelay === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (Math.abs(avgDelay - mean) > threshold && max / min > 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
dateMap[o].push({
|
dateMap[o] = (avgDelay).toFixed(2) * 1;
|
||||||
name: i.monitor_name,
|
|
||||||
value: (avgDelay).toFixed(2) * 1,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
const dateList = [];
|
let dateList = [];
|
||||||
Object.keys(dateMap).forEach((i) => {
|
|
||||||
if (dateMap[i]?.length) {
|
|
||||||
const time = parseInt(i, 10);
|
|
||||||
dateList.push(time);
|
|
||||||
dateMap[i].forEach((o) => {
|
|
||||||
cateMap[o.name].push([time, o.value]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
dateList.sort((a, b) => a - b);
|
|
||||||
const cateList = [];
|
const cateList = [];
|
||||||
const valueList = [];
|
const valueList = [];
|
||||||
Object.keys(cateMap).forEach((i) => {
|
Object.keys(cateMap).forEach((i) => {
|
||||||
if (cateMap[i]?.length) {
|
const {
|
||||||
cateList.push(i);
|
dateMap,
|
||||||
}
|
avgs,
|
||||||
|
} = cateMap[i];
|
||||||
|
Object.entries(dateMap).forEach(([key, value]) => {
|
||||||
|
const time = parseInt(key, 10);
|
||||||
|
avgs.push([time, value]);
|
||||||
|
dateList.push(time);
|
||||||
|
});
|
||||||
valueList.push({
|
valueList.push({
|
||||||
name: i,
|
name: i,
|
||||||
data: cateMap[i],
|
data: avgs,
|
||||||
});
|
});
|
||||||
|
if (avgs.length) {
|
||||||
|
cateList.push(i);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
// 去重
|
||||||
|
dateList = Array.from(new Set(dateList)).sort((a, b) => a - b);
|
||||||
return {
|
return {
|
||||||
cateList,
|
|
||||||
dateList,
|
dateList,
|
||||||
|
cateList,
|
||||||
valueList,
|
valueList,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -131,6 +165,10 @@ function switchPeakShaving() {
|
|||||||
peakShaving.value = !peakShaving.value;
|
peakShaving.value = !peakShaving.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function switchRefresh() {
|
||||||
|
refreshData.value = !refreshData.value;
|
||||||
|
}
|
||||||
|
|
||||||
async function loadMonitor() {
|
async function loadMonitor() {
|
||||||
await request({
|
await request({
|
||||||
url: (
|
url: (
|
||||||
@ -147,19 +185,21 @@ async function loadMonitor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let loadMonitorTimer = null;
|
let loadMonitorTimer = null;
|
||||||
async function setTimeLoadMonitor() {
|
async function setTimeLoadMonitor(force = false) {
|
||||||
if (loadMonitorTimer) {
|
if (loadMonitorTimer) {
|
||||||
clearTimeout(loadMonitorTimer);
|
clearTimeout(loadMonitorTimer);
|
||||||
}
|
}
|
||||||
await loadMonitor();
|
if (refreshData.value || force) {
|
||||||
|
await loadMonitor();
|
||||||
|
}
|
||||||
let monitorRefreshTime = parseInt(config.nazhua.monitorRefreshTime, 10);
|
let monitorRefreshTime = parseInt(config.nazhua.monitorRefreshTime, 10);
|
||||||
// 0 为不刷新
|
// 0 为不刷新
|
||||||
if (monitorRefreshTime === 0) {
|
if (monitorRefreshTime === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 非数字 强制为 10
|
// 非数字 强制为30
|
||||||
if (Number.isNaN(monitorRefreshTime)) {
|
if (Number.isNaN(monitorRefreshTime)) {
|
||||||
monitorRefreshTime = 10;
|
monitorRefreshTime = 30;
|
||||||
}
|
}
|
||||||
// 最小 10 秒
|
// 最小 10 秒
|
||||||
const sTime = Math.min(monitorRefreshTime, 10);
|
const sTime = Math.min(monitorRefreshTime, 10);
|
||||||
@ -169,7 +209,7 @@ async function setTimeLoadMonitor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setTimeLoadMonitor();
|
setTimeLoadMonitor(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
@ -197,7 +237,14 @@ onUnmounted(() => {
|
|||||||
color: #eee;
|
color: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
.peak-shaving-group {
|
.right-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.peak-shaving-group,
|
||||||
|
.refresh-data-group {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
|||||||
@ -18,7 +18,10 @@
|
|||||||
<span
|
<span
|
||||||
class="server-flag"
|
class="server-flag"
|
||||||
>
|
>
|
||||||
<span :class="platformLogoIconClassName" />
|
<span
|
||||||
|
class="fi"
|
||||||
|
:class="'fi-' + (info?.Host?.CountryCode || 'un')"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span class="server-name">
|
<span class="server-name">
|
||||||
{{ info.Name }}
|
{{ info.Name }}
|
||||||
@ -29,10 +32,7 @@
|
|||||||
v-if="cpuAndMemAndDisk"
|
v-if="cpuAndMemAndDisk"
|
||||||
class="cpu-mem-group"
|
class="cpu-mem-group"
|
||||||
>
|
>
|
||||||
<span
|
<span :class="platformLogoIconClassName" />
|
||||||
v-if="info?.Host?.Platform"
|
|
||||||
:class="'fl-' + info?.Host?.Platform"
|
|
||||||
/>
|
|
||||||
<span class="core-mem">{{ cpuAndMemAndDisk }}</span>
|
<span class="core-mem">{{ cpuAndMemAndDisk }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -8,13 +8,21 @@
|
|||||||
* @property {number} mean - 数据的平均值
|
* @property {number} mean - 数据的平均值
|
||||||
*/
|
*/
|
||||||
export function getThreshold(data, tolerance = 2) {
|
export function getThreshold(data, tolerance = 2) {
|
||||||
|
// 计算数据的平均值
|
||||||
const mean = data.reduce((sum, value) => sum + value, 0) / data.length;
|
const mean = data.reduce((sum, value) => sum + value, 0) / data.length;
|
||||||
|
// 计算数据的方差
|
||||||
const variance = data.reduce((sum, value) => sum + (value - mean) ** 2, 0) / data.length;
|
const variance = data.reduce((sum, value) => sum + (value - mean) ** 2, 0) / data.length;
|
||||||
|
// 计算标准差
|
||||||
const stdDev = Math.sqrt(variance);
|
const stdDev = Math.sqrt(variance);
|
||||||
|
// 计算阈值
|
||||||
const threshold = tolerance * stdDev;
|
const threshold = tolerance * stdDev;
|
||||||
|
// 过滤掉值为0的数据
|
||||||
const filteredData = data.filter((value) => value !== 0);
|
const filteredData = data.filter((value) => value !== 0);
|
||||||
|
// 计算过滤后数据的最小值
|
||||||
const min = Math.min(...filteredData);
|
const min = Math.min(...filteredData);
|
||||||
|
// 计算过滤后数据的最大值
|
||||||
const max = Math.max(...filteredData);
|
const max = Math.max(...filteredData);
|
||||||
|
// 返回包含阈值、平均值、最小值和最大值的对象
|
||||||
return {
|
return {
|
||||||
threshold,
|
threshold,
|
||||||
mean,
|
mean,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user