feat: 上传所有文件

This commit is contained in:
hello8693 2024-07-26 21:03:42 +08:00
commit 01964be6e2
66 changed files with 7681 additions and 0 deletions

9
.editorconfig Normal file
View File

@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

4
.eslintignore Normal file
View File

@ -0,0 +1,4 @@
node_modules
dist
out
.gitignore

View File

@ -0,0 +1,69 @@
{
"globals": {
"Component": true,
"ComponentPublicInstance": true,
"ComputedRef": true,
"EffectScope": true,
"ExtractDefaultPropTypes": true,
"ExtractPropTypes": true,
"ExtractPublicPropTypes": true,
"InjectionKey": true,
"PropType": true,
"Ref": true,
"VNode": true,
"WritableComputedRef": true,
"computed": true,
"createApp": true,
"customRef": true,
"defineAsyncComponent": true,
"defineComponent": true,
"effectScope": true,
"getCurrentInstance": true,
"getCurrentScope": true,
"h": true,
"inject": true,
"isProxy": true,
"isReactive": true,
"isReadonly": true,
"isRef": true,
"markRaw": true,
"nextTick": true,
"onActivated": true,
"onBeforeMount": true,
"onBeforeUnmount": true,
"onBeforeUpdate": true,
"onDeactivated": true,
"onErrorCaptured": true,
"onMounted": true,
"onRenderTracked": true,
"onRenderTriggered": true,
"onScopeDispose": true,
"onServerPrefetch": true,
"onUnmounted": true,
"onUpdated": true,
"provide": true,
"reactive": true,
"readonly": true,
"ref": true,
"resolveComponent": true,
"shallowReactive": true,
"shallowReadonly": true,
"shallowRef": true,
"toRaw": true,
"toRef": true,
"toRefs": true,
"toValue": true,
"triggerRef": true,
"unref": true,
"useAttrs": true,
"useCssModule": true,
"useCssVars": true,
"useRoute": true,
"useRouter": true,
"useSlots": true,
"watch": true,
"watchEffect": true,
"watchPostEffect": true,
"watchSyncEffect": true
}
}

17
.eslintrc.cjs Normal file
View File

@ -0,0 +1,17 @@
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution');
module.exports = {
extends: [
'eslint:recommended',
'plugin:vue/vue3-recommended',
'@electron-toolkit',
'@electron-toolkit/eslint-config-ts/eslint-recommended',
'@vue/eslint-config-typescript/recommended',
'@vue/eslint-config-prettier'
],
rules: {
'vue/require-default-prop': 'off',
'vue/multi-word-component-names': 'off'
}
};

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
node_modules
dist
out
.DS_Store
*.log*

4
.husky/pre-commit Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
yarn commitlint

2
.npmrc Normal file
View File

@ -0,0 +1,2 @@
electron_mirror=https://npmmirror.com/mirrors/electron/
electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/

6
.prettierignore Normal file
View File

@ -0,0 +1,6 @@
out
dist
pnpm-lock.yaml
LICENSE.md
tsconfig.json
tsconfig.*.json

4
.prettierrc.yaml Normal file
View File

@ -0,0 +1,4 @@
singleQuote: true
semi: true
printWidth: 100
trailingComma: none

3
.vscode/extensions.json vendored Normal file
View File

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

39
.vscode/launch.json vendored Normal file
View File

@ -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
}
}
]
}

29
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,29 @@
{
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"MicroPython.executeButton": [
{
"text": "▶",
"tooltip": "运行",
"alignment": "left",
"command": "extension.executeFile",
"priority": 3.5
}
],
"MicroPython.syncButton": [
{
"text": "$(sync)",
"tooltip": "同步",
"alignment": "left",
"command": "extension.execute",
"priority": 4
}
]
}

34
README.md Normal file
View File

@ -0,0 +1,34 @@
# dsz-exam-composer
An Electron application with Vue and TypeScript
## Recommended IDE Setup
- [VSCode](https://code.visualstudio.com/) + [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) + [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin)
## Project Setup
### Install
```bash
$ yarn
```
### Development
```bash
$ yarn dev
```
### Build
```bash
# For windows
$ yarn build:win
# For macOS
$ yarn build:mac
# For Linux
$ yarn build:linux
```

View File

@ -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 Normal file

Binary file not shown.

BIN
build/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

BIN
build/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

31
commitlint.config.cjs Normal file
View File

@ -0,0 +1,31 @@
module.exports = {
extends: ['@commitlint/config-conventional'],
// 校验规则
rules: {
'type-enum': [
2,
'always',
[
'feat',
'fix',
'docs',
'style',
'refactor',
'perf',
'test',
'chore',
'revert',
'build',
'init'
]
],
'type-case': [0],
'type-empty': [0],
'scope-empty': [0],
'scope-case': [0],
'subject-full-stop': [0, 'never'],
'subject-case': [0, 'never'],
'header-max-length': [0, 'always', 72],
'body-max-line-length': [0, 'never']
}
};

3
dev-app-update.yml Normal file
View File

@ -0,0 +1,3 @@
provider: generic
url: https://example.com/auto-updates
updaterCacheDirName: dsz-exam-composer-updater

45
electron-builder.yml Normal file
View File

@ -0,0 +1,45 @@
appId: com.electron.app
productName: dsz-exam-composer
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: dsz-exam-composer
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/

96
electron.vite.config.ts Normal file
View File

@ -0,0 +1,96 @@
import { resolve } from 'path';
import { defineConfig, externalizeDepsPlugin } from 'electron-vite';
// Plugins
import AutoImport from 'unplugin-auto-import/vite';
import Components from 'unplugin-vue-components/vite';
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import Fonts from 'unplugin-fonts/vite';
import Layouts from 'vite-plugin-vue-layouts';
import Vue from '@vitejs/plugin-vue';
import VueRouter from 'unplugin-vue-router/vite';
// import rawLoader from 'raw-loader'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
// import vue from '@vitejs/plugin-vue'
export default defineConfig({
main: {
plugins: [externalizeDepsPlugin()]
},
preload: {
plugins: [externalizeDepsPlugin()]
},
renderer: {
resolve: {
alias: {
'@renderer': resolve('src/renderer/src')
}
},
plugins: [
VueRouter({
dts: resolve('src/renderer/src/typed-router.d.ts'),
routesFolder: [
{
src: resolve('src/renderer/src/pages'),
path: '',
// override globals
exclude: (excluded) => excluded,
filePatterns: (filePatterns) => filePatterns,
extensions: (extensions) => extensions
}
]
}),
Layouts(),
Vue(),
// https://github.com/vuetifyjs/vuetify-loader/tree/master/packages/vite-plugin#readme
Components({
dts: 'src/components.d.ts',
resolvers: [ElementPlusResolver()],
}),
Fonts({
google: {
families: [
{
name: 'Roboto',
styles: 'wght@100;300;400;500;700;900'
}
]
}
}),
AutoImport({
imports: [
'vue',
{
'vue-router/auto': ['useRoute', 'useRouter']
}
],
dts: 'src/auto-imports.d.ts',
eslintrc: {
enabled: true
},
vueTemplate: true,
resolvers: [ElementPlusResolver()],
}),
createSvgIconsPlugin({
// Specify the icon folder to be cached
iconDirs: [resolve('src/renderer/src/icons')],
// Specify symbolId format
symbolId: 'icon-[dir]-[name]',
/**
* custom insert position
* @default: body-last
*/
// inject?: 'body-last' | 'body-first',
/**
* custom dom id
* @default: __svg__icons__dom__
*/
customDomId: '__svg__icons__dom__'
})
],
define: { 'process.env': {} }
}
});

17
examples/config.json Normal file
View File

@ -0,0 +1,17 @@
{
"examName": "2023-2024学年度期末考试",
"roomName": "第一考场",
"message": "诚信考试,禁止作弊",
"examInfos": [
{
"name": "语文",
"start": "2024-07-26T15:00:00",
"end": "2024-07-26T16:00:00"
},
{
"name": "数学",
"start": "2024-07-26T16:10:00",
"end": "2024-07-26T17:10:00"
}
]
}

76
package.json Normal file
View File

@ -0,0 +1,76 @@
{
"name": "dsz-exam-showboard",
"version": "1.0.0",
"description": "An Electron application with Vue",
"main": "./out/main/index.js",
"author": "Hello8693 <hello8693@hello8693.xyz>",
"homepage": "https://dsz.hello8693.xyz/",
"scripts": {
"preinstall": "node -e \"if (process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('Use yarn for installing: https://yarnpkg.com/en/docs/install')\"",
"format": "prettier --write .",
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts,.vue --fix",
"typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false",
"typecheck:web": "vue-tsc --noEmit -p tsconfig.web.json --composite false",
"typecheck": "npm run typecheck:node && npm run typecheck:web",
"start": "electron-vite preview",
"dev": "electron-vite dev",
"build": "electron-vite build",
"postinstall": "electron-builder install-app-deps",
"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",
"electron:generate-icons": "electron-icon-builder --input=./resources/icon.png --output=build --flatten",
"commitlint": "commitlint --config commitlint.config.cjs -e -V",
"prepare": "husky"
},
"dependencies": {
"@electron-toolkit/preload": "^3.0.0",
"@electron-toolkit/utils": "^3.0.0",
"core-js": "^3.34.0",
"date-fns": "^3.6.0",
"element-plus": "^2.7.7",
"github-markdown-css": "^5.5.1",
"moment": "^2.30.1",
"roboto-fontface": "*",
"uuid": "^9.0.1",
"vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-vue-layouts": "^0.11.0",
"vue": "^3.4.34",
"vue-showdown": "^4.2.0"
},
"devDependencies": {
"@commitlint/config-conventional": "^19.2.2",
"@electron-toolkit/eslint-config": "^1.0.1",
"@electron-toolkit/eslint-config-ts": "^1.0.1",
"@electron-toolkit/tsconfig": "^1.0.1",
"@mdi/font": "7.0.96",
"@rushstack/eslint-patch": "^1.6.1",
"@types/vue": "^2.0.0",
"@vitejs/plugin-vue": "^5.0.3",
"@vue/eslint-config-prettier": "^9.0.0",
"commitlint": "^19.3.0",
"core-js": "^3.34.0",
"electron": "^28.2.0",
"electron-builder": "^24.9.1",
"electron-vite": "^2.0.0",
"eslint": "^8.56.0",
"eslint-plugin-vue": "^9.20.1",
"husky": "^9.0.11",
"pinia": "^2.1.7",
"prettier": "^3.2.4",
"raw-loader": "^4.0.2",
"roboto-fontface": "*",
"sass": "^1.71.1",
"unplugin-auto-import": "^0.18.2",
"unplugin-fonts": "^1.1.1",
"unplugin-vue-components": "^0.27.3",
"unplugin-vue-router": "^0.8.4",
"vite": "^5.0.12",
"vite-plugin-optimizer": "^1.4.3",
"vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-vue-layouts": "^0.11.0",
"vue-router": "^4.3.0",
"vue-tsc": "^1.8.27"
}
}

4
pre-commit Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
yarn commitlint

BIN
resources/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

77
src/main/index.ts Normal file
View File

@ -0,0 +1,77 @@
import { app } from 'electron';
import { electronApp } from '@electron-toolkit/utils';
import windowManager from './utils/windowManager';
import ipcWindow from './ipc/window';
// 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']}/#mainWindow`)
// } else {
// mainWindow.loadFile(join(__dirname, '../renderer/index.html'), { hash: 'mainWindow' })
// }
// }
// 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()
// })
// })
app.whenReady().then(async () => {
// Set app user model id for windows
electronApp.setAppUserModelId('com.electron');
ipcWindow.register();
const wallPaperWindow = windowManager.createMainWindow();
// wallPaperWindow.show()
});
app.on('window-all-closed', () => {
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.

34
src/main/ipc/window.ts Normal file
View File

@ -0,0 +1,34 @@
import { ipcMain, BrowserWindow, app } from 'electron';
import windowManager from '../utils/windowManager';
import WindowName from '../types/WindowName';
import { fileUtils } from '../utils/fileManager';
const ipcWindow = {
register() {
ipcMain.on('window:minimize', (event) => {
const window = BrowserWindow.fromId(event.sender.id);
if (window) {
// 添加此行检查window是否为null
window.minimize();
} else {
console.error('Failed to minimize: Window not found');
}
});
ipcMain.on('prog:exit', (event) => {
windowManager.destroyAllWindows();
app.quit();
});
ipcMain.on('window:open', (event, name: WindowName) => {
return windowManager.createByName(name);
});
ipcMain.on('prog:loadjson', async (event) => {
const window = BrowserWindow.fromId(event.sender.id);
const file = await fileUtils.readFile()
await window.webContents.send('common:openFile', file);
});
}
};
export default ipcWindow;

3
src/main/types/WindowName.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
type WindowName = 'mainWindow';
export default WindowName;

View File

@ -0,0 +1,26 @@
import * as fs from 'fs/promises';
import { dialog } from 'electron';
/**
*
*/
export interface IFileInfo {
filePath?: string;
data: string;
}
/**
*
*/
export const fileUtils = {
/**
* text
* @returns text文件
*/
readFile: async (): Promise<IFileInfo> => {
const { canceled, filePaths } = await dialog.showOpenDialog({});
let filePath = '';
if (!canceled) filePath = filePaths[0];
const data = await fs.readFile(filePath);
return { filePath, data: data.toString() };
}
};

View File

@ -0,0 +1,79 @@
import { BrowserWindow, BrowserWindowConstructorOptions, shell } from 'electron';
import path from 'path';
import WindowName from '../types/WindowName';
import icon from '/resources/icon.png?asset';
import { join } from 'path';
import { is } from '@electron-toolkit/utils';
class WindowManager {
// 这些都设置成 private 了,要用这些窗口的时候用下面那些 create 的方法,会返回需要的窗口,这样保证它们都是存在的
private MainWindow?: BrowserWindow;
private createWindow(
route: string,
options: Partial<BrowserWindowConstructorOptions> = {},
onReadyToShow?: () => any
) {
const win = new BrowserWindow({
show: false,
autoHideMenuBar: true,
...(process.platform === 'linux' ? { icon } : {}),
webPreferences: {
preload: join(__dirname, '../preload/index.js'),
sandbox: false
},
...options
});
win.once('ready-to-show', () => {
onReadyToShow && onReadyToShow();
win.show();
});
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
// 🚧 Use ['ENV_NAME'] avoid vite:define plugin
const url = process.env['ELECTRON_RENDERER_URL'];
win.loadURL(`${url}#/${route}`);
} else {
win.loadFile(path.resolve(__dirname, '../renderer/index.html'), { hash: route });
}
// Make all links open with the browser, not with the application
win.webContents.setWindowOpenHandler(({ url }) => {
if (url.startsWith('https:')) shell.openExternal(url);
return { action: 'deny' };
});
return win;
}
public createMainWindow() {
if (this.MainWindow && !this.MainWindow.isDestroyed()) {
this.MainWindow.show();
return this.MainWindow;
}
this.MainWindow = this.createWindow('mainWindow', {
title: 'DSZ ExamComposer 制卷系统'
});
this.MainWindow.on('close', () => {
this.MainWindow = undefined;
});
return this.MainWindow;
}
public destroyAllWindows() {
if (this.MainWindow) {
this.MainWindow.destroy();
}
}
public createByName(name: WindowName) {
switch (name) {
case 'mainWindow':
return this.createMainWindow();
}
}
}
export default new WindowManager();

8
src/preload/index.d.ts vendored Normal file
View File

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

22
src/preload/index.ts Normal file
View File

@ -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;
}

209
src/renderer/auto-imports.d.ts vendored Normal file
View File

@ -0,0 +1,209 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
export {}
declare global {
const EffectScope: (typeof import('vue'))['EffectScope'];
const computed: (typeof import('vue'))['computed'];
const createApp: (typeof import('vue'))['createApp'];
const customRef: (typeof import('vue'))['customRef'];
const defineAsyncComponent: (typeof import('vue'))['defineAsyncComponent'];
const defineComponent: (typeof import('vue'))['defineComponent'];
const effectScope: (typeof import('vue'))['effectScope'];
const getCurrentInstance: (typeof import('vue'))['getCurrentInstance'];
const getCurrentScope: (typeof import('vue'))['getCurrentScope'];
const h: (typeof import('vue'))['h'];
const inject: (typeof import('vue'))['inject'];
const isProxy: (typeof import('vue'))['isProxy'];
const isReactive: (typeof import('vue'))['isReactive'];
const isReadonly: (typeof import('vue'))['isReadonly'];
const isRef: (typeof import('vue'))['isRef'];
const markRaw: (typeof import('vue'))['markRaw'];
const nextTick: (typeof import('vue'))['nextTick'];
const onActivated: (typeof import('vue'))['onActivated'];
const onBeforeMount: (typeof import('vue'))['onBeforeMount'];
const onBeforeRouteLeave: (typeof import('vue-router'))['onBeforeRouteLeave'];
const onBeforeRouteUpdate: (typeof import('vue-router'))['onBeforeRouteUpdate'];
const onBeforeUnmount: (typeof import('vue'))['onBeforeUnmount'];
const onBeforeUpdate: (typeof import('vue'))['onBeforeUpdate'];
const onDeactivated: (typeof import('vue'))['onDeactivated'];
const onErrorCaptured: (typeof import('vue'))['onErrorCaptured'];
const onMounted: (typeof import('vue'))['onMounted'];
const onRenderTracked: (typeof import('vue'))['onRenderTracked'];
const onRenderTriggered: (typeof import('vue'))['onRenderTriggered'];
const onScopeDispose: (typeof import('vue'))['onScopeDispose'];
const onServerPrefetch: (typeof import('vue'))['onServerPrefetch'];
const onUnmounted: (typeof import('vue'))['onUnmounted'];
const onUpdated: (typeof import('vue'))['onUpdated'];
const provide: (typeof import('vue'))['provide'];
const reactive: (typeof import('vue'))['reactive'];
const readonly: (typeof import('vue'))['readonly'];
const ref: (typeof import('vue'))['ref'];
const resolveComponent: (typeof import('vue'))['resolveComponent'];
const shallowReactive: (typeof import('vue'))['shallowReactive'];
const shallowReadonly: (typeof import('vue'))['shallowReadonly'];
const shallowRef: (typeof import('vue'))['shallowRef'];
const toRaw: (typeof import('vue'))['toRaw'];
const toRef: (typeof import('vue'))['toRef'];
const toRefs: (typeof import('vue'))['toRefs'];
const toValue: (typeof import('vue'))['toValue'];
const triggerRef: (typeof import('vue'))['triggerRef'];
const unref: (typeof import('vue'))['unref'];
const useAttrs: (typeof import('vue'))['useAttrs'];
const useCssModule: (typeof import('vue'))['useCssModule'];
const useCssVars: (typeof import('vue'))['useCssVars'];
const useLink: (typeof import('vue-router'))['useLink'];
const useRoute: (typeof import('vue-router'))['useRoute'];
const useRouter: (typeof import('vue-router'))['useRouter'];
const useSlots: (typeof import('vue'))['useSlots'];
const watch: (typeof import('vue'))['watch'];
const watchEffect: (typeof import('vue'))['watchEffect'];
const watchPostEffect: (typeof import('vue'))['watchPostEffect'];
const watchSyncEffect: (typeof import('vue'))['watchSyncEffect'];
}
// for type re-export
declare global {
// @ts-ignore
export type {
Component,
ComponentPublicInstance,
ComputedRef,
ExtractDefaultPropTypes,
ExtractPropTypes,
ExtractPublicPropTypes,
InjectionKey,
PropType,
Ref,
VNode,
WritableComputedRef
} from 'vue';
import('vue');
}
// for vue template auto import
import { UnwrapRef } from 'vue';
declare module 'vue' {
interface GlobalComponents {}
interface ComponentCustomProperties {
readonly EffectScope: UnwrapRef<(typeof import('vue'))['EffectScope']>;
readonly computed: UnwrapRef<(typeof import('vue'))['computed']>;
readonly createApp: UnwrapRef<(typeof import('vue'))['createApp']>;
readonly customRef: UnwrapRef<(typeof import('vue'))['customRef']>;
readonly defineAsyncComponent: UnwrapRef<(typeof import('vue'))['defineAsyncComponent']>;
readonly defineComponent: UnwrapRef<(typeof import('vue'))['defineComponent']>;
readonly effectScope: UnwrapRef<(typeof import('vue'))['effectScope']>;
readonly getCurrentInstance: UnwrapRef<(typeof import('vue'))['getCurrentInstance']>;
readonly getCurrentScope: UnwrapRef<(typeof import('vue'))['getCurrentScope']>;
readonly h: UnwrapRef<(typeof import('vue'))['h']>;
readonly inject: UnwrapRef<(typeof import('vue'))['inject']>;
readonly isProxy: UnwrapRef<(typeof import('vue'))['isProxy']>;
readonly isReactive: UnwrapRef<(typeof import('vue'))['isReactive']>;
readonly isReadonly: UnwrapRef<(typeof import('vue'))['isReadonly']>;
readonly isRef: UnwrapRef<(typeof import('vue'))['isRef']>;
readonly markRaw: UnwrapRef<(typeof import('vue'))['markRaw']>;
readonly nextTick: UnwrapRef<(typeof import('vue'))['nextTick']>;
readonly onActivated: UnwrapRef<(typeof import('vue'))['onActivated']>;
readonly onBeforeMount: UnwrapRef<(typeof import('vue'))['onBeforeMount']>;
readonly onBeforeRouteLeave: UnwrapRef<(typeof import('vue-router'))['onBeforeRouteLeave']>;
readonly onBeforeRouteUpdate: UnwrapRef<(typeof import('vue-router'))['onBeforeRouteUpdate']>;
readonly onBeforeUnmount: UnwrapRef<(typeof import('vue'))['onBeforeUnmount']>;
readonly onBeforeUpdate: UnwrapRef<(typeof import('vue'))['onBeforeUpdate']>;
readonly onDeactivated: UnwrapRef<(typeof import('vue'))['onDeactivated']>;
readonly onErrorCaptured: UnwrapRef<(typeof import('vue'))['onErrorCaptured']>;
readonly onMounted: UnwrapRef<(typeof import('vue'))['onMounted']>;
readonly onRenderTracked: UnwrapRef<(typeof import('vue'))['onRenderTracked']>;
readonly onRenderTriggered: UnwrapRef<(typeof import('vue'))['onRenderTriggered']>;
readonly onScopeDispose: UnwrapRef<(typeof import('vue'))['onScopeDispose']>;
readonly onServerPrefetch: UnwrapRef<(typeof import('vue'))['onServerPrefetch']>;
readonly onUnmounted: UnwrapRef<(typeof import('vue'))['onUnmounted']>;
readonly onUpdated: UnwrapRef<(typeof import('vue'))['onUpdated']>;
readonly provide: UnwrapRef<(typeof import('vue'))['provide']>;
readonly reactive: UnwrapRef<(typeof import('vue'))['reactive']>;
readonly readonly: UnwrapRef<(typeof import('vue'))['readonly']>;
readonly ref: UnwrapRef<(typeof import('vue'))['ref']>;
readonly resolveComponent: UnwrapRef<(typeof import('vue'))['resolveComponent']>;
readonly shallowReactive: UnwrapRef<(typeof import('vue'))['shallowReactive']>;
readonly shallowReadonly: UnwrapRef<(typeof import('vue'))['shallowReadonly']>;
readonly shallowRef: UnwrapRef<(typeof import('vue'))['shallowRef']>;
readonly toRaw: UnwrapRef<(typeof import('vue'))['toRaw']>;
readonly toRef: UnwrapRef<(typeof import('vue'))['toRef']>;
readonly toRefs: UnwrapRef<(typeof import('vue'))['toRefs']>;
readonly toValue: UnwrapRef<(typeof import('vue'))['toValue']>;
readonly triggerRef: UnwrapRef<(typeof import('vue'))['triggerRef']>;
readonly unref: UnwrapRef<(typeof import('vue'))['unref']>;
readonly useAttrs: UnwrapRef<(typeof import('vue'))['useAttrs']>;
readonly useCssModule: UnwrapRef<(typeof import('vue'))['useCssModule']>;
readonly useCssVars: UnwrapRef<(typeof import('vue'))['useCssVars']>;
readonly useLink: UnwrapRef<(typeof import('vue-router'))['useLink']>;
readonly useRoute: UnwrapRef<(typeof import('vue-router'))['useRoute']>;
readonly useRouter: UnwrapRef<(typeof import('vue-router'))['useRouter']>;
readonly useSlots: UnwrapRef<(typeof import('vue'))['useSlots']>;
readonly watch: UnwrapRef<(typeof import('vue'))['watch']>;
readonly watchEffect: UnwrapRef<(typeof import('vue'))['watchEffect']>;
readonly watchPostEffect: UnwrapRef<(typeof import('vue'))['watchPostEffect']>;
readonly watchSyncEffect: UnwrapRef<(typeof import('vue'))['watchSyncEffect']>;
}
}
declare module '@vue/runtime-core' {
interface GlobalComponents {}
interface ComponentCustomProperties {
readonly EffectScope: UnwrapRef<(typeof import('vue'))['EffectScope']>;
readonly computed: UnwrapRef<(typeof import('vue'))['computed']>;
readonly createApp: UnwrapRef<(typeof import('vue'))['createApp']>;
readonly customRef: UnwrapRef<(typeof import('vue'))['customRef']>;
readonly defineAsyncComponent: UnwrapRef<(typeof import('vue'))['defineAsyncComponent']>;
readonly defineComponent: UnwrapRef<(typeof import('vue'))['defineComponent']>;
readonly effectScope: UnwrapRef<(typeof import('vue'))['effectScope']>;
readonly getCurrentInstance: UnwrapRef<(typeof import('vue'))['getCurrentInstance']>;
readonly getCurrentScope: UnwrapRef<(typeof import('vue'))['getCurrentScope']>;
readonly h: UnwrapRef<(typeof import('vue'))['h']>;
readonly inject: UnwrapRef<(typeof import('vue'))['inject']>;
readonly isProxy: UnwrapRef<(typeof import('vue'))['isProxy']>;
readonly isReactive: UnwrapRef<(typeof import('vue'))['isReactive']>;
readonly isReadonly: UnwrapRef<(typeof import('vue'))['isReadonly']>;
readonly isRef: UnwrapRef<(typeof import('vue'))['isRef']>;
readonly markRaw: UnwrapRef<(typeof import('vue'))['markRaw']>;
readonly nextTick: UnwrapRef<(typeof import('vue'))['nextTick']>;
readonly onActivated: UnwrapRef<(typeof import('vue'))['onActivated']>;
readonly onBeforeMount: UnwrapRef<(typeof import('vue'))['onBeforeMount']>;
readonly onBeforeRouteLeave: UnwrapRef<(typeof import('vue-router'))['onBeforeRouteLeave']>;
readonly onBeforeRouteUpdate: UnwrapRef<(typeof import('vue-router'))['onBeforeRouteUpdate']>;
readonly onBeforeUnmount: UnwrapRef<(typeof import('vue'))['onBeforeUnmount']>;
readonly onBeforeUpdate: UnwrapRef<(typeof import('vue'))['onBeforeUpdate']>;
readonly onDeactivated: UnwrapRef<(typeof import('vue'))['onDeactivated']>;
readonly onErrorCaptured: UnwrapRef<(typeof import('vue'))['onErrorCaptured']>;
readonly onMounted: UnwrapRef<(typeof import('vue'))['onMounted']>;
readonly onRenderTracked: UnwrapRef<(typeof import('vue'))['onRenderTracked']>;
readonly onRenderTriggered: UnwrapRef<(typeof import('vue'))['onRenderTriggered']>;
readonly onScopeDispose: UnwrapRef<(typeof import('vue'))['onScopeDispose']>;
readonly onServerPrefetch: UnwrapRef<(typeof import('vue'))['onServerPrefetch']>;
readonly onUnmounted: UnwrapRef<(typeof import('vue'))['onUnmounted']>;
readonly onUpdated: UnwrapRef<(typeof import('vue'))['onUpdated']>;
readonly provide: UnwrapRef<(typeof import('vue'))['provide']>;
readonly reactive: UnwrapRef<(typeof import('vue'))['reactive']>;
readonly readonly: UnwrapRef<(typeof import('vue'))['readonly']>;
readonly ref: UnwrapRef<(typeof import('vue'))['ref']>;
readonly resolveComponent: UnwrapRef<(typeof import('vue'))['resolveComponent']>;
readonly shallowReactive: UnwrapRef<(typeof import('vue'))['shallowReactive']>;
readonly shallowReadonly: UnwrapRef<(typeof import('vue'))['shallowReadonly']>;
readonly shallowRef: UnwrapRef<(typeof import('vue'))['shallowRef']>;
readonly toRaw: UnwrapRef<(typeof import('vue'))['toRaw']>;
readonly toRef: UnwrapRef<(typeof import('vue'))['toRef']>;
readonly toRefs: UnwrapRef<(typeof import('vue'))['toRefs']>;
readonly toValue: UnwrapRef<(typeof import('vue'))['toValue']>;
readonly triggerRef: UnwrapRef<(typeof import('vue'))['triggerRef']>;
readonly unref: UnwrapRef<(typeof import('vue'))['unref']>;
readonly useAttrs: UnwrapRef<(typeof import('vue'))['useAttrs']>;
readonly useCssModule: UnwrapRef<(typeof import('vue'))['useCssModule']>;
readonly useCssVars: UnwrapRef<(typeof import('vue'))['useCssVars']>;
readonly useLink: UnwrapRef<(typeof import('vue-router'))['useLink']>;
readonly useRoute: UnwrapRef<(typeof import('vue-router'))['useRoute']>;
readonly useRouter: UnwrapRef<(typeof import('vue-router'))['useRouter']>;
readonly useSlots: UnwrapRef<(typeof import('vue'))['useSlots']>;
readonly watch: UnwrapRef<(typeof import('vue'))['watch']>;
readonly watchEffect: UnwrapRef<(typeof import('vue'))['watchEffect']>;
readonly watchPostEffect: UnwrapRef<(typeof import('vue'))['watchPostEffect']>;
readonly watchSyncEffect: UnwrapRef<(typeof import('vue'))['watchSyncEffect']>;
}
}

15
src/renderer/components.d.ts vendored Normal file
View File

@ -0,0 +1,15 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
export {}
declare module 'vue' {
export interface GlobalComponents {
AppFooter: (typeof import('./src/components/AppFooter.vue'))['default'];
HelloWorld: (typeof import('./src/components/HelloWorld.vue'))['default'];
RouterLink: (typeof import('vue-router'))['RouterLink'];
RouterView: (typeof import('vue-router'))['RouterView'];
}
}

14
src/renderer/index.html Normal file
View File

@ -0,0 +1,14 @@
<!doctype html>
<html lang="en" class="dark">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DSZ Exam Showboard</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

10
src/renderer/src/App.vue Normal file
View File

@ -0,0 +1,10 @@
<template>
<main>
<router-view />
</main>
</template>
<script setup>
const router = useRouter();
console.log(router.options.routes);
</script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,6 @@
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M261.126 140.65L164.624 307.732L256.001 466L377.028 256.5L498.001 47H315.192L261.126 140.65Z" fill="#1697F6"/>
<path d="M135.027 256.5L141.365 267.518L231.64 111.178L268.731 47H256H14L135.027 256.5Z" fill="#AEDDFF"/>
<path d="M315.191 47C360.935 197.446 256 466 256 466L164.624 307.732L315.191 47Z" fill="#1867C0"/>
<path d="M268.731 47C76.0026 47 141.366 267.518 141.366 267.518L268.731 47Z" fill="#7BC6FF"/>
</svg>

After

Width:  |  Height:  |  Size: 526 B

188
src/renderer/src/auto-imports.d.ts vendored Normal file
View File

@ -0,0 +1,188 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const effectScope: typeof import('vue')['effectScope']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onMounted: typeof import('vue')['onMounted']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useRoute: typeof import('vue-router/auto')['useRoute']
const useRouter: typeof import('vue-router/auto')['useRouter']
const useSlots: typeof import('vue')['useSlots']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
import('vue')
}
// for vue template auto import
import { UnwrapRef } from 'vue'
declare module 'vue' {
interface GlobalComponents {}
interface ComponentCustomProperties {
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
readonly computed: UnwrapRef<typeof import('vue')['computed']>
readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
readonly customRef: UnwrapRef<typeof import('vue')['customRef']>
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']>
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']>
readonly h: UnwrapRef<typeof import('vue')['h']>
readonly inject: UnwrapRef<typeof import('vue')['inject']>
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']>
readonly isRef: UnwrapRef<typeof import('vue')['isRef']>
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']>
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']>
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']>
readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']>
readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']>
readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']>
readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']>
readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']>
readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']>
readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']>
readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']>
readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']>
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
readonly provide: UnwrapRef<typeof import('vue')['provide']>
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
readonly ref: UnwrapRef<typeof import('vue')['ref']>
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']>
readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
readonly unref: UnwrapRef<typeof import('vue')['unref']>
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
readonly useRoute: UnwrapRef<typeof import('vue-router/auto')['useRoute']>
readonly useRouter: UnwrapRef<typeof import('vue-router/auto')['useRouter']>
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
readonly watch: UnwrapRef<typeof import('vue')['watch']>
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>
readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']>
readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']>
}
}
declare module '@vue/runtime-core' {
interface GlobalComponents {}
interface ComponentCustomProperties {
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
readonly computed: UnwrapRef<typeof import('vue')['computed']>
readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
readonly customRef: UnwrapRef<typeof import('vue')['customRef']>
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']>
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']>
readonly h: UnwrapRef<typeof import('vue')['h']>
readonly inject: UnwrapRef<typeof import('vue')['inject']>
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']>
readonly isRef: UnwrapRef<typeof import('vue')['isRef']>
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']>
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']>
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']>
readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']>
readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']>
readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']>
readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']>
readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']>
readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']>
readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']>
readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']>
readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']>
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
readonly provide: UnwrapRef<typeof import('vue')['provide']>
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
readonly ref: UnwrapRef<typeof import('vue')['ref']>
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']>
readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
readonly unref: UnwrapRef<typeof import('vue')['unref']>
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
readonly useRoute: UnwrapRef<typeof import('vue-router/auto')['useRoute']>
readonly useRouter: UnwrapRef<typeof import('vue-router/auto')['useRouter']>
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
readonly watch: UnwrapRef<typeof import('vue')['watch']>
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>
readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']>
readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']>
}
}

30
src/renderer/src/components.d.ts vendored Normal file
View File

@ -0,0 +1,30 @@
/* eslint-disable */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
AppFooter: (typeof import('./components/AppFooter.vue'))['default']
AppTopBar: (typeof import('./components/AppTopBar.vue'))['default']
DBtn: typeof import('vue-devui/btn/index.es.js')['Btn']
DButton: typeof import('vue-devui/button/index.es.js')['Button']
DCodeEditor: (typeof import('vue-devui/code-editor/index.es.js'))['CodeEditor']
DCol: typeof import('vue-devui/grid/index.es.js')['Col']
DRow: typeof import('vue-devui/grid/index.es.js')['Row']
DStatus: typeof import('vue-devui/status/index.es.js')['Status']
ElButton: typeof import('element-plus/es')['ElButton']
ElCol: typeof import('element-plus/es')['ElCol']
ElRow: typeof import('element-plus/es')['ElRow']
ElText: typeof import('element-plus/es')['ElText']
ExamStatus: typeof import('./components/ExamStatus.vue')['default']
GgbPlayer: (typeof import('./components/GgbPlayer.vue'))['default']
ReadmeRender: (typeof import('./components/ReadmeRender.vue'))['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SubjectInfo: typeof import('./components/SubjectInfo.vue')['default']
SvgIcon: typeof import('./components/SvgIcon.vue')['default']
}
}

View File

@ -0,0 +1,66 @@
<template>
<div class="exam-status">
<el-row class="exam-info-bar">
<el-col :span="3">
<strong>{{ exam.name }}</strong>
</el-col>
<el-col :span="8">
{{ formatDateTime(exam.start) }} ~ {{ formatDateTime(exam.end) }}
</el-col>
<el-col :span="3">
<el-text class="mx-1" size="large" :type="statusColor">{{ statusText }}</el-text>
</el-col>
</el-row>
</div>
</template>
<script setup>
import moment from 'moment';
const props = defineProps({
exam: {
type: Object,
required: true
}
});
const formatDateTime = (isoString) => moment(isoString).format('HH:mm');
const statusColor = computed(() => {
const now = moment();
const start = moment(props.exam.start);
const end = moment(props.exam.end);
if (now.isBefore(start)) return 'running';
if (now.isBetween(start, end)) return 'success';
if (now.isAfter(end)) return 'error';
});
const statusText = computed(() => {
const now = moment();
const start = moment(props.exam.start);
const end = moment(props.exam.end);
if (now.isBefore(start)) return '未开始';
if (now.isBetween(start, end)) return '进行中';
if (now.isAfter(end)) return '已结束';
});
</script>
<style scoped>
.exam-status {
padding: 10px;
border: 1px solid #e9e9e9;
margin-bottom: 10px;
}
.exam-info-bar {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 1.4em;
}
</style>

View File

@ -0,0 +1,50 @@
<template>
<div class="exam-info">
<h2>当前科目: {{ exam.name }}</h2>
<h2>考试时间: {{ formatDateTime(exam.start) }} ~ {{ formatDateTime(exam.end) }}</h2>
<h2>考试状态: {{ statusText }}</h2>
</div>
</template>
<script setup>
import moment from 'moment';
const props = defineProps({
exam: {
type: Object,
required: true
}
});
const formatDateTime = (isoString) => moment(isoString).format('HH:mm');
const statusColor = computed(() => {
const now = moment();
const start = moment(props.exam.start);
const end = moment(props.exam.end);
if (now.isBefore(start)) return 'running';
if (now.isBetween(start, end)) return 'success';
if (now.isAfter(end)) return 'error';
});
const statusText = computed(() => {
const now = moment();
const start = moment(props.exam.start);
const end = moment(props.exam.end);
if (now.isBefore(start)) return '未开始';
if (now.isBetween(start, end)) return '进行中';
if (now.isAfter(end)) return '已结束';
});
</script>
<style scoped>
.exam-info-bar {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 1.4em;
}
</style>

View File

@ -0,0 +1,35 @@
<template>
<svg aria-hidden="true" :style="{ width: size, height: size }">
<use :href="symbolId" :fill="color" />
</svg>
</template>
<script>
import { defineComponent, computed } from 'vue';
export default defineComponent({
name: 'SvgIcon',
props: {
prefix: {
type: String,
default: 'icon'
},
name: {
type: String,
required: true
},
color: {
type: String,
default: '#333'
},
size: {
type: [String, Number],
default: '12px'
}
},
setup(props) {
const symbolId = computed(() => `#${props.prefix}-${props.name}`);
return { symbolId };
}
});
</script>

View File

@ -0,0 +1,12 @@
export interface TimeSlot {
name: string;
start: string;
end: string;
}
export interface ExamSchedule {
examName: string;
roomName: string;
message: string;
examInfos: TimeSlot[];
}

View File

@ -0,0 +1,5 @@
# Layouts
Layouts are reusable components that wrap around pages. They are used to provide a consistent look and feel across multiple pages.
Full documentation for this feature can be found in the Official [vite-plugin-vue-layouts](https://github.com/JohnCampionJr/vite-plugin-vue-layouts) repository.

View File

@ -0,0 +1,9 @@
<template>
<v-app>
<div><router-view /></div>
</v-app>
</template>
<script lang="ts" setup>
//
</script>

31
src/renderer/src/main.ts Normal file
View File

@ -0,0 +1,31 @@
/**
* main.js
*
* Bootstraps Vuetify and other plugins then mounts the App`
*/
// Plugins
import { registerPlugins } from './plugins';
// Components
import App from './App.vue';
// Composables
import { createApp } from 'vue';
import { VueShowdownPlugin } from 'vue-showdown';
import 'virtual:svg-icons-register';
import 'element-plus/theme-chalk/dark/css-vars.css'
const app = createApp(App);
app.use(VueShowdownPlugin, {
// 设置 showdown 默认 flavor
flavor: 'github'
});
registerPlugins(app);
app.mount('#app');

View File

@ -0,0 +1,5 @@
# Pages
Vue components created in this folder will automatically be converted to navigatable routes.
Full documentation for this feature can be found in the Official [unplugin-vue-router](https://github.com/posva/unplugin-vue-router) repository.

View File

@ -0,0 +1,15 @@
<template>
<p>跳转首页中</p>
</template>
<script setup>
import { useRouter } from 'vue-router';
import { onMounted } from 'vue';
const router = useRouter();
onMounted(() => {
// '/mainWindow'
router.push('/mainWindow');
});
</script>

View File

@ -0,0 +1,52 @@
<template>
<div class="main-area">
<h1>{{ globalStore.examName }}</h1>
<el-row>
<el-col :span="13">
<SubjectInfo
v-if="isExamRunning"
:exam="runningExam"
></SubjectInfo>
<h2 v-else>
考试未开始
</h2>
</el-col>
<el-col :span="11">
<div v-for="exam in globalStore.examInfos">
<ExamStatus :exam="exam" />
</div>
</el-col>
</el-row>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router';
import { useAppStore } from '@renderer/stores/app';
import { getCurrentTimeSlot } from '@renderer/utils/subjectUtils'
const globalStore = useAppStore();
const router = useRouter();
getCurrentTimeSlot(globalStore.examInfos);
const runningExam = computed(() => {
return getCurrentTimeSlot(globalStore.examInfos);
});
const isExamRunning = computed(() =>{
return getCurrentTimeSlot(globalStore.examInfos) == null;
});
//
</script>
<style scoped>
.main-area {
padding-left: 20px;
padding-right: 20px;
}
</style>

View File

@ -0,0 +1,30 @@
<template>
<div>
<h1>电视猪考试看板</h1>
<el-button @click="OpenDialog">打开配置</el-button>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router';
import { useAppStore } from '@renderer/stores/app';
const globalStore = useAppStore()
function OpenDialog() {
window.electron.ipcRenderer.send('prog:loadjson');
}
window.electron.ipcRenderer.on('common:openFile', (event, message) => {
console.log(message.data);
let examdata = JSON.parse(message.data);
globalStore.$patch(examdata);
router.push('/infoPage');
});
const router = useRouter();
//
</script>

View File

@ -0,0 +1,19 @@
<template>
<div>
<h1>测试页面</h1>
<ExamStatus
:exam="{
name: '语文',
start: '2024-07-25T08:54:52.717Z',
end: '2024-07-25T08:55:40.428Z'
}"
/>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router';
const router = useRouter();
//
</script>

View File

@ -0,0 +1,3 @@
# Plugins
Plugins are a way to extend the functionality of your Vue application. Use this folder for registering plugins that you want to use globally.

View File

@ -0,0 +1,14 @@
/**
* plugins/index.js
*
* Automatically included in `./src/main.ts`
*/
// Plugins
import pinia from '../stores';
import router from '../router';
import { App } from 'vue';
export function registerPlugins(app: App) {
app.use(router).use(pinia);
}

View File

@ -0,0 +1,16 @@
/**
* router/index.ts
*
* Automatic routes for `./src/pages/*.vue`
*/
// Composables
import { createRouter, createWebHashHistory } from 'vue-router/auto';
import { setupLayouts } from 'virtual:generated-layouts';
const router = createRouter({
history: createWebHashHistory(),
extendRoutes: setupLayouts
});
export default router;

View File

@ -0,0 +1,5 @@
# Store
Pinia stores are used to store reactive state and expose actions to mutate it.
Full documentation for this feature can be found in the Official [Pinia](https://pinia.esm.dev/) repository.

View File

@ -0,0 +1,12 @@
// Utilities
import { defineStore } from 'pinia';
export const useAppStore = defineStore('app', {
state: () => ({
examName: '考试名称',
roomName: '考场名称',
message: '考试提醒信息',
examInfos: []
})
});

View File

@ -0,0 +1,4 @@
// Utilities
import { createPinia } from 'pinia';
export default createPinia();

View File

@ -0,0 +1,3 @@
# Styles
This directory is for configuring the styles of the application.

View File

@ -0,0 +1,10 @@
/**
* src/styles/settings.scss
*
* Configures SASS variables and Vuetify overwrites
*/
// https://vuetifyjs.com/features/sass-variables/`
// @use 'vuetify/settings' with (
// $color-pack: false
// );

26
src/renderer/src/typed-router.d.ts vendored Normal file
View File

@ -0,0 +1,26 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// Generated by unplugin-vue-router. ‼️ DO NOT MODIFY THIS FILE ‼️
// It's recommended to commit this file.
// Make sure to add this file to your tsconfig.json file as an "includes" or "files" entry.
declare module 'vue-router/auto-routes' {
import type {
RouteRecordInfo,
ParamValue,
ParamValueOneOrMore,
ParamValueZeroOrMore,
ParamValueZeroOrOne,
} from 'unplugin-vue-router/types'
/**
* Route name map generated by unplugin-vue-router
*/
export interface RouteNamedMap {
'/': RouteRecordInfo<'/', '/', Record<never, never>, Record<never, never>>,
'/infoPage': RouteRecordInfo<'/infoPage', '/infoPage', Record<never, never>, Record<never, never>>,
'/mainWindow': RouteRecordInfo<'/mainWindow', '/mainWindow', Record<never, never>, Record<never, never>>,
'/testComponents': RouteRecordInfo<'/testComponents', '/testComponents', Record<never, never>, Record<never, never>>,
}
}

View File

@ -0,0 +1,30 @@
import { parseISO, isBefore } from 'date-fns';
import { TimeSlot } from '@renderer/interfaces/timeTable';
/**
*
*
*
* null
*
* @param timeSlots
* @returns null
*/
export function getCurrentTimeSlot(timeSlots: TimeSlot[]): TimeSlot | null {
// 获取当前日期和时间
const now = new Date();
// 遍历时间段数组
for (const slot of timeSlots) {
// 解析时间段的开始时间
const startTime = parseISO(slot.start);
// 解析时间段的结束时间
const endTime = parseISO(slot.end);
// 判断当前时间是否在开始时间和结束时间之间
if (isBefore(startTime, now) && isBefore(now, endTime)) {
// 如果是,返回当前时间段
return slot;
}
}
// 如果没有找到包含当前时间的时间段返回null
return null;
}

4
tsconfig.json Normal file
View File

@ -0,0 +1,4 @@
{
"files": [],
"references": [{ "path": "./tsconfig.node.json" }, { "path": "./tsconfig.web.json" }]
}

9
tsconfig.node.json Normal file
View File

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

37
tsconfig.web.json Normal file
View File

@ -0,0 +1,37 @@
{
"extends": "@electron-toolkit/tsconfig/tsconfig.web.json",
"include": [
"src/renderer/src/env.d.ts",
"src/renderer/src/**/*",
"src/renderer/src/**/*.vue",
"src/preload/*.d.ts"
],
"compilerOptions": {
"composite": true,
"baseUrl": ".",
"paths": {
"@renderer/*": [
"src/renderer/src/*"
]
},
"target": "ESNext",
"jsx": "preserve",
"lib": ["DOM", "ESNext"],
"module": "ESNext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"types": [
"vite/client",
"vite-plugin-vue-layouts/client",
"unplugin-vue-router/client"
],
"allowJs": true,
"strict": true,
"strictNullChecks": true,
"noUnusedLocals": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"skipLibCheck": true
}
}

5949
yarn.lock Normal file

File diff suppressed because it is too large Load Diff