diff --git a/exam-vue/src/components/PanThumb/index.vue b/exam-vue/src/components/PanThumb/index.vue
new file mode 100644
index 0000000..a970af0
--- /dev/null
+++ b/exam-vue/src/components/PanThumb/index.vue
@@ -0,0 +1,95 @@
+
+
+
+
+
![avatar]()
+
+
+
+
+
+
diff --git a/exam-vue/vite.config.mjs b/exam-vue/vite.config.mjs
new file mode 100644
index 0000000..93c5398
--- /dev/null
+++ b/exam-vue/vite.config.mjs
@@ -0,0 +1,69 @@
+import { defineConfig, loadEnv } from 'vite'
+import vue from '@vitejs/plugin-vue'
+import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
+import path from 'path'
+import { fileURLToPath } from 'url'
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url))
+const resolve = (dir) => path.resolve(__dirname, dir)
+
+export default defineConfig(({ mode }) => {
+ const env = loadEnv(mode, process.cwd())
+
+ return {
+ plugins: [
+ vue(),
+ createSvgIconsPlugin({
+ iconDirs: [resolve('src/icons/svg')],
+ symbolId: 'icon-[name]'
+ })
+ ],
+ resolve: {
+ alias: {
+ '@': resolve('src')
+ }
+ },
+ define: {
+ 'process.env': {}
+ },
+ server: {
+ port: 9527,
+ open: true
+ },
+ build: {
+ outDir: '../exam-api/src/main/resources/static',
+ emptyOutDir: false,
+ assetsDir: 'static',
+ sourcemap: false,
+ chunkSizeWarningLimit: 1000,
+ rollupOptions: {
+ onwarn(warning, warn) {
+ // 忽略第三方库中的 /*#__PURE__*/ 注释警告
+ if (warning.code === 'INVALID_ANNOTATION') return
+ warn(warning)
+ },
+ output: {
+ chunkFileNames: 'static/js/[name]-[hash].js',
+ entryFileNames: 'static/js/[name]-[hash].js',
+ assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
+ manualChunks(id) {
+ if (id.includes('node_modules')) {
+ if (id.includes('element-plus')) {
+ return 'chunk-elementPlus'
+ }
+ return 'chunk-libs'
+ }
+ }
+ }
+ }
+ },
+ css: {
+ preprocessorOptions: {
+ scss: {
+ api: 'modern',
+ silenceDeprecations: ['import']
+ }
+ }
+ }
+ }
+})