CrazyIter_Bin 5 months ago
parent
commit
cb5846bf89
27 changed files with 388 additions and 206 deletions
  1. 2 2
      TEAMModelOS.Extension/HTEX.DataETL/HTEX.DataETL.csproj
  2. 11 0
      TEAMModelOS.Extension/IES.Exam/IES.ExamClient/CHANGELOG.md
  3. 3 0
      TEAMModelOS.Extension/IES.Exam/IES.ExamClient/IES.ExamClient.esproj
  4. 61 0
      TEAMModelOS.Extension/IES.Exam/IES.ExamClient/app.js
  5. 7 0
      TEAMModelOS.Extension/IES.Exam/IES.ExamClient/eslint.config.js
  6. 17 0
      TEAMModelOS.Extension/IES.Exam/IES.ExamClient/package.json
  7. 0 2
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/.browserslistrc
  8. 2 0
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/.gitignore
  9. 1 1
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/README.md
  10. 19 0
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/jsconfig.json
  11. 32 11
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/package.json
  12. 0 5
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/postcss.config.js
  13. 3 3
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/public/index.html
  14. 21 10
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/src/App.vue
  15. BIN
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/src/assets/logo.png
  16. 58 0
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/src/components/HelloWorld.vue
  17. 8 0
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/src/main.js
  18. 0 5
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/src/views/About.vue
  19. 0 55
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/src/views/Home.vue
  20. 0 39
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/tsconfig.json
  21. 0 19
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/tslint.json
  22. 77 6
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/vue.config.js
  23. 18 17
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/IES.ExamServer.csproj
  24. 10 1
      TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Program.cs
  25. 9 0
      TEAMModelOS.sln
  26. 1 2
      TEAMModelOS/Controllers/Student/StudentCommonController.cs
  27. 28 28
      TEAMModelOS/appsettings.Development.json

+ 2 - 2
TEAMModelOS.Extension/HTEX.DataETL/HTEX.DataETL.csproj

@@ -7,11 +7,11 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <ProjectReference Include="..\TEAMModelOS.Extension\HTEX.Lib\HTEX.Lib.csproj" />
+    <ProjectReference Include="..\HTEX.Lib\HTEX.Lib.csproj" />
     <ProjectReference Include="..\TEAMModelOS.SDK\TEAMModelOS.SDK.csproj" />
   </ItemGroup>
 	<ItemGroup>
-		<Content Include="..\TEAMModelOS.Extension\HTEX.Lib\summary.xml">
+		<Content Include="..\HTEX.Lib\summary.xml">
 			<Link>summary.xml</Link>
 		</Content>
 	</ItemGroup>

+ 11 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamClient/CHANGELOG.md

@@ -0,0 +1,11 @@
+This file explains how Visual Studio created the project.
+
+The following steps were used to generate this project:
+- Create project file (`IES.ExamClient.esproj`).
+- Create `launch.json` to enable debugging.
+- Install npm packages: `npm init && npm i --save-dev eslint`.
+- Create `app.js`.
+- Update `package.json` entry point.
+- Create `eslint.config.js` to enable linting.
+- Add project to solution.
+- Write this file.

+ 3 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamClient/IES.ExamClient.esproj

@@ -0,0 +1,3 @@
+<Project Sdk="Microsoft.VisualStudio.JavaScript.Sdk/1.0.1738743">
+
+</Project>

+ 61 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamClient/app.js

@@ -0,0 +1,61 @@
+const { app, BrowserWindow, Menu } = require('electron/main');
+const { spawn } = require('child_process');
+const net = require('net');
+
+let dotnetProcess;
+const startDotnet = () => {
+    return new Promise((resolve, reject) => {
+        dotnetProcess = spawn('dotnet', ['run', '--project', '../IES.ExamServer/IES.ExamServer.csproj']);
+        dotnetProcess.stdout.on('data', (data) => {
+            console.log(`stdout: ${data}`);
+            // 假设dotnet服务启动后会输出包含"Now listening on"的日志
+            if (data.toString().includes('Now listening on')) {
+                resolve();
+            }
+        });
+
+        dotnetProcess.stderr.on('data', (data) => {
+            console.log(`stderr: ${data}`);
+            reject(new Error(`Dotnet process error: ${data}`));
+        });
+
+        dotnetProcess.on('close', (code) => {
+            console.log(`child process exited with code ${code}`);
+            if (code !== 0) {
+                reject(new Error(`Dotnet process exited with code ${code}`));
+            }
+        });
+    });
+};
+
+const createWindow = async () => {
+    try {
+        await startDotnet();
+        const win = new BrowserWindow({
+            width: 800,
+            height: 600
+        });
+        win.maximize();
+        win.loadURL('https://localhost:5001/api/WeatherForecast');
+    } catch (error) {
+        console.error('Error starting dotnet or loading window:', error);
+    }
+};
+
+// Menu.setApplicationMenu(null);
+
+app.whenReady().then(() => {
+    createWindow();
+
+    app.on('activate', () => {
+        if (BrowserWindow.getAllWindows().length === 0) {
+            createWindow();
+        }
+    });
+});
+
+app.on('window-all-closed', () => {
+    if (process.platform !== 'darwin') {
+        app.quit();
+    }
+});

+ 7 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamClient/eslint.config.js

@@ -0,0 +1,7 @@
+module.exports = [
+    {
+        rules: {
+            // Add rules here.
+        }
+    }
+];

+ 17 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamClient/package.json

@@ -0,0 +1,17 @@
+{
+  "name": "ies.examclient",
+  "version": "1.0.0",
+  "description": "",
+  "main": "app.js",
+  "scripts": {
+    "start": "electron .",
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "keywords": [],
+  "author": "",
+  "license": "ISC",
+  "devDependencies": {
+    "electron": "^33.2.1",
+    "eslint": "^9.17.0"
+  }
+}

+ 0 - 2
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/.browserslistrc

@@ -1,2 +0,0 @@
-> 1%
-last 2 versions

+ 2 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/.gitignore

@@ -2,6 +2,7 @@
 node_modules
 /dist
 
+
 # local env files
 .env.local
 .env.*.local
@@ -10,6 +11,7 @@ node_modules
 npm-debug.log*
 yarn-debug.log*
 yarn-error.log*
+pnpm-debug.log*
 
 # Editor directories and files
 .idea

+ 1 - 1
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/README.md

@@ -1,4 +1,4 @@
-# clientapp
+# app
 
 ## Project setup
 ```

+ 19 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/jsconfig.json

@@ -0,0 +1,19 @@
+{
+  "compilerOptions": {
+    "target": "es5",
+    "module": "esnext",
+    "baseUrl": "./",
+    "moduleResolution": "node",
+    "paths": {
+      "@/*": [
+        "src/*"
+      ]
+    },
+    "lib": [
+      "esnext",
+      "dom",
+      "dom.iterable",
+      "scripthost"
+    ]
+  }
+}

+ 32 - 11
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/package.json

@@ -1,22 +1,43 @@
 {
-  "name": "ies.examwebview",
+  "name": "app",
   "version": "0.1.0",
   "private": true,
   "scripts": {
     "serve": "vue-cli-service serve",
-    "build": "set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service build",
-    "fix-memory-limit": "cross-env LIMIT=4096 increase-memory-limit",
+    "build": "vue-cli-service build",
     "lint": "vue-cli-service lint"
   },
   "dependencies": {
-    "axios": "^0.21.4",
-    "core-js": "^3.1.2",
-    "vue": "^2.6.10",
-    "vue-router": "^3.0.6"
+    "core-js": "^3.8.3",
+    "vue": "^2.6.14"
   },
   "devDependencies": {
-    "@vue/cli-plugin-babel": "^4.0.0",
-    "@vue/cli-service": "^4.5.13",
-    "vue-template-compiler": "^2.6.10"
-  }
+    "@babel/core": "^7.12.16",
+    "@babel/eslint-parser": "^7.12.16",
+    "@vue/cli-plugin-babel": "~5.0.0",
+    "@vue/cli-plugin-eslint": "~5.0.0",
+    "@vue/cli-service": "~5.0.0",
+    "eslint": "^7.32.0",
+    "eslint-plugin-vue": "^8.0.3",
+    "vue-template-compiler": "^2.6.14"
+  },
+  "eslintConfig": {
+    "root": true,
+    "env": {
+      "node": true
+    },
+    "extends": [
+      "plugin:vue/essential",
+      "eslint:recommended"
+    ],
+    "parserOptions": {
+      "parser": "@babel/eslint-parser"
+    },
+    "rules": {}
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not dead"
+  ]
 }

+ 0 - 5
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/postcss.config.js

@@ -1,5 +0,0 @@
-module.exports = {
-  plugins: {
-    autoprefixer: {}
-  }
-}

+ 3 - 3
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/public/index.html

@@ -1,15 +1,15 @@
 <!DOCTYPE html>
-<html lang="en">
+<html lang="">
   <head>
     <meta charset="utf-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width,initial-scale=1.0">
     <link rel="icon" href="<%= BASE_URL %>favicon.ico">
-    <title>clientapp</title>
+    <title><%= htmlWebpackPlugin.options.title %></title>
   </head>
   <body>
     <noscript>
-      <strong>We're sorry but clientapp doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
     </noscript>
     <div id="app"></div>
     <!-- built files will be auto injected -->

+ 21 - 10
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/src/App.vue

@@ -1,17 +1,28 @@
 <template>
   <div id="app">
-    <div id="nav">
-      <router-link to="/">Home</router-link> |
-      <router-link to="/about">About</router-link>
-    </div>
-    <router-view/>
+    <img alt="Vue logo" src="./assets/logo.png">
+    <HelloWorld msg="Welcome to Your Vue.js App"/>
   </div>
 </template>
 
-<script lang="ts">
-import { Component, Vue} from 'vue-property-decorator';
-@Component
-export default class App extends Vue {
+<script>
+import HelloWorld from './components/HelloWorld.vue'
 
+export default {
+  name: 'App',
+  components: {
+    HelloWorld
+  }
 }
-</script>
+</script>
+
+<style>
+#app {
+  font-family: Avenir, Helvetica, Arial, sans-serif;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  text-align: center;
+  color: #2c3e50;
+  margin-top: 60px;
+}
+</style>

BIN
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/src/assets/logo.png


+ 58 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/src/components/HelloWorld.vue

@@ -0,0 +1,58 @@
+<template>
+  <div class="hello">
+    <h1>{{ msg }}</h1>
+    <p>
+      For a guide and recipes on how to configure / customize this project,<br>
+      check out the
+      <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
+    </p>
+    <h3>Installed CLI Plugins</h3>
+    <ul>
+      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
+      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
+    </ul>
+    <h3>Essential Links</h3>
+    <ul>
+      <li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
+      <li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
+      <li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
+      <li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
+      <li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
+    </ul>
+    <h3>Ecosystem</h3>
+    <ul>
+      <li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
+      <li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
+      <li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
+      <li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
+      <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
+    </ul>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'HelloWorld',
+  props: {
+    msg: String
+  }
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+h3 {
+  margin: 40px 0 0;
+}
+ul {
+  list-style-type: none;
+  padding: 0;
+}
+li {
+  display: inline-block;
+  margin: 0 10px;
+}
+a {
+  color: #42b983;
+}
+</style>

+ 8 - 0
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/src/main.js

@@ -0,0 +1,8 @@
+import Vue from 'vue'
+import App from './App.vue'
+
+Vue.config.productionTip = false
+
+new Vue({
+  render: h => h(App),
+}).$mount('#app')

+ 0 - 5
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/src/views/About.vue

@@ -1,5 +0,0 @@
-<template>
-  <div class="about">
-    <h1>This is an about page</h1>
-  </div>
-</template>

+ 0 - 55
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/src/views/Home.vue

@@ -1,55 +0,0 @@
-<template>
-  <div class="home">
-    <img alt="Vue logo" src="../assets/logo.png">
-    <h1>Welcome to Your Vue.js App</h1>
-     <table>
-      <thead>
-        <tr>
-          <th v-for="(item, index) in forecastCols" v-bind:key="index"> 
-            {{ item.label | capitalize }}
-          </th>
-        </tr>
-      </thead>
-      <tbody>
-        <tr v-for="(item, index) in forecasts" v-bind:key="index">
-          <td v-for="(col, index) in forecastCols" v-bind:key="index">
-            {{ col.field(item) }}
-          </td>
-        </tr>
-      </tbody>
-    </table>
-  </div>
-</template>
-
-<script lang="ts">
-import { Component, Vue} from 'vue-property-decorator';
-import { IWeatherForecast } from '../models/IWeatherForecast';
-import axios from 'axios';
-
-@Component({
-  filters: {
-    capitalize: (value: string) => {
-      if (!value) { return ''; }
-      value = value.toString();
-      return value.charAt(0).toUpperCase() + value.slice(1);
-    },
-  },
-})
-export default class Home extends Vue {
-  private forecasts: IWeatherForecast[] = [{ summary: 'No data.' } as IWeatherForecast];
-  private forecastCols: any[] = [
-    { name: 'Summary', label: 'Summary', field: (row: IWeatherForecast) => row.summary },
-    { name: 'F',       label: 'F',       field: (row: IWeatherForecast) => row.temperatureF },
-    { name: 'C',       label: 'C',       field: (row: IWeatherForecast) => row.temperatureC },
-    { name: 'Date',     label: 'Date',   field: (row: IWeatherForecast) => row.date },
-  ];
-
-  public async mounted() {
-    try {
-      this.forecasts = (await axios.get('api/weatherforecast')).data;
-    } catch {
-      this.forecasts = [{ summary: 'No data.' } as IWeatherForecast];
-    }
-  }
-}
-</script>

+ 0 - 39
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/tsconfig.json

@@ -1,39 +0,0 @@
-{
-  "compilerOptions": {
-    "target": "esnext",
-    "module": "esnext",
-    "strict": true,
-    "jsx": "preserve",
-    "importHelpers": true,
-    "moduleResolution": "node",
-    "experimentalDecorators": true,
-    "esModuleInterop": true,
-    "allowSyntheticDefaultImports": true,
-    "sourceMap": true,
-    "baseUrl": ".",
-    "types": [
-      "webpack-env"
-    ],
-    "paths": {
-      "@/*": [
-        "src/*"
-      ]
-    },
-    "lib": [
-      "esnext",
-      "dom",
-      "dom.iterable",
-      "scripthost"
-    ]
-  },
-  "include": [
-    "src/**/*.ts",
-    "src/**/*.tsx",
-    "src/**/*.vue",
-    "tests/**/*.ts",
-    "tests/**/*.tsx"
-  ],
-  "exclude": [
-    "node_modules"
-  ]
-}

+ 0 - 19
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/tslint.json

@@ -1,19 +0,0 @@
-{
-  "defaultSeverity": "warning",
-  "extends": [
-    "tslint:recommended"
-  ],
-  "linterOptions": {
-    "exclude": [
-      "node_modules/**"
-    ]
-  },
-  "rules": {
-    "indent": [true, "spaces", 2],
-    "interface-name": false,
-    "no-consecutive-blank-lines": false,
-    "object-literal-sort-keys": false,
-    "ordered-imports": false,
-    "quotemark": [true, "single"]
-  }
-}

+ 77 - 6
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/ClientApp/vue.config.js

@@ -1,6 +1,77 @@
-// vue.config.js
-module.exports = {
-    devServer: {
-      progress: false
-    }
-  }
+const path = require('path')
+const { CleanWebpackPlugin } = require('clean-webpack-plugin')
+const { defineConfig } = require('@vue/cli-service')
+const Timestamp = new Date().getTime();
+function resolve(dir) {
+	return path.join(__dirname, './', dir)
+}
+
+module.exports = defineConfig({
+	transpileDependencies: true,
+	outputDir: '../wwwroot',
+	lintOnSave: false,
+	//transpileDependencies: ['@azure'],
+	productionSourceMap: false, // 设置上线后是否加载webpack文件
+	devServer: {
+		progress: false
+	},
+	pages: {
+		app: {
+			entry: 'src/main.js',
+			template: 'public/index.html',
+			filename: 'index.html',
+			// chunks: ['chunk-vendors','chunk-common','app','chunk-viewDesign','chunk-static','chunk-konva','chunk-azure','chunk-xlsx','chunk-video','chunk-pdfjs','chunk-wangeditor','chunk-h2c','chunk-corejs']
+		}
+	},
+	chainWebpack(config) {
+		// 移除prefetch插件,避免加载多余的资源
+		config.plugins.delete('prefetch')
+		// 移除 preload 插件,避免加载多余的资源
+		config.plugins.delete('preload');
+		config.module
+			.rule('svg')
+			.exclude
+			.add(resolve('src/icons/svg'))
+			.add(resolve('src/assets/student-web/icons'))
+			.end()
+		config.module
+			.rule('icons')
+			.test(/\.svg$/)
+			.include
+			.add(resolve('src/icons/svg'))
+			.add(resolve('src/assets/student-web/icons'))
+			.end()
+			.use('svg-sprite-loader')
+			.loader('svg-sprite-loader')
+			.options({
+				symbolId: 'icon-[name]'
+			})
+			.end()
+	},
+	pluginOptions: {
+		'style-resources-loader': {
+			preProcessor: 'less',
+			patterns: [
+				// 这个是加上自己的路径,不能使用(如下:alias)中配置的别名路径
+				path.resolve(__dirname, './src/css/less-variable.less')
+			]
+		}
+	},
+	configureWebpack: {
+		plugins: [
+			new CleanWebpackPlugin()
+		]
+	},
+	configureWebpack: config => {
+		config.optimization.minimizer[0].options.terserOptions.compress.drop_console = process.env.NODE_ENV === 'production'
+		config.output.filename = `js/[name].${Timestamp}.js`
+		config.output.chunkFilename = `js/[name].${Timestamp}.js`
+		config.externals = {
+			'vue': 'Vue',
+			'vue-router': 'VueRouter',
+			'view-design': 'iview'
+		}
+		
+	},
+
+})

+ 18 - 17
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/IES.ExamServer.csproj

@@ -10,14 +10,10 @@
 		<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
 	</PropertyGroup>
 
-	<ItemGroup>
-		<!-- Don't publish the SPA source files, but do show them in the project files list -->
-		<Content Remove="$(SpaRoot)**" />
-		<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
-	</ItemGroup>
+
 
 	<ItemGroup>
-		<Folder Include="ClientApp\src\models\" />
+	 
 		<Folder Include="wwwroot\" />
 	</ItemGroup>
 
@@ -25,19 +21,24 @@
 	  <PackageReference Include="VueCliMiddleware" Version="6.0.0" />
 	</ItemGroup>
 	<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build">
-	<!-- Build Target:  Ensure Node.js is installed -->
-	<Exec Command="node --version" ContinueOnError="true">
-		<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
-	</Exec>
-	<Exec Command="npm --version" ContinueOnError="true">
-		<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
-	</Exec>
-	<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js and npm are required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
+		<!-- Build Target:  Ensure Node.js is installed -->
+		<Exec Command="node --version" ContinueOnError="true">
+			<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
+		</Exec>
+		<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
 	</Target>
 
-	<Target Name="EnsureNodeModulesInstalled" BeforeTargets="Build" Inputs="package.json" Outputs="packages-lock.json" Condition="!Exists('$(SpaRoot)node_modules')">
+	<Target Name="DebugEnsureNpm" AfterTargets="DebugEnsureNodeEnv">
+		<!-- Build Target:  Ensure Node.js is installed -->
+		<Exec Command="npm --version" ContinueOnError="true">
+			<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
+		</Exec>
+	</Target>
+
+	<Target Name="EnsureNodeModulesInstalled" BeforeTargets="Build" Inputs="package.json" Outputs="packages-lock.json">
 		<!-- Build Target: Restore NPM packages using npm -->
 		<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
+
 		<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
 	</Target>
 
@@ -48,12 +49,12 @@
 
 		<!-- Include the newly-built files in the publish output -->
 		<ItemGroup>
-			<DistFiles Include="$(SpaRoot)dist\**" />
+			<DistFiles Include="$wwwroot\**" />
 			<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
 				<RelativePath>%(DistFiles.Identity)</RelativePath>
 				<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
-				<ExcludeFromSingleFile>True</ExcludeFromSingleFile>
 			</ResolvedFileToPublish>
 		</ItemGroup>
 	</Target>
+
 </Project>

+ 10 - 1
TEAMModelOS.Extension/IES.Exam/IES.ExamServer/Program.cs

@@ -43,13 +43,22 @@ namespace IES.ExamServer
                 // You could wrap this proxy in either
                 // if (System.Diagnostics.Debugger.IsAttached)
                 // or a preprocessor such as #if DEBUG
+
+                /*
+                 npm install -g @vue
+                 vue create app
+                 */
+#if DEBUG
                 endpoints.MapToVueCliProxy(
                     "{*path}",
                     new SpaOptions { SourcePath = "ClientApp" },
                     npmScript: (System.Diagnostics.Debugger.IsAttached) ? "serve" : null,
-                    regex: "Compiled successfully",
+                    // regex: "Compiled successfully",
                     forceKill: true
                     );
+#else
+                endpoints.MapFallbackToFile("index.html");
+#endif
             });
             app.Run();
         }

+ 9 - 0
TEAMModelOS.sln

@@ -37,6 +37,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IES.HybridCloud", "TEAMMode
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IES.ExamServer", "TEAMModelOS.Extension\IES.Exam\IES.ExamServer\IES.ExamServer.csproj", "{A8C336A0-8272-41C0-9D01-88D6BC652B76}"
 EndProject
+Project("{54A90642-561A-4BB1-A94E-469ADEE60C69}") = "IES.ExamClient", "TEAMModelOS.Extension\IES.Exam\IES.ExamClient\IES.ExamClient.esproj", "{7CBA0472-933D-49A7-8B59-CD35715DE393}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -109,6 +111,12 @@ Global
 		{A8C336A0-8272-41C0-9D01-88D6BC652B76}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{A8C336A0-8272-41C0-9D01-88D6BC652B76}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{A8C336A0-8272-41C0-9D01-88D6BC652B76}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7CBA0472-933D-49A7-8B59-CD35715DE393}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7CBA0472-933D-49A7-8B59-CD35715DE393}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7CBA0472-933D-49A7-8B59-CD35715DE393}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+		{7CBA0472-933D-49A7-8B59-CD35715DE393}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7CBA0472-933D-49A7-8B59-CD35715DE393}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7CBA0472-933D-49A7-8B59-CD35715DE393}.Release|Any CPU.Deploy.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -126,6 +134,7 @@ Global
 		{5A3E1C89-D2BA-4758-A017-189811E0935F} = {9B74B53F-20E8-46CC-903B-62AEB1583DD7}
 		{0FC9DE8A-488B-4ACD-88D5-8DEDECA1FF42} = {9B74B53F-20E8-46CC-903B-62AEB1583DD7}
 		{A8C336A0-8272-41C0-9D01-88D6BC652B76} = {9B74B53F-20E8-46CC-903B-62AEB1583DD7}
+		{7CBA0472-933D-49A7-8B59-CD35715DE393} = {9B74B53F-20E8-46CC-903B-62AEB1583DD7}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {76440725-5E50-4288-851F-BA5C0BC8E8C6}

+ 1 - 2
TEAMModelOS/Controllers/Student/StudentCommonController.cs

@@ -61,10 +61,9 @@ namespace TEAMModelOS.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("student-activity")]
-#if !DEBUG
         [Authorize(Roles = "IES")]
         [AuthToken(Roles = "teacher,admin,student")]
-#endif
+ 
         public async Task<IActionResult> StudentActivity(JsonElement request)
         {
             var (id, name, pic, school) = HttpContext.GetAuthTokenInfo();

File diff suppressed because it is too large
+ 28 - 28
TEAMModelOS/appsettings.Development.json