zhangjie 1 год назад
Родитель
Сommit
19ebfef36c

+ 3 - 1
.eslintignore

@@ -1,3 +1,5 @@
 /*.json
 /*.js
-dist
+dist
+node_modules
+out

+ 5 - 1
.eslintrc.js

@@ -27,11 +27,15 @@ module.exports = {
     'plugin:import/typescript',
     'plugin:vue/vue3-recommended',
     'plugin:prettier/recommended',
+    '@electron-toolkit',
+    '@electron-toolkit/eslint-config-ts/eslint-recommended',
+    '@vue/eslint-config-typescript/recommended',
+    '@vue/eslint-config-prettier',
   ],
   settings: {
     'import/resolver': {
       typescript: {
-        project: path.resolve(__dirname, './tsconfig.json'),
+        project: path.resolve(__dirname, './tsconfig.web.json'),
       },
     },
   },

+ 1 - 0
.gitignore

@@ -1,6 +1,7 @@
 node_modules
 .DS_Store
 dist
+out
 dist-ssr
 *.local
 

+ 3 - 0
.npmrc

@@ -0,0 +1,3 @@
+electron_mirror=https://npmmirror.com/mirrors/electron/
+electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/
+shamefully-hoist=true

+ 3 - 0
.prettierignore

@@ -1,7 +1,10 @@
+/out/*
 /dist/*
 .local
 .output.js
 /node_modules/**
+tsconfig.json
+tsconfig.*.json
 
 **/*.svg
 **/*.sh

+ 3 - 0
.vscode/extensions.json

@@ -0,0 +1,3 @@
+{
+  "recommendations": ["dbaeumer.vscode-eslint"]
+}

+ 39 - 0
.vscode/launch.json

@@ -0,0 +1,39 @@
+{
+  "version": "0.2.0",
+  "configurations": [
+    {
+      "name": "Debug Main Process",
+      "type": "node",
+      "request": "launch",
+      "cwd": "${workspaceRoot}",
+      "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite",
+      "windows": {
+        "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite.cmd"
+      },
+      "runtimeArgs": ["--sourcemap"],
+      "env": {
+        "REMOTE_DEBUGGING_PORT": "9222"
+      }
+    },
+    {
+      "name": "Debug Renderer Process",
+      "port": 9222,
+      "request": "attach",
+      "type": "chrome",
+      "webRoot": "${workspaceFolder}/src/renderer",
+      "timeout": 60000,
+      "presentation": {
+        "hidden": true
+      }
+    }
+  ],
+  "compounds": [
+    {
+      "name": "Debug All",
+      "configurations": ["Debug Main Process", "Debug Renderer Process"],
+      "presentation": {
+        "order": 1
+      }
+    }
+  ]
+}

+ 11 - 0
.vscode/settings.json

@@ -0,0 +1,11 @@
+{
+  "[typescript]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "[javascript]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "[json]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  }
+}

+ 12 - 0
build/entitlements.mac.plist

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+  <dict>
+    <key>com.apple.security.cs.allow-jit</key>
+    <true/>
+    <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
+    <true/>
+    <key>com.apple.security.cs.allow-dyld-environment-variables</key>
+    <true/>
+  </dict>
+</plist>

BIN
build/icon.icns


BIN
build/icon.ico


BIN
build/icon.png


+ 45 - 0
electron-builder.yml

@@ -0,0 +1,45 @@
+appId: com.electron.app
+productName: teachcloud-mark-tool
+directories:
+  buildResources: build
+files:
+  - '!**/.vscode/*'
+  - '!src/*'
+  - '!electron.vite.config.{js,ts,mjs,cjs}'
+  - '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
+  - '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
+  - '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}'
+asarUnpack:
+  - resources/**
+win:
+  executableName: teachcloud-mark-tool
+nsis:
+  artifactName: ${name}-${version}-setup.${ext}
+  shortcutName: ${productName}
+  uninstallDisplayName: ${productName}
+  createDesktopShortcut: always
+mac:
+  entitlementsInherit: build/entitlements.mac.plist
+  extendInfo:
+    - NSCameraUsageDescription: Application requests access to the device's camera.
+    - NSMicrophoneUsageDescription: Application requests access to the device's microphone.
+    - NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
+    - NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
+  notarize: false
+dmg:
+  artifactName: ${name}-${version}.${ext}
+linux:
+  target:
+    - AppImage
+    - snap
+    - deb
+  maintainer: electronjs.org
+  category: Utility
+appImage:
+  artifactName: ${name}-${version}.${ext}
+npmRebuild: false
+publish:
+  provider: generic
+  url: https://example.com/auto-updates
+electronDownload:
+  mirror: https://npmmirror.com/mirrors/electron/

+ 52 - 0
electron.vite.config.ts

@@ -0,0 +1,52 @@
+import {
+  defineConfig,
+  defineViteConfig,
+  externalizeDepsPlugin,
+} from 'electron-vite';
+import { mergeConfig } from 'vite';
+import { resolve } from 'path';
+import productionConfig from './config/vite.config.prod';
+import developmentConfig from './config/vite.config.dev';
+
+export default defineConfig({
+  main: {
+    plugins: [externalizeDepsPlugin()],
+    build: {
+      rollupOptions: {
+        input: {
+          index: resolve(__dirname, 'electron/main/index.ts'),
+        },
+      },
+    },
+  },
+  preload: {
+    plugins: [externalizeDepsPlugin()],
+    build: {
+      rollupOptions: {
+        input: {
+          index: resolve(__dirname, 'electron/preload/index.ts'),
+        },
+      },
+    },
+  },
+  renderer: defineViteConfig(({ mode }) => {
+    console.log(mode);
+
+    const config = mergeConfig(
+      {
+        root: '.',
+        build: {
+          rollupOptions: {
+            input: {
+              index: resolve(__dirname, 'index.html'),
+            },
+          },
+        },
+      },
+      mode === 'production' ? productionConfig : developmentConfig
+    );
+
+    console.log(config);
+    return config;
+  }),
+});

+ 74 - 0
electron/main/index.ts

@@ -0,0 +1,74 @@
+import { app, shell, BrowserWindow, ipcMain } from 'electron';
+import { join } from 'path';
+import { electronApp, optimizer, is } from '@electron-toolkit/utils';
+import icon from '../../resources/icon.png?asset';
+
+function createWindow(): void {
+  // Create the browser window.
+  const mainWindow = new BrowserWindow({
+    width: 900,
+    height: 670,
+    show: false,
+    autoHideMenuBar: true,
+    ...(process.platform === 'linux' ? { icon } : {}),
+    webPreferences: {
+      preload: join(__dirname, '../preload/index.js'),
+      sandbox: false,
+    },
+  });
+
+  mainWindow.on('ready-to-show', () => {
+    mainWindow.show();
+  });
+
+  mainWindow.webContents.setWindowOpenHandler((details) => {
+    shell.openExternal(details.url);
+    return { action: 'deny' };
+  });
+
+  // HMR for renderer base on electron-vite cli.
+  // Load the remote URL for development or the local html file for production.
+  if (is.dev && process.env.ELECTRON_RENDERER_URL) {
+    mainWindow.loadURL(process.env.ELECTRON_RENDERER_URL);
+  } else {
+    mainWindow.loadFile(join(__dirname, '../renderer/index.html'));
+  }
+}
+
+// This method will be called when Electron has finished
+// initialization and is ready to create browser windows.
+// Some APIs can only be used after this event occurs.
+app.whenReady().then(() => {
+  // Set app user model id for windows
+  electronApp.setAppUserModelId('com.electron');
+
+  // Default open or close DevTools by F12 in development
+  // and ignore CommandOrControl + R in production.
+  // see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
+  app.on('browser-window-created', (_, window) => {
+    optimizer.watchWindowShortcuts(window);
+  });
+
+  // IPC test
+  ipcMain.on('ping', () => console.log('pong'));
+
+  createWindow();
+
+  app.on('activate', function () {
+    // On macOS it's common to re-create a window in the app when the
+    // dock icon is clicked and there are no other windows open.
+    if (BrowserWindow.getAllWindows().length === 0) createWindow();
+  });
+});
+
+// Quit when all windows are closed, except on macOS. There, it's common
+// for applications and their menu bar to stay active until the user quits
+// explicitly with Cmd + Q.
+app.on('window-all-closed', () => {
+  if (process.platform !== 'darwin') {
+    app.quit();
+  }
+});
+
+// In this file you can include the rest of your app"s specific main process
+// code. You can also put them in separate files and require them here.

+ 8 - 0
electron/preload/index.d.ts

@@ -0,0 +1,8 @@
+import { ElectronAPI } from '@electron-toolkit/preload';
+
+declare global {
+  interface Window {
+    electron: ElectronAPI;
+    api: unknown;
+  }
+}

+ 22 - 0
electron/preload/index.ts

@@ -0,0 +1,22 @@
+import { contextBridge } from 'electron';
+import { electronAPI } from '@electron-toolkit/preload';
+
+// Custom APIs for renderer
+const api = {};
+
+// Use `contextBridge` APIs to expose Electron APIs to
+// renderer only if context isolation is enabled, otherwise
+// just add to the DOM global.
+if (process.contextIsolated) {
+  try {
+    contextBridge.exposeInMainWorld('electron', electronAPI);
+    contextBridge.exposeInMainWorld('api', api);
+  } catch (error) {
+    console.error(error);
+  }
+} else {
+  // @ts-ignore (define in dts)
+  window.electron = electronAPI;
+  // @ts-ignore (define in dts)
+  window.api = api;
+}

+ 35 - 14
package.json

@@ -2,18 +2,26 @@
   "name": "teachcloud-mark-tool",
   "description": "teachcloud mark tool",
   "version": "1.0.0",
-  "private": true,
+  "main": "./out/main/index.js",
   "author": "chulinice",
   "license": "MIT",
   "scripts": {
-    "start": "vite --config ./config/vite.config.dev.ts",
-    "dev": "vite --config ./config/vite.config.dev.ts",
-    "build": "vue-tsc --noEmit && vite build --config ./config/vite.config.prod.ts",
+    "start": "electron-vite preview",
+    "dev": "electron-vite dev",
+    "format": "prettier --write .",
     "report": "cross-env REPORT=true npm run build",
     "preview": "npm run build && vite preview --host",
-    "check": "vue-tsc --noEmit --skipLibCheck",
+    "typecheck:node": "tsc --noEmit --skipLibCheck -p tsconfig.node.json --composite false",
+    "typecheck:web": "vue-tsc --noEmit --skipLibCheck -p tsconfig.web.json --composite false",
+    "typecheck": "npm run typecheck:node && npm run typecheck:web",
     "lint-staged": "npx lint-staged",
-    "prepare": "husky install"
+    "prepare": "husky install",
+    "postinstall": "electron-builder install-app-deps",
+    "build": "npm run typecheck && electron-vite build",
+    "build:unpack": "npm run build && electron-builder --dir",
+    "build:win": "npm run build && electron-builder --win",
+    "build:mac": "npm run build && electron-builder --mac",
+    "build:linux": "npm run build && electron-builder --linux"
   },
   "lint-staged": {
     "*.{js,ts,jsx,tsx}": [
@@ -30,6 +38,8 @@
   },
   "dependencies": {
     "@arco-design/web-vue": "^2.44.7",
+    "@electron-toolkit/preload": "^3.0.0",
+    "@electron-toolkit/utils": "^3.0.0",
     "@types/vue-ls": "^3.2.7",
     "@vueuse/core": "^9.3.0",
     "axios": "^0.24.0",
@@ -50,40 +60,51 @@
     "@arco-plugins/vite-vue": "^1.4.5",
     "@commitlint/cli": "^17.1.2",
     "@commitlint/config-conventional": "^17.1.0",
+    "@electron-toolkit/eslint-config": "^1.0.2",
+    "@electron-toolkit/eslint-config-ts": "^1.0.1",
+    "@electron-toolkit/tsconfig": "^1.0.1",
+    "@rushstack/eslint-patch": "^1.7.1",
     "@types/crypto-js": "^4.2.1",
     "@types/lodash": "^4.14.186",
     "@types/mockjs": "^1.0.7",
+    "@types/node": "^18.19.9",
     "@types/nprogress": "^0.2.0",
     "@typescript-eslint/eslint-plugin": "^5.40.0",
     "@typescript-eslint/parser": "^5.40.0",
-    "@vitejs/plugin-vue": "^3.1.2",
+    "@vitejs/plugin-vue": "^5.0.3",
     "@vitejs/plugin-vue-jsx": "^2.0.1",
     "@vue/babel-plugin-jsx": "^1.1.1",
+    "@vue/eslint-config-prettier": "^9.0.0",
+    "@vue/eslint-config-typescript": "^12.0.0",
     "consola": "^2.15.3",
     "cross-env": "^7.0.3",
-    "eslint": "^8.25.0",
+    "electron": "^28.2.0",
+    "electron-builder": "^24.9.1",
+    "electron-vite": "^2.2.0",
+    "eslint": "^8.56.0",
     "eslint-config-airbnb-base": "^15.0.0",
     "eslint-config-prettier": "^8.5.0",
     "eslint-import-resolver-typescript": "^3.5.1",
     "eslint-plugin-import": "^2.26.0",
     "eslint-plugin-prettier": "^4.2.1",
-    "eslint-plugin-vue": "^9.6.0",
+    "eslint-plugin-vue": "^9.20.1",
     "husky": "^8.0.1",
     "less": "^4.1.3",
     "lint-staged": "^13.0.3",
     "mockjs": "^1.1.0",
     "postcss-html": "^1.5.0",
-    "prettier": "^2.7.1",
+    "prettier": "^2.8.8",
     "rollup": "^3.9.1",
     "rollup-plugin-visualizer": "^5.8.2",
-    "typescript": "^4.8.4",
+    "typescript": "^4.9.5",
     "unplugin-vue-components": "^0.24.1",
-    "vite": "^3.2.5",
+    "vite": "^4.3.9",
     "vite-plugin-compression": "^0.5.1",
     "vite-plugin-eslint": "^1.8.1",
     "vite-plugin-imagemin": "^0.6.1",
     "vite-svg-loader": "^3.6.0",
-    "vue-tsc": "^1.0.14"
+    "vue": "^3.4.15",
+    "vue-tsc": "^1.8.27"
   },
   "engines": {
     "node": ">=14.0.0"
@@ -93,4 +114,4 @@
     "rollup": "^2.56.3",
     "gifsicle": "5.2.0"
   }
-}
+}

Разница между файлами не показана из-за своего большого размера
+ 735 - 25
pnpm-lock.yaml


BIN
resources/icon.png


+ 2 - 18
tsconfig.json

@@ -1,20 +1,4 @@
 {
-  "compilerOptions": {
-    "target": "ES2020",
-    "module": "ES2020",
-    "moduleResolution": "node",
-    "strict": true,
-    "jsx": "preserve",
-    "sourceMap": true,
-    "resolveJsonModule": true,
-    "esModuleInterop": true,
-    "baseUrl": ".",
-    "paths": {
-      "@/*": ["src/*"]
-    },
-    "lib": ["es2020", "dom"],
-    "skipLibCheck": true
-  },
-  "include": ["src/**/*", "src/**/*.vue"],
-  "exclude": ["node_modules"]
+  "files": [],
+  "references": [{ "path": "./tsconfig.node.json" }, { "path": "./tsconfig.web.json" }]
 }

+ 14 - 0
tsconfig.node.json

@@ -0,0 +1,14 @@
+{
+  "extends": "@electron-toolkit/tsconfig/tsconfig.node.json",
+  "include": [
+    "electron.vite.config.*",
+    "electron/main/**/*",
+    "electron/preload/**/*"
+  ],
+  "compilerOptions": {
+    "composite": true,
+    "types": [
+      "electron-vite/node"
+    ]
+  }
+}

+ 34 - 0
tsconfig.web.json

@@ -0,0 +1,34 @@
+{
+  "compilerOptions": {
+    "target": "ES2020",
+    "module": "ES2020",
+    "moduleResolution": "node",
+    "strict": true,
+    "jsx": "preserve",
+    "sourceMap": true,
+    "resolveJsonModule": true,
+    "esModuleInterop": true,
+    "baseUrl": ".",
+    "paths": {
+      "@/*": [
+        "src/*"
+      ]
+    },
+    "lib": [
+      "es2020",
+      "dom"
+    ],
+    "skipLibCheck": true,
+    "composite": true,
+  },
+  "include": [
+    "src/env.d.ts",
+    "src/**/*",
+    "src/**/*.vue",
+    "electron/preload/*.d.ts"
+  ],
+  "exclude": [
+    "node_modules",
+    "@electron-toolkit/tsconfig/tsconfig.web.json"
+  ]
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов