mirror of https://github.com/certd/certd
perf: 支持网络测试
parent
aee13ad909
commit
2bef608e07
|
@ -1,8 +1,8 @@
|
||||||
//转换为import
|
//转换为import
|
||||||
import childProcess from 'child_process';
|
import childProcess from "child_process";
|
||||||
import { safePromise } from './util.promise.js';
|
import { safePromise } from "./util.promise.js";
|
||||||
import { ILogger, logger } from './util.log.js';
|
import { ILogger, logger } from "./util.log.js";
|
||||||
import iconv from 'iconv-lite';
|
import iconv from "iconv-lite";
|
||||||
export type ExecOption = {
|
export type ExecOption = {
|
||||||
cmd: string | string[];
|
cmd: string | string[];
|
||||||
env: any;
|
env: any;
|
||||||
|
@ -11,12 +11,12 @@ export type ExecOption = {
|
||||||
};
|
};
|
||||||
|
|
||||||
async function exec(opts: ExecOption): Promise<string> {
|
async function exec(opts: ExecOption): Promise<string> {
|
||||||
let cmd = '';
|
let cmd = "";
|
||||||
const log = opts.logger || logger;
|
const log = opts.logger || logger;
|
||||||
if (opts.cmd instanceof Array) {
|
if (opts.cmd instanceof Array) {
|
||||||
for (const item of opts.cmd) {
|
for (const item of opts.cmd) {
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
cmd += ' && ' + item;
|
cmd += " && " + item;
|
||||||
} else {
|
} else {
|
||||||
cmd = item;
|
cmd = item;
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ async function exec(opts: ExecOption): Promise<string> {
|
||||||
log.error(`exec error: ${error}`);
|
log.error(`exec error: ${error}`);
|
||||||
reject(error);
|
reject(error);
|
||||||
} else {
|
} else {
|
||||||
const res = stdout.toString('utf-8');
|
const res = stdout.toString("utf-8");
|
||||||
log.info(`stdout: ${res}`);
|
log.info(`stdout: ${res}`);
|
||||||
resolve(res);
|
resolve(res);
|
||||||
}
|
}
|
||||||
|
@ -57,11 +57,11 @@ export type SpawnOption = {
|
||||||
};
|
};
|
||||||
|
|
||||||
function isWindows() {
|
function isWindows() {
|
||||||
return process.platform === 'win32';
|
return process.platform === "win32";
|
||||||
}
|
}
|
||||||
function convert(buffer: any) {
|
function convert(buffer: any) {
|
||||||
if (isWindows()) {
|
if (isWindows()) {
|
||||||
const decoded = iconv.decode(buffer, 'GBK');
|
const decoded = iconv.decode(buffer, "GBK");
|
||||||
// 检查是否有有效字符
|
// 检查是否有有效字符
|
||||||
return decoded && decoded.trim().length > 0 ? decoded : buffer.toString();
|
return decoded && decoded.trim().length > 0 ? decoded : buffer.toString();
|
||||||
} else {
|
} else {
|
||||||
|
@ -74,12 +74,12 @@ function convert(buffer: any) {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
async function spawn(opts: SpawnOption): Promise<string> {
|
async function spawn(opts: SpawnOption): Promise<string> {
|
||||||
let cmd = '';
|
let cmd = "";
|
||||||
const log = opts.logger || logger;
|
const log = opts.logger || logger;
|
||||||
if (opts.cmd instanceof Array) {
|
if (opts.cmd instanceof Array) {
|
||||||
for (const item of opts.cmd) {
|
for (const item of opts.cmd) {
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
cmd += ' && ' + item;
|
cmd += " && " + item;
|
||||||
} else {
|
} else {
|
||||||
cmd = item;
|
cmd = item;
|
||||||
}
|
}
|
||||||
|
@ -88,8 +88,8 @@ async function spawn(opts: SpawnOption): Promise<string> {
|
||||||
cmd = opts.cmd;
|
cmd = opts.cmd;
|
||||||
}
|
}
|
||||||
log.info(`执行命令: ${cmd}`);
|
log.info(`执行命令: ${cmd}`);
|
||||||
let stdout = '';
|
let stdout = "";
|
||||||
let stderr = '';
|
let stderr = "";
|
||||||
return safePromise((resolve, reject) => {
|
return safePromise((resolve, reject) => {
|
||||||
const ls = childProcess.spawn(cmd, {
|
const ls = childProcess.spawn(cmd, {
|
||||||
shell: true,
|
shell: true,
|
||||||
|
@ -99,23 +99,23 @@ async function spawn(opts: SpawnOption): Promise<string> {
|
||||||
},
|
},
|
||||||
...opts.options,
|
...opts.options,
|
||||||
});
|
});
|
||||||
ls.stdout.on('data', data => {
|
ls.stdout.on("data", data => {
|
||||||
data = convert(data);
|
data = convert(data);
|
||||||
log.info(`stdout: ${data}`);
|
log.info(`stdout: ${data}`);
|
||||||
stdout += data;
|
stdout += data;
|
||||||
});
|
});
|
||||||
|
|
||||||
ls.stderr.on('data', data => {
|
ls.stderr.on("data", data => {
|
||||||
data = convert(data);
|
data = convert(data);
|
||||||
log.warn(`stderr: ${data}`);
|
log.warn(`stderr: ${data}`);
|
||||||
stderr += data;
|
stderr += data;
|
||||||
});
|
});
|
||||||
ls.on('error', error => {
|
ls.on("error", error => {
|
||||||
log.error(`child process error: ${error}`);
|
log.error(`child process error: ${error}`);
|
||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
ls.on('close', (code: number) => {
|
ls.on("close", (code: number) => {
|
||||||
if (code !== 0) {
|
if (code !== 0) {
|
||||||
log.error(`child process exited with code ${code}`);
|
log.error(`child process exited with code ${code}`);
|
||||||
reject(new Error(stderr));
|
reject(new Error(stderr));
|
||||||
|
|
|
@ -175,6 +175,7 @@ export default {
|
||||||
suiteSetting: "Suite Settings",
|
suiteSetting: "Suite Settings",
|
||||||
orderManager: "Order Management",
|
orderManager: "Order Management",
|
||||||
userSuites: "User Suites",
|
userSuites: "User Suites",
|
||||||
|
netTest: "Network Test",
|
||||||
},
|
},
|
||||||
certificateRepo: {
|
certificateRepo: {
|
||||||
title: "Certificate Repository",
|
title: "Certificate Repository",
|
||||||
|
|
|
@ -181,6 +181,7 @@ export default {
|
||||||
suiteSetting: "套餐设置",
|
suiteSetting: "套餐设置",
|
||||||
orderManager: "订单管理",
|
orderManager: "订单管理",
|
||||||
userSuites: "用户套餐",
|
userSuites: "用户套餐",
|
||||||
|
netTest: "网络测试",
|
||||||
},
|
},
|
||||||
certificateRepo: {
|
certificateRepo: {
|
||||||
title: "证书仓库",
|
title: "证书仓库",
|
||||||
|
|
|
@ -249,6 +249,17 @@ export const sysResources = [
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "certd.sysResources.netTest",
|
||||||
|
name: "NetTest",
|
||||||
|
path: "/sys/nettest",
|
||||||
|
component: "/sys/nettest/index.vue",
|
||||||
|
meta: {
|
||||||
|
icon: "ion:build-outline",
|
||||||
|
auth: true,
|
||||||
|
keepAlive: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -0,0 +1,186 @@
|
||||||
|
<template>
|
||||||
|
<div class="domain-test-card">
|
||||||
|
<div class="card-header">
|
||||||
|
<a-form v-if="editing" layout="inline" :model="formData">
|
||||||
|
<a-form-item label="域名">
|
||||||
|
<a-input v-model:value="formData.domain" placeholder="请输入要测试的域名或IP" style="width: 240px" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="端口">
|
||||||
|
<a-input-number v-model:value="formData.port" placeholder="请输入端口" :min="1" :max="65535" style="width: 120px" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
|
||||||
|
<div v-else class="domain-info">
|
||||||
|
<span>域名: {{ formData.domain }}</span>
|
||||||
|
<span>端口: {{ formData.port }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-button :disabled="!formData.domain" size="small" type="primary" :loading="loading" @click="runAllTests"> 开始测试 </a-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="test-results">
|
||||||
|
<!-- 域名解析结果 -->
|
||||||
|
<test-case ref="domainResolveRef" title="域名解析" :test-method="() => createDomainResolveMethod()" :disabled="!getCurrentDomain()" />
|
||||||
|
|
||||||
|
<!-- Ping测试结果 -->
|
||||||
|
<test-case ref="pingTestRef" title="Ping测试" :test-method="() => createPingTestMethod()" :disabled="!getCurrentDomain()" />
|
||||||
|
|
||||||
|
<!-- Telnet测试结果 -->
|
||||||
|
<test-case ref="telnetTestRef" title="Telnet测试" :port="getCurrentPort()" :test-method="() => createTelnetTestMethod()" :disabled="!getCurrentDomain() || !getCurrentPort()" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, reactive, computed, onMounted } from "vue";
|
||||||
|
import { message } from "ant-design-vue";
|
||||||
|
import { DomainResolve, PingTest, TelnetTest } from "./api";
|
||||||
|
import TestCase from "./TestCase.vue";
|
||||||
|
|
||||||
|
// 组件属性
|
||||||
|
const props = defineProps<{
|
||||||
|
domain?: string;
|
||||||
|
port?: number;
|
||||||
|
autoStart?: boolean;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const editing = ref(!props.domain);
|
||||||
|
|
||||||
|
// 测试组件的引用
|
||||||
|
const domainResolveRef = ref();
|
||||||
|
const pingTestRef = ref();
|
||||||
|
const telnetTestRef = ref();
|
||||||
|
|
||||||
|
// 表单数据
|
||||||
|
const formData = reactive({
|
||||||
|
domain: props.domain || "",
|
||||||
|
port: props.port || 443,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 加载状态
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
|
// 创建域名解析测试方法
|
||||||
|
const createDomainResolveMethod = async () => {
|
||||||
|
const domain = getCurrentDomain();
|
||||||
|
return DomainResolve(domain);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建Ping测试方法
|
||||||
|
const createPingTestMethod = async () => {
|
||||||
|
const domain = getCurrentDomain();
|
||||||
|
return PingTest(domain);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建Telnet测试方法
|
||||||
|
const createTelnetTestMethod = async () => {
|
||||||
|
const domain = getCurrentDomain();
|
||||||
|
const port = getCurrentPort();
|
||||||
|
|
||||||
|
return TelnetTest(domain, port);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取当前使用的域名
|
||||||
|
const getCurrentDomain = () => {
|
||||||
|
return formData.domain;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取当前使用的端口
|
||||||
|
const getCurrentPort = () => {
|
||||||
|
return formData.port;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 运行全部测试
|
||||||
|
async function runAllTests() {
|
||||||
|
const domain = getCurrentDomain();
|
||||||
|
|
||||||
|
// 检查是否有域名
|
||||||
|
if (!domain) {
|
||||||
|
message.error("请输入域名");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.value = true;
|
||||||
|
|
||||||
|
// 通过组件引用调用测试方法
|
||||||
|
try {
|
||||||
|
await Promise.allSettled([domainResolveRef.value?.test(), pingTestRef.value?.test(), telnetTestRef.value?.test()]);
|
||||||
|
|
||||||
|
message.success("所有测试已完成");
|
||||||
|
} catch (error) {
|
||||||
|
message.error("部分测试执行失败,请查看详细结果");
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (props.autoStart) {
|
||||||
|
runAllTests();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.domain-test-card {
|
||||||
|
border: 1px solid #e8e8e8;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 16px;
|
||||||
|
background-color: #fafafa;
|
||||||
|
border-bottom: 1px solid #e8e8e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-content {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-form {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
background-color: #fafafa;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.domain-info {
|
||||||
|
padding: 5.5px 12px;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.test-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.test-results {
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 调整按钮大小 */
|
||||||
|
.ant-btn {
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,146 @@
|
||||||
|
<template>
|
||||||
|
<a-card title="服务端信息" class="server-info-card">
|
||||||
|
<template #extra>
|
||||||
|
<a-button size="small" :loading="loading" @click="refreshServerInfo">
|
||||||
|
<template #icon>
|
||||||
|
<a-icon type="sync" :spin="loading" />
|
||||||
|
</template>
|
||||||
|
刷新
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
<div v-if="loading" class="loading">
|
||||||
|
<a-spin size="small" />
|
||||||
|
<span style="margin-left: 8px">加载中...</span>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="error" class="error">
|
||||||
|
<a-alert message="获取服务器信息失败" :description="error" type="error" show-icon />
|
||||||
|
</div>
|
||||||
|
<div v-else class="server-info-grid">
|
||||||
|
<!-- 本地IP -->
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="info-label">本地IP:</div>
|
||||||
|
<div v-if="serverInfo.localIP" class="info-value">
|
||||||
|
<a-list item-layout="horizontal" :data-source="serverInfo.localIP">
|
||||||
|
<template #renderItem="{ item }">
|
||||||
|
<a-list-item>
|
||||||
|
<a-list-item-meta description="{{ item }}" />
|
||||||
|
</a-list-item>
|
||||||
|
</template>
|
||||||
|
</a-list>
|
||||||
|
</div>
|
||||||
|
<div v-else class="info-empty">暂无信息</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 外网IP -->
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="info-label">外网IP:</div>
|
||||||
|
<div v-if="serverInfo.publicIP" class="info-value">
|
||||||
|
{{ serverInfo.publicIP }}
|
||||||
|
</div>
|
||||||
|
<div v-else class="info-empty">暂无信息</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- DNS服务器 -->
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="info-label">DNS服务器:</div>
|
||||||
|
<div v-if="serverInfo.dnsServers && serverInfo.dnsServers.length > 0" class="info-value">
|
||||||
|
{{ serverInfo.dnsServers.join(", ") }}
|
||||||
|
</div>
|
||||||
|
<div v-else class="info-empty">暂无信息</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import { message } from "ant-design-vue";
|
||||||
|
import { GetServerInfo } from "./api";
|
||||||
|
|
||||||
|
// 服务器信息类型
|
||||||
|
interface ServerInfo {
|
||||||
|
localIP?: string[];
|
||||||
|
publicIP?: string;
|
||||||
|
dnsServers?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const loading = ref(false);
|
||||||
|
const error = ref<string | null>(null);
|
||||||
|
const serverInfo = ref<ServerInfo>({});
|
||||||
|
|
||||||
|
// 加载服务器信息
|
||||||
|
const loadServerInfo = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
error.value = null;
|
||||||
|
try {
|
||||||
|
serverInfo.value = await GetServerInfo();
|
||||||
|
} catch (e) {
|
||||||
|
error.value = e instanceof Error ? e.message : String(e);
|
||||||
|
message.error("获取服务器信息失败");
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 刷新服务器信息
|
||||||
|
const refreshServerInfo = () => {
|
||||||
|
loadServerInfo();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 组件挂载时加载数据
|
||||||
|
onMounted(() => {
|
||||||
|
loadServerInfo();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.server-info-card {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 20px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.server-info-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item {
|
||||||
|
background-color: #fafafa;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 12px;
|
||||||
|
|
||||||
|
.info-label {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-value {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
|
||||||
|
.ant-list-item {
|
||||||
|
padding: 4px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-empty {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #999;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,185 @@
|
||||||
|
<template>
|
||||||
|
<div class="test-case" :class="{ loading }">
|
||||||
|
<div class="case-header">
|
||||||
|
<span class="flex items-center">
|
||||||
|
<fs-button size="small" type="text" icon="ion:play-circle" :loading="loading" :disabled="disabled" class="test-button" @click="runTest" />
|
||||||
|
<a-tag color="blue" class="case-title">
|
||||||
|
{{ title }}
|
||||||
|
</a-tag>
|
||||||
|
<span v-if="port" class="port-info">{{ port }}</span>
|
||||||
|
</span>
|
||||||
|
<span v-if="result && isNetTestResult" class="result-status flex-1" :style="{ color: isSuccess ? 'green' : 'red' }">
|
||||||
|
<span>
|
||||||
|
{{ isSuccess ? "✓" : "✗" }}
|
||||||
|
</span>
|
||||||
|
<span class="ml-2">
|
||||||
|
{{ result.message }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="result" class="result-content">
|
||||||
|
<div v-if="error" class="error-message">
|
||||||
|
<span style="color: red">{{ error }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="isNetTestResult">
|
||||||
|
<div v-if="resultTestLog" class="test-log">
|
||||||
|
<pre>{{ resultTestLog }}</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="typeof result === 'object'" class="object-result">
|
||||||
|
<pre>{{ JSON.stringify(result, null, 2) }}</pre>
|
||||||
|
</div>
|
||||||
|
<div v-else class="text-result">
|
||||||
|
<pre>{{ result }}</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="no-result">
|
||||||
|
<p>暂无结果</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, computed } from "vue";
|
||||||
|
import { message } from "ant-design-vue";
|
||||||
|
|
||||||
|
// 组件属性
|
||||||
|
const props = defineProps<{
|
||||||
|
title: string;
|
||||||
|
port?: number | string;
|
||||||
|
testMethod: () => Promise<any>;
|
||||||
|
disabled?: boolean;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
// 内部状态
|
||||||
|
const loading = ref(false);
|
||||||
|
const result = ref<any>(null);
|
||||||
|
const error = ref<string | null>(null);
|
||||||
|
|
||||||
|
// 运行测试
|
||||||
|
const runTest = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
error.value = null;
|
||||||
|
result.value = null;
|
||||||
|
try {
|
||||||
|
const testResult = await props.testMethod();
|
||||||
|
// 如果结果有 data 属性,则使用 data,否则使用整个结果
|
||||||
|
result.value = testResult.data || testResult;
|
||||||
|
} catch (err: any) {
|
||||||
|
result.value = null;
|
||||||
|
error.value = err.message || "测试失败";
|
||||||
|
message.error(`${props.title} 测试失败: ${error.value}`);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 暴露方法给父组件
|
||||||
|
defineExpose({
|
||||||
|
test: runTest,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 辅助计算属性,用于模板中显示结果
|
||||||
|
const isNetTestResult = computed(() => {
|
||||||
|
return typeof result.value === "object" && result.value !== null && "success" in result.value && "message" in result.value && "testLog" in result.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
const isSuccess = computed(() => {
|
||||||
|
return isNetTestResult.value && result.value.success;
|
||||||
|
});
|
||||||
|
|
||||||
|
const resultMessage = computed(() => {
|
||||||
|
return isNetTestResult.value ? result.value.message : "";
|
||||||
|
});
|
||||||
|
|
||||||
|
const resultTestLog = computed(() => {
|
||||||
|
return isNetTestResult.value ? result.value.testLog : "";
|
||||||
|
});
|
||||||
|
|
||||||
|
const resultError = computed(() => {
|
||||||
|
return isNetTestResult.value ? result.value.error : "";
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.test-case {
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.loading {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.case-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
|
||||||
|
.result-status {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #999;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.case-title {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.port-info {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #999;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 3px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.test-button {
|
||||||
|
color: #1890ff;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-content {
|
||||||
|
.error-message,
|
||||||
|
.object-result,
|
||||||
|
.text-result {
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
padding: 8px 10px;
|
||||||
|
border-radius: 3px;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.4;
|
||||||
|
font-family: "Monaco", "Menlo", "Ubuntu Mono", monospace;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.test-log {
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
padding: 8px 10px;
|
||||||
|
border-radius: 3px;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-result {
|
||||||
|
padding: 12px 0;
|
||||||
|
text-align: center;
|
||||||
|
color: #999;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { request } from "/@/api/service";
|
||||||
|
|
||||||
|
export async function DomainResolve(domain: string) {
|
||||||
|
return await request({
|
||||||
|
url: "/sys/nettest/domainResolve",
|
||||||
|
method: "post",
|
||||||
|
data: { domain },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function PingTest(domain: string) {
|
||||||
|
return await request({
|
||||||
|
url: "/sys/nettest/ping",
|
||||||
|
method: "post",
|
||||||
|
data: { domain },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function TelnetTest(domain: string, port: number) {
|
||||||
|
return await request({
|
||||||
|
url: "/sys/nettest/telnet",
|
||||||
|
method: "post",
|
||||||
|
data: { domain, port },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取服务器信息(包括本地IP、外网IP和DNS服务器)
|
||||||
|
export async function GetServerInfo() {
|
||||||
|
return await request({
|
||||||
|
url: "/sys/nettest/serverInfo",
|
||||||
|
method: "post",
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
<template>
|
||||||
|
<fs-page class="page-sys-nettest">
|
||||||
|
<template #header>
|
||||||
|
<div class="title">网络测试</div>
|
||||||
|
</template>
|
||||||
|
<div class="nettest-container">
|
||||||
|
<!-- 服务端信息 -->
|
||||||
|
<server-info-card />
|
||||||
|
|
||||||
|
<!-- 测试区域 -->
|
||||||
|
<div class="test-areas">
|
||||||
|
<!-- 用户输入域名测试 -->
|
||||||
|
<domain-test-card class="w-50%" />
|
||||||
|
|
||||||
|
<!-- 百度域名测试 (用于对比) -->
|
||||||
|
<domain-test-card class="w-50%" :domain="'baidu.com'" :port="443" :auto-start="true" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fs-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import DomainTestCard from "./DomainTestCard.vue";
|
||||||
|
import ServerInfoCard from "./ServerInfoCard.vue";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.page-sys-nettest {
|
||||||
|
.nettest-container {
|
||||||
|
padding: 16px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.test-areas {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,47 @@
|
||||||
|
import { BaseController } from '@certd/lib-server';
|
||||||
|
import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
|
||||||
|
import { NetTestService } from '../../../modules/sys/nettest/nettest-service.js';
|
||||||
|
|
||||||
|
|
||||||
|
@Provide()
|
||||||
|
@Controller('/api/sys/nettest/')
|
||||||
|
export class SysNetTestController extends BaseController {
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
netTestService: NetTestService;
|
||||||
|
|
||||||
|
|
||||||
|
@Post('/domainResolve', { summary: 'sys:settings:view' })
|
||||||
|
public async domainResolve(@Body(ALL) body: { domain: string }) {
|
||||||
|
|
||||||
|
const { domain } = body;
|
||||||
|
const result = await this.netTestService.domainResolve(domain);
|
||||||
|
return this.ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ping
|
||||||
|
@Post('/ping', { summary: 'sys:settings:view' })
|
||||||
|
public async ping(@Body(ALL) body: { domain: string }) {
|
||||||
|
|
||||||
|
const { domain } = body;
|
||||||
|
const result = await this.netTestService.ping(domain);
|
||||||
|
return this.ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// telnet
|
||||||
|
@Post('/telnet', { summary: 'sys:settings:view' })
|
||||||
|
public async telnet(@Body(ALL) body: { domain: string, port: number }) {
|
||||||
|
|
||||||
|
const { domain, port } = body;
|
||||||
|
const result = await this.netTestService.telnet(domain, port);
|
||||||
|
return this.ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// telnet
|
||||||
|
@Post('/serverInfo', { summary: 'sys:settings:view' })
|
||||||
|
public async serverInfo() {
|
||||||
|
|
||||||
|
const result = await this.netTestService.serverInfo();
|
||||||
|
return this.ok(result);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,208 @@
|
||||||
|
import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
|
import { http, utils } from '@certd/basic';
|
||||||
|
|
||||||
|
// 使用@certd/basic包中已有的utils.sp.spawn函数替代自定义的asyncExec
|
||||||
|
// 该函数已经内置了Windows系统编码问题的解决方案
|
||||||
|
|
||||||
|
export type NetTestResult = {
|
||||||
|
success: boolean; //是否成功
|
||||||
|
message: string; //结果
|
||||||
|
testLog: string; //测试日志
|
||||||
|
error?: string; //执行错误信息
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provide('nettestService')
|
||||||
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||||
|
export class NetTestService {
|
||||||
|
/**
|
||||||
|
* 执行Telnet测试
|
||||||
|
* @param domain 域名
|
||||||
|
* @param port 端口
|
||||||
|
* @returns 测试结果
|
||||||
|
*/
|
||||||
|
async telnet(domain: string, port: number): Promise<NetTestResult> {
|
||||||
|
try {
|
||||||
|
let command = '';
|
||||||
|
|
||||||
|
if (this.isWindows()) {
|
||||||
|
// Windows系统使用PowerShell执行测试,避免输入重定向问题
|
||||||
|
// 使用PowerShell的Test-NetConnection命令进行端口测试
|
||||||
|
command = `powershell -Command "& { $result = Test-NetConnection -ComputerName ${domain} -Port ${port} -InformationLevel Quiet; if ($result) { Write-Host '端口连接成功' } else { Write-Host '端口连接失败' } }"`;
|
||||||
|
} else {
|
||||||
|
// Linux系统使用nc命令进行端口测试
|
||||||
|
command = `nc -zv -w 5 ${domain} ${port} 2>&1`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用utils.sp.spawn执行命令,它会自动处理Windows编码问题
|
||||||
|
const output = await utils.sp.spawn({
|
||||||
|
cmd: command,
|
||||||
|
logger: undefined // 可以根据需要传入logger
|
||||||
|
});
|
||||||
|
|
||||||
|
// 判断测试是否成功
|
||||||
|
const success = this.isWindows()
|
||||||
|
? output.includes('端口连接成功')
|
||||||
|
: output.includes('succeeded') || output.includes('open');
|
||||||
|
|
||||||
|
// 处理结果
|
||||||
|
return {
|
||||||
|
success,
|
||||||
|
message: success ? '端口连接测试成功' : '端口连接测试失败',
|
||||||
|
testLog: output,
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: 'Telnet测试执行失败',
|
||||||
|
testLog: error instanceof Error ? error.message : String(error),
|
||||||
|
error: error instanceof Error ? error.message : String(error)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行Ping测试
|
||||||
|
* @param domain 域名
|
||||||
|
* @returns 测试结果
|
||||||
|
*/
|
||||||
|
async ping(domain: string): Promise<NetTestResult> {
|
||||||
|
try {
|
||||||
|
let command = '';
|
||||||
|
|
||||||
|
if (this.isWindows()) {
|
||||||
|
// Windows系统ping命令,发送4个包
|
||||||
|
command = `ping -n 4 ${domain}`;
|
||||||
|
} else {
|
||||||
|
// Linux系统ping命令,发送4个包
|
||||||
|
command = `ping -c 4 ${domain}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用utils.sp.spawn执行命令
|
||||||
|
const output = await utils.sp.spawn({
|
||||||
|
cmd: command,
|
||||||
|
logger: undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
// 判断测试是否成功
|
||||||
|
const success = this.isWindows()
|
||||||
|
? output.includes('TTL=')
|
||||||
|
: output.includes('0% packet loss');
|
||||||
|
|
||||||
|
return {
|
||||||
|
success,
|
||||||
|
message: success ? 'Ping测试成功' : 'Ping测试失败',
|
||||||
|
testLog: output,
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: 'Ping测试执行失败',
|
||||||
|
testLog: errorMessage,
|
||||||
|
error: errorMessage
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private isWindows() {
|
||||||
|
return process.platform === 'win32';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行域名解析测试
|
||||||
|
* @param domain 域名
|
||||||
|
* @returns 解析结果
|
||||||
|
*/
|
||||||
|
async domainResolve(domain: string): Promise<NetTestResult> {
|
||||||
|
try {
|
||||||
|
let command = '';
|
||||||
|
if (this.isWindows()) {
|
||||||
|
// Windows系统使用nslookup命令
|
||||||
|
command = `nslookup ${domain}`;
|
||||||
|
} else {
|
||||||
|
// Linux系统优先使用dig命令,如果没有则回退到nslookup
|
||||||
|
command = `which dig > /dev/null && dig ${domain} || nslookup ${domain}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用utils.sp.spawn执行命令
|
||||||
|
const output = await utils.sp.spawn({
|
||||||
|
cmd: command,
|
||||||
|
logger: undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
// 判断测试是否成功
|
||||||
|
const success = output.includes('Address:') || output.includes('IN A') ||
|
||||||
|
(this.isWindows() && output.includes('Name:'));
|
||||||
|
|
||||||
|
return {
|
||||||
|
success,
|
||||||
|
message: success ? '域名解析测试成功' : '域名解析测试失败',
|
||||||
|
testLog: output,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: '域名解析测试执行失败',
|
||||||
|
testLog: errorMessage,
|
||||||
|
error: errorMessage
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async getLocalIP(): Promise<string> {
|
||||||
|
try {
|
||||||
|
const output = await utils.sp.spawn({
|
||||||
|
cmd: 'bash -c "ip a | grep \'inet \' | grep -v \'127.0.0.1\' | awk \'{print $2}\' | cut -d/ -f1"',
|
||||||
|
logger: undefined
|
||||||
|
});
|
||||||
|
return output.trim();
|
||||||
|
} catch (error) {
|
||||||
|
return error instanceof Error ? error.message : String(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getPublicIP(): Promise<string> {
|
||||||
|
try {
|
||||||
|
const res = await http.request({
|
||||||
|
url:"https://ipinfo.io/ip",
|
||||||
|
method:"GET",
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
} catch (error) {
|
||||||
|
return error instanceof Error ? error.message : String(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getDNSservers(): Promise<string[]> {
|
||||||
|
try {
|
||||||
|
const output = await utils.sp.spawn({
|
||||||
|
cmd: 'cat /etc/resolv.conf | grep nameserver | awk \'{print $2}\'',
|
||||||
|
logger: undefined
|
||||||
|
});
|
||||||
|
return output.trim().split('\n');
|
||||||
|
} catch (error) {
|
||||||
|
return [error instanceof Error ? error.message : String(error)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取服务器信息(包括本地IP、外网IP和DNS服务器)
|
||||||
|
* @returns 服务器信息
|
||||||
|
*/
|
||||||
|
async serverInfo(): Promise<any> {
|
||||||
|
|
||||||
|
const res = {
|
||||||
|
localIP: '',
|
||||||
|
publicIP: '',
|
||||||
|
dnsServers: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
res.localIP = await this.getLocalIP();
|
||||||
|
res.publicIP = await this.getPublicIP();
|
||||||
|
res.dnsServers = await this.getDNSservers();
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,9 +8,6 @@ importers:
|
||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/ui-server':
|
|
||||||
specifier: link:packages/ui/certd-server
|
|
||||||
version: link:packages/ui/certd-server
|
|
||||||
axios:
|
axios:
|
||||||
specifier: ^1.7.7
|
specifier: ^1.7.7
|
||||||
version: 1.9.0(debug@4.4.1)
|
version: 1.9.0(debug@4.4.1)
|
||||||
|
@ -49,7 +46,7 @@ importers:
|
||||||
packages/core/acme-client:
|
packages/core/acme-client:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../basic
|
version: link:../basic
|
||||||
'@peculiar/x509':
|
'@peculiar/x509':
|
||||||
specifier: ^1.11.0
|
specifier: ^1.11.0
|
||||||
|
@ -210,10 +207,10 @@ importers:
|
||||||
packages/core/pipeline:
|
packages/core/pipeline:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../basic
|
version: link:../basic
|
||||||
'@certd/plus-core':
|
'@certd/plus-core':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../pro/plus-core
|
version: link:../../pro/plus-core
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.7
|
specifier: ^1.11.7
|
||||||
|
@ -418,7 +415,7 @@ importers:
|
||||||
packages/libs/lib-k8s:
|
packages/libs/lib-k8s:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@kubernetes/client-node':
|
'@kubernetes/client-node':
|
||||||
specifier: 0.21.0
|
specifier: 0.21.0
|
||||||
|
@ -458,19 +455,19 @@ importers:
|
||||||
packages/libs/lib-server:
|
packages/libs/lib-server:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/acme-client':
|
'@certd/acme-client':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../core/acme-client
|
version: link:../../core/acme-client
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@certd/plugin-lib':
|
'@certd/plugin-lib':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../plugins/plugin-lib
|
version: link:../../plugins/plugin-lib
|
||||||
'@certd/plus-core':
|
'@certd/plus-core':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../pro/plus-core
|
version: link:../../pro/plus-core
|
||||||
'@midwayjs/cache':
|
'@midwayjs/cache':
|
||||||
specifier: 3.14.0
|
specifier: 3.14.0
|
||||||
|
@ -616,16 +613,16 @@ importers:
|
||||||
packages/plugins/plugin-cert:
|
packages/plugins/plugin-cert:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/acme-client':
|
'@certd/acme-client':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../core/acme-client
|
version: link:../../core/acme-client
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@certd/plugin-lib':
|
'@certd/plugin-lib':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../plugin-lib
|
version: link:../plugin-lib
|
||||||
'@google-cloud/publicca':
|
'@google-cloud/publicca':
|
||||||
specifier: ^1.3.0
|
specifier: ^1.3.0
|
||||||
|
@ -707,10 +704,10 @@ importers:
|
||||||
specifier: ^3.787.0
|
specifier: ^3.787.0
|
||||||
version: 3.810.0(aws-crt@1.26.2)
|
version: 3.810.0(aws-crt@1.26.2)
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@kubernetes/client-node':
|
'@kubernetes/client-node':
|
||||||
specifier: 0.21.0
|
specifier: 0.21.0
|
||||||
|
@ -798,19 +795,19 @@ importers:
|
||||||
packages/pro/commercial-core:
|
packages/pro/commercial-core:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@certd/lib-server':
|
'@certd/lib-server':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../libs/lib-server
|
version: link:../../libs/lib-server
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@certd/plugin-plus':
|
'@certd/plugin-plus':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../plugin-plus
|
version: link:../plugin-plus
|
||||||
'@certd/plus-core':
|
'@certd/plus-core':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../plus-core
|
version: link:../plus-core
|
||||||
'@midwayjs/core':
|
'@midwayjs/core':
|
||||||
specifier: 3.20.11
|
specifier: 3.20.11
|
||||||
|
@ -895,19 +892,19 @@ importers:
|
||||||
specifier: ^1.0.2
|
specifier: ^1.0.2
|
||||||
version: 1.0.3
|
version: 1.0.3
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@certd/lib-k8s':
|
'@certd/lib-k8s':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../libs/lib-k8s
|
version: link:../../libs/lib-k8s
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@certd/plugin-cert':
|
'@certd/plugin-cert':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../plugins/plugin-cert
|
version: link:../../plugins/plugin-cert
|
||||||
'@certd/plus-core':
|
'@certd/plus-core':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../plus-core
|
version: link:../plus-core
|
||||||
ali-oss:
|
ali-oss:
|
||||||
specifier: ^6.21.0
|
specifier: ^6.21.0
|
||||||
|
@ -1010,7 +1007,7 @@ importers:
|
||||||
packages/pro/plus-core:
|
packages/pro/plus-core:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.7
|
specifier: ^1.11.7
|
||||||
|
@ -1306,10 +1303,10 @@ importers:
|
||||||
version: 0.1.3(zod@3.24.4)
|
version: 0.1.3(zod@3.24.4)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@certd/lib-iframe':
|
'@certd/lib-iframe':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../libs/lib-iframe
|
version: link:../../libs/lib-iframe
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@rollup/plugin-commonjs':
|
'@rollup/plugin-commonjs':
|
||||||
specifier: ^25.0.7
|
specifier: ^25.0.7
|
||||||
|
@ -1492,46 +1489,46 @@ importers:
|
||||||
specifier: ^3.705.0
|
specifier: ^3.705.0
|
||||||
version: 3.810.0(aws-crt@1.26.2)
|
version: 3.810.0(aws-crt@1.26.2)
|
||||||
'@certd/acme-client':
|
'@certd/acme-client':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../core/acme-client
|
version: link:../../core/acme-client
|
||||||
'@certd/basic':
|
'@certd/basic':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../core/basic
|
version: link:../../core/basic
|
||||||
'@certd/commercial-core':
|
'@certd/commercial-core':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../pro/commercial-core
|
version: link:../../pro/commercial-core
|
||||||
'@certd/cv4pve-api-javascript':
|
'@certd/cv4pve-api-javascript':
|
||||||
specifier: ^8.4.2
|
specifier: ^8.4.2
|
||||||
version: 8.4.2
|
version: 8.4.2
|
||||||
'@certd/jdcloud':
|
'@certd/jdcloud':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../libs/lib-jdcloud
|
version: link:../../libs/lib-jdcloud
|
||||||
'@certd/lib-huawei':
|
'@certd/lib-huawei':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../libs/lib-huawei
|
version: link:../../libs/lib-huawei
|
||||||
'@certd/lib-k8s':
|
'@certd/lib-k8s':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../libs/lib-k8s
|
version: link:../../libs/lib-k8s
|
||||||
'@certd/lib-server':
|
'@certd/lib-server':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../libs/lib-server
|
version: link:../../libs/lib-server
|
||||||
'@certd/midway-flyway-js':
|
'@certd/midway-flyway-js':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../libs/midway-flyway-js
|
version: link:../../libs/midway-flyway-js
|
||||||
'@certd/pipeline':
|
'@certd/pipeline':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../core/pipeline
|
version: link:../../core/pipeline
|
||||||
'@certd/plugin-cert':
|
'@certd/plugin-cert':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../plugins/plugin-cert
|
version: link:../../plugins/plugin-cert
|
||||||
'@certd/plugin-lib':
|
'@certd/plugin-lib':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../plugins/plugin-lib
|
version: link:../../plugins/plugin-lib
|
||||||
'@certd/plugin-plus':
|
'@certd/plugin-plus':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../pro/plugin-plus
|
version: link:../../pro/plugin-plus
|
||||||
'@certd/plus-core':
|
'@certd/plus-core':
|
||||||
specifier: ^1.36.24
|
specifier: ^1.37.1
|
||||||
version: link:../../pro/plus-core
|
version: link:../../pro/plus-core
|
||||||
'@huaweicloud/huaweicloud-sdk-cdn':
|
'@huaweicloud/huaweicloud-sdk-cdn':
|
||||||
specifier: ^3.1.120
|
specifier: ^3.1.120
|
||||||
|
|
Loading…
Reference in New Issue