-
10.env.development
-
15.env.production
-
24.gitignore
-
3.vscode/extensions.json
-
9README.md
-
43build/utils.js
-
44build/vite/build.js
-
26build/vite/plugin/autoImport.js
-
21build/vite/plugin/autocomponents.js
-
34build/vite/plugin/compress.js
-
37build/vite/plugin/index.js
-
19build/vite/plugin/mock.js
-
43build/vite/proxy.js
-
13index.html
-
2297package-lock.json
-
23package.json
-
BINpublic/bg.png
-
BINpublic/bg2.png
-
BINpublic/pan.png
-
BINpublic/tanchuang.png
-
1public/vite.svg
-
BINpublic/wheel-base.png
-
BINpublic/wheel-base2.png
-
9src/App.vue
-
BINsrc/assets/img/j.png
-
BINsrc/assets/img/jiantou.png
-
1src/assets/vue.svg
-
16src/main.js
-
29src/router/index.js
-
87src/style.css
-
229src/views/animation/anima.vue
-
44src/views/homepage.vue
-
132src/views/hxl_DZP/dzp1.vue
-
29vite.config.js
@ -0,0 +1,10 @@ |
|||
# must start with VITE_ |
|||
VITE_ENV = 'development' |
|||
VITE_OUTPUT_DIR = 'dev' |
|||
# public path |
|||
VITE_PUBLIC_PATH = / |
|||
|
|||
|
|||
# Whether to open mock |
|||
VITE_USE_MOCK = true |
|||
|
@ -0,0 +1,15 @@ |
|||
# must start with VITE_ |
|||
VITE_ENV = 'production' |
|||
VITE_OUTPUT_DIR = 'dist' |
|||
# public path |
|||
VITE_PUBLIC_PATH = /dazhuanpan |
|||
|
|||
# Whether to open mock |
|||
VITE_USE_MOCK = true |
|||
# Whether to enable gzip or brotli compression |
|||
# Optional: gzip | brotli | none |
|||
# If you need multiple forms, you can use `,` to separate |
|||
VITE_BUILD_COMPRESS = 'none' |
|||
|
|||
# Whether to delete origin files when using compress, default false |
|||
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false |
@ -0,0 +1,24 @@ |
|||
# Logs |
|||
logs |
|||
*.log |
|||
npm-debug.log* |
|||
yarn-debug.log* |
|||
yarn-error.log* |
|||
pnpm-debug.log* |
|||
lerna-debug.log* |
|||
|
|||
node_modules |
|||
dist |
|||
dist-ssr |
|||
*.local |
|||
|
|||
# Editor directories and files |
|||
.vscode/* |
|||
!.vscode/extensions.json |
|||
.idea |
|||
.DS_Store |
|||
*.suo |
|||
*.ntvs* |
|||
*.njsproj |
|||
*.sln |
|||
*.sw? |
@ -0,0 +1,3 @@ |
|||
{ |
|||
"recommendations": ["Vue.volar"] |
|||
} |
@ -0,0 +1,9 @@ |
|||
# Vue 3 + Vite |
|||
|
|||
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more. |
|||
|
|||
Learn more about IDE Support for Vue in the [Vue Docs Scaling up Guide](https://vuejs.org/guide/scaling-up/tooling.html#ide-support). |
|||
npm install vue-router 下载路由 |
|||
npm install @lucky-canvas/vue@latest 下载转盘插件 |
|||
npm install element-plus --save 下载element-plus |
|||
npm install @element-plus/icons-vue 下载element-plus图标 |
@ -0,0 +1,43 @@ |
|||
import fs from 'fs' |
|||
import path from 'path' |
|||
|
|||
// 移除未使用的导入
|
|||
/** |
|||
* 是否是 dev 环境 |
|||
* @export |
|||
* @param {string} mode |
|||
* @return {boolean} |
|||
*/ |
|||
export function isDevFn(mode) { |
|||
return mode === 'development'; |
|||
} |
|||
|
|||
/** |
|||
* 是否是 prod 环境 |
|||
* @export |
|||
* @param {string} mode |
|||
* @return {boolean} |
|||
*/ |
|||
export function isProdFn(mode) { |
|||
return mode === 'production'; |
|||
} |
|||
|
|||
/** |
|||
* Read all environment variable configuration files to process.env |
|||
*/ |
|||
export function wrapperEnv(envConf) { |
|||
const ret = {}; |
|||
|
|||
for (const envName of Object.keys(envConf)) { |
|||
let realName = envConf[envName].replace(/\\n/g, '\n'); |
|||
realName = realName === 'true' ? true : realName === 'false' ? false : realName; |
|||
|
|||
ret[envName] = realName; |
|||
if (typeof realName === 'string') { |
|||
process.env[envName] = realName; |
|||
} else if (typeof realName === 'object') { |
|||
process.env[envName] = JSON.stringify(realName); |
|||
} |
|||
} |
|||
return ret; |
|||
} |
@ -0,0 +1,44 @@ |
|||
export function createBuild(viteEnv) { |
|||
const { VITE_OUTPUT_DIR } = viteEnv; |
|||
return { |
|||
sourcemap: false, // 是否启用
|
|||
outDir: VITE_OUTPUT_DIR, |
|||
cssCodeSplit: true, // 禁用 CSS 代码拆分,将整个项目中的所有 CSS 将被提取到一个 CSS 文件中
|
|||
brotliSize: false, // 关闭打包计算
|
|||
target: 'esnext', |
|||
minify: 'terser', // 混淆器, terser 构建后文件体积更小, esbuild
|
|||
// 小于此阈值的导入或引用资源将内联为 base64 编码,以避免额外的 http 请求。设置为 0 可以完全禁用此项
|
|||
assetsInlineLimit: 4096, |
|||
chunkSizeWarningLimit: 2000, // chunk 大小警告的限制(以 kbs 为单位)
|
|||
assetsDir: 'static', // 静态资源目录
|
|||
// rollup 打包配置
|
|||
rollupOptions: { |
|||
output: { |
|||
chunkFileNames: 'static/js/[name]-[hash].js', |
|||
entryFileNames: 'static/js/[name]-[hash].js', |
|||
assetFileNames: (chunkInfo) => { |
|||
if (chunkInfo.name) { |
|||
const info = chunkInfo.name.split('.'); |
|||
let extType = info[info.length - 1]; |
|||
if (/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/i.test(chunkInfo.name)) { |
|||
extType = 'media'; |
|||
} else if (/\.(png|jpe?g|gif|svg)(\?.*)?$/.test(chunkInfo.name)) { |
|||
extType = 'images'; |
|||
} else if (/\.(woff2?|eot|ttf|otf)(\?.*)?$/i.test(chunkInfo.name)) { |
|||
extType = 'fonts'; |
|||
} |
|||
return `static/${extType}/[name]-[hash][extname]`; |
|||
} |
|||
return 'static/[ext]/[name]-[hash].[ext]'; |
|||
} |
|||
} |
|||
}, |
|||
// 压缩配置
|
|||
terserOptions: { |
|||
compress: { |
|||
drop_console: false, // 生产环境移除console
|
|||
drop_debugger: true // 生产环境移除debugger
|
|||
} |
|||
} |
|||
}; |
|||
} |
@ -0,0 +1,26 @@ |
|||
/** |
|||
* Introduces component library styles on demand. |
|||
* https://github.com/antfu/unplugin-auto-import
|
|||
*/ |
|||
import AutoImport from 'unplugin-auto-import/vite' |
|||
|
|||
export function configAutoImportPlugin() { |
|||
return AutoImport({ |
|||
include: [ |
|||
/\.[tj]sx?$/, // .ts, .tsx, .js, .jsx
|
|||
/\.vue$/, |
|||
/\.vue\?vue/, // .vue
|
|||
/\.md$/ // .md
|
|||
], |
|||
imports: ['vue', 'vue-router', '@vueuse/core'], |
|||
// 可以选择auto-import.d.ts生成的位置,使用ts建议设置为'src/auto-import.d.ts'
|
|||
dts: 'src/auto-import.d.ts', |
|||
// eslint globals Docs - https://eslint.org/docs/user-guide/configuring/language-options#specifying-globals
|
|||
// 生成全局声明文件,给eslint用
|
|||
eslintrc: { |
|||
enabled: true, // Default `false`
|
|||
filepath: './.eslintrc-auto-import.json', // Default `./.eslintrc-auto-import.json`
|
|||
globalsPropValue: true // Default `true`, (true | false | 'readonly' | 'readable' | 'writable' | 'writeable')
|
|||
} |
|||
}) |
|||
} |
@ -0,0 +1,21 @@ |
|||
/** |
|||
* Introduces component library styles on demand. |
|||
* https://github.com/antfu/unplugin-vue-components
|
|||
*/ |
|||
import Components from 'unplugin-vue-components/vite' |
|||
import ViteComponents, { VantResolver } from 'unplugin-vue-components/resolvers' |
|||
|
|||
export function configAutoComponentsPlugin() { |
|||
return Components({ |
|||
// 指定组件位置,默认是src/components
|
|||
dirs: ['src/components'], |
|||
extensions: ['vue', 'tsx'], |
|||
// 配置文件生成位置
|
|||
dts: 'src/components.d.ts', |
|||
// 搜索子目录
|
|||
deep: true, |
|||
// 允许子目录作为组件的命名空间前缀。
|
|||
directoryAsNamespace: false |
|||
// include:[]
|
|||
}) |
|||
} |
@ -0,0 +1,34 @@ |
|||
/** |
|||
* Used to package and output gzip. Note that this does not work properly in Vite, the specific reason is still being investigated |
|||
* https://github.com/anncwb/vite-plugin-compression
|
|||
*/ |
|||
import compressPlugin from 'vite-plugin-compression' |
|||
|
|||
export function configCompressPlugin( |
|||
compress, |
|||
deleteOriginFile = false |
|||
) { |
|||
const compressList = compress.split(',') |
|||
|
|||
const plugins = [] |
|||
|
|||
if (compressList.includes('gzip')) { |
|||
plugins.push( |
|||
compressPlugin({ |
|||
ext: '.gz', |
|||
deleteOriginFile |
|||
}) |
|||
) |
|||
} |
|||
|
|||
if (compressList.includes('brotli')) { |
|||
plugins.push( |
|||
compressPlugin({ |
|||
ext: '.br', |
|||
algorithm: 'brotliCompress', |
|||
deleteOriginFile |
|||
}) |
|||
) |
|||
} |
|||
return plugins |
|||
} |
@ -0,0 +1,37 @@ |
|||
import vue from '@vitejs/plugin-vue' |
|||
import vueJsx from '@vitejs/plugin-vue-jsx' |
|||
// import { configMockPlugin } from './mock'
|
|||
import { configAutoImportPlugin } from './autoImport' |
|||
import { configAutoComponentsPlugin } from './autocomponents' |
|||
import { configCompressPlugin } from './compress' |
|||
|
|||
export function createVitePlugins(viteEnv, isBuild) { |
|||
const { VITE_USE_MOCK, VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE } = viteEnv |
|||
|
|||
const vitePlugins = [ |
|||
// have to
|
|||
vue(), |
|||
// have to
|
|||
vueJsx({ |
|||
// include: /\.(jsx|tsx)/
|
|||
}) |
|||
] |
|||
|
|||
// unplugin-vue-components
|
|||
vitePlugins.push(configAutoComponentsPlugin()) |
|||
|
|||
// unplugin-auto-import
|
|||
vitePlugins.push(configAutoImportPlugin()) |
|||
|
|||
// // vite-plugin-mock
|
|||
// VITE_USE_MOCK && vitePlugins.push(configMockPlugin(isBuild))
|
|||
|
|||
// The following plugins only work in the production environment
|
|||
if (isBuild) { |
|||
// rollup-plugin-gzip
|
|||
vitePlugins.push( |
|||
configCompressPlugin(VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE) |
|||
) |
|||
} |
|||
return vitePlugins |
|||
} |
@ -0,0 +1,19 @@ |
|||
/** |
|||
* Mock plugin for development and production. |
|||
* https://github.com/anncwb/vite-plugin-mock
|
|||
*/ |
|||
// import { viteMockServe } from 'vite-plugin-mock'
|
|||
|
|||
// export function configMockPlugin(isBuild: boolean) {
|
|||
// return viteMockServe({
|
|||
// ignore: /^_/,
|
|||
// mockPath: 'mock',
|
|||
// localEnabled: !isBuild,
|
|||
// prodEnabled: isBuild,
|
|||
// injectCode: `
|
|||
// import { setupProdMockServer } from '../mock/_createProductionServer';
|
|||
// setupProdMockServer();
|
|||
// `
|
|||
// })
|
|||
// }
|
|||
export {} |
@ -0,0 +1,43 @@ |
|||
/** |
|||
* Generate proxy |
|||
* @param list |
|||
*/ |
|||
|
|||
export function createProxy() { |
|||
return { |
|||
// 字符串简写写法
|
|||
// '/foo': 'http://localhost:4567',
|
|||
// 选项写法
|
|||
// '/api': {
|
|||
// target: process .env.VITE_APP_API_BASE_URL || 'http://192.168.8.93:3001',
|
|||
// changeOrigin: true,
|
|||
// rewrite: (path) => path.replace(/^\/api/, '')
|
|||
// },
|
|||
// // 全球指数
|
|||
// '/hcm': {
|
|||
// target: process.env.VITE_APP_API_BASE_URL_HCM || 'http://192.168.8.93:3001',
|
|||
// changeOrigin: true,
|
|||
// rewrite: (path) => path.replace(/^\/hcm/, '')
|
|||
// },
|
|||
// // 时空预测
|
|||
// '/pre': {
|
|||
// target: process.env.VITE_APP_API_BASE_URL_AI || 'http://192.168.8.93:3001',
|
|||
// changeOrigin: true,
|
|||
// rewrite: (path) => path.replace(/^\/pre/, '')
|
|||
// }
|
|||
// 正则表达式写法
|
|||
// '^/fallback/.*': {
|
|||
// target: 'http://jsonplaceholder.typicode.com',
|
|||
// changeOrigin: true,
|
|||
// rewrite: (path) => path.replace(/^\/fallback/, '')
|
|||
// }
|
|||
// 使用 proxy 实例
|
|||
// "/api": {
|
|||
// target: "http://jsonplaceholder.typicode.com",
|
|||
// changeOrigin: true,
|
|||
// configure: (proxy, options) => {
|
|||
// // proxy 是 'http-proxy' 的实例
|
|||
// },
|
|||
// },
|
|||
} |
|||
} |
@ -0,0 +1,13 @@ |
|||
<!doctype html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8" /> |
|||
<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> |
|||
</head> |
|||
<body> |
|||
<div id="app"></div> |
|||
<script type="module" src="/src/main.js"></script> |
|||
</body> |
|||
</html> |
2297
package-lock.json
File diff suppressed because it is too large
View File
@ -0,0 +1,23 @@ |
|||
{ |
|||
"name": "dzp", |
|||
"private": true, |
|||
"version": "0.0.0", |
|||
"type": "module", |
|||
"scripts": { |
|||
"dev": "vite --host", |
|||
"build": "vite build", |
|||
"preview": "vite preview" |
|||
}, |
|||
"dependencies": { |
|||
"@element-plus/icons-vue": "^2.3.1", |
|||
"@lucky-canvas/vue": "^0.1.11", |
|||
"element-plus": "^2.9.8", |
|||
"lucky-canvas": "^1.7.27", |
|||
"vue": "^3.5.13", |
|||
"vue-router": "^4.5.0" |
|||
}, |
|||
"devDependencies": { |
|||
"@vitejs/plugin-vue": "^5.2.1", |
|||
"vite": "^6.2.6" |
|||
} |
|||
} |
After Width: 1920 | Height: 1080 | Size: 462 KiB |
After Width: 1920 | Height: 1080 | Size: 474 KiB |
After Width: 360 | Height: 360 | Size: 100 KiB |
After Width: 300 | Height: 300 | Size: 278 KiB |
@ -0,0 +1 @@ |
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg> |
After Width: 597 | Height: 690 | Size: 242 KiB |
After Width: 520 | Height: 600 | Size: 224 KiB |
@ -0,0 +1,9 @@ |
|||
<script setup> |
|||
</script> |
|||
|
|||
<template> |
|||
<router-view></router-view> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
</style> |
After Width: 142 | Height: 177 | Size: 27 KiB |
After Width: 142 | Height: 177 | Size: 27 KiB |
@ -0,0 +1 @@ |
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg> |
@ -0,0 +1,16 @@ |
|||
import { createApp } from "vue"; |
|||
import "./style.css"; |
|||
import App from "./App.vue"; |
|||
import router from "./router"; |
|||
import VueLuckyCanvas from "@lucky-canvas/vue"; |
|||
import ElementPlus from "element-plus"; |
|||
import "element-plus/dist/index.css"; |
|||
import * as ElementPlusIconsVue from "@element-plus/icons-vue"; |
|||
|
|||
const app = createApp(App); |
|||
|
|||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) { |
|||
app.component(key, component); |
|||
} |
|||
|
|||
app.use(router).use(ElementPlus).use(VueLuckyCanvas).mount("#app"); |
@ -0,0 +1,29 @@ |
|||
import { createRouter, createWebHistory } from 'vue-router' |
|||
const routes = [ |
|||
{ |
|||
path: '/', |
|||
redirect: '/homepage' |
|||
}, |
|||
{ |
|||
path: '/homepage', |
|||
name: 'homepage', |
|||
component: () => import('../views/homepage.vue') |
|||
}, |
|||
{ |
|||
path: '/hxl_dzp1', |
|||
name: 'hxl_dzp1', |
|||
component: () => import('../views/hxl_DZP/dzp1.vue') |
|||
}, |
|||
{ |
|||
path: '/animation', |
|||
name: 'animation', |
|||
component: () => import('../views/animation/anima.vue') |
|||
} |
|||
] |
|||
// 创建路由实例
|
|||
const router = createRouter({ |
|||
history: createWebHistory(import.meta.env.VITE_PUBLIC_PATH), |
|||
routes |
|||
}) |
|||
// 导出
|
|||
export default router |
@ -0,0 +1,87 @@ |
|||
:root { |
|||
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; |
|||
line-height: 1.5; |
|||
font-weight: 400; |
|||
|
|||
color-scheme: light dark; |
|||
color: rgba(255, 255, 255, 0.87); |
|||
background-color: #242424; |
|||
|
|||
font-synthesis: none; |
|||
text-rendering: optimizeLegibility; |
|||
-webkit-font-smoothing: antialiased; |
|||
-moz-osx-font-smoothing: grayscale; |
|||
} |
|||
|
|||
a { |
|||
font-weight: 500; |
|||
color: #646cff; |
|||
text-decoration: inherit; |
|||
} |
|||
a:hover { |
|||
color: #535bf2; |
|||
} |
|||
|
|||
body { |
|||
margin: 0; |
|||
display: flex; |
|||
place-items: center; |
|||
min-width: 320px; |
|||
min-height: 100vh; |
|||
} |
|||
|
|||
h1 { |
|||
font-size: 3.2em; |
|||
line-height: 1.1; |
|||
margin: 0; |
|||
} |
|||
|
|||
button { |
|||
border-radius: 8px; |
|||
border: 1px solid transparent; |
|||
padding: 0.6em 1.2em; |
|||
font-size: 1em; |
|||
font-weight: 500; |
|||
font-family: inherit; |
|||
background-color: #1a1a1a; |
|||
cursor: pointer; |
|||
transition: border-color 0.25s; |
|||
} |
|||
button:hover { |
|||
border-color: #646cff; |
|||
} |
|||
button:focus, |
|||
button:focus-visible { |
|||
outline: 4px auto -webkit-focus-ring-color; |
|||
} |
|||
|
|||
.card { |
|||
padding: 2em; |
|||
} |
|||
|
|||
|
|||
@media (prefers-color-scheme: light) { |
|||
:root { |
|||
color: #213547; |
|||
background-color: #ffffff; |
|||
} |
|||
a:hover { |
|||
color: #747bff; |
|||
} |
|||
button { |
|||
background-color: #f9f9f9; |
|||
} |
|||
} |
|||
|
|||
html { |
|||
width: 100vw; |
|||
height: 100vh; |
|||
margin: 0; |
|||
padding: 0; |
|||
} |
|||
body,#app{ |
|||
width: 100%; |
|||
height: 100%; |
|||
margin: 0; |
|||
padding: 0; |
|||
} |
@ -0,0 +1,229 @@ |
|||
<template> |
|||
<div class="total"> |
|||
<div class="box" :class="{ 'box-animaToR': isAnimating, 'box-animaToL': !isAnimating }" @click="startAnimation"> |
|||
<div v-if="!isTextAnimating"> |
|||
<span class="title" :class="{ 'title-animaT': isAnimating }">管理员登录</span> |
|||
<el-icon class="right" :class="{ 'arrow-anima': !isAnimating, 'title-animaT': isAnimating }"> |
|||
<Right /> |
|||
</el-icon> |
|||
</div> |
|||
|
|||
<div v-else> |
|||
<span class="title" :class="{ 'title-animaT': !isAnimating }">用户登录</span> |
|||
<el-icon class="left" :class="{ 'arrow-anima': isAnimating, 'title-animaT': !isAnimating }"> |
|||
<Back /> |
|||
</el-icon> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="login user"> |
|||
<div class="loginTitle">用户登录</div> |
|||
<el-form :model="userInfo" label-width="auto" style="max-width: 600px"> |
|||
<el-form-item label="账号"> |
|||
<el-input v-model="userInfo.username" /> |
|||
</el-form-item> |
|||
<el-form-item label="密码"> |
|||
<el-input v-model="userInfo.password" /> |
|||
</el-form-item> |
|||
<el-form-item> |
|||
<el-button type="success" style="width:100%">登录</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</div> |
|||
<div class="login admin"> |
|||
<div class="loginTitle">管理员登录</div> |
|||
<el-form :model="userInfo" label-width="auto" style="max-width: 600px"> |
|||
<el-form-item label="账号"> |
|||
<el-input v-model="userInfo.username" /> |
|||
</el-form-item> |
|||
<el-form-item label="密码"> |
|||
<el-input v-model="userInfo.password" /> |
|||
</el-form-item> |
|||
<el-form-item> |
|||
<el-button type="success" style="width:100%">登录</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</div> |
|||
|
|||
|
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, onMounted } from 'vue'; |
|||
|
|||
const firstAnimating=ref(false); |
|||
const isAnimating = ref(false); |
|||
const isTextAnimating = ref(false); |
|||
const startAnimation = () => { |
|||
isAnimating.value = !isAnimating.value; |
|||
setTimeout(() => { |
|||
isTextAnimating.value = !isTextAnimating.value; |
|||
}, 400); |
|||
} |
|||
|
|||
const userInfo = ref({ |
|||
username: '', |
|||
password: '', |
|||
}); |
|||
|
|||
|
|||
</script> |
|||
|
|||
<style scoped> |
|||
.login { |
|||
position: absolute; |
|||
z-index: 1; |
|||
width: 30%; |
|||
} |
|||
|
|||
.loginTitle { |
|||
font-size: 48px; |
|||
font-weight: bold; |
|||
margin-bottom: 20px; |
|||
text-align: center; |
|||
} |
|||
|
|||
.user{ |
|||
top: 30%; |
|||
left: 10%; |
|||
} |
|||
|
|||
.admin{ |
|||
top: 30%; |
|||
left: 55%; |
|||
} |
|||
|
|||
|
|||
.total { |
|||
width: 100%; |
|||
height: 100%; |
|||
display: flex; |
|||
} |
|||
|
|||
.title { |
|||
position: absolute; |
|||
font-size: 48px; |
|||
font-weight: bold; |
|||
top: 40%; |
|||
left: 30%; |
|||
z-index: 2; |
|||
} |
|||
|
|||
.title-animaT { |
|||
animation: textAnimaT 0.7s forwards; |
|||
} |
|||
|
|||
.title-animaF { |
|||
animation: textAnimaF 0.7s forwards; |
|||
} |
|||
|
|||
@keyframes textAnimaF { |
|||
0% { |
|||
opacity: 1; |
|||
} |
|||
|
|||
50% { |
|||
opacity: 0; |
|||
} |
|||
|
|||
100% { |
|||
opacity: 0; |
|||
} |
|||
} |
|||
|
|||
@keyframes textAnimaT { |
|||
0% { |
|||
opacity: 1; |
|||
} |
|||
|
|||
50% { |
|||
opacity: 0; |
|||
} |
|||
|
|||
100% { |
|||
opacity: 0; |
|||
} |
|||
} |
|||
|
|||
.box { |
|||
width: 50%; |
|||
height: 100%; |
|||
margin: 0; |
|||
background: linear-gradient(90deg, #ffae00, #ffffff); |
|||
border-radius: 5%; |
|||
z-index: 99; |
|||
} |
|||
|
|||
.box-animaToR { |
|||
animation: animaToR 1s forwards; |
|||
} |
|||
|
|||
.box-animaToL { |
|||
animation: animaToL 1s forwards; |
|||
} |
|||
|
|||
@keyframes animaToR { |
|||
0% { |
|||
transform: translateX(0) scaleX(1); |
|||
background: linear-gradient(90deg, #ffffff, #29e6ff); |
|||
} |
|||
|
|||
/* 50% { |
|||
transform: translateX(50%) scaleX(2); |
|||
} */ |
|||
|
|||
100% { |
|||
transform: translateX(100%) scaleX(1); |
|||
background: linear-gradient(90deg, #ffffff, #29e6ff); |
|||
} |
|||
} |
|||
|
|||
@keyframes animaToL { |
|||
0% { |
|||
transform: translateX(100%) scaleX(1); |
|||
} |
|||
|
|||
/* 50% { |
|||
transform: translateX(50%) scaleX(2); |
|||
} */ |
|||
|
|||
100% { |
|||
transform: translateX(0%) scaleX(1); |
|||
background: linear-gradient(90deg, #ffae00, #ffffff); |
|||
} |
|||
} |
|||
|
|||
.right { |
|||
position: absolute; |
|||
right: 10%; |
|||
top: 40%; |
|||
font-size: 72px; |
|||
} |
|||
|
|||
.left { |
|||
position: absolute; |
|||
left: 10%; |
|||
top: 40%; |
|||
font-size: 72px; |
|||
z-index: 2; |
|||
} |
|||
|
|||
.arrow-anima { |
|||
animation: arrowAnima 1s infinite; |
|||
} |
|||
|
|||
@keyframes arrowAnima { |
|||
0% { |
|||
transform: translateX(0); |
|||
} |
|||
|
|||
50% { |
|||
transform: translateX(10px); |
|||
} |
|||
|
|||
100% { |
|||
transform: translateX(0); |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,44 @@ |
|||
<template> |
|||
<h1 style="width:100%;text-align:center;margin:20px 0px 10px 0px">练习首页</h1> |
|||
<el-divider> |
|||
<el-icon><star-filled /></el-icon> |
|||
</el-divider> |
|||
<div class="btns"> |
|||
<div v-for="button in buttons" :key="button.text" :type="button.type" class="btn" @click="router.push(button.path)"> |
|||
{{ button.text }} |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref } from 'vue' |
|||
import { useRouter } from 'vue-router' |
|||
const router = useRouter() |
|||
|
|||
const buttons = [ |
|||
{ type: 'primary', text: '转盘',path:'/hxl_dzp1' }, |
|||
{ type: 'success', text: '动画',path:'/animation' }, |
|||
] |
|||
|
|||
|
|||
</script> |
|||
|
|||
<style scoped> |
|||
.btns{ |
|||
width: 100%; |
|||
height: auto; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 20px; |
|||
} |
|||
|
|||
.btn { |
|||
width: 100%; |
|||
height: auto; |
|||
font-size: 30px; |
|||
font-weight: bold; |
|||
text-align: center; |
|||
cursor: pointer; |
|||
} |
|||
</style> |
|||
<style></style> |
@ -0,0 +1,132 @@ |
|||
<script setup> |
|||
import { ref, onMounted } from 'vue' |
|||
|
|||
const showPopup = ref(false); |
|||
const popupMessage = ref(''); |
|||
const totalScore = ref(4000) // 初始分数 |
|||
const myLucky = ref() |
|||
// 新增状态 |
|||
const spinCount = ref(0) |
|||
const isSpinning = ref(false) |
|||
// 新增变量记录基础分数 |
|||
//const baseScore = 4000 |
|||
const wheelConfig = ref({ |
|||
}) |
|||
const prizes = ref([ |
|||
{ fonts: [{ text: '-199', top: '10%', fontColor: '#FF2C29', fontSize: '40px' }], background: '#FAF9F0' }, //0 |
|||
{ fonts: [{ text: '-55', top: '10%', fontColor: '#FF2C29', fontSize: '40px' }], background: '#F5D7AD' }, //1 |
|||
{ fonts: [{ text: '+200', top: '10%', fontColor: '#FF2C29', fontSize: '40px' }], background: '#FAF9F0' }, //2 |
|||
{ fonts: [{ text: '-88', top: '10%', fontColor: '#FF2C29', fontSize: '40px' }], background: '#F5D7AD' }, //3 |
|||
{ fonts: [{ text: '-11', top: '10%', fontColor: '#FF2C29', fontSize: '40px' }], background: '#FAF9F0' }, //4 |
|||
{ fonts: [{ text: '-299', top: '10%', fontColor: '#FF2C29', fontSize: '40px' }], background: '#F5D7AD' }, //5 |
|||
{ fonts: [{ text: '+200', top: '10%', fontColor: '#FF2C29', fontSize: '40px' }], background: '#FAF9F0' }, //6 |
|||
{ fonts: [{ text: '-66', top: '10%', fontColor: '#FF2C29', fontSize: '40px' }], background: '#F5D7AD' }, //7 |
|||
]) |
|||
const blocks = ref([{ padding: '13px', background: ' #FF2A00' }]) |
|||
const buttons = ref([ |
|||
{ radius: '50%', background: '#617df2' }, |
|||
{ radius: '45%', background: '#afc8ff' }, |
|||
{ |
|||
radius: '40%', background: '#869cfa', pointer: true, |
|||
fonts: [{ text: '开始\n抽奖', top: '-20px' }] |
|||
}]) |
|||
|
|||
//自定义数组 |
|||
const customOrder = ref([0, 4, 3, 1, 2, 4, 5, 7, 3, 4, 0]) |
|||
let orderIndex = 0; |
|||
|
|||
function startCallback() { |
|||
// 检查转动条件和次数 |
|||
if (spinCount.value >= 11) { // 从0开始计数,11表示第12次 |
|||
alert('已达最大转动次数!') |
|||
return |
|||
} |
|||
|
|||
isSpinning.value = true |
|||
spinCount.value++ |
|||
// 重置为初始分数 |
|||
//totalScore.value = baseScore |
|||
// 调用抽奖组件的play方法开始游戏 |
|||
myLucky.value.play() |
|||
// 模拟调用接口异步抽奖 |
|||
setTimeout(() => { |
|||
// |
|||
console.log(orderIndex, 'orderIndex') |
|||
|
|||
const index = orderIndex |
|||
|
|||
console.log(customOrder.value[index], 'custome') |
|||
// 调用stop停止旋转并传递中奖索引 |
|||
myLucky.value.stop(customOrder.value[index]) |
|||
//更新指针(循环) |
|||
orderIndex = (index + 1) % customOrder.value.length; |
|||
}, 3000) |
|||
} |
|||
const scoreAnimation = ref(false) |
|||
|
|||
|
|||
// 抽奖结束end回调 |
|||
function endCallback(prize) { |
|||
const result = Number(prize.fonts[0].text) |
|||
console.log(prize.fonts[0].text) |
|||
// 更新总分 |
|||
setTimeout(() => { |
|||
totalScore.value = totalScore.value + result |
|||
}, 1000); |
|||
|
|||
// 触发动画 |
|||
animateScoreChange() |
|||
// 先清空文字 |
|||
popupMessage.value = ""; |
|||
showPopup.value = true; |
|||
// 设置弹窗内容 |
|||
setTimeout(() => { |
|||
popupMessage.value = `${result}金币`; |
|||
}, 1000); // <--- 正确的用法 |
|||
|
|||
showPopup.value = true; |
|||
// 3秒后隐藏弹窗 |
|||
setTimeout(() => { |
|||
showPopup.value = false; |
|||
}, 3000); |
|||
} |
|||
// 添加分数变化动画方法 |
|||
const animateScoreChange = () => { |
|||
scoreAnimation.value = true |
|||
setTimeout(() => { |
|||
scoreAnimation.value = false |
|||
}, 3000) |
|||
} |
|||
|
|||
onMounted(() => { |
|||
console.log(import.meta.env.MODE, '1111') |
|||
console.log(process.env.NODE_ENV, '2222') |
|||
}) |
|||
</script> |
|||
|
|||
<template> |
|||
<div style="display:flex;height:100%;width:100%"> |
|||
<el-card class="manageCard"> |
|||
管理台 |
|||
</el-card> |
|||
<el-card class="wheelCard"> |
|||
<div class="luckyWheel"> |
|||
<LuckyWheel class="lucky" ref="myLucky" width="434px" height="434px" :default-config="wheelConfig" |
|||
:prizes="prizes" :blocks="blocks" :buttons="buttons" @start="startCallback" @end="endCallback" /> |
|||
|
|||
</div> |
|||
</el-card> |
|||
</div> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
.el-card { |
|||
margin: 20px; |
|||
} |
|||
|
|||
.manageCard{ |
|||
width: auto; |
|||
flex: 1; |
|||
} |
|||
|
|||
</style> |
@ -0,0 +1,29 @@ |
|||
import { defineConfig,loadEnv } from "vite"; |
|||
import { wrapperEnv } from "./build/utils"; |
|||
import vue from "@vitejs/plugin-vue"; |
|||
import { resolve } from "path"; //
|
|||
|
|||
export default defineConfig(({ command, mode }) => { |
|||
const root = process.cwd(); |
|||
const env = loadEnv(mode, root); |
|||
const viteEnv = wrapperEnv(env); |
|||
const { VITE_PUBLIC_PATH, VITE_OUTPUT_DIR } = viteEnv; |
|||
return { |
|||
base: VITE_PUBLIC_PATH, |
|||
plugins: [vue()], //
|
|||
server: { |
|||
host: "192.168.1.102", |
|||
port: 5173, |
|||
// 错误1:server 块内不能嵌套 plugins 配置(已删除)
|
|||
proxy: { |
|||
"/api": { |
|||
target: "http://192.168.99.223:3000", |
|||
changeOrigin: true, |
|||
rewrite: (path) => path.replace(/^\/api/, ""), |
|||
}, |
|||
}, |
|||
}, |
|||
resolve: { |
|||
}, |
|||
}; |
|||
}); |