mirror of
https://github.com/YILS-LIN/short-video-factory.git
synced 2025-11-25 03:15:03 +08:00
优化IPC通信暴露方法的结构和类型,增加文件夹选择与文件列出基础方法
This commit is contained in:
20
electron/electron-env.d.ts
vendored
20
electron/electron-env.d.ts
vendored
@@ -23,12 +23,20 @@ declare namespace NodeJS {
|
||||
|
||||
// 在渲染器进程中使用,在 `preload.ts` 中暴露方法
|
||||
interface Window {
|
||||
ipcRenderer: import('electron').IpcRenderer
|
||||
ipcRenderer: Pick<import('electron').IpcRenderer, 'on' | 'once' | 'off' | 'send' | 'invoke'>
|
||||
electron: {
|
||||
isWinMaxed: () => Promise<boolean>
|
||||
winMin: () => void
|
||||
winMax: () => void
|
||||
winClose: () => void
|
||||
selectFolder: (params: import('./types').SelectFolderParams) => Promise<string>
|
||||
listFilesFromFolder: (params: import('./types').ListFilesFromFolderParams) => Promise<string[]>
|
||||
}
|
||||
sqlite: {
|
||||
query: (param: import('./sqlite/types').queryParam) => Promise<any>
|
||||
insert: (param: import('./sqlite/types').insertParam) => Promise<any>
|
||||
update: (param: import('./sqlite/types').updateParam) => Promise<any>
|
||||
delete: (param: import('./sqlite/types').deleteParam) => Promise<any>
|
||||
bulkInsertOrUpdate: (param: import('./sqlite/types').bulkInsertOrUpdateParam) => Promise<any>
|
||||
query: (param: import('./sqlite/types').queryParams) => Promise<any>
|
||||
insert: (param: import('./sqlite/types').insertParams) => Promise<any>
|
||||
update: (param: import('./sqlite/types').updateParams) => Promise<any>
|
||||
delete: (param: import('./sqlite/types').deleteParams) => Promise<any>
|
||||
bulkInsertOrUpdate: (param: import('./sqlite/types').bulkInsertOrUpdateParams) => Promise<any>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { BrowserWindow, ipcMain } from 'electron'
|
||||
import { queryParam, insertParam, updateParam, deleteParam } from './sqlite/types'
|
||||
import { BrowserWindow, ipcMain, dialog, app } from 'electron'
|
||||
import { queryParams, insertParams, updateParams, deleteParams } from './sqlite/types'
|
||||
import { sqBulkInsertOrUpdate, sqDelete, sqInsert, sqQuery, sqUpdate } from './sqlite'
|
||||
import { ListFilesFromFolderParams, SelectFolderParams } from './types'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
@@ -18,8 +20,29 @@ process.env.VITE_PUBLIC = VITE_DEV_SERVER_URL
|
||||
: RENDERER_DIST
|
||||
|
||||
export default function initIPC(win: BrowserWindow) {
|
||||
// sqlite 查询
|
||||
ipcMain.handle('sqlite-query', (_event, params: queryParams) => {
|
||||
return sqQuery(params)
|
||||
})
|
||||
// sqlite 插入
|
||||
ipcMain.handle('sqlite-insert', (_event, params: insertParams) => {
|
||||
return sqInsert(params)
|
||||
})
|
||||
// sqlite 更新
|
||||
ipcMain.handle('sqlite-update', (_event, params: updateParams) => {
|
||||
return sqUpdate(params)
|
||||
})
|
||||
// sqlite 删除
|
||||
ipcMain.handle('sqlite-delete', (_event, params: deleteParams) => {
|
||||
return sqDelete(params)
|
||||
})
|
||||
// sqlite 批量插入或更新
|
||||
ipcMain.handle('sqlite-bulk-insert-or-update', (_event, params: any) => {
|
||||
return sqBulkInsertOrUpdate(params)
|
||||
})
|
||||
|
||||
// 是否最大化
|
||||
ipcMain.handle('win-maxed', () => {
|
||||
ipcMain.handle('is-win-maxed', () => {
|
||||
return win?.isMaximized()
|
||||
})
|
||||
//最小化
|
||||
@@ -39,24 +62,23 @@ export default function initIPC(win: BrowserWindow) {
|
||||
win?.close()
|
||||
})
|
||||
|
||||
// sqlite 查询
|
||||
ipcMain.handle('sqlite-query', (_event, params: queryParam) => {
|
||||
return sqQuery(params)
|
||||
// 选择文件夹
|
||||
ipcMain.handle('select-folder', async (_event, params?: SelectFolderParams) => {
|
||||
const result = await dialog.showOpenDialog(win, {
|
||||
properties: ['openDirectory'],
|
||||
title: params?.title || '选择文件夹',
|
||||
defaultPath: params?.defaultPath || app.getPath('downloads'), // 默认打开 Downloads
|
||||
})
|
||||
if (!result.canceled && result.filePaths.length > 0) {
|
||||
return result.filePaths[0] // 返回绝对路径
|
||||
}
|
||||
return null
|
||||
})
|
||||
// sqlite 插入
|
||||
ipcMain.handle('sqlite-insert', async (_event, params: insertParam) => {
|
||||
return await sqInsert(params)
|
||||
})
|
||||
// sqlite 更新
|
||||
ipcMain.handle('sqlite-update', async (_event, params: updateParam) => {
|
||||
return await sqUpdate(params)
|
||||
})
|
||||
// sqlite 删除
|
||||
ipcMain.handle('sqlite-delete', async (_event, params: deleteParam) => {
|
||||
return await sqDelete(params)
|
||||
})
|
||||
// sqlite 批量插入或更新
|
||||
ipcMain.handle('sqlite-bulk-insert-or-update', async (_event, params: any) => {
|
||||
return await sqBulkInsertOrUpdate(params)
|
||||
|
||||
// 读取文件夹内所有文件
|
||||
ipcMain.handle('list-files-from-folder', async (_event, params: ListFilesFromFolderParams) => {
|
||||
const files = await fs.promises.readdir(params.folderPath, { withFileTypes: true })
|
||||
|
||||
return files.filter((file) => file.isFile()).map((file) => file.name)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { ipcRenderer, contextBridge } from 'electron'
|
||||
import { queryParam, insertParam, updateParam, deleteParam } from './sqlite/types'
|
||||
import { queryParams, insertParams, updateParams, deleteParams } from './sqlite/types'
|
||||
import { ListFilesFromFolderParams, SelectFolderParams } from './types'
|
||||
|
||||
// --------- 向界面渲染进程暴露某些API ---------
|
||||
|
||||
@@ -26,20 +27,20 @@ contextBridge.exposeInMainWorld('ipcRenderer', {
|
||||
},
|
||||
})
|
||||
|
||||
contextBridge.exposeInMainWorld('sqlite', {
|
||||
query: async (param: queryParam) => {
|
||||
return await ipcRenderer.invoke('sqlite-query', param)
|
||||
},
|
||||
insert: async (param: insertParam) => {
|
||||
return await ipcRenderer.invoke('sqlite-insert', param)
|
||||
},
|
||||
update: async (param: updateParam) => {
|
||||
return await ipcRenderer.invoke('sqlite-update', param)
|
||||
},
|
||||
delete: async (param: deleteParam) => {
|
||||
return await ipcRenderer.invoke('sqlite-delete', param)
|
||||
},
|
||||
bulkInsertOrUpdate: async (param: any) => {
|
||||
return await ipcRenderer.invoke('sqlite-bulk-insert-or-update', param)
|
||||
},
|
||||
contextBridge.exposeInMainWorld('electron', {
|
||||
isWinMaxed: () => ipcRenderer.invoke('is-win-maxed'),
|
||||
winMin: () => ipcRenderer.send('win-min'),
|
||||
winMax: () => ipcRenderer.send('win-max'),
|
||||
winClose: () => ipcRenderer.send('win-close'),
|
||||
selectFolder: (params: SelectFolderParams) => ipcRenderer.invoke('select-folder', params),
|
||||
listFilesFromFolder: (params: ListFilesFromFolderParams) =>
|
||||
ipcRenderer.invoke('list-files-from-folder', params),
|
||||
})
|
||||
|
||||
contextBridge.exposeInMainWorld('sqlite', {
|
||||
query: (params: queryParams) => ipcRenderer.invoke('sqlite-query', params),
|
||||
insert: (params: insertParams) => ipcRenderer.invoke('sqlite-insert', params),
|
||||
update: (params: updateParams) => ipcRenderer.invoke('sqlite-update', params),
|
||||
delete: (params: deleteParams) => ipcRenderer.invoke('sqlite-delete', params),
|
||||
bulkInsertOrUpdate: (params: any) => ipcRenderer.invoke('sqlite-bulk-insert-or-update', params),
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import BetterSqlite3 from 'better-sqlite3'
|
||||
import { queryParam, insertParam, updateParam, deleteParam, bulkInsertOrUpdateParam } from './types'
|
||||
import { queryParams, insertParams, updateParams, deleteParams, bulkInsertOrUpdateParams } from './types'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
process.env.APP_ROOT = path.join(__dirname, '..')
|
||||
@@ -53,7 +53,7 @@ class Database {
|
||||
})
|
||||
}
|
||||
|
||||
query(param: queryParam): Promise<any[]> {
|
||||
query(param: queryParams): Promise<any[]> {
|
||||
return new Promise<any[]>((resolve, _reject) => {
|
||||
const stmt = this.db.prepare(param.sql)
|
||||
const rows = param.params ? stmt.all(...param.params) : stmt.all()
|
||||
@@ -61,7 +61,7 @@ class Database {
|
||||
})
|
||||
}
|
||||
|
||||
insert(param: insertParam): Promise<number> {
|
||||
insert(param: insertParams): Promise<number> {
|
||||
return new Promise<number>((resolve, _reject) => {
|
||||
const keys = Object.keys(param.data)
|
||||
const values = Object.values(param.data)
|
||||
@@ -79,7 +79,7 @@ class Database {
|
||||
return result.length > 0
|
||||
}
|
||||
|
||||
update(param: updateParam): Promise<number> {
|
||||
update(param: updateParams): Promise<number> {
|
||||
return new Promise<number>((resolve, _reject) => {
|
||||
const entries = Object.entries(param.data)
|
||||
.map(([key, _value]) => `${key} = ?`)
|
||||
@@ -93,7 +93,7 @@ class Database {
|
||||
})
|
||||
}
|
||||
|
||||
delete(param: deleteParam): Promise<void> {
|
||||
delete(param: deleteParams): Promise<void> {
|
||||
return new Promise<void>((resolve, _reject) => {
|
||||
const sql = `DELETE FROM ${param.table} WHERE ${param.condition}`
|
||||
const stmt = this.db.prepare(sql)
|
||||
@@ -102,7 +102,7 @@ class Database {
|
||||
})
|
||||
}
|
||||
|
||||
async bulkInsertOrUpdate(param: bulkInsertOrUpdateParam): Promise<void> {
|
||||
async bulkInsertOrUpdate(param: bulkInsertOrUpdateParams): Promise<void> {
|
||||
return new Promise<void>((resolve, _reject) => {
|
||||
const keys = Object.keys(param.data[0])
|
||||
const placeholders = keys.map(() => '?').join(',')
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
export interface queryParam {
|
||||
export interface queryParams {
|
||||
sql: string
|
||||
params?: any[]
|
||||
}
|
||||
|
||||
export interface insertParam {
|
||||
export interface insertParams {
|
||||
table: string
|
||||
data: { [key: string]: any }
|
||||
}
|
||||
|
||||
export interface updateParam {
|
||||
export interface updateParams {
|
||||
table: string
|
||||
data: { [key: string]: any }
|
||||
condition: string
|
||||
}
|
||||
|
||||
export interface deleteParam {
|
||||
export interface deleteParams {
|
||||
table: string
|
||||
condition: string
|
||||
}
|
||||
|
||||
export interface bulkInsertOrUpdateParam {
|
||||
export interface bulkInsertOrUpdateParams {
|
||||
table: string
|
||||
data: any[]
|
||||
}
|
||||
|
||||
8
electron/types.ts
Normal file
8
electron/types.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export interface SelectFolderParams {
|
||||
title?: string
|
||||
defaultPath?: string
|
||||
}
|
||||
|
||||
export interface ListFilesFromFolderParams {
|
||||
folderPath: string
|
||||
}
|
||||
@@ -32,6 +32,7 @@
|
||||
"devDependencies": {
|
||||
"@mdi/font": "^7.4.47",
|
||||
"@types/better-sqlite3": "^7.6.13",
|
||||
"@types/wicg-file-system-access": "^2023.10.6",
|
||||
"@vitejs/plugin-vue": "^6.0.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"electron": "^22.3.27",
|
||||
|
||||
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
@@ -48,6 +48,9 @@ importers:
|
||||
'@types/better-sqlite3':
|
||||
specifier: ^7.6.13
|
||||
version: 7.6.13
|
||||
'@types/wicg-file-system-access':
|
||||
specifier: ^2023.10.6
|
||||
version: 2023.10.6
|
||||
'@vitejs/plugin-vue':
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.0(vite@7.0.3(@types/node@24.0.12)(jiti@2.4.2)(sass@1.89.2))(vue@3.5.17(typescript@5.6.2))
|
||||
@@ -792,6 +795,9 @@ packages:
|
||||
'@types/web-bluetooth@0.0.21':
|
||||
resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==}
|
||||
|
||||
'@types/wicg-file-system-access@2023.10.6':
|
||||
resolution: {integrity: sha512-YO/183gNRzZFSdKu+ikkD7ambAj4PhgjFAF2A/Mw/7wroSF6ne8r804RkpZzqrJ/F6DO2/IYlQF/ULOZ/bhKyA==}
|
||||
|
||||
'@types/yauzl@2.10.3':
|
||||
resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
|
||||
|
||||
@@ -3310,6 +3316,8 @@ snapshots:
|
||||
|
||||
'@types/web-bluetooth@0.0.21': {}
|
||||
|
||||
'@types/wicg-file-system-access@2023.10.6': {}
|
||||
|
||||
'@types/yauzl@2.10.3':
|
||||
dependencies:
|
||||
'@types/node': 16.18.126
|
||||
|
||||
0
src/global.d.ts
vendored
Normal file
0
src/global.d.ts
vendored
Normal file
@@ -29,17 +29,17 @@ const route = useRoute()
|
||||
const windowIsMaxed = ref(false)
|
||||
|
||||
window.addEventListener('resize', async () => {
|
||||
windowIsMaxed.value = await window.ipcRenderer.invoke('win-maxed')
|
||||
windowIsMaxed.value = await window.electron.isWinMaxed()
|
||||
})
|
||||
|
||||
const handleMin = () => {
|
||||
window.ipcRenderer.send('win-min')
|
||||
window.electron.winMin()
|
||||
}
|
||||
const handleMax = () => {
|
||||
window.ipcRenderer.send('win-max')
|
||||
window.electron.winMax()
|
||||
}
|
||||
const handleClose = () => {
|
||||
window.ipcRenderer.send('win-close')
|
||||
window.electron.winClose()
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -10,15 +10,19 @@ export const useAppStore = defineStore(
|
||||
apiUrl: '',
|
||||
apiKey: '',
|
||||
})
|
||||
|
||||
const updateLLMConfig = (newConfig: typeof llmConfig.value) => {
|
||||
llmConfig.value = newConfig
|
||||
}
|
||||
|
||||
const videoAssetsFolder = ref('')
|
||||
const videoExportFolder = ref('')
|
||||
|
||||
return {
|
||||
prompt,
|
||||
llmConfig,
|
||||
updateLLMConfig,
|
||||
videoAssetsFolder,
|
||||
videoExportFolder,
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -2,8 +2,15 @@
|
||||
<div class="w-full h-full">
|
||||
<v-sheet class="h-full p-2 flex flex-col" border rounded>
|
||||
<div class="flex gap-2">
|
||||
<v-text-field label="分镜视频素材文件夹" density="compact"></v-text-field>
|
||||
<v-btn class="mt-[2px]" prepend-icon="mdi-folder-open"> 选择 </v-btn>
|
||||
<v-text-field
|
||||
:model-value="appStore.videoAssetsFolder"
|
||||
label="分镜视频素材文件夹"
|
||||
density="compact"
|
||||
readonly
|
||||
></v-text-field>
|
||||
<v-btn class="mt-[2px]" prepend-icon="mdi-folder-open" @click="handleSelectFolder">
|
||||
选择
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 h-full w-full border">
|
||||
@@ -14,14 +21,37 @@
|
||||
</div>
|
||||
|
||||
<div class="my-2">
|
||||
<v-btn prepend-icon="mdi-refresh" block> 刷新素材库 </v-btn>
|
||||
<v-btn prepend-icon="mdi-refresh" block @click="refreshAssets"> 刷新素材库 </v-btn>
|
||||
</div>
|
||||
</v-sheet>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//
|
||||
import { useAppStore } from '@/store'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const appStore = useAppStore()
|
||||
|
||||
const handleSelectFolder = async () => {
|
||||
const folderPath = await window.electron.selectFolder({
|
||||
title: '选择分镜素材文件夹',
|
||||
defaultPath: appStore.videoAssetsFolder,
|
||||
})
|
||||
if (folderPath) {
|
||||
appStore.videoAssetsFolder = folderPath
|
||||
}
|
||||
console.log('用户选择的文件夹绝对路径:', folderPath)
|
||||
}
|
||||
|
||||
const videoAssets = ref([])
|
||||
const refreshAssets = async () => {
|
||||
console.log('刷新素材库')
|
||||
const assets = await window.electron.listFilesFromFolder({
|
||||
folderPath: appStore.videoAssetsFolder,
|
||||
})
|
||||
console.log(`素材:`, assets)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
Reference in New Issue
Block a user