This commit is contained in:
zyj
2025-10-14 17:56:28 +08:00
commit 81c18c94e3
74 changed files with 12668 additions and 0 deletions

24
frontend/.gitignore vendored Normal file
View File

@@ -0,0 +1,24 @@
# Nuxt dev/build outputs
.output
.data
.nuxt
.nitro
.cache
dist
# Node dependencies
node_modules
# Logs
logs
*.log
# Misc
.DS_Store
.fleet
.idea
# Local env files
.env
.env.*
!.env.example

75
frontend/README.md Normal file
View File

@@ -0,0 +1,75 @@
# Nuxt Minimal Starter
Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
## Setup
Make sure to install dependencies:
```bash
# npm
npm install
# pnpm
pnpm install
# yarn
yarn install
# bun
bun install
```
## Development Server
Start the development server on `http://localhost:3000`:
```bash
# npm
npm run dev
# pnpm
pnpm dev
# yarn
yarn dev
# bun
bun run dev
```
## Production
Build the application for production:
```bash
# npm
npm run build
# pnpm
pnpm build
# yarn
yarn build
# bun
bun run build
```
Locally preview production build:
```bash
# npm
npm run preview
# pnpm
pnpm preview
# yarn
yarn preview
# bun
bun run preview
```
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.

11
frontend/app/app.vue Normal file
View File

@@ -0,0 +1,11 @@
<script setup>
</script>
<template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>
<style></style>

View File

@@ -0,0 +1,93 @@
Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com),
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

View File

@@ -0,0 +1,53 @@
<template>
<!-- Active Users Card -->
<a-card :bordered="false" class="dashboard-bar-chart" style="margin-bottom: 20px;">
<chart-bar :height="220" :data="barChartData"></chart-bar>
<div class="card-title">
<h2>Active Users</h2>
<p>than last week <span class="text-success">+23%</span></p>
</div>
<div class="card-content">
<p>We have created multiple options for you to put together and customise into pixel perfect pages.</p>
</div>
<a-row class="card-footer" type="flex" justify="center" align="top">
<a-col :span="6">
<h4>3,6K</h4>
<span>Users</span>
</a-col>
<a-col :span="6">
<h4>2m</h4>
<span>Clicks</span>
</a-col>
<a-col :span="6">
<h4>$772</h4>
<span>Sales</span>
</a-col>
<a-col :span="6">
<h4>82</h4>
<span>Items</span>
</a-col>
</a-row>
</a-card>
<!-- Active Users Card -->
</template>
<script setup lang="ts">
const barChartData = {
labels: ["01", "02", "03", "04", "05", "06", "07", "08", "09"],
datasets: [
{
label: "Sales",
backgroundColor: '#fff',
borderWidth: 0,
borderSkipped: false,
borderRadius: 6,
data: [850, 600, 500, 620, 900, 500, 900, 630, 900],
maxBarThickness: 20
}
]
}
</script>

View File

@@ -0,0 +1,44 @@
<template>
<a-card :bordered="false" class="dashboard-bar-line header-solid">
<template #title>
<h2>Sales Overview</h2>
<p>than last year <span class="text-success">+20%</span></p>
</template>
<template #extra>
<a-badge color="primary" class="badge-dot-primary" text="Traffic" />
<a-badge color="primary" class="badge-dot-secondary" text="Sales" />
</template>
<chart-line :height="310" :data="lineChartData" />
</a-card>
</template>
<script setup lang="ts">
// 定义折线图数据
const lineChartData = {
labels: ["Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
datasets: [
{
label: "Mobile apps",
tension: 0.4,
borderWidth: 0,
pointRadius: 0,
borderColor: "#1890FF",
borderWidth: 3,
data: [50, 40, 300, 220, 500, 250, 400, 230, 500],
maxBarThickness: 6
},
{
label: "Websites",
tension: 0.4,
borderWidth: 0,
pointRadius: 0,
borderColor: "#B37FEB",
borderWidth: 3,
data: [30, 90, 40, 140, 290, 290, 340, 230, 400],
maxBarThickness: 6
}
]
}
</script>

View File

@@ -0,0 +1,101 @@
<template>
<div>
<canvas ref="chartRef" :style="{ height: height + 'px' }"></canvas>
</div>
</template>
<script setup lang="ts">
import { Chart, registerables } from 'chart.js'
import { ref, onMounted, onBeforeUnmount } from 'vue'
// 注册 Chart.js 所有组件
Chart.register(...registerables)
// 定义 props
const props = defineProps<{
data: any
height: number
}>()
// chart 实例引用
const chartRef = ref<HTMLCanvasElement | null>(null)
let chartInstance: Chart | null = null
onMounted(() => {
if (chartRef.value) {
const ctx = chartRef.value.getContext('2d')
if (!ctx) return
chartInstance = new Chart(ctx, {
type: 'bar',
data: props.data,
options: {
layout: {
padding: { top: 30, right: 15, left: 10, bottom: 5 }
},
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { display: false }
},
// Chart.js v3+ 的 tooltip 配置在 plugins.tooltip
// 如果你用的是 v4tooltips 配置需要改为 plugins.tooltip
// 这里保留原写法
tooltips: {
enabled: true,
mode: 'index',
intersect: false
},
scales: {
y: {
grid: {
display: true,
color: 'rgba(255, 255, 255, .2)',
borderDash: [6],
borderDashOffset: 6
},
ticks: {
suggestedMin: 0,
suggestedMax: 1000,
display: true,
color: '#fff',
font: {
size: 14,
lineHeight: 1.5,
weight: '600',
family: 'Open Sans'
}
}
},
x: {
grid: { display: false },
ticks: {
display: true,
color: '#fff',
font: {
size: 14,
lineHeight: 1.5,
weight: '600',
family: 'Open Sans'
}
}
}
}
}
})
}
})
onBeforeUnmount(() => {
if (chartInstance) {
chartInstance.destroy()
chartInstance = null
}
})
</script>
<style scoped lang="scss">
canvas {
background-image: linear-gradient(to right, #00369E, #005CFD, #A18DFF);
}
</style>

View File

@@ -0,0 +1,98 @@
<template>
<div>
<canvas ref="chartRef" :style="{ height: height + 'px' }"></canvas>
</div>
</template>
<script setup lang="ts">
import { Chart, registerables } from 'chart.js'
import { ref, onMounted, onBeforeUnmount } from 'vue'
// 注册 Chart.js 所有组件
Chart.register(...registerables)
// 定义 props
const props = defineProps<{
data: any
height: number
}>()
// DOM 引用
const chartRef = ref<HTMLCanvasElement | null>(null)
// Chart 实例
let chartInstance: Chart | null = null
onMounted(() => {
if (!chartRef.value) return
const ctx = chartRef.value.getContext('2d')
if (!ctx) return
chartInstance = new Chart(ctx, {
type: 'line',
data: props.data,
options: {
layout: {
padding: { top: 30, right: 15, left: 10, bottom: 5 }
},
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { display: false }
},
// Chart.js v3+ 的 tooltip 配置在 plugins.tooltip
// 如果你用的是 v4需要改成 plugins.tooltip
tooltips: {
enabled: true,
mode: 'index',
intersect: false
},
scales: {
y: {
grid: {
display: true,
color: 'rgba(0, 0, 0, .2)',
borderDash: [6],
borderDashOffset: 6
},
ticks: {
suggestedMin: 0,
suggestedMax: 1000,
display: true,
color: '#8C8C8C',
font: {
size: 14,
lineHeight: 1.8,
weight: '600',
family: 'Open Sans'
}
}
},
x: {
grid: { display: false },
ticks: {
display: true,
color: '#8C8C8C',
font: {
size: 14,
lineHeight: 1.5,
weight: '600',
family: 'Open Sans'
}
}
}
}
}
})
})
onBeforeUnmount(() => {
if (chartInstance) {
chartInstance.destroy()
chartInstance = null
}
})
</script>
<style scoped lang="scss">
/* 你可以在这里加样式 */
</style>

View File

@@ -0,0 +1,34 @@
<template>
<div class="header-outside">
<a-layout-header class="header">
<div class="header-menu">
<div></div>
<div>
</div>
</div>
</a-layout-header>
</div>
</template>
<script lang="ts" setup>
import { DownOutlined } from '@ant-design/icons-vue';
</script>
<style scoped>
.header-menu{
display: flex;
justify-content: space-between;
align-items: center;
}
.header-outside {
position: sticky;
top: 0;
left: 0;
right: 0;
/* z-index: 9999; */
}
</style>

View File

@@ -0,0 +1,49 @@
<script setup>
import { ref, onMounted } from 'vue'
import {GreetService} from "../../bindings/go-site-clone";
import {Events} from "@wailsio/runtime";
const name = ref('')
const result = ref('Please enter your name below 👇')
const time = ref('Listening for Time event...')
const doGreet = () => {
let localName = name.value;
if (!localName) {
localName = 'anonymous';
}
GreetService.Greet(localName).then((resultValue) => {
result.value = resultValue;
}).catch((err) => {
console.log(err);
});
}
onMounted(() => {
Events.On('time', (timeValue) => {
time.value = timeValue.data;
});
})
defineProps({
msg: String,
})
</script>
<template>
<h1>{{ msg }}</h1>
<div class="result">{{ result }}</div>
<div class="card">
<div class="input-box">
<input class="input" v-model="name" type="text" autocomplete="off"/>
<button class="btn" @click="doGreet">Greet</button>
</div>
</div>
<div class="footer">
<div><p>Click on the Wails logo to learn more</p></div>
<div><p>{{ time }}</p></div>
</div>
</template>

View File

@@ -0,0 +1,72 @@
<template>
<div>
<div class="menu-out">
<a-layout-sider v-model:collapsed="collapsed" collapsible style="height: 100%;">
<div class="logo" />
<a-menu v-model:selectedKeys="selectedKeys" theme="dark" mode="inline" @click="menuClick">
<a-menu-item key="">
<pie-chart-outlined />
<span>控制台</span>
</a-menu-item>
<a-sub-menu key="device">
<template #title>
<span>
<user-outlined />
<span>设备管理</span>
</span>
</template>
<a-menu-item key="list">设备列表</a-menu-item>
</a-sub-menu>
</a-menu>
</a-layout-sider>
</div>
<div>
<a-layout-sider v-model:collapsed="collapsed" collapsible style="height: 100%;"></a-layout-sider>
</div>
</div>
</template>
<script lang="ts" setup>
import {
PieChartOutlined,
UserOutlined,
} from '@ant-design/icons-vue';
import { ref } from 'vue';
const collapsed = ref<boolean>(false);
const selectedKeys = ref<string[]>(['']);
function menuClick(e: any) {
console.log(e);
const keyList = e.keyPath
let path = ''
for (let i = 0; i < keyList.length; i++) {
const element = keyList[i];
path += "/"+element
}
navigateTo(path)
}
</script>
<style scoped>
.logo {
height: 32px;
margin: 16px;
background: rgba(255, 255, 255, 0.3);
}
.site-layout .site-layout-background {
background: #fff;
}
[data-theme='dark'] .site-layout .site-layout-background {
background: #141414;
}
.menu-out{
position: fixed;
top: 0;
bottom: 0;
left: 0;
z-index: 9999;
min-height: 100vh;
}
</style>

View File

@@ -0,0 +1,35 @@
<template>
<a-card :bordered="false" class="widget-1" style="margin-bottom: 20px;">
<a-statistic
:title="title"
:value="value"
:prefix="prefix"
:suffix="suffix"
:precision="0"
class="text-success"
:class="'text-' + status"
/>
<div class="icon" v-html="icon"></div>
</a-card>
</template>
<script setup lang="ts">
const props = defineProps<{
title?: string
value?: number
prefix?: string
suffix?: string
icon?: string
status?: string
}>()
// 默认值处理(可选)
const {
title = '',
value = 0,
prefix = '',
suffix = '',
icon = '',
status = 'success'
} = props
</script>

View File

@@ -0,0 +1,26 @@
<template>
<div>
<a-layout style="min-height: 100vh">
<SiderMenu />
<a-layout>
<Header></Header>
<a-layout-content style="margin: 0 16px">
<div style="min-height: calc(100vh - 155px)">
<slot />
</div>
</a-layout-content>
<a-layout-footer style="text-align: center">
<!-- Ant Design ©2018 Created by Ant UED -->
</a-layout-footer>
</a-layout>
</a-layout>
</div>
</template>
<script setup lang="ts">
onMounted(() => {
});
</script>

View File

@@ -0,0 +1,79 @@
<template>
<div>
<a-breadcrumb style="margin: 10px 0">
<a-breadcrumb-item>控制台</a-breadcrumb-item>
</a-breadcrumb>
<div>
<a-row :gutter="24">
<a-col :span="24" :lg="12" :xl="6" class="mb-24" v-for="(stat, index) in stats" :key="index">
<WidgetCounter :title="stat.title" :value="stat.value" :prefix="stat.prefix" :suffix="stat.suffix"
:icon="stat.icon" :status="stat.status"></WidgetCounter>
</a-col>
</a-row>
<a-row :gutter="24" type="flex" align="stretch">
<a-col :span="24" :lg="10" class="mb-24">
<CardBarChart></CardBarChart>
</a-col>
<a-col :span="24" :lg="14" class="mb-24">
<CardLineChart></CardLineChart>
</a-col>
</a-row>
</div>
</div>
</template>
<script setup lang="ts">
// Counter Widgets stats
const stats = [
{
title: "Todays Sales",
value: 53000,
prefix: "$",
suffix: "+30%",
icon: `
<svg width="22" height="22" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.43338 7.41784C8.58818 7.31464 8.77939 7.2224 9 7.15101L9.00001 8.84899C8.77939 8.7776 8.58818 8.68536 8.43338 8.58216C8.06927 8.33942 8 8.1139 8 8C8 7.8861 8.06927 7.66058 8.43338 7.41784Z" fill="#111827"/>
<path d="M11 12.849L11 11.151C11.2206 11.2224 11.4118 11.3146 11.5666 11.4178C11.9308 11.6606 12 11.8861 12 12C12 12.1139 11.9308 12.3394 11.5666 12.5822C11.4118 12.6854 11.2206 12.7776 11 12.849Z" fill="#111827"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 18C14.4183 18 18 14.4183 18 10C18 5.58172 14.4183 2 10 2C5.58172 2 2 5.58172 2 10C2 14.4183 5.58172 18 10 18ZM11 5C11 4.44772 10.5523 4 10 4C9.44772 4 9 4.44772 9 5V5.09199C8.3784 5.20873 7.80348 5.43407 7.32398 5.75374C6.6023 6.23485 6 7.00933 6 8C6 8.99067 6.6023 9.76515 7.32398 10.2463C7.80348 10.5659 8.37841 10.7913 9.00001 10.908L9.00002 12.8492C8.60902 12.7223 8.31917 12.5319 8.15667 12.3446C7.79471 11.9275 7.16313 11.8827 6.74599 12.2447C6.32885 12.6067 6.28411 13.2382 6.64607 13.6554C7.20855 14.3036 8.05956 14.7308 9 14.9076L9 15C8.99999 15.5523 9.44769 16 9.99998 16C10.5523 16 11 15.5523 11 15L11 14.908C11.6216 14.7913 12.1965 14.5659 12.676 14.2463C13.3977 13.7651 14 12.9907 14 12C14 11.0093 13.3977 10.2348 12.676 9.75373C12.1965 9.43407 11.6216 9.20873 11 9.09199L11 7.15075C11.391 7.27771 11.6808 7.4681 11.8434 7.65538C12.2053 8.07252 12.8369 8.11726 13.254 7.7553C13.6712 7.39335 13.7159 6.76176 13.354 6.34462C12.7915 5.69637 11.9405 5.26915 11 5.09236V5Z" fill="#111827"/>
</svg>`,
},
{
title: "Todays Users",
value: 3200,
suffix: "+20%",
icon: `
<svg width="22" height="22" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9 6C9 7.65685 7.65685 9 6 9C4.34315 9 3 7.65685 3 6C3 4.34315 4.34315 3 6 3C7.65685 3 9 4.34315 9 6Z" fill="#111827"/>
<path d="M17 6C17 7.65685 15.6569 9 14 9C12.3431 9 11 7.65685 11 6C11 4.34315 12.3431 3 14 3C15.6569 3 17 4.34315 17 6Z" fill="#111827"/>
<path d="M12.9291 17C12.9758 16.6734 13 16.3395 13 16C13 14.3648 12.4393 12.8606 11.4998 11.6691C12.2352 11.2435 13.0892 11 14 11C16.7614 11 19 13.2386 19 16V17H12.9291Z" fill="#111827"/>
<path d="M6 11C8.76142 11 11 13.2386 11 16V17H1V16C1 13.2386 3.23858 11 6 11Z" fill="#111827"/>
</svg>`,
},
{
title: "New Clients",
value: 1200,
prefix: "+",
status: "danger",
suffix: "-20%",
icon: `
<svg width="22" height="22" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.17157 5.17157C4.73367 3.60948 7.26633 3.60948 8.82843 5.17157L10 6.34315L11.1716 5.17157C12.7337 3.60948 15.2663 3.60948 16.8284 5.17157C18.3905 6.73367 18.3905 9.26633 16.8284 10.8284L10 17.6569L3.17157 10.8284C1.60948 9.26633 1.60948 6.73367 3.17157 5.17157Z" fill="#111827"/>
</svg>`,
},
{
title: "New Orders",
value: 13200,
prefix: "$",
suffix: "+10%",
icon: `
<svg width="22" height="22" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 2C7.79086 2 6 3.79086 6 6V7H5C4.49046 7 4.06239 7.38314 4.00612 7.88957L3.00612 16.8896C2.97471 17.1723 3.06518 17.455 3.25488 17.6669C3.44458 17.8789 3.71556 18 4 18H16C16.2844 18 16.5554 17.8789 16.7451 17.6669C16.9348 17.455 17.0253 17.1723 16.9939 16.8896L15.9939 7.88957C15.9376 7.38314 15.5096 7 15 7H14V6C14 3.79086 12.2091 2 10 2ZM12 7V6C12 4.89543 11.1046 4 10 4C8.89543 4 8 4.89543 8 6V7H12ZM6 10C6 9.44772 6.44772 9 7 9C7.55228 9 8 9.44772 8 10C8 10.5523 7.55228 11 7 11C6.44772 11 6 10.5523 6 10ZM13 9C12.4477 9 12 9.44772 12 10C12 10.5523 12.4477 11 13 11C13.5523 11 14 10.5523 14 10C14 9.44772 13.5523 9 13 9Z" fill="#111827"/>
</svg>`,
},
];
</script>
<style scoped></style>

View File

@@ -0,0 +1,8 @@
import { defineNuxtPlugin } from '#app'
import Antd, { notification } from 'ant-design-vue'
import 'ant-design-vue/dist/reset.css' // v4 使用新样式重置文件
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(Antd)
nuxtApp.provide('notification', notification)
})

View File

@@ -0,0 +1,15 @@
// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime";
/**
* @param {string} name
* @returns {$CancellablePromise<string>}
*/
export function Greet(name) {
return $Call.ByID(1411160069, name);
}

View File

@@ -0,0 +1,8 @@
// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
import * as GreetService from "./greetservice.js";
export {
GreetService
};

18
frontend/nuxt.config.ts Normal file
View File

@@ -0,0 +1,18 @@
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
compatibilityDate: '2025-07-15',
devtools: { enabled: true },
ssr: false, // 关闭 SSR改为 CSR
nitro: {
preset: 'static',
output: {
publicDir: './dist' // 相对 Nuxt3 项目根目录的路径
}
},
app: {
baseURL: './' // 确保相对路径,方便打包到 Wails
},
plugins: [
'~/plugins/ant-design-vue',
],
})

9655
frontend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

20
frontend/package.json Normal file
View File

@@ -0,0 +1,20 @@
{
"name": "nuxt-app",
"type": "module",
"private": true,
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare"
},
"dependencies": {
"@wailsio/runtime": "latest",
"ant-design-vue": "^4.2.6",
"chart.js": "^4.5.1",
"nuxt": "^4.1.2",
"vue": "^3.5.21",
"vue-router": "^4.5.1"
}
}

Binary file not shown.

BIN
frontend/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -0,0 +1,2 @@
User-Agent: *
Disallow:

145
frontend/public/style.css Normal file
View File

@@ -0,0 +1,145 @@
:root {
font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
font-size: 16px;
line-height: 24px;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: rgba(27, 38, 54, 1);
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
* {
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 400;
src: local(""),
url("./Inter-Medium.ttf") format("truetype");
}
h3 {
font-size: 3em;
line-height: 1.1;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
button {
width: 60px;
height: 30px;
line-height: 30px;
border-radius: 3px;
border: none;
margin: 0 0 0 20px;
padding: 0 8px;
cursor: pointer;
}
.result {
height: 20px;
line-height: 20px;
}
body {
margin: 0;
display: flex;
place-items: center;
place-content: center;
min-width: 320px;
min-height: 100vh;
}
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
#app {
max-width: 1280px;
margin: 0 auto;
text-align: center;
}
.result {
height: 20px;
line-height: 20px;
margin: 1.5rem auto;
text-align: center;
}
.footer {
margin-top: 1rem;
align-content: center;
text-align: center;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}
.input-box .btn:hover {
background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%);
color: #333333;
}
.input-box .input {
border: none;
border-radius: 3px;
outline: none;
height: 30px;
line-height: 30px;
padding: 0 10px;
color: black;
background-color: rgba(240, 240, 240, 1);
-webkit-font-smoothing: antialiased;
}
.input-box .input:hover {
border: none;
background-color: rgba(255, 255, 255, 1);
}
.input-box .input:focus {
border: none;
background-color: rgba(255, 255, 255, 1);
}

1
frontend/public/vue.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

After

Width:  |  Height:  |  Size: 496 B

BIN
frontend/public/wails.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

18
frontend/tsconfig.json Normal file
View File

@@ -0,0 +1,18 @@
{
// https://nuxt.com/docs/guide/concepts/typescript
"files": [],
"references": [
{
"path": "./.nuxt/tsconfig.app.json"
},
{
"path": "./.nuxt/tsconfig.server.json"
},
{
"path": "./.nuxt/tsconfig.shared.json"
},
{
"path": "./.nuxt/tsconfig.node.json"
}
]
}