初步实现功能

This commit is contained in:
2025-08-06 14:15:15 +08:00
parent cbe3f72d1c
commit d57b5fb540
8 changed files with 3657 additions and 58 deletions

View File

@ -1,7 +1,7 @@
const { app, BrowserWindow, ipcMain } = require('electron') const { app, BrowserWindow, ipcMain } = require("electron");
const path = require('path') const path = require("path");
let mainWindow let mainWindow;
function createWindow() { function createWindow() {
mainWindow = new BrowserWindow({ mainWindow = new BrowserWindow({
@ -9,22 +9,42 @@ function createWindow() {
height: 300, height: 300,
transparent: true, transparent: true,
frame: false, frame: false,
resizable: false, // 固定大小
webPreferences: { webPreferences: {
preload: path.join(__dirname, 'preload.js'), preload: path.join(__dirname, "preload.js"),
contextIsolation: true contextIsolation: true,
} },
}) });
// 开发模式加载Vite服务器 // 开发模式加载Vite服务器
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === "development") {
mainWindow.loadURL('http://localhost:5173') mainWindow.loadURL("http://localhost:5173");
} else { } else {
mainWindow.loadFile(path.join(__dirname, '../renderer/dist/index.html')) mainWindow.loadFile(path.join(__dirname, "../renderer/dist/index.html"));
} }
mainWindow.setIgnoreMouseEvents(true, { // 窗口拖拽功能
forward: true let isDragging = false;
}) mainWindow.webContents.on("before-input-event", (_, input) => {
if (input.type === "mouseDown") {
isDragging = true;
mainWindow.webContents.executeJavaScript(`
window.dragOffset = { x: ${input.x}, y: ${input.y} }
`);
} else if (input.type === "mouseUp") {
isDragging = false;
}
});
mainWindow.on("moved", () => {
if (isDragging) {
mainWindow.webContents.executeJavaScript(`
window.electronAPI.updatePosition()
`);
}
const [x, y] = mainWindow.getPosition();
mainWindow.webContents.send("update-position", { x, y });
});
} }
app.whenReady().then(createWindow) app.whenReady().then(createWindow);

View File

@ -1,6 +1,9 @@
const { contextBridge, ipcRenderer } = require('electron') const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', { contextBridge.exposeInMainWorld('electronAPI', {
playSound: (file) => ipcRenderer.send('play-sound', file), playSound: (soundFile) => ipcRenderer.send('play-sound', soundFile),
showTooltip: (text) => ipcRenderer.send('show-tooltip', text) showTooltip: (text) => ipcRenderer.send('show-tooltip', text),
onUpdatePosition: (callback) => {
ipcRenderer.on('update-position', (_, position) => callback(position))
}
}) })

View File

@ -4,7 +4,9 @@
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"dev": "concurrently \"cd renderer && npm run dev\" \"wait-on http://localhost:5173 && electron .\"" "dev": "concurrently \"cd renderer && npm run dev\" \"wait-on http://localhost:5173 && electron .\"",
"build": "cd renderer && npm run build && electron-builder",
"start": "electron ."
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -20,9 +22,14 @@
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^6.0.1", "@vitejs/plugin-vue": "^6.0.1",
"electron": "^37.2.5", "electron": "^37.2.5",
"vue": "^3.5.18" "vue": "^3.5.18",
"concurrently": "^8.0.0",
"vite": "^4.0.0",
"wait-on": "^7.0.0"
}, },
"dependencies": { "dependencies": {
"electron": "^37.2.5",
"vue": "^3.5.18",
"fs-extra": "^11.3.1", "fs-extra": "^11.3.1",
"howler": "^2.2.4", "howler": "^2.2.4",
"path": "^0.12.7" "path": "^0.12.7"

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,7 @@
"@vitejs/plugin-vue": "^6.0.0", "@vitejs/plugin-vue": "^6.0.0",
"@vue/tsconfig": "^0.7.0", "@vue/tsconfig": "^0.7.0",
"concurrently": "^9.2.0", "concurrently": "^9.2.0",
"electron-builder": "^26.0.12",
"typescript": "~5.8.3", "typescript": "~5.8.3",
"vite": "^7.0.4", "vite": "^7.0.4",
"vue-tsc": "^2.2.12", "vue-tsc": "^2.2.12",

View File

@ -1,39 +1,48 @@
<script setup> <script setup>
import { ref, onMounted } from 'vue' import { ref, onMounted } from "vue";
import petVideo from './assets/pet.mp4' import petGif from "./assets/pet.gif";
// 配置数据
const tooltips = [ const tooltips = [
"说的道理", "说的道理~",
] "尊尼获加",
const sounds = [ "为什么不开大!!",
"(凤鸣)",
] ];
const soundFiles = ["example.mp3"];
const showTooltip = ref(false) // 状态管理
const currentTooltip = ref('') const showTooltip = ref(false);
const currentTooltip = ref("");
const position = ref({ x: 0, y: 0 });
// 点击事件处理
const handleClick = () => { const handleClick = () => {
// 随机播放音效 const randomSound = soundFiles[Math.floor(Math.random() * soundFiles.length)];
const sound = sounds[Math.floor(Math.random() * sounds.length)] window.electronAPI?.playSound(randomSound);
window.electronAPI.playSound(sound)
currentTooltip.value = tooltips[Math.floor(Math.random() * tooltips.length)];
// 随机显示提示 showTooltip.value = true;
showTooltip.value = true setTimeout(() => (showTooltip.value = false), 2000);
currentTooltip.value = tooltips[Math.floor(Math.random() * tooltips.length)] };
setTimeout(() => showTooltip.value = false, 2000)
} // 初始化位置监听
onMounted(() => {
if (window.electronAPI) {
window.electronAPI.onUpdatePosition((pos) => {
position.value = pos;
});
}
});
</script> </script>
<template> <template>
<div class="container"> <div
<!-- MP4素材播放 --> class="pet-container"
<video :style="{ left: `${position.x}px`, top: `${position.y}px` }"
autoplay loop muted >
:src="petVideo" <img :src="petGif" class="pet-gif" @click="handleClick" draggable="false" />
@click="handleClick"
/>
<!-- 文字提示框 -->
<transition name="fade"> <transition name="fade">
<div v-if="showTooltip" class="tooltip"> <div v-if="showTooltip" class="tooltip">
{{ currentTooltip }} {{ currentTooltip }}
@ -43,22 +52,24 @@ const handleClick = () => {
</template> </template>
<style scoped> <style scoped>
.container { .pet-container {
width: 100vw; position: absolute;
height: 100vh; width: 300px;
overflow: hidden; height: 300px;
-webkit-app-region: no-drag;
} }
video { .pet-gif {
width: 100%; width: 100%;
height: 100%; height: 100%;
object-fit: contain;
cursor: pointer; cursor: pointer;
user-select: none;
-webkit-user-drag: none;
} }
.tooltip { .tooltip {
position: absolute; position: absolute;
bottom: 20px; bottom: -40px;
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
background: rgba(0, 0, 0, 0.7); background: rgba(0, 0, 0, 0.7);
@ -66,12 +77,15 @@ video {
padding: 8px 16px; padding: 8px 16px;
border-radius: 20px; border-radius: 20px;
font-size: 14px; font-size: 14px;
white-space: nowrap;
} }
.fade-enter-active, .fade-leave-active { .fade-enter-active,
transition: opacity 0.5s; .fade-leave-active {
transition: opacity 0.3s;
} }
.fade-enter, .fade-leave-to { .fade-enter-from,
.fade-leave-to {
opacity: 0; opacity: 0;
} }
</style> </style>

BIN
renderer/src/assets/pet.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 MiB

View File

@ -1,7 +1,11 @@
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue' import vue from '@vitejs/plugin-vue'
// https://vite.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [vue()], plugins: [vue()],
}) base: './',
build: {
assetsInlineLimit: 0
// 强制所有资源作为文件输出
}
})