Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
3657364146 | |||
ae3c4abac2 | |||
4cf5a6d2f6 | |||
f146d3dca7 | |||
79128529bf | |||
b65cb471e3 | |||
ef444ad9e8 | |||
d8342fe580 |
16
.eslintrc.json
Normal file
16
.eslintrc.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:import/recommended",
|
||||
"plugin:import/electron",
|
||||
"plugin:import/typescript"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser"
|
||||
}
|
14
.gitignore
vendored
14
.gitignore
vendored
@ -1,3 +1,13 @@
|
||||
/node_modules
|
||||
/.next
|
||||
src/.umi
|
||||
/.env.local
|
||||
/.umirc.local.ts
|
||||
/config/config.local.ts
|
||||
/src/.umi
|
||||
/src/.umi-production
|
||||
/src/.umi-test
|
||||
/dist
|
||||
.swc
|
||||
.electron
|
||||
.electron-production
|
||||
yarn-error.log
|
||||
pnpm-lock.yaml
|
||||
|
4
.npmrc
Normal file
4
.npmrc
Normal file
@ -0,0 +1,4 @@
|
||||
registry=https://registry.npmmirror.com
|
||||
strict-peer-dependencies=false
|
||||
electron-mirror=https://registry.npmmirror.com/-/binary/electron/
|
||||
electron-builder-binaries-mirror=https://registry.npmmirror.com/binary.html?path=electron-builder-binaries/
|
3
.prettierignore
Normal file
3
.prettierignore
Normal file
@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
.umi
|
||||
.umi-production
|
8
.prettierrc
Normal file
8
.prettierrc
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"printWidth": 80,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"proseWrap": "never",
|
||||
"overrides": [{ "files": ".prettierrc", "options": { "parser": "json" } }],
|
||||
"plugins": ["prettier-plugin-organize-imports", "prettier-plugin-packagejson"]
|
||||
}
|
30
.umirc.ts
Normal file
30
.umirc.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { defineConfig } from "umi";
|
||||
import { Platform, createTargets } from "@umijs/plugin-electron";
|
||||
|
||||
// example: mac & windows
|
||||
const targets = createTargets([Platform.WINDOWS]);
|
||||
|
||||
// example: mac m1
|
||||
// const targets = Platform.MAC.createTarget(['dmg'], Arch.arm64);
|
||||
|
||||
export default defineConfig({
|
||||
npmClient: "pnpm",
|
||||
plugins: ["@umijs/plugin-electron", "@umijs/plugins/dist/dva"],
|
||||
// metas: [
|
||||
// {
|
||||
// 'http-equiv': 'Content-Security-Policy',
|
||||
// content: "default-src 'none'"
|
||||
// }
|
||||
// ],
|
||||
electron: {
|
||||
builder: {
|
||||
targets,
|
||||
config: {}
|
||||
},
|
||||
extraDevFiles: {}
|
||||
},
|
||||
define: {
|
||||
APP_ENV: "dev"
|
||||
},
|
||||
dva: {},
|
||||
});
|
21
.vscode/launch.json
vendored
Normal file
21
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Electron Main",
|
||||
"runtimeExecutable": "${workspaceFolder}/node_modules/@electron-forge/cli/script/vscode.sh",
|
||||
"windows": {
|
||||
"runtimeExecutable": "${workspaceFolder}/node_modules/@electron-forge/cli/script/vscode.cmd"
|
||||
},
|
||||
// runtimeArgs will be passed directly to your Electron application
|
||||
"runtimeArgs": [
|
||||
"foo",
|
||||
"bar"
|
||||
],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"console": "integratedTerminal"
|
||||
}
|
||||
]
|
||||
}
|
35
README.md
35
README.md
@ -1,34 +1 @@
|
||||
## 目前已有脚手架列表
|
||||
|
||||
| 名称 | 说明 | 技术栈 |
|
||||
| ------- | --------------------------- | --------------------- |
|
||||
| nextJs | 基于 React 的服务端渲染方案 | nextJs + axios + antd |
|
||||
| ReactJs | 基于 React 的业务型脚手架 | umiJs + axios + antd |
|
||||
| TaroJs | 基于 React 的多端适配方案 | TaroJs 全家桶 |
|
||||
| Vue | 基于 Vue 的业务型脚手架 | vueJs 全家桶 |
|
||||
| Gulp | 基于 Gulp 的清凉型脚手架 | -- |
|
||||
|
||||
## 快速上手
|
||||
|
||||
### 1. 安装相关依赖
|
||||
|
||||
```js
|
||||
// 推荐
|
||||
yarn global add @nicecode/cli
|
||||
|
||||
// or
|
||||
// npm install @nicecode/cli -g
|
||||
```
|
||||
|
||||
### 2. 运行命令
|
||||
|
||||
```js
|
||||
// 查看脚手架版本号,是否安装成功
|
||||
nice - V
|
||||
```
|
||||
|
||||
### 3. 创建项目
|
||||
|
||||
```js
|
||||
nice create ${项目名称}
|
||||
```
|
||||
notice: run `pnpm install clear-module lodash chokidar` while using pnpm.
|
||||
|
9
global.d.ts
vendored
Normal file
9
global.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
interface IBaseAPI {
|
||||
uploadFile: (path: File[]) => void
|
||||
setTitle: (value: string) => void
|
||||
onUploadProgress: (progress: unknown) => void
|
||||
}
|
||||
|
||||
interface Window {
|
||||
baseAPI: IBaseAPI
|
||||
}
|
2
jest-setup.ts
Normal file
2
jest-setup.ts
Normal file
@ -0,0 +1,2 @@
|
||||
import '@testing-library/jest-dom';
|
||||
import 'umi/test-setup'
|
27
jest.config.ts
Normal file
27
jest.config.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { Config, configUmiAlias, createConfig } from 'umi/test';
|
||||
|
||||
export default async () => {
|
||||
try{
|
||||
return (await configUmiAlias({
|
||||
...createConfig({
|
||||
target: 'browser',
|
||||
jsTransformer: 'esbuild',
|
||||
// config opts for esbuild , it will pass to esbuild directly
|
||||
jsTransformerOpts: { jsx: 'automatic' },
|
||||
}),
|
||||
|
||||
setupFilesAfterEnv: ['<rootDir>/jest-setup.ts'],
|
||||
collectCoverageFrom: [
|
||||
'src/**/*.{ts,js,tsx,jsx}',
|
||||
'!src/.umi/**',
|
||||
'!src/.umi-test/**',
|
||||
'!src/.umi-production/**'
|
||||
],
|
||||
// if you require some es-module npm package, please uncomment below line and insert your package name
|
||||
// transformIgnorePatterns: ['node_modules/(?!.*(lodash-es|your-es-pkg-name)/)']
|
||||
})) as Config.InitialOptions;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
throw e;
|
||||
}
|
||||
};
|
62
package.json
Normal file
62
package.json
Normal file
@ -0,0 +1,62 @@
|
||||
{
|
||||
"name": "electron-template",
|
||||
"version": "1.0.2",
|
||||
"author": {
|
||||
"name": "dev"
|
||||
},
|
||||
"description": "eggKnife-electron的客户端模板",
|
||||
"scripts": {
|
||||
"dev": "cross-env umi dev",
|
||||
"build": "cross-env NODE_ENV=production umi build",
|
||||
"postinstall": "cross-env umi setup",
|
||||
"setup": "cross-env umi setup",
|
||||
"start": "cross-env npm run dev",
|
||||
"test": "cross-env TS_NODE_TRANSPILE_ONLY=yes jest --passWithNoTests"
|
||||
},
|
||||
"build": {
|
||||
"productName": "测试",
|
||||
"appId": "nicecode"
|
||||
},
|
||||
"dependencies": {
|
||||
"antd": "^5.16.1",
|
||||
"chokidar": "^3.6.0",
|
||||
"clear-module": "^4.1.2",
|
||||
"lodash": "^4.17.21",
|
||||
"normalize.css": "^8.0.1",
|
||||
"umi": "^4.0.42"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/jest-dom": "^5",
|
||||
"@testing-library/react": "^14",
|
||||
"@tsconfig/node21": "^21.0.3",
|
||||
"@types/jest": "^29",
|
||||
"@types/react": "^18.0.0",
|
||||
"@types/react-dom": "^18.0.0",
|
||||
"@types/testing-library__jest-dom": "^5.14.5",
|
||||
"@umijs/plugin-electron": "^0.2.0",
|
||||
"@umijs/plugins": "^4.1.8",
|
||||
"cross-env": "^7",
|
||||
"electron": "29.1.6",
|
||||
"jest": "^29",
|
||||
"jest-environment-jsdom": "^29",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier-plugin-organize-imports": "^3.2.2",
|
||||
"prettier-plugin-packagejson": "^2.4.3",
|
||||
"ts-node": "^10",
|
||||
"typescript": "^5"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org"
|
||||
},
|
||||
"files": [
|
||||
"src/**/*",
|
||||
"tsconfig.json",
|
||||
".npmrc",
|
||||
".gitignore",
|
||||
"README.md",
|
||||
".umirc.ts",
|
||||
"package.json",
|
||||
"typings.d.ts"
|
||||
]
|
||||
}
|
12647
pnpm-lock.yaml
Normal file
12647
pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load Diff
1
src/app.ts
Normal file
1
src/app.ts
Normal file
@ -0,0 +1 @@
|
||||
import 'normalize.css'
|
BIN
src/assets/avatar.jpg
Normal file
BIN
src/assets/avatar.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 137 KiB |
5
src/global.scss
Normal file
5
src/global.scss
Normal file
@ -0,0 +1,5 @@
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica,
|
||||
Arial, sans-serif;
|
||||
margin: auto;
|
||||
}
|
10
src/layouts/index.less
Normal file
10
src/layouts/index.less
Normal file
@ -0,0 +1,10 @@
|
||||
.navs {
|
||||
ul {
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
display: flex;
|
||||
}
|
||||
li {
|
||||
margin-right: 1em;
|
||||
}
|
||||
}
|
61
src/layouts/index.tsx
Normal file
61
src/layouts/index.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
import { Outlet, history } from 'umi';
|
||||
import { Layout, Menu, theme, Image, Affix } from 'antd'
|
||||
import avatar from '../assets/avatar.jpg';
|
||||
import styles from './index.less';
|
||||
|
||||
const { Header, Content, Footer } = Layout;
|
||||
|
||||
const items = [
|
||||
{
|
||||
key: '/',
|
||||
label: '首页'
|
||||
},
|
||||
{
|
||||
key: '/docs',
|
||||
label: '上传页'
|
||||
}
|
||||
]
|
||||
|
||||
export default function BaseLayout() {
|
||||
|
||||
const {
|
||||
token: { colorBgContainer, borderRadiusLG },
|
||||
} = theme.useToken();
|
||||
|
||||
return (
|
||||
<div className={styles.navs}>
|
||||
<Layout>
|
||||
<Affix>
|
||||
<Header style={{ height: '32px', display: 'flex', alignItems: 'center' }}>
|
||||
<div style={{ marginRight: '12px', height: '32px' }}>
|
||||
<Image style={{ fontSize: 0 }} src={avatar} alt="nicecode" width={'24px'} preview={false} />
|
||||
</div>
|
||||
<Menu
|
||||
style={{ height: '32px', lineHeight: '32px' }}
|
||||
theme="dark"
|
||||
mode="horizontal"
|
||||
defaultSelectedKeys={['2']}
|
||||
items={items}
|
||||
onClick={item => history.push(item.key)}
|
||||
/>
|
||||
</Header>
|
||||
</Affix>
|
||||
<Content style={{ padding: '0 24px' }}>
|
||||
<div
|
||||
style={{
|
||||
background: colorBgContainer,
|
||||
minHeight: 280,
|
||||
padding: 24,
|
||||
borderRadius: borderRadiusLG,
|
||||
}}
|
||||
>
|
||||
<Outlet />
|
||||
</div>
|
||||
</Content>
|
||||
<Footer style={{ textAlign: 'center' }}>
|
||||
nicecode ©{new Date().getFullYear()} Created by dev
|
||||
</Footer>
|
||||
</Layout>
|
||||
</div>
|
||||
);
|
||||
}
|
17
src/main/config.ts
Normal file
17
src/main/config.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { BrowserWindowConstructorOptions } from 'electron';
|
||||
|
||||
export default {
|
||||
browserWindow: {
|
||||
title: 'nicecode 客户端模板',
|
||||
titleBarStyle: 'hidden',
|
||||
titleBarOverlay: {
|
||||
color: '#2f3241',
|
||||
symbolColor: '#74b1be',
|
||||
height: 32
|
||||
},
|
||||
maximizable: false,
|
||||
webPreferences: {
|
||||
enableRemoteModule: true,
|
||||
}
|
||||
} as BrowserWindowConstructorOptions
|
||||
};
|
1
src/main/forks/init.ts
Normal file
1
src/main/forks/init.ts
Normal file
@ -0,0 +1 @@
|
||||
console.log('123', 123)
|
114
src/main/index.ts
Normal file
114
src/main/index.ts
Normal file
@ -0,0 +1,114 @@
|
||||
import { app, Menu } from 'electron';
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
getBrowserWindowRuntime().webContents.openDevTools();
|
||||
}
|
||||
|
||||
const isMac = process.platform === 'darwin'
|
||||
|
||||
const template = [
|
||||
// { role: 'appMenu' }
|
||||
...(isMac
|
||||
? [{
|
||||
label: app.name,
|
||||
submenu: [
|
||||
{ label: '关于', role: 'about' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'services' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'hide' },
|
||||
{ role: 'hideOthers' },
|
||||
{ role: 'unhide' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'quit' }
|
||||
]
|
||||
}]
|
||||
: []),
|
||||
// { role: 'fileMenu' }
|
||||
{
|
||||
label: '文件',
|
||||
submenu: [
|
||||
isMac ? { label: '退出', role: 'close' } : { label: '退出', role: 'quit' }
|
||||
]
|
||||
},
|
||||
// { role: 'editMenu' }
|
||||
{
|
||||
label: '编辑',
|
||||
submenu: [
|
||||
{ role: 'undo' },
|
||||
{ role: 'redo' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'cut' },
|
||||
{ role: 'copy' },
|
||||
{ role: 'paste' },
|
||||
...(isMac
|
||||
? [
|
||||
{ role: 'pasteAndMatchStyle' },
|
||||
{ role: 'delete' },
|
||||
{ role: 'selectAll' },
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Speech',
|
||||
submenu: [
|
||||
{ role: 'startSpeaking' },
|
||||
{ role: 'stopSpeaking' }
|
||||
]
|
||||
}
|
||||
]
|
||||
: [
|
||||
{ role: 'delete' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'selectAll' }
|
||||
])
|
||||
]
|
||||
},
|
||||
// { role: 'viewMenu' }
|
||||
{
|
||||
label: '视图',
|
||||
submenu: [
|
||||
{ label: '重新加载', role: 'reload' },
|
||||
{ label: '强制重新加载', role: 'forceReload' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'resetZoom' },
|
||||
{ role: 'zoomIn' },
|
||||
{ role: 'zoomOut' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'togglefullscreen' }
|
||||
]
|
||||
},
|
||||
// { role: 'windowMenu' }
|
||||
{
|
||||
label: '窗口',
|
||||
submenu: [
|
||||
{ role: 'minimize' },
|
||||
{ role: 'zoom' },
|
||||
...(isMac
|
||||
? [
|
||||
{ type: 'separator' },
|
||||
{ role: 'front' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'window' }
|
||||
]
|
||||
: [
|
||||
{ role: 'close' }
|
||||
])
|
||||
]
|
||||
},
|
||||
{
|
||||
role: 'help',
|
||||
submenu: [
|
||||
{ label: '控制台', role: 'toggleDevTools' },
|
||||
{
|
||||
label: '更多',
|
||||
click: async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const { shell } = require('electron')
|
||||
await shell.openExternal('https://electronjs.org')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const menu = Menu.buildFromTemplate(template)
|
||||
Menu.setApplicationMenu(menu)
|
9
src/main/ipc/platform.ts
Normal file
9
src/main/ipc/platform.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { ipcMain, app } from 'electron';
|
||||
|
||||
ipcMain.handle('getPlatform', () => {
|
||||
return `hi, i'm from ${process.platform}`;
|
||||
});
|
||||
|
||||
// node: () => process.versions.node,
|
||||
// chrome: () => process.versions.chrome,
|
||||
// electron: () => process.versions.electron,
|
67
src/main/ipc/upload.ts
Normal file
67
src/main/ipc/upload.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import { app, ipcMain } from 'electron';
|
||||
// import fs from 'fs';
|
||||
// import path from 'node:path';
|
||||
|
||||
ipcMain.on('uploadFile', (event, filePaths: string[]) => {
|
||||
// 获取用户当前文件夹路径
|
||||
console.log('app', app.getGPUInfo('basic'))
|
||||
// const saveDirectoryPath = await app.getPath('downloads');
|
||||
// for (let i = 0; i < filePaths.length; i++) {
|
||||
// const fileName = path.basename(filePaths[i]);
|
||||
// const targetFilePath = path.join(__dirname, fileName);
|
||||
// const fileStream = fs.createWriteStream(targetFilePath);
|
||||
// fileStream.write(fs.readFileSync(filePaths[i]));
|
||||
// fileStream.end();
|
||||
// console.log('Uploaded file saved at:', targetFilePath);
|
||||
// }
|
||||
// const fileSize = fs.statSync(filePath).size;
|
||||
// let uploadedSize = 0;
|
||||
|
||||
// const readStream = fs.createReadStream(filePath);
|
||||
|
||||
// readStream.on('data', (chunk) => {
|
||||
// uploadedSize += chunk.length;
|
||||
// const progress = Math.round((uploadedSize / fileSize) * 100);
|
||||
// sender.send('upload-progress', progress);
|
||||
// });
|
||||
|
||||
// readStream.on('end', () => {
|
||||
// sender.send('upload-success');
|
||||
// });
|
||||
|
||||
// readStream.on('error', (err) => {
|
||||
// sender.send('upload-error', err.message);
|
||||
// });
|
||||
});
|
||||
|
||||
|
||||
export const singleUpload = (file: File) => {
|
||||
const path = file.path; //文件本地路径
|
||||
const stats = fs.statSync(path); //读取文件信息
|
||||
const chunkSize = 3 * 1024 * 1024; //每片分块的大小3M
|
||||
const size = stats.size; //文件大小
|
||||
const pieces = Math.ceil(size / chunkSize); //总共的分片数
|
||||
function uploadPiece (i: number) {
|
||||
//计算每块的结束位置
|
||||
const endData = Math.min(size, (i + 1) * chunkSize);
|
||||
const arr: any[] = [];
|
||||
//创建一个readStream对象,根据文件起始位置和结束位置读取固定的分片
|
||||
const readStream = fs.createReadStream(path, { start: i * chunkSize, end: endData - 1 });
|
||||
//on data读取数据
|
||||
readStream.on('data', (data)=>{
|
||||
arr.push(data)
|
||||
})
|
||||
//on end在该分片读取完成时触发
|
||||
readStream.on('end', ()=>{
|
||||
//这里服务端只接受blob对象,需要把原始的数据流转成blob对象,这块为了配合后端才转
|
||||
const blob = new Blob(arr)
|
||||
//新建formdata数据对象
|
||||
const formdata = new FormData();
|
||||
formdata.append("file", blob);
|
||||
console.log('blob.size',blob.size)
|
||||
formdata.append("size", size + ''); // 数字30被转换成字符串"30"
|
||||
formdata.append("chunk", i + '');//第几个分片,从0开始
|
||||
formdata.append("chunks", pieces + '');//分片数
|
||||
})
|
||||
}
|
||||
}
|
8
src/main/preload.ts
Normal file
8
src/main/preload.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { contextBridge, ipcRenderer } from 'electron';
|
||||
|
||||
contextBridge.exposeInMainWorld('$api', {
|
||||
getPlatform: async () => {
|
||||
return await ipcRenderer.invoke('getPlatform');
|
||||
},
|
||||
uploadFile: (filePaths: string[]) => ipcRenderer.send('uploadFile', filePaths),
|
||||
});
|
3
src/main/tsconfig.json
Normal file
3
src/main/tsconfig.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "@tsconfig/node21"
|
||||
}
|
6
src/main/typing.d.ts
vendored
Normal file
6
src/main/typing.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
import { BrowserWindow } from 'electron';
|
||||
|
||||
declare global {
|
||||
export function getBrowserWindowRuntime(): BrowserWindow;
|
||||
const APP_ENV: string
|
||||
}
|
21
src/models/count.ts
Normal file
21
src/models/count.ts
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
const delay = (ms: number) => new Promise((res) => setTimeout(res, ms));
|
||||
|
||||
export default {
|
||||
namespace: 'count',
|
||||
state: {
|
||||
num: 0,
|
||||
},
|
||||
reducers: {
|
||||
add(state: any) {
|
||||
state.num += 1;
|
||||
},
|
||||
},
|
||||
effects: {
|
||||
*addAsync(_action: any, { put }: any) {
|
||||
yield delay(1000);
|
||||
yield put({ type: 'add' });
|
||||
},
|
||||
},
|
||||
};
|
||||
|
65
src/pages/docs.tsx
Normal file
65
src/pages/docs.tsx
Normal file
@ -0,0 +1,65 @@
|
||||
import { Button, message, Space, Upload } from 'antd'
|
||||
import { useEffect, useState } from 'react';
|
||||
import type { GetProp, UploadFile, UploadProps } from 'antd';
|
||||
|
||||
type FileType = Parameters<GetProp<UploadProps, 'beforeUpload'>>[0];
|
||||
|
||||
const { Dragger } = Upload;
|
||||
|
||||
export default () => {
|
||||
const [progress, setProgress] = useState(0)
|
||||
|
||||
const [fileList, setFileList] = useState<UploadFile[]>([]);
|
||||
const [uploading, setUploading] = useState(false);
|
||||
|
||||
const handleUpload = () => {
|
||||
const formData = new FormData();
|
||||
fileList.forEach((file) => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
formData.append('files[]', file as FileType);
|
||||
});
|
||||
setUploading(true);
|
||||
const filePaths = fileList.map((_file: any) => _file.path)
|
||||
console.log('filePaths', filePaths)
|
||||
window.$api.uploadFile(filePaths)
|
||||
setUploading(false)
|
||||
};
|
||||
|
||||
|
||||
const uploadProps: UploadProps = {
|
||||
name: 'file',
|
||||
multiple: true,
|
||||
capture: 'user',
|
||||
hasControlInside: false,
|
||||
onRemove: (file) => {
|
||||
const index = fileList.indexOf(file);
|
||||
const newFileList = fileList.slice();
|
||||
newFileList.splice(index, 1);
|
||||
setFileList(newFileList);
|
||||
},
|
||||
beforeUpload: (file) => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
setFileList([...fileList, file]);
|
||||
|
||||
return false;
|
||||
},
|
||||
onDrop(e) {
|
||||
console.log('Dropped files', e.dataTransfer.files);
|
||||
},
|
||||
fileList,
|
||||
};
|
||||
|
||||
return (
|
||||
<Space direction='vertical' style={{ width: '600px' }}>
|
||||
<Dragger {...uploadProps}>
|
||||
<p className="ant-upload-drag-icon">
|
||||
✋{progress}
|
||||
</p>
|
||||
<p className="ant-upload-text">文件拖拽到这上传</p>
|
||||
</Dragger>
|
||||
<Button type='primary' block onClick={() => handleUpload()} >上传</Button>
|
||||
</Space>
|
||||
)
|
||||
}
|
23
src/pages/index.tsx
Normal file
23
src/pages/index.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import { Button, message } from 'antd';
|
||||
import avatar from '../assets/avatar.jpg';
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<div>
|
||||
<h2>Welcome to nicecode electron!</h2>
|
||||
<p>
|
||||
<img src={avatar} width="388" />
|
||||
</p>
|
||||
<p>
|
||||
To get started, edit <code>pages/index.tsx</code> and save to reload.
|
||||
</p>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
message.info(await window.$api.getPlatform());
|
||||
}}
|
||||
>
|
||||
what is my platform?
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
0
src/utils/index.ts
Normal file
0
src/utils/index.ts
Normal file
3
tsconfig.json
Normal file
3
tsconfig.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "./src/.umi/tsconfig.json"
|
||||
}
|
7
typings.d.ts
vendored
Normal file
7
typings.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
import 'umi/typings';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
$api: any;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user