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

@@ -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')