Compare commits
9
Commits
c7b5ef75a3
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0267fac3a1 | ||
|
|
01fb8bb7c2 | ||
|
|
d20dc84d9d | ||
|
|
c1be93739d | ||
|
|
370ec61f3d | ||
|
|
e0d967f736 | ||
|
|
a27291d82b | ||
|
|
2e5203c69a | ||
|
|
5e254af81f |
No files matched your search
@@ -9,6 +9,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: debian:12
|
||||
env:
|
||||
DOCKER_DEFAULT_PLATFORM: linux/amd64
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
|
||||
@@ -2,9 +2,13 @@
|
||||
<div :class="wrapperClass">
|
||||
<div class="cm-header">
|
||||
<div class="cm-header-title">
|
||||
<span>CodeMirror</span>
|
||||
<span>{{ props.type ?? 'CodeMirror' }}</span>
|
||||
</div>
|
||||
<div class="cm-header-controls">
|
||||
<div class="cm-header-controls-copy" :class="{ 'cm-header-controls-copy-hide': !show }"
|
||||
@click="copyCode">
|
||||
复制
|
||||
</div>
|
||||
<div class="cm-switch-show-hide" @click="show = !show">
|
||||
{{ show ? '收起' : '展开' }}
|
||||
</div>
|
||||
@@ -106,6 +110,11 @@ const useLangExtensions = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const copyCode = () => {
|
||||
navigator.clipboard.writeText(props.data)
|
||||
ElMessage.success('复制成功')
|
||||
}
|
||||
|
||||
let cm: EditorView
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -142,13 +151,16 @@ onBeforeUnmount(() => {
|
||||
.cm-rander-wrapper {
|
||||
&-inline {
|
||||
display: inline-block;
|
||||
|
||||
.cm-header {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.cm-gutters {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.cm-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -161,6 +173,23 @@ onBeforeUnmount(() => {
|
||||
user-select: none;
|
||||
|
||||
.cm-header-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
|
||||
.cm-header-controls-copy {
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
fill: #fff;
|
||||
transition: all 0.2s ease;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.cm-header-controls-copy-hide {
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.cm-switch-show-hide {
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
|
||||
+180
-53
@@ -2,79 +2,43 @@
|
||||
|
||||
<template>
|
||||
<div class="md-render-wrapper markdown-body">
|
||||
<!-- <div v-html="renderedData" :key="_key"></div> -->
|
||||
<VNodeArr></VNodeArr>
|
||||
<VNodeMD v-if="VNodeMD && props.data"></VNodeMD>
|
||||
<div v-else>
|
||||
<el-skeleton v-if="!props.disableSkeleton" :rows="12" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import codemirrorMiddleware from '~/hooks/h2v/codemirrorMiddleware';
|
||||
import useMarkdownit from '~/hooks/useMarkdownit';
|
||||
import Html2VNode from '~/utils/html2VNode';
|
||||
import codeMirror from './codeMirror.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
data: string
|
||||
disableSkeleton?: boolean
|
||||
}>()
|
||||
|
||||
const _key = ref(Math.random())
|
||||
const VNodeMD = shallowRef<any>()
|
||||
|
||||
const markdownIt = await useMarkdownit()
|
||||
|
||||
const VNodeArr = computed(() => {
|
||||
watch(() => props.data, async () => {
|
||||
if (!props.data) {
|
||||
return () => []
|
||||
}
|
||||
const markdownIt = await useMarkdownit()
|
||||
const renderedData = markdownIt.render(props.data)
|
||||
const h2v = new Html2VNode()
|
||||
h2v.use(
|
||||
{
|
||||
filter(tagName) {
|
||||
return tagName === 'code'
|
||||
},
|
||||
rander({
|
||||
item,
|
||||
// tagName,
|
||||
tagAttrs,
|
||||
// middlewareMap
|
||||
}) {
|
||||
// console.log({
|
||||
// tagName,
|
||||
// tagAttrs,
|
||||
// })
|
||||
const codeType = tagAttrs?.class?.slice(1, -1)?.split('-')?.[1] ?? ''
|
||||
// console.log({
|
||||
// codeType,
|
||||
// })
|
||||
// @ts-ignore
|
||||
const inline = (item.children[0].children.trim() as string).includes('\n') ? false : true
|
||||
console.log({
|
||||
inline,
|
||||
c: item.children
|
||||
})
|
||||
return h(
|
||||
codeMirror,
|
||||
{
|
||||
// @ts-ignore
|
||||
data: item.children[0].children.trim(),
|
||||
type: codeType,
|
||||
inline,
|
||||
},
|
||||
)
|
||||
},
|
||||
}
|
||||
)
|
||||
const res = h2v.rander(renderedData)
|
||||
return {
|
||||
h2v.use(codemirrorMiddleware)
|
||||
const res = await h2v.render(renderedData)
|
||||
VNodeMD.value = {
|
||||
setup: () => {
|
||||
return () => res
|
||||
},
|
||||
}
|
||||
}, {
|
||||
immediate: true
|
||||
})
|
||||
|
||||
// watch(() => renderedData.value, () => {
|
||||
// _key.value = Math.random()
|
||||
// })
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@@ -92,11 +56,174 @@ const VNodeArr = computed(() => {
|
||||
|
||||
hr {
|
||||
display: block;
|
||||
margin: 0;
|
||||
margin: 1em 0;
|
||||
padding-top: 1em;
|
||||
unicode-bidi: isolate;
|
||||
overflow: hidden;
|
||||
border-style: inset;
|
||||
border-width: 0;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* 恢复标题样式 */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 0.5em;
|
||||
font-weight: bold;
|
||||
line-height: 1.25;
|
||||
color: #111;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
border-bottom: 1px solid #eaecef;
|
||||
padding-bottom: 0.3em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.5em;
|
||||
border-bottom: 1px solid #eaecef;
|
||||
padding-bottom: 0.3em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 0.85em;
|
||||
color: #6a737d;
|
||||
}
|
||||
|
||||
/* 恢复段落样式 */
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1em;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* 恢复列表样式 */
|
||||
ul,
|
||||
ol {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1em;
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
ol {
|
||||
list-style-type: decimal;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
|
||||
li>ul,
|
||||
li>ol {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* 恢复链接样式 */
|
||||
a {
|
||||
color: #0366d6;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
/* 恢复引用块样式 */
|
||||
blockquote {
|
||||
margin: 0 0 1em;
|
||||
padding: 0 1em;
|
||||
color: #6a737d;
|
||||
border-left: 0.25em solid #dfe2e5;
|
||||
|
||||
> :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
> :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 恢复表格样式 */
|
||||
table {
|
||||
display: block;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1em;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: 600;
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #dfe2e5;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #dfe2e5;
|
||||
}
|
||||
|
||||
tr {
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #c6cbd1;
|
||||
|
||||
&:nth-child(2n) {
|
||||
background-color: #f6f8fa;
|
||||
}
|
||||
}
|
||||
|
||||
/* 恢复行内代码样式 */
|
||||
code:not(pre code) {
|
||||
padding: 0.2em 0.4em;
|
||||
margin: 0;
|
||||
font-size: 85%;
|
||||
background-color: rgba(27, 31, 35, 0.05);
|
||||
border-radius: 3px;
|
||||
font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
|
||||
}
|
||||
|
||||
/* 恢复图片样式 */
|
||||
img {
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
/* 恢复预格式化文本样式 */
|
||||
pre {
|
||||
padding: 16px;
|
||||
overflow: auto;
|
||||
font-size: 85%;
|
||||
line-height: 1.45;
|
||||
background-color: #f6f8fa;
|
||||
border-radius: 3px;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1em;
|
||||
word-wrap: normal;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -18,7 +18,31 @@
|
||||
</el-input>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-input type="textarea" v-model:model-value="content" placeholder="content" :autosize="{ minRows: 15 }" :disabled="disabled"/>
|
||||
<el-row>
|
||||
<el-col :span="16"></el-col>
|
||||
<el-col :span="8">
|
||||
<div
|
||||
class="switch-button overflow-hidden z-10 border-0 border-gray-300 rounded-bl-sm rounded-tr-sm flex select-none">
|
||||
<div class="switch-button-item" :class="{ 'switch-button-item-active': isEditing }"
|
||||
@click="isEditing = true">
|
||||
编辑
|
||||
</div>
|
||||
<div class="switch-button-item" :class="{ 'switch-button-item-active': !isEditing }"
|
||||
@click="isEditing = false">
|
||||
预览
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col>
|
||||
<el-input v-if="isEditing" type="textarea" v-model:model-value="content" placeholder="content"
|
||||
:autosize="{ minRows: 15 }" :disabled="disabled" />
|
||||
<div class=" border-1 border-gray-300 rounded-sm p-2" v-else>
|
||||
<markdown-render :data="content ?? ''" :disable-skeleton="true" />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -33,6 +57,8 @@ const summary = defineModel<string>('summary')
|
||||
const tags = defineModel<string[]>('tags')
|
||||
const content = defineModel<string>('content')
|
||||
|
||||
const isEditing = ref(true)
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -42,3 +68,30 @@ const content = defineModel<string>('content')
|
||||
gap: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.switch-button {
|
||||
|
||||
&-item {
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
cursor: pointer;
|
||||
transition: all .15s ease;
|
||||
padding: 0 5px;
|
||||
|
||||
&:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
&-active {
|
||||
color: #0077ff;
|
||||
background-color: #d3e7ff;
|
||||
|
||||
&:hover {
|
||||
background-color: #c3e0ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,28 @@
|
||||
const codemirrorMiddleware: middlewareType = {
|
||||
filter(tagName: string) {
|
||||
return tagName === 'code'
|
||||
},
|
||||
async render({
|
||||
item,
|
||||
tagAttrs,
|
||||
}) {
|
||||
const codeMirror = await cachedPromise('component:codeMirror', async () => {
|
||||
const codeMirror = (await import('~/components/codeMirror.vue')).default
|
||||
return codeMirror
|
||||
})
|
||||
const codeType = tagAttrs?.class?.slice(1, -1)?.split('-')?.[1] ?? ''
|
||||
// @ts-ignore
|
||||
const inline = (item.children[0].children.trim() as string).includes('\n') ? false : true
|
||||
return h(
|
||||
codeMirror,
|
||||
{
|
||||
// @ts-ignore
|
||||
data: item.children[0].children.trim(),
|
||||
type: codeType,
|
||||
inline,
|
||||
},
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
export default codemirrorMiddleware
|
||||
+21
-2
@@ -4,7 +4,7 @@
|
||||
<span>导航</span>
|
||||
</div>
|
||||
<div class="content-wrap">
|
||||
<div v-for="(item) in PageContent" :key="item.subTitle" class="content">
|
||||
<div v-for="(item) in pageContent" :key="item.subTitle" class="content">
|
||||
<div class="sub-title">
|
||||
<miao-divider-left>
|
||||
<div class="sub-title-wrapper">
|
||||
@@ -60,7 +60,7 @@ type ContentItem = {
|
||||
}[]
|
||||
}
|
||||
|
||||
const PageContent = reactive<PageContent[]>([
|
||||
const pageContent = reactive<PageContent[]>([
|
||||
{
|
||||
subTitle: '个人项目',
|
||||
show: true,
|
||||
@@ -89,6 +89,25 @@ const PageContent = reactive<PageContent[]>([
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Bobj',
|
||||
description: '模块化的JS对象序列化库,名字完全抄袭至BSON',
|
||||
links: [
|
||||
{
|
||||
name: "github",
|
||||
url: "https://github.com/Zioywishing/bobj"
|
||||
}, {
|
||||
name: "npm",
|
||||
url: "https://www.npmjs.com/package/bobj"
|
||||
}
|
||||
],
|
||||
nuxtLinks: [
|
||||
{
|
||||
name: 'demo',
|
||||
to: `/iframe/${encodeURIComponent('/iframe-source/bobj-demo/index.html')}`
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'MiaoBlog',
|
||||
description: '施工中,不过最好不要抱有太大期待,毕竟还是以实现功能为目标去做的',
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<template>
|
||||
<div class="user-wrapper">
|
||||
<Suspense>
|
||||
<NuxtPage />
|
||||
</Suspense>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
+17
-22
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="posts-wrapper">
|
||||
<article class="posts-item" v-for="post in postsData" :key="post.id">
|
||||
<article class="posts-item" v-for="post in posts" :key="post.id">
|
||||
<header class="post-title">
|
||||
<nuxt-link :to="`/posts/post-${post.id}`">{{ post.title }}</nuxt-link>
|
||||
</header>
|
||||
@@ -18,7 +18,7 @@
|
||||
</div>
|
||||
</footer>
|
||||
</article>
|
||||
<div class="posts-skeleton" v-if="!isInit">
|
||||
<div class="posts-skeleton" v-if="pending && 0">
|
||||
<div class="posts-skeleton-item" v-for="_ in range(5)">
|
||||
<el-skeleton :rows="3" />
|
||||
</div>
|
||||
@@ -33,29 +33,24 @@ import bookmark from '~/components/icons/tag.vue'
|
||||
import type { postItem } from '~/types/post';
|
||||
|
||||
const store = useDefaultStore()
|
||||
const isInit = ref(false)
|
||||
|
||||
const postsData = ref<postItem[]>([])
|
||||
|
||||
const getData = async () => {
|
||||
const cache = store.getCache('posts')
|
||||
if (cache) {
|
||||
return cache as postItem[]
|
||||
// 使用useFetch在服务器端获取数据
|
||||
const { data, pending } = await useFetch<{ code: number, data: postItem[] }>('/api/posts/getPostList', {
|
||||
// 如果缓存中已有数据,优先使用缓存
|
||||
key: 'posts-list',
|
||||
transform: (response) => {
|
||||
if (response && response.data) {
|
||||
store.setCache('posts', response.data)
|
||||
return response
|
||||
}
|
||||
const response = await $fetch('/api/posts/getPostList')
|
||||
const res = response.data
|
||||
store.setCache('posts', res)
|
||||
return res
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
// router.push('/posts/temp')
|
||||
// await sleep(1000)
|
||||
postsData.value = await getData()
|
||||
isInit.value = true;
|
||||
// console.log(postsData.value)
|
||||
return { code: 0, data: [] }
|
||||
},
|
||||
// 添加以下选项
|
||||
lazy: true, // 避免客户端自动重新获取
|
||||
server: true, // 仅在服务器端获取数据
|
||||
})
|
||||
|
||||
// 从响应中提取文章列表
|
||||
const posts = computed(() => data.value?.data || []) as ComputedRef<postItem[]>
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
+12
-51
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div class="md-wrapper">
|
||||
<div class="md" v-if="isInit">
|
||||
<div class="md-title">{{ title }}</div>
|
||||
<div class="md" v-if="!loading && postData">
|
||||
<div class="md-title">{{ postData.title }}</div>
|
||||
<div class="md-divider"></div>
|
||||
<markdown-render :data="content"></markdown-render>
|
||||
<markdown-render :data="postData.data"></markdown-render>
|
||||
</div>
|
||||
<div v-else class="md-skeleton-item">
|
||||
<el-skeleton :rows="12" />
|
||||
@@ -12,61 +12,22 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import useMarkdownit from '~/hooks/useMarkdownit';
|
||||
import usePostStore from '~/hooks/pinia/usePostStore';
|
||||
import markdownRender from '~/components/markdownRender.vue';
|
||||
import type { postContent } from '~/types/post';
|
||||
|
||||
const postStore = usePostStore()
|
||||
|
||||
const markdownRender = shallowRef<any>()
|
||||
const route = useRoute()
|
||||
|
||||
const isInit = ref(false)
|
||||
|
||||
const title = ref('')
|
||||
|
||||
const content = ref('')
|
||||
|
||||
const renderedData = ref('')
|
||||
|
||||
const id = route.params.id as string
|
||||
|
||||
onMounted(async () => {
|
||||
const loading = ref(true)
|
||||
|
||||
const _p = new Promise<postContent>(async (resolve, reject) => {
|
||||
try {
|
||||
const cache = postStore.getPostCache(id)
|
||||
if (cache) {
|
||||
resolve(cache)
|
||||
return
|
||||
}
|
||||
const res = await $fetch('/api/posts/getPostContent', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
id
|
||||
}
|
||||
}) as postContent
|
||||
postStore.setPostCache(id, res)
|
||||
resolve(res)
|
||||
} catch (error) {
|
||||
reject(error)
|
||||
}
|
||||
const postData = ref<postContent>()
|
||||
|
||||
onBeforeMount(async () => {
|
||||
const postDataPromise = getPostData(Number(id))
|
||||
markdownRender.value = (await import('~/components/markdownRender.vue')).default
|
||||
postData.value = await postDataPromise
|
||||
loading.value = false
|
||||
})
|
||||
|
||||
const markdownIt = await useMarkdownit()
|
||||
|
||||
const postsData = await _p
|
||||
|
||||
content.value = postsData.data
|
||||
|
||||
renderedData.value = markdownIt.render(postsData.data)
|
||||
|
||||
title.value = postsData.title
|
||||
|
||||
isInit.value = true
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
+207
-5
@@ -1,13 +1,215 @@
|
||||
<template>
|
||||
<div class=" flex justify-center items-center h-full">
|
||||
主页还没做
|
||||
<div class="p-6">
|
||||
<div class="bg-white rounded-lg shadow-md p-6">
|
||||
<h1 class="text-2xl font-bold mb-6 text-gray-800">系统信息</h1>
|
||||
|
||||
<div v-if="isLoading" class="flex justify-center items-center h-40">
|
||||
<div class="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500"></div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="error" class="text-red-500 text-center">
|
||||
{{ error }}
|
||||
</div>
|
||||
|
||||
<div v-else class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<!-- 系统信息 -->
|
||||
<div class="bg-gray-50 p-4 rounded-lg">
|
||||
<h2 class="text-lg font-semibold mb-3 text-gray-700">操作系统</h2>
|
||||
<div class="space-y-2">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">平台:</span>
|
||||
<span class="font-medium">{{ systemInfo?.system?.platform }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">版本:</span>
|
||||
<span class="font-medium">{{ systemInfo?.system?.release }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">主机名:</span>
|
||||
<span class="font-medium">{{ systemInfo?.system?.hostname }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">Node.js版本:</span>
|
||||
<span class="font-medium">{{ systemInfo?.node }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 硬件信息 -->
|
||||
<div class="bg-gray-50 p-4 rounded-lg">
|
||||
<h2 class="text-lg font-semibold mb-3 text-gray-700">硬件信息</h2>
|
||||
<div class="space-y-2">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">CPU型号:</span>
|
||||
<span class="font-medium">{{ systemInfo?.hardware?.cpu?.model }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">CPU核心数:</span>
|
||||
<span class="font-medium">{{ systemInfo?.hardware?.cpu?.cores }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">CPU使用率:</span>
|
||||
<div class="w-32 bg-gray-200 rounded-full h-4 overflow-hidden">
|
||||
<div class="bg-blue-600 h-4 rounded-full" :style="`width: ${performanceData?.cpu?.usage < 5 ? 5 : performanceData?.cpu?.usage}%`"></div>
|
||||
</div>
|
||||
<span class="font-medium">{{ performanceData?.cpu?.usage }}%</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">内存使用情况:</span>
|
||||
<span class="font-medium">{{ performanceData?.memory?.used || systemInfo?.hardware?.memory?.used }} / {{ performanceData?.memory?.total || systemInfo?.hardware?.memory?.total }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600">内存使用率:</span>
|
||||
<div class="w-32 bg-gray-200 rounded-full h-4 overflow-hidden">
|
||||
<div class="bg-green-600 h-4 rounded-full" :style="`width: ${performanceData?.memory?.percent}%`"></div>
|
||||
</div>
|
||||
<span class="font-medium">{{ performanceData?.memory?.percent }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-gray-500 text-sm flex justify-between">
|
||||
<div>性能数据更新时间: {{ performanceUpdated }}</div>
|
||||
<div>系统数据更新时间: {{ lastUpdated }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const systemInfo = ref<any>(null);
|
||||
const performanceData = ref<any>(null);
|
||||
const isLoading = ref(true);
|
||||
const error = ref('');
|
||||
const lastUpdated = ref('');
|
||||
const performanceUpdated = ref('');
|
||||
|
||||
// 格式化时间
|
||||
const formatTime = () => {
|
||||
const now = new Date();
|
||||
const hours = now.getHours().toString().padStart(2, '0');
|
||||
const minutes = now.getMinutes().toString().padStart(2, '0');
|
||||
const seconds = now.getSeconds().toString().padStart(2, '0');
|
||||
return `${hours}:${minutes}:${seconds}`;
|
||||
};
|
||||
|
||||
// 定义API响应类型
|
||||
interface SystemInfoResponse {
|
||||
success: boolean;
|
||||
data?: {
|
||||
system: {
|
||||
platform: string;
|
||||
release: string;
|
||||
hostname: string;
|
||||
};
|
||||
node: string;
|
||||
hardware: {
|
||||
cpu: {
|
||||
model: string;
|
||||
cores: number;
|
||||
usage: number;
|
||||
};
|
||||
memory: {
|
||||
total: string;
|
||||
free: string;
|
||||
used: string;
|
||||
percent: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
message?: string;
|
||||
}
|
||||
|
||||
interface PerformanceResponse {
|
||||
success: boolean;
|
||||
data?: {
|
||||
cpu: {
|
||||
usage: number;
|
||||
};
|
||||
memory: {
|
||||
total: string;
|
||||
free: string;
|
||||
used: string;
|
||||
percent: number;
|
||||
};
|
||||
};
|
||||
message?: string;
|
||||
}
|
||||
|
||||
// 获取系统信息
|
||||
const fetchSystemInfo = async () => {
|
||||
try {
|
||||
if (!systemInfo.value) {
|
||||
isLoading.value = true;
|
||||
}
|
||||
error.value = '';
|
||||
|
||||
const response = await $fetch<SystemInfoResponse>('/api/system/info');
|
||||
|
||||
if (response && response.success && response.data) {
|
||||
systemInfo.value = response.data;
|
||||
|
||||
// 如果还没有性能数据,初始化它
|
||||
if (!performanceData.value) {
|
||||
performanceData.value = {
|
||||
cpu: {
|
||||
usage: response.data.hardware.cpu.usage
|
||||
},
|
||||
memory: response.data.hardware.memory
|
||||
};
|
||||
}
|
||||
|
||||
lastUpdated.value = formatTime();
|
||||
} else {
|
||||
error.value = response?.message || '获取系统信息失败';
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = '请求发生错误';
|
||||
console.error('Error fetching system info:', err);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取性能数据(CPU和内存使用率)
|
||||
const fetchPerformanceData = async () => {
|
||||
try {
|
||||
const response = await $fetch<PerformanceResponse>('/api/system/performance');
|
||||
|
||||
if (response && response.success && response.data) {
|
||||
performanceData.value = response.data;
|
||||
performanceUpdated.value = formatTime();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error fetching performance data:', err);
|
||||
}
|
||||
};
|
||||
|
||||
// 首次获取数据
|
||||
onMounted(() => {
|
||||
// 获取完整系统信息
|
||||
fetchSystemInfo();
|
||||
|
||||
// 设置30秒定时更新系统信息
|
||||
const systemTimer = setInterval(() => {
|
||||
fetchSystemInfo();
|
||||
}, 30000);
|
||||
|
||||
// 立即获取一次性能数据
|
||||
fetchPerformanceData();
|
||||
|
||||
// 设置5秒定时更新性能数据
|
||||
const performanceTimer = setInterval(() => {
|
||||
fetchPerformanceData();
|
||||
}, 5000);
|
||||
|
||||
// 组件卸载时清除定时器
|
||||
onUnmounted(() => {
|
||||
clearInterval(systemTimer);
|
||||
clearInterval(performanceTimer);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1 @@
|
||||
(function(){"use strict";var w=r=>{throw TypeError(r)},g=(r,e,t)=>e.has(r)||w("Cannot "+t),l=(r,e,t)=>(g(r,e,"read from private field"),e.get(r)),f=(r,e,t)=>e.has(r)?w("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(r):e.set(r,t);function z(r){const e=new ArrayBuffer(8),t=new Uint8Array(e);for(let a=0;a<8;a++)t[a]=r[a]||0;return new DataView(e).getFloat64(0,!0)}const p=[{filter:new Uint8Array([0]),deserialize:r=>r.deserializer.deserialize(r.targetArray)},{filter:new Uint8Array([1]),deserialize:async r=>{const e=await r.deserializer.deserialize(r.targetArray),t=new Array(e.l).fill(0);for(let a=0;a<e.l;a++)t[a]=e[a];return t}},{filter:new Uint8Array([2]),deserialize:r=>new Uint8Array(r.targetArray)},{filter:new Uint8Array([3]),deserialize:r=>new TextDecoder().decode(r.targetArray)},{filter:new Uint8Array([4]),deserialize:r=>z(r.targetArray)},{filter:new Uint8Array([5]),deserialize:r=>r.targetArray[0]===1},{filter:new Uint8Array([6]),deserialize:r=>{}},{filter:new Uint8Array([7]),deserialize:r=>null}];function v(r){let e=0;for(let t=0;t<r.length;t++)e=(e<<8)+r[t];return e}function U(r){const{targetArray:e,textDecoder:t=new TextDecoder}=r,a=e[0],n=e[1],i=e[2],s=t.decode(e.subarray(3,3+a)),y=e.subarray(3+a,3+a+n),b=e.subarray(3+a+n,3+a+n+i),A=v(b),k=e.subarray(3+a+n+i,3+a+n+i+A);return{key:s,valueType:y,value:k,totalLength:3+a+n+i+A}}const h=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"],d=r=>r.reduce((e,t)=>e+h[t>>8]+h[t&255],"");var o,c,u;class m{constructor(){f(this,o,new Map),f(this,c,[]),f(this,u,new TextDecoder),p.forEach(e=>{this.registerPlugin(e)})}async deserialize(e){const t={};let a=0;for(;a<e.length;){const n=e.subarray(a),i=U({targetArray:n,textDecoder:l(this,u)});if(l(this,o).has(d(i.valueType))){const s=l(this,o).get(d(i.valueType)).deserialize({targetArray:i.value,deserializer:this});t[i.key]=s instanceof Promise?await s:s}else for(const s of l(this,c))if(s.filter(i.valueType)){const y=s.deserialize({targetArray:i.value,deserializer:this});t[i.key]=y instanceof Promise?await y:y}a+=i.totalLength}return t}registerPlugin(e){if(e.filter instanceof Uint8Array){l(this,o).set(d(e.filter),e);return}l(this,c).unshift(e)}}o=new WeakMap,c=new WeakMap,u=new WeakMap;const T=new m;self.onmessage=async r=>{const e=new Uint8Array(r.data),t=await T.deserialize(e);self.postMessage(t)}})();
|
||||
@@ -0,0 +1 @@
|
||||
@charset "UTF-8";/*! tailwindcss v4.1.7 | MIT License | https://tailwindcss.com */@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--spacing:.25rem;--container-2xs:18rem;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.relative{position:relative}.ml-2{margin-left:calc(var(--spacing)*2)}.flex{display:flex}.w-full{width:100%}.min-w-2xs{min-width:var(--container-2xs)}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.p-0\.5{padding:calc(var(--spacing)*.5)}}body{margin:0}:root{--el-color-white:#ffffff;--el-color-black:#000000;--el-color-primary-rgb:64,158,255;--el-color-success-rgb:103,194,58;--el-color-warning-rgb:230,162,60;--el-color-danger-rgb:245,108,108;--el-color-error-rgb:245,108,108;--el-color-info-rgb:144,147,153;--el-font-size-extra-large:20px;--el-font-size-large:18px;--el-font-size-medium:16px;--el-font-size-base:14px;--el-font-size-small:13px;--el-font-size-extra-small:12px;--el-font-family:"Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","MicrLine truncated
|
||||
@@ -0,0 +1,17 @@
|
||||
var hd=Object.defineProperty;var vd=(e,t,n)=>t in e?hd(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var Sn=(e,t,n)=>vd(e,typeof t!="symbol"?t+"":t,n);(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))r(o);new MutationObserver(o=>{for(const s of o)if(s.type==="childList")for(const i of s.addedNodes)i.tagName==="LINK"&&i.rel==="modulepreload"&&r(i)}).observe(document,{childList:!0,subtree:!0});function n(o){const s={};return o.integrity&&(s.integrity=o.integrity),o.referrerPolicy&&(s.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?s.credentials="include":o.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function r(o){if(o.ep)return;o.ep=!0;const s=n(o);fetch(o.href,s)}})();/**
|
||||
* @vue/shared v3.5.14
|
||||
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
||||
* @license MIT
|
||||
**//*! #__NO_SIDE_EFFECTS__ */function Ti(e){const t=Object.create(null);for(const n of e.split(","))t[n]=1;return n=>n in t}const Ee={},dr=[],st=()=>{},gd=()=>!1,ns=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&(e.charCodeAt(2)>122||e.charCodeAt(2)<97),Ci=e=>e.startsWith("onUpdate:"),je=Object.assign,Oi=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},md=Object.prototype.hasOwnProperty,we=(e,t)=>md.call(e,t),Y=Array.isArray,pr=e=>rs(e)==="[object Map]",Ou=e=>rs(e)==="[object Set]",ee=e=>typeof e=="function",ye=e=>typeof e=="string",gn=e=>typeof e=="symbol",de=e=>e!==null&&typeof e=="object",ko=e=>(de(e)||ee(e))&&ee(e.then)&&ee(e.catch),Iu=Object.prototype.toString,rs=e=>Iu.call(e),bd=e=>rs(e).slice(8,-1),Ii=e=>rs(e)==="[object Object]",Ai=e=>ye(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,jr=Ti(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),os=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},yd=/-(\w)/g,wt=os(e=>e.replace(yd,(t,n)=>n?n.toUpperCase():"")),_d=/\B([A-Z])/g,mn=os(e=>e.replace(_d,"-$1").toLowerCase()),ss=os(e=>e.charAt(0).toUpperCase()+e.slice(1)),Mo=os(e=>e?`on${ss(e)}`:""),pt=(e,t)=>!Object.is(e,t),Ro=(e,...t)=>{for(let n=0;n<e.length;n++)e[n](...t)},Au=(e,t,n,r=!1)=>{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,writable:r,value:n})},ei=e=>{const t=parseFloat(e);return isNaN(t)?e:t},wd=e=>{const t=ye(e)?Number(e):NaN;return isNaN(t)?e:t};let Oa;const is=()=>Oa||(Oa=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function Ge(e){if(Y(e)){const t={};for(let n=0;n<e.length;n++){const r=e[n],o=ye(r)?Cd(r):Ge(r);if(o)for(const s in o)t[s]=o[s]}return t}else if(ye(e)||de(e))return e}const Sd=/;(?![^(]*\))/g,Ed=/:([^]+)/,Td=/\/\*[^]*?\*\//g;function Cd(e){const t={};return e.replace(Td,"").split(Sd).forEach(n=>{if(n){const r=n.split(Ed);r.length>1&&(t[r[0].trim()]=r[1].trim())}}),t}function U(e){let t="";if(ye(e))t=e;else if(Y(e))for(let n=0;n<e.length;n++){const r=U(e[n]);r&&(t+=r+" ")}else if(de(e))for(const n in e)e[n]&&(t+=n+" ");return t.trim()}const Od="itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly",Id=Ti(Od);function xu(e){return!!e||e===""}const Pu=e=>!!(e&&e.__v_isRef===!0),Ae=e=>ye(e)?e:e==null?"":Y(e)||de(e)&&(e.toString===Iu||!ee(e.toString))?Pu(e)?Ae(e.value):JSON.stringify(e,Mu,2):String(e),Mu=(e,t)=>Pu(t)?Mu(e,t.value):pr(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((n,[r,o],s)=>(n[Rs(r,s)+" =>"]=o,n),{})}:Ou(t)?{[`Set(${t.size})`]:[...t.values()].map(n=>Rs(n))}:gn(t)?Rs(t):de(t)&&!Y(t)&&!Ii(t)?String(t):t,Rs=(e,t="")=>{var n;return gn(e)?`Symbol(${(n=e.description)!=null?n:t})`:e};/**
|
||||
* @vue/reactivity v3.5.14
|
||||
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
||||
* @license MIT
|
||||
**/let et;class Ad{constructor(t=!1){this.detached=t,this._active=!0,this._on=0,this.effects=[],this.cleanups=[],this._isPaused=!1,this.parent=et,!t&&et&&(this.index=(et.scopes||(et.scopes=[])).push(this)-1)}get active(){return this._active}pause(){if(this._active){this._isPaused=!0;let t,n;if(this.scopes)for(t=0,n=this.scopes.length;t<n;t++)this.scopes[t].pause();for(t=0,n=this.effects.length;t<n;t++)this.effects[t].pause()}}resume(){if(this._active&&this._isPaused){this._isPaused=!1;let t,n;if(this.scopes)for(t=0,n=this.scopes.length;t<n;t++)this.scopes[t].resume();for(t=0,n=this.effects.length;t<n;t++)this.effects[t].resume()}}run(t){if(this._active){const n=et;try{return et=this,t()}finally{et=n}}}on(){++this._on===1&&(this.prevScope=et,et=this)}off(){this._on>0&&--this._on===0&&(et=this.prevScope,this.prevScope=void 0)}stop(t){if(this._active){this._active=!1;let n,r;for(n=0,r=this.effects.length;n<r;n++)this.effects[n].stop();for(this.effects.length=0,n=0,r=this.cleanups.length;n<r;n++)this.cleanups[n]();if(this.cleanups.length=0,this.scopes){for(n=0,r=this.scopes.length;n<r;n++)this.scopes[n].stop(!0);this.scopes.length=0}if(!this.detached&&this.parent&&!t){const o=this.parent.scopes.pop();o&&o!==this&&(this.parent.scopes[this.index]=o,o.index=this.index)}this.parent=void 0}}}function Ru(){return et}function xd(e,t=!1){et&&et.cleanups.push(e)}let Ce;const $s=new WeakSet;class $u{constructor(t){this.fn=t,this.deps=void 0,this.depsTail=void 0,this.flags=5,this.next=void 0,this.cleanup=void 0,this.scheduler=void 0,et&&et.active&&et.effects.push(this)}pause(){this.flags|=64}resume(){this.flags&64&&(this.flags&=-65,$s.has(this)&&($s.delete(this),this.trigger()))}notify(){this.flags&2&&!(this.flags&32)||this.flags&8||Fu(this)}run(){if(!(this.flags&1))return this.fn();this.flags|=2,Ia(this),Lu(this);const t=Ce,n=kt;Ce=this,kt=!0;try{return this.fn()}finally{ku(this),Ce=t,kt=n,this.flags&=-3}}stop(){if(this.flags&1){for(let t=this.deps;t;t=t.nextDep)Mi(t);this.deps=this.depsTail=void 0,Ia(this),this.onStop&&this.onStop(),this.flags&=-2}}trigger(){this.flags&64?$s.add(this):this.scheduler?this.scheduler():this.runIfDirty()}runIfDirty(){ti(this)&&this.run()}get dirty(){return ti(this)}}let Nu=0,Vr,Hr;function Fu(e,t=!1){if(e.flags|=8,t){e.next=Hr,Hr=e;return}e.next=Vr,Vr=e}function xi(){Nu++}function Pi(){if(--Nu>0)return;if(Hr){let t=Hr;for(Hr=void 0;t;){const n=t.next;t.next=void 0,t.flags&=-9,t=n}}let e;for(;Vr;){let t=Vr;for(Vr=void 0;t;){const n=t.next;if(t.next=void 0,t.flags&=-9,t.flags&1)try{t.trigger()}catch(r){e||(e=r)}t=n}}if(e)throw e}function Lu(e){for(let t=e.deps;t;t=t.nextDep)t.version=-1,t.prevActiveLink=t.dep.activeLink,t.dep.activeLink=t}function ku(e){let t,n=e.depsTail,r=n;for(;r;){const o=r.prevDep;r.version===-1?(r===n&&(n=o),Mi(r),Pd(r)):t=r,r.dep.activeLink=r.prevActiveLink,r.prevActiveLink=void 0,r=o}e.deps=t,e.depsTail=n}function ti(e){for(let t=e.deps;t;t=t.nextDep)if(t.dep.version!==t.version||t.dep.computed&&(Bu(t.dep.computed)||t.dep.version!==t.version))return!0;return!!e._dirty}function Bu(e){if(e.flags&4&&!(e.flags&16)||(e.flags&=-17,e.globalVersion===Jr)||(e.globalVersion=Jr,!e.isSSR&&e.flags&128&&(!e.deps&&!e._dirty||!ti(e))))return;e.flags|=2;const t=e.dep,n=Ce,r=kt;Ce=e,kt=!0;try{Lu(e);const o=e.fn(e._value);(t.version===0||pt(o,e._value))&&(e.flags|=128,e._value=o,t.version++)}catch(o){throw t.version++,o}finally{Ce=n,kt=r,ku(e),e.flags&=-3}}function Mi(e,t=!1){const{dep:n,prevSub:r,nextSub:o}=e;if(r&&(r.nextSub=o,e.prevSub=void 0),o&&(o.prevSub=r,e.nextSub=void 0),n.subs===e&&(n.subs=r,!r&&n.computed)){n.computed.flags&=-5;for(let s=n.computed.deps;s;s=s.nextDep)Mi(s,!0)}!t&&!--n.sc&&n.map&&n.map.delete(n.key)}function Pd(e){const{prevDep:t,nextDep:n}=e;t&&(t.nextDep=n,e.prevDep=void 0),n&&(n.prevDep=t,e.nextDep=void 0)}let kt=!0;const Du=[];function dn(){Du.push(kt),kt=!1}function pn(){const e=Du.pop();kt=e===void 0?!0:e}function Ia(e){const{cleanup:t}=e;if(e.cleanup=void 0,t){const n=Ce;Ce=void 0;try{t()}finally{Ce=n}}}let Jr=0;class Md{constructor(t,n){this.sub=t,this.dep=n,this.version=n.version,this.nextDep=this.prevDep=this.nextSub=this.prevSub=this.prevActiveLink=void 0}}class as{constructor(t){this.computed=t,this.version=0,this.activeLink=void 0,this.subs=void 0,this.map=void 0,this.key=void 0,this.sc=0}track(t){if(!Ce||!kt||Ce===this.computed)return;let n=this.activeLink;if(n===void 0||n.sub!==Ce)n=this.activeLink=new Md(Ce,this),Ce.deps?(n.prevDep=Ce.depsTail,Ce.depsTail.nextDep=n,Ce.depsTail=n):Ce.deps=Ce.depsTail=n,ju(n);else if(n.version===-1&&(n.version=this.version,n.nextDep)){const r=n.nextDep;r.prevDep=n.prevDep,n.prevDep&&(n.prevDep.nextDep=r),n.prevDep=Ce.depsTail,n.nextDep=void 0,Ce.depsTail.nextDep=n,Ce.depsTail=n,Ce.deps===n&&(Ce.deps=r)}return n}trigger(t){this.version++,Jr++,this.notify(t)}notify(t){xi();try{for(let n=this.subs;n;n=n.prevSub)n.sub.notify()&&n.sub.dep.notify()}finally{Pi()}}}function ju(e){if(e.dep.sc++,e.sub.flags&4){const t=e.dLine truncated
|
||||
* @vue/runtime-core v3.5.14
|
||||
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
||||
* @license MIT
|
||||
**/function lo(e,t,n,r){try{return r?e(...r):e()}catch(o){cs(o,t,n)}}function Bt(e,t,n,r){if(ee(e)){const o=lo(e,t,n,r);return o&&ko(o)&&o.catch(s=>{cs(s,t,n)}),o}if(Y(e)){const o=[];for(let s=0;s<e.length;s++)o.push(Bt(e[s],t,n,r));return o}}function cs(e,t,n,r=!0){const o=t?t.vnode:null,{errorHandler:s,throwUnhandledErrorInProduction:i}=t&&t.appContext.config||Ee;if(t){let a=t.parent;const l=t.proxy,c=`https://vuejs.org/error-reference/#runtime-${n}`;for(;a;){const u=a.ec;if(u){for(let f=0;f<u.length;f++)if(u[f](e,l,c)===!1)return}a=a.parent}if(s){dn(),lo(s,null,10,[e,l,c]),pn();return}}ap(e,n,o,r,i)}function ap(e,t,n,r=!0,o=!1){if(o)throw e;console.error(e)}const ct=[];let Kt=-1;const vr=[];let On=null,lr=0;const Ju=Promise.resolve();let Vo=null;function Fe(e){const t=Vo||Ju;return e?t.then(this?e.bind(this):e):t}function lp(e){let t=Kt+1,n=ct.length;for(;t<n;){const r=t+n>>>1,o=ct[r],s=Xr(o);s<e||s===e&&o.flags&2?t=r+1:n=r}return t}function Li(e){if(!(e.flags&1)){const t=Xr(e),n=ct[ct.length-1];!n||!(e.flags&2)&&t>=Xr(n)?ct.push(e):ct.splice(lp(t),0,e),e.flags|=1,Zu()}}function Zu(){Vo||(Vo=Ju.then(Qu))}function up(e){Y(e)?vr.push(...e):On&&e.id===-1?On.splice(lr+1,0,e):e.flags&1||(vr.push(e),e.flags|=1),Zu()}function xa(e,t,n=Kt+1){for(;n<ct.length;n++){const r=ct[n];if(r&&r.flags&2){if(e&&r.id!==e.uid)continue;ct.splice(n,1),n--,r.flags&4&&(r.flags&=-2),r(),r.flags&4||(r.flags&=-2)}}}function Xu(e){if(vr.length){const t=[...new Set(vr)].sort((n,r)=>Xr(n)-Xr(r));if(vr.length=0,On){On.push(...t);return}for(On=t,lr=0;lr<On.length;lr++){const n=On[lr];n.flags&4&&(n.flags&=-2),n.flags&8||n(),n.flags&=-2}On=null,lr=0}}const Xr=e=>e.id==null?e.flags&2?-1:1/0:e.id;function Qu(e){try{for(Kt=0;Kt<ct.length;Kt++){const t=ct[Kt];t&&!(t.flags&8)&&(t.flags&4&&(t.flags&=-2),lo(t,t.i,t.i?15:14),t.flags&4||(t.flags&=-2))}}finally{for(;Kt<ct.length;Kt++){const t=ct[Kt];t&&(t.flags&=-2)}Kt=-1,ct.length=0,Xu(),Vo=null,(ct.length||vr.length)&&Qu()}}let He=null,ec=null;function Ho(e){const t=He;return He=e,ec=e&&e.type.__scopeId||null,t}function ne(e,t=He,n){if(!t||e._n)return e;const r=(...o)=>{r._d&&za(-1);const s=Ho(t);let i;try{i=e(...o)}finally{Ho(s),r._d&&za(1)}return i};return r._n=!0,r._c=!0,r._d=!0,r}function $n(e,t){if(He===null)return e;const n=vs(He),r=e.dirs||(e.dirs=[]);for(let o=0;o<t.length;o++){let[s,i,a,l=Ee]=t[o];s&&(ee(s)&&(s={mounted:s,updated:s}),s.deep&&sn(i),r.push({dir:s,instance:n,value:i,oldValue:void 0,arg:a,modifiers:l}))}return e}function Vn(e,t,n,r){const o=e.dirs,s=t&&t.dirs;for(let i=0;i<o.length;i++){const a=o[i];s&&(a.oldValue=s[i].value);let l=a.dir[r];l&&(dn(),Bt(l,n,8,[e.el,a,e,t]),pn())}}const tc=Symbol("_vte"),nc=e=>e.__isTeleport,zr=e=>e&&(e.disabled||e.disabled===""),Pa=e=>e&&(e.defer||e.defer===""),Ma=e=>typeof SVGElement<"u"&&e instanceof SVGElement,Ra=e=>typeof MathMLElement=="function"&&e instanceof MathMLElement,oi=(e,t)=>{const n=e&&e.to;return ye(n)?t?t(n):null:n},rc={name:"Teleport",__isTeleport:!0,process(e,t,n,r,o,s,i,a,l,c){const{mc:u,pc:f,pbc:d,o:{insert:h,querySelector:p,createText:v,createComment:w}}=c,y=zr(t.props);let{shapeFlag:A,children:E,dynamicChildren:C}=t;if(e==null){const _=t.el=v(""),x=t.anchor=v("");h(_,n,r),h(x,n,r);const B=(M,q)=>{A&16&&(o&&o.isCE&&(o.ce._teleportTarget=M),u(E,M,q,o,s,i,a,l))},j=()=>{const M=t.target=oi(t.props,p),q=oc(M,t,v,h);M&&(i!=="svg"&&Ma(M)?i="svg":i!=="mathml"&&Ra(M)&&(i="mathml"),y||(B(M,q),$o(t,!1)))};y&&(B(n,x),$o(t,!0)),Pa(t.props)?lt(()=>{j(),t.el.__isMounted=!0},s):j()}else{if(Pa(t.props)&&!e.el.__isMounted){lt(()=>{rc.process(e,t,n,r,o,s,i,a,l,c),delete e.el.__isMounted},s);return}t.el=e.el,t.targetStart=e.targetStart;const _=t.anchor=e.anchor,x=t.target=e.target,B=t.targetAnchor=e.targetAnchor,j=zr(e.props),M=j?n:x,q=j?_:B;if(i==="svg"||Ma(x)?i="svg":(i==="mathml"||Ra(x))&&(i="mathml"),C?(d(e.dynamicChildren,C,M,o,s,i,a),Hi(e,t,!0)):l||f(e,t,M,q,o,s,i,a,!1),y)j?t.props&&e.props&&t.props.to!==e.props.to&&(t.props.to=e.props.to):So(t,n,_,c,1);else if((t.props&&t.props.to)!==(e.props&&e.props.to)){const te=t.target=oi(t.props,p);te&&So(t,te,null,c,0)}else j&&So(t,x,B,c,1);$o(t,y)}},remove(e,t,n,{um:r,o:{remove:o}},s){const{shapeFlag:i,children:a,anchor:l,targetStart:c,targetAnchor:u,target:f,props:d}=e;if(f&&(o(c),o(u)),s&&o(l),i&16){const h=s||!zr(d);for(let p=0;p<a.length;p++){const v=a[p];r(v,t,n,h,!!v.dynamicChildren)}}},move:So,hydrate:cp};function So(e,t,n,{o:{insert:r},m:o},s=2){s===0&&r(e.targetAnchor,t,n);const{el:i,anchor:a,shapeFlag:l,children:c,props:u}=e,f=s===2;if(f&&r(i,t,n),(!f||zr(u))&&l&16)for(let d=0;d<c.length;d++)o(c[d],t,n,2);f&&r(a,t,n)}function cp(e,t,n,r,o,s,{o:{nextSibling:i,parentNode:a,querySelector:l,insert:c,createText:u}},f){const d=t.target=oi(t.props,l);if(d){const h=zr(t.props),p=d._lpa||d.firstChild;if(t.shapeFlag&16)if(h)t.anchor=f(i(e),t,a(e),n,r,o,s),t.targetStart=p,t.targetAnchor=p&&i(p);else{t.anchor=i(e);let v=p;for(;v;){if(v&&v.nodeType===8){if(v.data==="teleport start anchor")t.tar
Line truncated
|
||||
* @vue/runtime-dom v3.5.14
|
||||
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
||||
* @license MIT
|
||||
**/let fi;const Wa=typeof window<"u"&&window.trustedTypes;if(Wa)try{fi=Wa.createPolicy("vue",{createHTML:e=>e})}catch{}const Hc=fi?e=>fi.createHTML(e):e=>e,dh="http://www.w3.org/2000/svg",ph="http://www.w3.org/1998/Math/MathML",tn=typeof document<"u"?document:null,Ga=tn&&tn.createElement("template"),hh={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,r)=>{const o=t==="svg"?tn.createElementNS(dh,e):t==="mathml"?tn.createElementNS(ph,e):n?tn.createElement(e,{is:n}):tn.createElement(e);return e==="select"&&r&&r.multiple!=null&&o.setAttribute("multiple",r.multiple),o},createText:e=>tn.createTextNode(e),createComment:e=>tn.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>tn.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,r,o,s){const i=n?n.previousSibling:t.lastChild;if(o&&(o===s||o.nextSibling))for(;t.insertBefore(o.cloneNode(!0),n),!(o===s||!(o=o.nextSibling)););else{Ga.innerHTML=Hc(r==="svg"?`<svg>${e}</svg>`:r==="mathml"?`<math>${e}</math>`:e);const a=Ga.content;if(r==="svg"||r==="mathml"){const l=a.firstChild;for(;l.firstChild;)a.appendChild(l.firstChild);a.removeChild(l)}t.insertBefore(a,n)}return[i?i.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}},En="transition",$r="animation",no=Symbol("_vtc"),zc={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String},vh=je({},sc,zc),gh=e=>(e.displayName="Transition",e.props=vh,e),Ki=gh((e,{slots:t})=>uh(hp,mh(e),t)),Un=(e,t=[])=>{Y(e)?e.forEach(n=>n(...t)):e&&e(...t)},qa=e=>e?Y(e)?e.some(t=>t.length>1):e.length>1:!1;function mh(e){const t={};for(const $ in e)$ in zc||(t[$]=e[$]);if(e.css===!1)return t;const{name:n="v",type:r,duration:o,enterFromClass:s=`${n}-enter-from`,enterActiveClass:i=`${n}-enter-active`,enterToClass:a=`${n}-enter-to`,appearFromClass:l=s,appearActiveClass:c=i,appearToClass:u=a,leaveFromClass:f=`${n}-leave-from`,leaveActiveClass:d=`${n}-leave-active`,leaveToClass:h=`${n}-leave-to`}=e,p=bh(o),v=p&&p[0],w=p&&p[1],{onBeforeEnter:y,onEnter:A,onEnterCancelled:E,onLeave:C,onLeaveCancelled:_,onBeforeAppear:x=y,onAppear:B=A,onAppearCancelled:j=E}=t,M=($,ie,ve,Oe)=>{$._enterCancelled=Oe,Kn($,ie?u:a),Kn($,ie?c:i),ve&&ve()},q=($,ie)=>{$._isLeaving=!1,Kn($,f),Kn($,h),Kn($,d),ie&&ie()},te=$=>(ie,ve)=>{const Oe=$?B:A,ae=()=>M(ie,$,ve);Un(Oe,[ie,ae]),Ya(()=>{Kn(ie,$?l:s),Qt(ie,$?u:a),qa(Oe)||Ja(ie,r,v,ae)})};return je(t,{onBeforeEnter($){Un(y,[$]),Qt($,s),Qt($,i)},onBeforeAppear($){Un(x,[$]),Qt($,l),Qt($,c)},onEnter:te(!1),onAppear:te(!0),onLeave($,ie){$._isLeaving=!0;const ve=()=>q($,ie);Qt($,f),$._enterCancelled?(Qt($,d),Qa()):(Qa(),Qt($,d)),Ya(()=>{$._isLeaving&&(Kn($,f),Qt($,h),qa(C)||Ja($,r,w,ve))}),Un(C,[$,ve])},onEnterCancelled($){M($,!1,void 0,!0),Un(E,[$])},onAppearCancelled($){M($,!0,void 0,!0),Un(j,[$])},onLeaveCancelled($){q($),Un(_,[$])}})}function bh(e){if(e==null)return null;if(de(e))return[js(e.enter),js(e.leave)];{const t=js(e);return[t,t]}}function js(e){return wd(e)}function Qt(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e[no]||(e[no]=new Set)).add(t)}function Kn(e,t){t.split(/\s+/).forEach(r=>r&&e.classList.remove(r));const n=e[no];n&&(n.delete(t),n.size||(e[no]=void 0))}function Ya(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let yh=0;function Ja(e,t,n,r){const o=e._endId=++yh,s=()=>{o===e._endId&&r()};if(n!=null)return setTimeout(s,n);const{type:i,timeout:a,propCount:l}=_h(e,t);if(!i)return r();const c=i+"end";let u=0;const f=()=>{e.removeEventListener(c,d),s()},d=h=>{h.target===e&&++u>=l&&f()};setTimeout(()=>{u<l&&f()},a+1),e.addEventListener(c,d)}function _h(e,t){const n=window.getComputedStyle(e),r=p=>(n[p]||"").split(", "),o=r(`${En}Delay`),s=r(`${En}Duration`),i=Za(o,s),a=r(`${$r}Delay`),l=r(`${$r}Duration`),c=Za(a,l);let u=null,f=0,d=0;t===En?i>0&&(u=En,f=i,d=s.length):t===$r?c>0&&(u=$r,f=c,d=l.length):(f=Math.max(i,c),u=f>0?i>c?En:$r:null,d=u?u===En?s.length:l.length:0);const h=u===En&&/\b(transform|all)(,|$)/.test(r(`${En}Property`).toString());return{type:u,timeout:f,propCount:d,hasTransform:h}}function Za(e,t){for(;e.length<t.length;)e=e.concat(e);return Math.max(...t.map((n,r)=>Xa(n)+Xa(e[r])))}function Xa(e){return e==="auto"?0:Number(e.slice(0,-1).replace(",","."))*1e3}function Qa(){return document.body.offsetHeight}function wh(e,t,n){const r=e[no];r&&(t=(t?[t,...r]:[...r]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}const qo=Symbol("_vod"),Uc=Symbol("_vsh"),co={beforeMount(e,{value:t},{transition:n}){e[qo]=e.style.display==="none"?"":e.style.display,n&&t?n.beforeEnter(e):Nr(e,t)},mounted(e,{value:t},{transition
Line truncated
|
||||
@@ -0,0 +1 @@
|
||||
(function(){"use strict";var y=e=>{throw TypeError(e)},g=(e,t,r)=>t.has(e)||y("Cannot "+r),l=(e,t,r)=>(g(e,t,"read from private field"),r?r.call(e):t.get(e)),w=(e,t,r)=>t.has(e)?y("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,r);const c=new WeakMap,f=e=>{if(e instanceof Uint8Array)return e.length;{if(c.has(e))return c.get(e);const t=e.reduce((r,n)=>r+f(n),0);return c.set(e,t),t}},h=(e,t)=>{t=t||1;const r=[];for(;e>0||t>0;)r.unshift(e&255),e=e>>8,t--;return new Uint8Array(r)},p=e=>{const{key:t,valueType:r,value:n,textEncoder:i=new TextEncoder}=e,a=i.encode(t),s=h(f(n));return[new Uint8Array([a.length,r.length,s.length]),a,r,s,n]};function A(e){const t=new ArrayBuffer(8);return new DataView(t).setFloat64(0,e,!0),new Uint8Array(Array.from(new Uint8Array(t)))}const u=async e=>e instanceof Promise?await e:e,U=[{filter:e=>e instanceof Object,targetType:new Uint8Array([0]),async serialize(e){const t=new TextEncoder,r=[];for(const n in e.target){const i=e.target[n],a=await e.serializer.filterPlugin(i),s=a.targetType;if(!s)throw new Error("Unknown value type");const v=await u(a.serialize({target:i,serializer:e.serializer}))??new Uint8Array(0);r.push(p({key:n,valueType:s,value:v,textEncoder:t}))}return r}},{filter:e=>e instanceof Array,targetType:new Uint8Array([1]),async serialize(e){const t={...e.target,l:e.target.length};return await e.serializer.serialize(t)}},{filter:e=>e instanceof Uint8Array,targetType:new Uint8Array([2]),serialize(e){return e.target}},{filter(e){return typeof e=="string"},targetType:new Uint8Array([3]),serialize(e){return(e.textEncoder||new TextEncoder).encode(e.target)}},{filter(e){return typeof e=="number"},targetType:new Uint8Array([4]),serialize(e){return A(e.target)}},{filter(e){return typeof e=="boolean"},targetType:new Uint8Array([5]),serialize(e){return new Uint8Array([e.target?1:0])}},{filter(e){return typeof e>"u"},targetType:new Uint8Array([6]),serialize(){return new Uint8Array(0)}},{filter(e){return e===null},targetType:new Uint8Array([7]),serialize(){return new Uint8Array(0)}}];function z(e,t){const r=t??e.reduce((a,s)=>a+s.length,0),n=new Uint8Array(r);let i=0;for(const a of e)n.set(a,i),i+=a.length;return n}var o;class d{constructor(){w(this,o,[]),U.forEach(t=>{this.registerPlugin(t)})}async serialize(t){for(const r of l(this,o))if(r.filter(t)){const n=await u(r.serialize({target:t,serializer:this}));return n instanceof Uint8Array?n:z(n.flat(1/0),f(n))}}async filterPlugin(t){for(const r of l(this,o))if(r.filter(t))return r}registerPlugin(t){l(this,o).unshift(t)}}o=new WeakMap;const T=new d;self.onmessage=async e=>{const t=e.data,r=await T.serialize(t);self.postMessage(r)}})();
|
||||
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Bobj Demo</title>
|
||||
<script type="module" crossorigin src="./assets/index-DhXdPBmT.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="./assets/index-CvYTlbt6.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,92 @@
|
||||
import os from 'os';
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
// 获取操作系统信息
|
||||
const platform = os.platform();
|
||||
const release = os.release();
|
||||
const hostname = os.hostname();
|
||||
|
||||
// 获取Node.js版本
|
||||
const nodeVersion = process.version;
|
||||
|
||||
// 硬件信息
|
||||
const cpuInfo = os.cpus();
|
||||
const totalMemory = os.totalmem();
|
||||
const freeMemory = os.freemem();
|
||||
|
||||
// 计算CPU使用率
|
||||
const cpuUsage = getCpuUsage();
|
||||
|
||||
// 计算内存使用率
|
||||
const memoryUsage = {
|
||||
total: formatBytes(totalMemory),
|
||||
free: formatBytes(freeMemory),
|
||||
used: formatBytes(totalMemory - freeMemory),
|
||||
percent: Math.round(((totalMemory - freeMemory) / totalMemory) * 100)
|
||||
};
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
system: {
|
||||
platform,
|
||||
release,
|
||||
hostname
|
||||
},
|
||||
node: nodeVersion,
|
||||
hardware: {
|
||||
cpu: {
|
||||
model: cpuInfo[0]?.model || 'Unknown',
|
||||
cores: cpuInfo.length,
|
||||
usage: cpuUsage
|
||||
},
|
||||
memory: memoryUsage
|
||||
}
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error fetching system info:', error);
|
||||
return {
|
||||
success: false,
|
||||
message: '获取系统信息失败'
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// 格式化字节数为可读格式
|
||||
function formatBytes(bytes: number) {
|
||||
if (bytes === 0) return '0 Bytes';
|
||||
|
||||
const k = 1024;
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
// 获取CPU使用率
|
||||
function getCpuUsage() {
|
||||
try {
|
||||
const cpus = os.cpus();
|
||||
let totalIdle = 0;
|
||||
let totalTick = 0;
|
||||
|
||||
cpus.forEach(cpu => {
|
||||
for (const type in cpu.times) {
|
||||
totalTick += cpu.times[type as keyof typeof cpu.times];
|
||||
}
|
||||
totalIdle += cpu.times.idle;
|
||||
});
|
||||
|
||||
const idle = totalIdle / cpus.length;
|
||||
const total = totalTick / cpus.length;
|
||||
const usagePercent = Math.round(100 - (idle / total * 100));
|
||||
|
||||
return usagePercent;
|
||||
} catch (error) {
|
||||
console.error('Error calculating CPU usage:', error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import os from 'os';
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
// 获取CPU信息
|
||||
const cpuUsage = getCpuUsage();
|
||||
|
||||
// 获取内存信息
|
||||
const totalMemory = os.totalmem();
|
||||
const freeMemory = os.freemem();
|
||||
const memoryUsage = {
|
||||
total: formatBytes(totalMemory),
|
||||
free: formatBytes(freeMemory),
|
||||
used: formatBytes(totalMemory - freeMemory),
|
||||
percent: Math.round(((totalMemory - freeMemory) / totalMemory) * 100)
|
||||
};
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
cpu: {
|
||||
usage: cpuUsage
|
||||
},
|
||||
memory: memoryUsage
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error fetching performance info:', error);
|
||||
return {
|
||||
success: false,
|
||||
message: '获取性能数据失败'
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// 格式化字节数为可读格式
|
||||
function formatBytes(bytes: number) {
|
||||
if (bytes === 0) return '0 Bytes';
|
||||
|
||||
const k = 1024;
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
// 获取CPU使用率
|
||||
function getCpuUsage() {
|
||||
try {
|
||||
const cpus = os.cpus();
|
||||
let totalIdle = 0;
|
||||
let totalTick = 0;
|
||||
|
||||
cpus.forEach(cpu => {
|
||||
for (const type in cpu.times) {
|
||||
totalTick += cpu.times[type as keyof typeof cpu.times];
|
||||
}
|
||||
totalIdle += cpu.times.idle;
|
||||
});
|
||||
|
||||
const idle = totalIdle / cpus.length;
|
||||
const total = totalTick / cpus.length;
|
||||
const usagePercent = Math.round(100 - (idle / total * 100));
|
||||
|
||||
return usagePercent;
|
||||
} catch (error) {
|
||||
console.error('Error calculating CPU usage:', error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import useDefaultStore from "~/hooks/pinia/useDefaultStore"
|
||||
|
||||
export default async function cachedPromise<T>(key: string, promise: () =>Promise<T>): Promise<T> {
|
||||
const cache = useDefaultStore().getCache(key)
|
||||
if (cache) {
|
||||
return cache
|
||||
}
|
||||
const res = await promise()
|
||||
useDefaultStore().setCache(key, res)
|
||||
return res
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import useDefaultStore from "~/hooks/pinia/useDefaultStore"
|
||||
import usePostStore from "~/hooks/pinia/usePostStore"
|
||||
import useMiaoFetch from "~/hooks/useMiaoFetch"
|
||||
// import useMiaoFetch from "~/hooks/useMiaoFetch"
|
||||
// import usePostStore from "~/hooks/pinia/usePostStore"
|
||||
import type { postContent, postItem } from "~/types/post"
|
||||
|
||||
|
||||
+14
-13
@@ -11,11 +11,12 @@ export default class Html2VNode {
|
||||
public use(middleware: middlewareType) {
|
||||
this.middlewareList.push(middleware)
|
||||
}
|
||||
public rander(htmlString: string) {
|
||||
const html2ObjResult = this.html2Obj(htmlString);
|
||||
public render(htmlString: string) {
|
||||
const htmlString2 = htmlString.replaceAll('<hr>', '<hr></hr>').replaceAll('<br>', '<br></br>')
|
||||
const html2ObjResult = this.html2Obj(htmlString2);
|
||||
const middlewareMap = this.buildMiddlewareMap(html2ObjResult);
|
||||
const wrinklesResult = this.wrinkles(html2ObjResult)
|
||||
const vnodes = this.rander2VNode(wrinklesResult, middlewareMap)
|
||||
const vnodes = this.render2VNode(wrinklesResult, middlewareMap)
|
||||
return vnodes;
|
||||
}
|
||||
|
||||
@@ -40,36 +41,36 @@ export default class Html2VNode {
|
||||
return middlewareMap;
|
||||
}
|
||||
|
||||
private rander2VNode = (
|
||||
private render2VNode = async (
|
||||
wrinklesResult: (miaoVNodeType | string)[],
|
||||
middlewareMap: Map<string, middlewareType[]>
|
||||
): (VNode | string)[] => {
|
||||
return wrinklesResult.map((item: miaoVNodeType | string): VNode | string => {
|
||||
): Promise<(VNode | string)[]> => {
|
||||
return Promise.all(wrinklesResult.map((async (item: miaoVNodeType | string): Promise<VNode | string> => {
|
||||
if (typeof item === 'string') {
|
||||
return item;
|
||||
}
|
||||
const { tagName = '', tagAttrs } = this.parseTag(item.tag);
|
||||
const middlewares = middlewareMap.get(tagName)
|
||||
for(const middleware of middlewares!) {
|
||||
const _res = middleware.rander({
|
||||
const _res = middleware.render({
|
||||
item,
|
||||
tagName,
|
||||
tagAttrs,
|
||||
middlewareMap
|
||||
})
|
||||
if(_res) {
|
||||
return _res
|
||||
return await _res
|
||||
}
|
||||
}
|
||||
return ''
|
||||
})
|
||||
})))
|
||||
}
|
||||
|
||||
private defaultMiddleware: middlewareType = {
|
||||
filter: (_: string) => {
|
||||
return true;
|
||||
},
|
||||
rander: ({
|
||||
render: async ({
|
||||
item, tagName, tagAttrs, middlewareMap
|
||||
}) => {
|
||||
if (!tagName) {
|
||||
@@ -77,7 +78,7 @@ export default class Html2VNode {
|
||||
}
|
||||
let child: string | (string | VNode)[] = item.children as string
|
||||
if (typeof item.children !== 'string') {
|
||||
child = this.rander2VNode(item.children, middlewareMap)
|
||||
child = await this.render2VNode(item.children, middlewareMap)
|
||||
}
|
||||
return h(tagName ?? 'span', tagAttrs, child)
|
||||
}
|
||||
@@ -214,11 +215,11 @@ type TagType = {
|
||||
// 要优化也是以后优化了
|
||||
export type middlewareType = {
|
||||
filter: (tagName: string) => boolean,
|
||||
rander: (option: {
|
||||
render: (option: {
|
||||
item: miaoVNodeType,
|
||||
tagName: string,
|
||||
tagAttrs: { [key: string]: string },
|
||||
middlewareMap: Map<string, middlewareType[]>
|
||||
}
|
||||
) => VNode | string
|
||||
) => Promise<VNode | string>
|
||||
}
|
||||
Reference in new issue
Block a user