ZhangXianQiang
2024-06-13 6c34d8df858b0c795dd06da0962c22f9d1c40bd2
feat(在线培训):添加在线培训流程
7个文件已修改
5个文件已添加
616 ■■■■■ 已修改文件
dist-electron/background.js 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
index.html 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json 336 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/image/list-card-bg.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/background.js 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/preload.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/meet/index.vue 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menu/index.vue 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/train/data-list/index.vue 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/train/index.vue 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
dist-electron/background.js
@@ -1,15 +1,18 @@
"use strict";
const { app, BrowserWindow, screen } = require("electron");
const { app, BrowserWindow, screen, globalShortcut, ipcMain } = require("electron");
const { join } = require("path");
process.env["ELECTRON_DISABLE_SECURITY_WARNINGS"] = "true";
const createWindow = () => {
  const { width, height } = screen.getPrimaryDisplay().bounds;
const createWindow = (width, height) => {
  const win = new BrowserWindow({
    width,
    height,
    minWidth: 1280,
    minHeight: 720
    minHeight: 720,
    webPreferences: {
      preload: join(__dirname, "preload.js")
    }
  });
  win.maximize();
  if (process.env.VITE_DEV_SERVER_URL) {
    win.loadURL(process.env.VITE_DEV_SERVER_URL);
    win.webContents.openDevTools();
@@ -18,11 +21,31 @@
  }
};
app.whenReady().then(() => {
  createWindow();
  const { width, height } = screen.getPrimaryDisplay().bounds;
  createWindow(width, height);
  app.on("activate", () => {
    if (BrowserWindow.getAllWindows().length === 0)
      createWindow();
  });
  ipcMain.on("open-new-window", () => {
    const childWin = new BrowserWindow({
      width,
      height,
      minWidth: width,
      minHeight: height,
      webPreferences: {
        preload: join(__dirname, "preload.js")
      }
    });
    childWin.maximize();
    if (process.env.VITE_DEV_SERVER_URL) {
      childWin.loadURL(process.env.VITE_DEV_SERVER_URL + "#/meet");
    } else {
      childWin.loadFile(join(__dirname, "../dist/index.html"), {
        hash: "/meet"
      });
    }
  });
});
app.on("window-all-closed", () => {
  if (process.platform !== "darwin")
index.html
@@ -5,9 +5,15 @@
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + Vue</title>
    <script src='https://meet.jit.si/external_api.js'></script>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.js"></script>
    <script>
      window.onload = () => {
        window.JitsiMeetExternalAPI = JitsiMeetExternalAPI;
      }
    </script>
  </body>
</html>
package-lock.json
@@ -8,6 +8,7 @@
      "name": "jxkg-new-ui",
      "version": "0.0.0",
      "dependencies": {
        "@jitsi/electron-sdk": "^6.0.40",
        "axios": "^1.7.2",
        "dayjs": "^1.11.11",
        "element-plus": "^2.7.3",
@@ -832,6 +833,48 @@
        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
      }
    },
    "node_modules/@jitsi/electron-sdk": {
      "version": "6.0.40",
      "resolved": "https://registry.npmmirror.com/@jitsi/electron-sdk/-/electron-sdk-6.0.40.tgz",
      "integrity": "sha512-dUr74XakxX4Keiq8Z2VSNhKw5W3e2GQy4TVh5JhhLi/lltxito5ulZzak22rlHaL1qQ3u35hI2+Lale7x2FFIQ==",
      "hasInstallScript": true,
      "dependencies": {
        "@jitsi/logger": "^2.0.2",
        "@jitsi/robotjs": "^0.6.13",
        "electron-store": "^8.0.1",
        "node-addon-api": "^8.0.0",
        "node-gyp-build": "4.8.1",
        "postis": "^2.2.0"
      }
    },
    "node_modules/@jitsi/electron-sdk/node_modules/node-addon-api": {
      "version": "8.0.0",
      "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-8.0.0.tgz",
      "integrity": "sha512-ipO7rsHEBqa9STO5C5T10fj732ml+5kLN1cAG8/jdHd56ldQeGj3Q7+scUS+VHK/qy1zLEwC4wMK5+yM0btPvw==",
      "engines": {
        "node": "^18 || ^20 || >= 21"
      }
    },
    "node_modules/@jitsi/logger": {
      "version": "2.0.2",
      "resolved": "https://registry.npmmirror.com/@jitsi/logger/-/logger-2.0.2.tgz",
      "integrity": "sha512-qwbpRwuwkBFgh0F5jivq/5fAm46yVoXURc5LCklEs8lAShYVangFEXKW7RLpZuZ5nQnrHrlvU8MswQNREmvahg=="
    },
    "node_modules/@jitsi/robotjs": {
      "version": "0.6.13",
      "resolved": "https://registry.npmmirror.com/@jitsi/robotjs/-/robotjs-0.6.13.tgz",
      "integrity": "sha512-uFxRQp83jbKfMzk3lYIjgevy1X1dU/Z7OMPnqfdO1LcyPaXsOf+FCWSxM/KIxz0PvbBbORxUzuae5O5dAF5Kqw==",
      "hasInstallScript": true,
      "dependencies": {
        "node-addon-api": "^4.2.0",
        "node-gyp-build": "^4.3.0"
      }
    },
    "node_modules/@jitsi/robotjs/node_modules/node-addon-api": {
      "version": "4.3.0",
      "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-4.3.0.tgz",
      "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ=="
    },
    "node_modules/@jridgewell/gen-mapping": {
      "version": "0.3.5",
      "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
@@ -1623,6 +1666,42 @@
        "url": "https://github.com/sponsors/epoberezkin"
      }
    },
    "node_modules/ajv-formats": {
      "version": "2.1.1",
      "resolved": "https://registry.npmmirror.com/ajv-formats/-/ajv-formats-2.1.1.tgz",
      "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
      "dependencies": {
        "ajv": "^8.0.0"
      },
      "peerDependencies": {
        "ajv": "^8.0.0"
      },
      "peerDependenciesMeta": {
        "ajv": {
          "optional": true
        }
      }
    },
    "node_modules/ajv-formats/node_modules/ajv": {
      "version": "8.16.0",
      "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.16.0.tgz",
      "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==",
      "dependencies": {
        "fast-deep-equal": "^3.1.3",
        "json-schema-traverse": "^1.0.0",
        "require-from-string": "^2.0.2",
        "uri-js": "^4.4.1"
      },
      "funding": {
        "type": "github",
        "url": "https://github.com/sponsors/epoberezkin"
      }
    },
    "node_modules/ajv-formats/node_modules/json-schema-traverse": {
      "version": "1.0.0",
      "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
    },
    "node_modules/ajv-keywords": {
      "version": "3.5.2",
      "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
@@ -1908,6 +1987,14 @@
      "dev": true,
      "engines": {
        "node": ">= 4.0.0"
      }
    },
    "node_modules/atomically": {
      "version": "1.7.0",
      "resolved": "https://registry.npmmirror.com/atomically/-/atomically-1.7.0.tgz",
      "integrity": "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==",
      "engines": {
        "node": ">=10.12.0"
      }
    },
    "node_modules/autoprefixer": {
@@ -2440,6 +2527,60 @@
      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
      "dev": true
    },
    "node_modules/conf": {
      "version": "10.2.0",
      "resolved": "https://registry.npmmirror.com/conf/-/conf-10.2.0.tgz",
      "integrity": "sha512-8fLl9F04EJqjSqH+QjITQfJF8BrOVaYr1jewVgSRAEWePfxT0sku4w2hrGQ60BC/TNLGQ2pgxNlTbWQmMPFvXg==",
      "dependencies": {
        "ajv": "^8.6.3",
        "ajv-formats": "^2.1.1",
        "atomically": "^1.7.0",
        "debounce-fn": "^4.0.0",
        "dot-prop": "^6.0.1",
        "env-paths": "^2.2.1",
        "json-schema-typed": "^7.0.3",
        "onetime": "^5.1.2",
        "pkg-up": "^3.1.0",
        "semver": "^7.3.5"
      },
      "engines": {
        "node": ">=12"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/conf/node_modules/ajv": {
      "version": "8.16.0",
      "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.16.0.tgz",
      "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==",
      "dependencies": {
        "fast-deep-equal": "^3.1.3",
        "json-schema-traverse": "^1.0.0",
        "require-from-string": "^2.0.2",
        "uri-js": "^4.4.1"
      },
      "funding": {
        "type": "github",
        "url": "https://github.com/sponsors/epoberezkin"
      }
    },
    "node_modules/conf/node_modules/json-schema-traverse": {
      "version": "1.0.0",
      "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
    },
    "node_modules/conf/node_modules/semver": {
      "version": "7.6.2",
      "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.2.tgz",
      "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
      "bin": {
        "semver": "bin/semver.js"
      },
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/confbox": {
      "version": "0.1.7",
      "resolved": "https://registry.npmmirror.com/confbox/-/confbox-0.1.7.tgz",
@@ -2580,6 +2721,17 @@
      "version": "1.11.11",
      "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.11.tgz",
      "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg=="
    },
    "node_modules/debounce-fn": {
      "version": "4.0.0",
      "resolved": "https://registry.npmmirror.com/debounce-fn/-/debounce-fn-4.0.0.tgz",
      "integrity": "sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==",
      "dependencies": {
        "mimic-fn": "^3.0.0"
      },
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/debug": {
      "version": "4.3.4",
@@ -2805,6 +2957,20 @@
      },
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/dot-prop": {
      "version": "6.0.1",
      "resolved": "https://registry.npmmirror.com/dot-prop/-/dot-prop-6.0.1.tgz",
      "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==",
      "dependencies": {
        "is-obj": "^2.0.0"
      },
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/dotenv": {
@@ -3047,6 +3213,29 @@
        "node": ">= 10.0.0"
      }
    },
    "node_modules/electron-store": {
      "version": "8.2.0",
      "resolved": "https://registry.npmmirror.com/electron-store/-/electron-store-8.2.0.tgz",
      "integrity": "sha512-ukLL5Bevdil6oieAOXz3CMy+OgaItMiVBg701MNlG6W5RaC0AHN7rvlqTCmeb6O7jP0Qa1KKYTE0xV0xbhF4Hw==",
      "dependencies": {
        "conf": "^10.2.0",
        "type-fest": "^2.17.0"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/electron-store/node_modules/type-fest": {
      "version": "2.19.0",
      "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-2.19.0.tgz",
      "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
      "engines": {
        "node": ">=12.20"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/electron-to-chromium": {
      "version": "1.4.788",
      "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.788.tgz",
@@ -3108,7 +3297,6 @@
      "version": "2.2.1",
      "resolved": "https://registry.npmmirror.com/env-paths/-/env-paths-2.2.1.tgz",
      "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
      "dev": true,
      "engines": {
        "node": ">=6"
      }
@@ -3252,8 +3440,7 @@
    "node_modules/fast-deep-equal": {
      "version": "3.1.3",
      "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
      "dev": true
      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
    },
    "node_modules/fast-glob": {
      "version": "3.3.2",
@@ -3314,6 +3501,17 @@
      },
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/find-up": {
      "version": "3.0.0",
      "resolved": "https://registry.npmmirror.com/find-up/-/find-up-3.0.0.tgz",
      "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
      "dependencies": {
        "locate-path": "^3.0.0"
      },
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/follow-redirects": {
@@ -3913,6 +4111,14 @@
        "node": ">=0.12.0"
      }
    },
    "node_modules/is-obj": {
      "version": "2.0.0",
      "resolved": "https://registry.npmmirror.com/is-obj/-/is-obj-2.0.0.tgz",
      "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/isarray": {
      "version": "1.0.0",
      "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz",
@@ -4030,6 +4236,11 @@
      "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
      "dev": true
    },
    "node_modules/json-schema-typed": {
      "version": "7.0.3",
      "resolved": "https://registry.npmmirror.com/json-schema-typed/-/json-schema-typed-7.0.3.tgz",
      "integrity": "sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A=="
    },
    "node_modules/json-stringify-safe": {
      "version": "5.0.1",
@@ -4202,6 +4413,18 @@
        "url": "https://github.com/sponsors/antfu"
      }
    },
    "node_modules/locate-path": {
      "version": "3.0.0",
      "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-3.0.0.tgz",
      "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
      "dependencies": {
        "p-locate": "^3.0.0",
        "path-exists": "^3.0.0"
      },
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/lodash": {
      "version": "4.17.21",
      "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
@@ -4357,6 +4580,14 @@
        "node": ">= 0.6"
      }
    },
    "node_modules/mimic-fn": {
      "version": "3.1.0",
      "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-3.1.0.tgz",
      "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/mimic-response": {
      "version": "1.0.1",
      "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-1.0.1.tgz",
@@ -4486,6 +4717,16 @@
      "dev": true,
      "optional": true
    },
    "node_modules/node-gyp-build": {
      "version": "4.8.1",
      "resolved": "https://registry.npmmirror.com/node-gyp-build/-/node-gyp-build-4.8.1.tgz",
      "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==",
      "bin": {
        "node-gyp-build": "bin.js",
        "node-gyp-build-optional": "optional.js",
        "node-gyp-build-test": "build-test.js"
      }
    },
    "node_modules/node-releases": {
      "version": "2.0.14",
      "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.14.tgz",
@@ -4564,6 +4805,28 @@
        "wrappy": "1"
      }
    },
    "node_modules/onetime": {
      "version": "5.1.2",
      "resolved": "https://registry.npmmirror.com/onetime/-/onetime-5.1.2.tgz",
      "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
      "dependencies": {
        "mimic-fn": "^2.1.0"
      },
      "engines": {
        "node": ">=6"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/onetime/node_modules/mimic-fn": {
      "version": "2.1.0",
      "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-2.1.0.tgz",
      "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/p-cancelable": {
      "version": "2.1.1",
      "resolved": "https://registry.npmmirror.com/p-cancelable/-/p-cancelable-2.1.1.tgz",
@@ -4573,11 +4836,52 @@
        "node": ">=8"
      }
    },
    "node_modules/p-limit": {
      "version": "2.3.0",
      "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-2.3.0.tgz",
      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
      "dependencies": {
        "p-try": "^2.0.0"
      },
      "engines": {
        "node": ">=6"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/p-locate": {
      "version": "3.0.0",
      "resolved": "https://registry.npmmirror.com/p-locate/-/p-locate-3.0.0.tgz",
      "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
      "dependencies": {
        "p-limit": "^2.0.0"
      },
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/p-try": {
      "version": "2.2.0",
      "resolved": "https://registry.npmmirror.com/p-try/-/p-try-2.2.0.tgz",
      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/pako": {
      "version": "1.0.11",
      "resolved": "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz",
      "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
      "dev": true
    },
    "node_modules/path-exists": {
      "version": "3.0.0",
      "resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-3.0.0.tgz",
      "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/path-is-absolute": {
      "version": "1.0.1",
@@ -4734,6 +5038,17 @@
        "confbox": "^0.1.7",
        "mlly": "^1.7.0",
        "pathe": "^1.1.2"
      }
    },
    "node_modules/pkg-up": {
      "version": "3.1.0",
      "resolved": "https://registry.npmmirror.com/pkg-up/-/pkg-up-3.1.0.tgz",
      "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==",
      "dependencies": {
        "find-up": "^3.0.0"
      },
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/plist": {
@@ -4898,6 +5213,11 @@
      "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
      "dev": true
    },
    "node_modules/postis": {
      "version": "2.2.0",
      "resolved": "https://registry.npmmirror.com/postis/-/postis-2.2.0.tgz",
      "integrity": "sha512-MKoPQqjjNU6aDr9IN3VFMZk+ND2jXjBGVHdU/Kgyffb8mr11ZQSE7QwmpLw+iYRjF8YIDSgdVoaPLugJ0ycHYg=="
    },
    "node_modules/process-nextick-args": {
      "version": "2.0.1",
      "resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -4945,7 +5265,6 @@
      "version": "2.3.1",
      "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz",
      "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
      "dev": true,
      "engines": {
        "node": ">=6"
      }
@@ -5050,6 +5369,14 @@
      "resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz",
      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
      "dev": true,
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/require-from-string": {
      "version": "2.0.2",
      "resolved": "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz",
      "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
      "engines": {
        "node": ">=0.10.0"
      }
@@ -6077,7 +6404,6 @@
      "version": "4.4.1",
      "resolved": "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz",
      "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
      "dev": true,
      "dependencies": {
        "punycode": "^2.1.0"
      }
package.json
@@ -10,6 +10,7 @@
    "electron:dev": "vite && electron"
  },
  "dependencies": {
    "@jitsi/electron-sdk": "^6.0.40",
    "axios": "^1.7.2",
    "dayjs": "^1.11.11",
    "element-plus": "^2.7.3",
src/assets/image/list-card-bg.jpg
src/background.js
@@ -1,5 +1,5 @@
// src-electron/main.js
const { app, BrowserWindow,screen  } = require('electron');
const { app, BrowserWindow, screen, globalShortcut, ipcMain } = require('electron');
const { join } = require('path');
// 屏蔽安全警告
@@ -7,16 +7,18 @@
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true';
// 创建浏览器窗口时,调用这个函数。
const createWindow = () => {
    const {width, height} = screen.getPrimaryDisplay().bounds;
const createWindow = (width, height) => {
    const win = new BrowserWindow({
        width: width,
        height: height,
        minWidth: 1280,
        minHeight: 720,
        webPreferences: {
            preload: join(__dirname, 'preload.js')
        }
    });
    // win.loadURL('http://localhost:3000')
    win.maximize();
    // development模式
    if (process.env.VITE_DEV_SERVER_URL) {
        win.loadURL(process.env.VITE_DEV_SERVER_URL);
@@ -29,12 +31,38 @@
// Electron 会在初始化后并准备
app.whenReady().then(() => {
    createWindow();
    const { width, height } = screen.getPrimaryDisplay().bounds;
    createWindow(width, height);
    app.on('activate', () => {
        if (BrowserWindow.getAllWindows().length === 0) createWindow();
    });
    // 监听打开新窗口
    ipcMain.on('open-new-window', () => {
        const childWin = new BrowserWindow({
            width: width,
            height: height,
            minWidth: width,
            minHeight: height,
            webPreferences: {
                preload: join(__dirname, 'preload.js')
            }
        });
        childWin.maximize();
        // development模式
        if (process.env.VITE_DEV_SERVER_URL) {
            childWin.loadURL(process.env.VITE_DEV_SERVER_URL + '#/meet');
        } else {
            childWin.loadFile(join(__dirname, '../dist/index.html'), {
                hash: '/meet'
            });
        }
    });
});
app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') app.quit();
});
src/preload.js
New file
@@ -0,0 +1,5 @@
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electron', {
  openNewWindow: (arg) => ipcRenderer.send('open-new-window', arg)
});
src/router/index.js
@@ -1,11 +1,11 @@
import { createMemoryHistory, createRouter } from 'vue-router';
import { createWebHashHistory, createRouter } from 'vue-router';
import Layout from '@/layout/index.vue';
const routes = [
  {
    path: '/',
    redirect: '/exam'
    redirect: '/index'
  },
  {
@@ -24,7 +24,16 @@
      },
    ]
  },
  // 在线培训
  {
    path: '/train',
    component: () => import('@/views/train/index.vue'),
  },
  // 会议
  {
    path: '/meet',
    component: () => import('@/views/meet/index.vue'),
  },
  // 考试列表
  {
    path: '/exam-list',
@@ -44,7 +53,7 @@
];
const router = createRouter({
  history: createMemoryHistory(),
  history: createWebHashHistory(),
  routes,
});
src/views/meet/index.vue
New file
@@ -0,0 +1,30 @@
<template>
  <div class="meet-container w-screen h-screen">
    <div id="meet" ref="meet"></div>
  </div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const meet = ref(null);
onMounted(() => {
  const width = window.innerWidth;
  const height = window.innerHeight;
  const domain = 'ycl.easyblog.vip:8443';
  const options = {
    roomName: 'test',
    width: width,
    height: height,
    parentNode: meet.value,
    lang: 'zh_CN',
    configOverwrite: {
      prejoinConfig: {
        enabled: false
      }
    },
  };
  const api = new JitsiMeetExternalAPI(domain, options);
});
</script>
<style lang="scss" scoped></style>
src/views/menu/index.vue
@@ -25,7 +25,7 @@
<script setup>
import { ref } from 'vue';
import {useRouter} from 'vue-router';
import { useRouter } from 'vue-router';
const router = useRouter();
@@ -33,6 +33,11 @@
  {
    name: '课程',
    categroy: [
      {
        title: '在线培训',
        iconPath: new URL('@/assets/icons/icon2.png', import.meta.url).href,
        path: '/train'
      },
      {
        title: '我的课程',
        iconPath: new URL('@/assets/icons/icon1.png', import.meta.url).href,
@@ -58,10 +63,10 @@
]);
const menuClick = (item) => {
  if(item.path) {
  if (item.path) {
    router.push(item.path);
  }
}
};
</script>
<style lang="scss" scoped>
src/views/train/data-list/index.vue
New file
@@ -0,0 +1,78 @@
<template>
  <div class="list-container w-full h-full">
    <el-scrollbar>
      <el-row :gutter="20">
        <el-col :span="6" v-for="item in dataList">
          <el-card shadow="hover" class="list-card cursor-pointer" :body-style="{ padding: 0 }" @click="itemClick(item)">
            <div class="img-container w-full">
              <img src="@/assets/image/list-card-bg.jpg" class="w-full">
            </div>
            <div class="item-info p-3">
              <div class="info-title font-bold">{{ item.title }}</div>
              <div class="info-teacher flex text-sm text-gray-500">
                <div class="info-label">主讲:</div>
                <div class="info-text">{{ item.teacher }}</div>
              </div>
              <div class="info-time flex text-sm text-gray-500">
                <div class="info-label">开始时间:</div>
                <div class="info-text">{{ item.startTime }}</div>
              </div>
              <div class="info-time flex text-sm text-gray-500">
                <div class="info-label">结束时间:</div>
                <div class="info-text">{{ item.endTime }}</div>
              </div>
            </div>
          </el-card>
        </el-col>
      </el-row>
    </el-scrollbar>
  </div>
</template>
<script setup>
import { ref } from 'vue';
import { Timer } from '@element-plus/icons-vue';
import { useRouter } from 'vue-router';
const router = useRouter();
const dataList = ref([
  {
    title: '测试1',
    startTime: '2024-6-13 8:00',
    endTime: '2024-6-13 8:00',
    teacher: '测试测试',
    roomName: 'test'
  }
])
const itemClick = (item) => {
  if(window.electron) {
    window.electron.openNewWindow();
  }
}
</script>
<style lang="scss" scoped>
.item {
  width: 100%;
  min-height: 120px;
}
.bottom-item {
  margin-right: 30px;
}
.img-container {
  object-fit: cover;
  object-position: center;
  width: 100%;
  max-height: 160px;
  overflow: hidden;
}
.list-card {
  border-radius: 10px;
}
</style>
src/views/train/index.vue
New file
@@ -0,0 +1,61 @@
<template>
  <div class="train-container w-screen h-screen bg-slate-50 flex flex-col items-center">
    <NormalHeader class="shrink-0"></NormalHeader>
    <div class="list-container container grow relative">
      <div class="list-content absolute top-0 bottom-0 left-0 right-0 py-4">
        <div class="list-wrapper w-full h-full">
          <el-card class="h-full" :body-style="{ height: '100%' }">
            <div class="card-wrapper w-full h-full flex flex-col px-8 box-border">
              <div class="card-header flex justify-between items-center shrink-0">
                <div class="header-tab">
                  <el-tabs v-model="activeName" @tab-click="handleClick">
                    <el-tab-pane label="全部" name="1"></el-tab-pane>
                    <el-tab-pane label="未开始" name="2"></el-tab-pane>
                    <el-tab-pane label="进行中" name="3"></el-tab-pane>
                    <el-tab-pane label="已结束" name="4"></el-tab-pane>
                  </el-tabs>
                </div>
                <div class="header-search flex items-center">
                  <el-input v-model="searchText" placeholder="请输入考试名称" :prefix-icon="Search" />
                  <el-button type="primary" class="ml-4">搜索</el-button>
                </div>
              </div>
              <div class="card-main flex-1 my-5 relative">
                <div class="main-content absolute top-0 bottom-0 left-0 right-0">
                  <DataList></DataList>
                  <div id="meet" ref="meet"></div>
                </div>
              </div>
              <div class="card-footer flex justify-center mb-7 shrink-0">
                <el-pagination background layout="prev, pager, next" :total="1000" />
              </div>
            </div>
          </el-card>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup>
import { ref } from 'vue';
import NormalHeader from '@/components/NormalHeader/index.vue';
import DataList from './data-list/index.vue';
import { Search } from '@element-plus/icons-vue';
const activeName = ref('1');
const searchText = ref('');
const handleClick = (tab, event) => {
};
</script>
<style lang="scss" scoped>
:deep(.el-tabs__nav-wrap:after) {
  display: none;
}
</style>