feat 临时

This commit is contained in:
2026-03-20 01:12:29 +08:00
parent a0baf2ad7c
commit 21965ef95e
14 changed files with 1186 additions and 98 deletions

View File

@@ -8,6 +8,7 @@
"name": "frontend",
"version": "0.0.0",
"dependencies": {
"element-plus": "^2.13.5",
"vue": "^3.2.37"
},
"devDependencies": {
@@ -61,6 +62,24 @@
"node": ">=6.9.0"
}
},
"node_modules/@ctrl/tinycolor": {
"version": "4.2.0",
"resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-4.2.0.tgz",
"integrity": "sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==",
"license": "MIT",
"engines": {
"node": ">=14"
}
},
"node_modules/@element-plus/icons-vue": {
"version": "2.3.2",
"resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz",
"integrity": "sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==",
"license": "MIT",
"peerDependencies": {
"vue": "^3.2.0"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.15.18",
"resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.15.18.tgz",
@@ -95,12 +114,69 @@
"node": ">=12"
}
},
"node_modules/@floating-ui/core": {
"version": "1.7.5",
"resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-1.7.5.tgz",
"integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==",
"license": "MIT",
"dependencies": {
"@floating-ui/utils": "^0.2.11"
}
},
"node_modules/@floating-ui/dom": {
"version": "1.7.6",
"resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.7.6.tgz",
"integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==",
"license": "MIT",
"dependencies": {
"@floating-ui/core": "^1.7.5",
"@floating-ui/utils": "^0.2.11"
}
},
"node_modules/@floating-ui/utils": {
"version": "0.2.11",
"resolved": "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.11.tgz",
"integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==",
"license": "MIT"
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5",
"resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"license": "MIT"
},
"node_modules/@popperjs/core": {
"name": "@sxzz/popperjs-es",
"version": "2.11.8",
"resolved": "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.8.tgz",
"integrity": "sha512-wOwESXvvED3S8xBmcPWHs2dUuzrE4XiZeFu7e1hROIJkm02a49N120pmOXxY33sBb6hArItm5W5tcg1cBtV+HQ==",
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@types/lodash": {
"version": "4.17.24",
"resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.24.tgz",
"integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==",
"license": "MIT"
},
"node_modules/@types/lodash-es": {
"version": "4.17.12",
"resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz",
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
"license": "MIT",
"dependencies": {
"@types/lodash": "*"
}
},
"node_modules/@types/web-bluetooth": {
"version": "0.0.20",
"resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz",
"integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==",
"license": "MIT"
},
"node_modules/@vitejs/plugin-vue": {
"version": "3.2.0",
"resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-3.2.0.tgz",
@@ -215,12 +291,85 @@
"integrity": "sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==",
"license": "MIT"
},
"node_modules/@vueuse/core": {
"version": "12.0.0",
"resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-12.0.0.tgz",
"integrity": "sha512-C12RukhXiJCbx4MGhjmd/gH52TjJsc3G0E0kQj/kb19H3Nt6n1CA4DRWuTdWWcaFRdlTe0npWDS942mvacvNBw==",
"license": "MIT",
"dependencies": {
"@types/web-bluetooth": "^0.0.20",
"@vueuse/metadata": "12.0.0",
"@vueuse/shared": "12.0.0",
"vue": "^3.5.13"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/metadata": {
"version": "12.0.0",
"resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-12.0.0.tgz",
"integrity": "sha512-Yzimd1D3sjxTDOlF05HekU5aSGdKjxhuhRFHA7gDWLn57PRbBIh+SF5NmjhJ0WRgF3my7T8LBucyxdFJjIfRJQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/shared": {
"version": "12.0.0",
"resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-12.0.0.tgz",
"integrity": "sha512-3i6qtcq2PIio5i/vVYidkkcgvmTjCqrf26u+Fd4LhnbBmIT6FN8y6q/GJERp8lfcB9zVEfjdV0Br0443qZuJpw==",
"license": "MIT",
"dependencies": {
"vue": "^3.5.13"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/async-validator": {
"version": "4.2.5",
"resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz",
"integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==",
"license": "MIT"
},
"node_modules/csstype": {
"version": "3.2.3",
"resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
"license": "MIT"
},
"node_modules/dayjs": {
"version": "1.11.20",
"resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.20.tgz",
"integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==",
"license": "MIT"
},
"node_modules/element-plus": {
"version": "2.13.5",
"resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.13.5.tgz",
"integrity": "sha512-dmY24fhSREfZN/PuUt0YZigMso7wWzl+B5o+YKNN15kQIn/0hzamsPU+ebj9SES0IbUqsLX1wkrzYmzU8VrVOQ==",
"license": "MIT",
"dependencies": {
"@ctrl/tinycolor": "^4.2.0",
"@element-plus/icons-vue": "^2.3.2",
"@floating-ui/dom": "^1.0.1",
"@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
"@types/lodash": "^4.17.20",
"@types/lodash-es": "^4.17.12",
"@vueuse/core": "12.0.0",
"async-validator": "^4.2.5",
"dayjs": "^1.11.19",
"lodash": "^4.17.23",
"lodash-es": "^4.17.23",
"lodash-unified": "^1.0.3",
"memoize-one": "^6.0.0",
"normalize-wheel-es": "^1.2.0"
},
"peerDependencies": {
"vue": "^3.3.0"
}
},
"node_modules/entities": {
"version": "7.0.1",
"resolved": "https://registry.npmmirror.com/entities/-/entities-7.0.1.tgz",
@@ -671,6 +820,29 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/lodash": {
"version": "4.17.23",
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.23.tgz",
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
"license": "MIT"
},
"node_modules/lodash-es": {
"version": "4.17.23",
"resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.23.tgz",
"integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==",
"license": "MIT"
},
"node_modules/lodash-unified": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.3.tgz",
"integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==",
"license": "MIT",
"peerDependencies": {
"@types/lodash-es": "*",
"lodash": "*",
"lodash-es": "*"
}
},
"node_modules/magic-string": {
"version": "0.30.21",
"resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz",
@@ -680,6 +852,12 @@
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/memoize-one": {
"version": "6.0.0",
"resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz",
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==",
"license": "MIT"
},
"node_modules/nanoid": {
"version": "3.3.11",
"resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz",
@@ -698,6 +876,12 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/normalize-wheel-es": {
"version": "1.2.0",
"resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz",
"integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==",
"license": "BSD-3-Clause"
},
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz",

View File

@@ -9,10 +9,11 @@
"preview": "vite preview"
},
"dependencies": {
"element-plus": "^2.13.5",
"vue": "^3.2.37"
},
"devDependencies": {
"@vitejs/plugin-vue": "^3.0.3",
"vite": "^3.0.7"
}
}
}

View File

@@ -1 +1 @@
21d2a2199c4fb87865d8160b492f51c3
1ad03e99e099a0ecaf49d3493b03c367

View File

@@ -1,21 +1,200 @@
<script setup>
import HelloWorld from './components/HelloWorld.vue'</script>
import { ref, watch } from 'vue'
import Sidebar from './components/Sidebar.vue'
import { GetNovelContent, WriteNovelContent } from '../wailsjs/go/backend/App'
const activeButton = ref('')
const content = ref('请选择要查看的小说')
const currentTitle = ref('小说内容')
const viewMode = ref('original')
const currentFilename = ref('')
const isLoading = ref(false)
// 监听 viewMode 变化
watch(viewMode, (newMode) => {
if (newMode === 'imitation') {
content.value = currentFilename.value + ' 的仿写内容'
} else if (newMode === 'original' && currentFilename.value) {
// 切换回原文模式时,重新加载原文
handleMenuClick({ id: activeButton.value, filename: currentFilename.value })
}
})
async function handleMenuClick(menuData) {
if (menuData && menuData.id) {
activeButton.value = menuData.id
viewMode.value = 'original'
// 检查是否是小说文件
if (menuData.id.startsWith('novel') && menuData.filename) {
currentFilename.value = menuData.filename
currentTitle.value = `小说内容 - ${menuData.filename}`
content.value = '加载中...'
try {
const novelContent = await GetNovelContent(menuData.filename)
content.value = novelContent
} catch (error) {
console.error('Error loading novel content:', error)
content.value = '加载小说内容失败'
}
} else {
currentTitle.value = '小说内容'
content.value = '请选择要查看的小说'
}
}
}
async function handleImitation() {
if (currentFilename.value) {
isLoading.value = true
content.value = '正在生成仿写内容...'
try {
const imitationContent = await WriteNovelContent(currentFilename.value)
content.value = imitationContent
} catch (error) {
console.error('Error generating imitation content:', error)
content.value = '生成仿写内容失败'
} finally {
isLoading.value = false
}
} else {
content.value = '请先选择要仿写的小说'
}
}
</script>
<template>
<img id="logo" alt="Wails logo" src="./assets/images/logo-universal.png"/>
<HelloWorld/>
<div class="container">
<Sidebar
v-model:activeButton="activeButton"
@menu-click="handleMenuClick"
/>
<div class="content">
<div class="content-header">
<h3>{{ currentTitle }}</h3>
<div class="header-buttons" v-if="activeButton">
<el-button
:type="viewMode === 'original' ? 'primary' : 'default'"
@click="viewMode = 'original'"
>
原文
</el-button>
<el-button
:type="viewMode === 'imitation' ? 'primary' : 'default'"
@click="viewMode = 'imitation'"
>
仿文
</el-button>
</div>
</div>
<div class="content-body">
<div v-if="viewMode === 'original'">
{{ content }}
</div>
<div v-else-if="viewMode === 'imitation'" class="imitation-container">
<div v-if="!isLoading && (content === '请选择要查看的小说' || content === '正在生成仿写内容...' || content === currentFilename + ' 的仿写内容')" class="imitation-button-container">
<el-button
type="primary"
size="large"
class="imitation-button"
@click="handleImitation"
:loading="isLoading"
:disabled="isLoading"
>
仿写
</el-button>
</div>
<div v-else class="imitation-content">
{{ content }}
</div>
</div>
<div v-else>
{{ content }}
</div>
</div>
</div>
</div>
</template>
<style>
#logo {
display: block;
width: 50%;
height: 50%;
margin: auto;
padding: 10% 0 0;
background-position: center;
background-repeat: no-repeat;
background-size: 100% 100%;
background-origin: content-box;
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
background-color: #1b2636;
color: #fff;
}
.container {
display: flex;
height: 100vh;
overflow: hidden;
}
.content {
flex: 1;
display: flex;
flex-direction: column;
padding: 20px;
overflow-y: auto;
}
.content-header {
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
display: flex;
justify-content: space-between;
align-items: center;
}
.content-header h3 {
color: #fff;
font-size: 18px;
margin: 0;
}
.header-buttons {
display: flex;
gap: 10px;
}
.content-body {
flex: 1;
background-color: rgba(255, 255, 255, 0.05);
border-radius: 8px;
padding: 20px;
color: #ecf0f1;
min-height: 400px;
}
.imitation-container {
height: 100%;
padding: 20px;
}
.imitation-button-container {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
.imitation-button {
padding: 15px 30px;
font-size: 18px;
}
.imitation-content {
height: 100%;
overflow-y: auto;
white-space: pre-wrap;
word-break: break-word;
}
</style>

View File

@@ -1,71 +0,0 @@
<script setup>
import {reactive} from 'vue'
import {Greet} from '../../wailsjs/go/backend/App'
const data = reactive({
name: "",
resultText: "Please enter your name below 👇",
})
function greet() {
Greet(data.name).then(result => {
data.resultText = result
})
}
</script>
<template>
<main>
<div id="result" class="result">{{ data.resultText }}</div>
<div id="input" class="input-box">
<input id="name" v-model="data.name" autocomplete="off" class="input" type="text"/>
<button class="btn" @click="greet">Greet</button>
</div>
</main>
</template>
<style scoped>
.result {
height: 20px;
line-height: 20px;
margin: 1.5rem auto;
}
.input-box .btn {
width: 60px;
height: 30px;
line-height: 30px;
border-radius: 3px;
border: none;
margin: 0 0 0 20px;
padding: 0 8px;
cursor: pointer;
}
.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;
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);
}
</style>

View File

@@ -0,0 +1,114 @@
<script setup>
import { ref, onMounted } from 'vue'
import { Document } from '@element-plus/icons-vue'
import { GetNovelList } from '../../wailsjs/go/backend/App'
const props = defineProps({
activeButton: {
type: String,
default: ''
}
})
const emit = defineEmits(['update:activeButton', 'menu-click'])
const novels = ref([])
function handleNovelClick(novelId, novelLabel) {
emit('update:activeButton', novelId)
emit('menu-click', { id: novelId, filename: novelLabel })
}
async function loadNovelList() {
try {
const novelList = await GetNovelList()
novels.value = novelList.map((novel, index) => ({
id: `novel${index + 1}`,
label: novel
}))
} catch (error) {
console.error('Error loading novel list:', error)
novels.value = []
}
}
onMounted(() => {
// 组件挂载时加载小说列表
loadNovelList()
})
</script>
<template>
<div class="sidebar">
<h2>小说列表</h2>
<div class="novel-list">
<div
v-for="novel in novels"
:key="novel.id"
class="novel-item"
:class="{ active: activeButton === novel.id }"
@click="handleNovelClick(novel.id, novel.label)"
>
<el-icon><Document /></el-icon>
<span>{{ novel.label }}</span>
</div>
<div v-if="novels.length === 0" class="empty-state">
暂无小说文件
</div>
</div>
</div>
</template>
<style scoped>
.sidebar {
width: 400px;
background-color: #2c3e50;
padding: 20px 0;
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
height: 100vh;
overflow-y: auto;
}
.sidebar h2 {
text-align: center;
margin-bottom: 20px;
color: #fff;
font-size: 18px;
}
.novel-list {
padding: 0 10px;
}
.novel-item {
display: flex;
align-items: center;
padding: 12px 15px;
margin-bottom: 5px;
border-radius: 5px;
color: #ecf0f1;
cursor: pointer;
transition: background-color 0.3s;
}
.novel-item:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.novel-item.active {
background-color: #3498db;
color: #fff;
}
.novel-item .el-icon {
margin-right: 10px;
font-size: 16px;
}
.empty-state {
padding: 20px;
text-align: center;
color: #95a5a6;
font-style: italic;
}
</style>

View File

@@ -1,5 +1,12 @@
import {createApp} from 'vue'
import App from './App.vue'
import './style.css';
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
createApp(App).mount('#app')
const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.use(ElementPlus).mount('#app')

View File

@@ -1,6 +1,8 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
export function Greet(arg1:string):Promise<string>;
export function GetNovelContent(arg1:string):Promise<string>;
export function Greet2(arg1:string):Promise<string>;
export function GetNovelList():Promise<Array<string>>;
export function WriteNovelContent(arg1:string):Promise<string>;

View File

@@ -2,10 +2,14 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
export function Greet(arg1) {
return window['go']['backend']['App']['Greet'](arg1);
export function GetNovelContent(arg1) {
return window['go']['backend']['App']['GetNovelContent'](arg1);
}
export function Greet2(arg1) {
return window['go']['backend']['App']['Greet2'](arg1);
export function GetNovelList() {
return window['go']['backend']['App']['GetNovelList']();
}
export function WriteNovelContent(arg1) {
return window['go']['backend']['App']['WriteNovelContent'](arg1);
}