73 Commits

Author SHA1 Message Date
no99 a3730c2f44 解决了当第一个奖品已经抽完,但是没有揭示的时候,可以直接揭示第二个奖品的问题 4 weeks ago
no99 0b45b72670 修改图片链接的变量名称 4 weeks ago
no99 0ff34d3ed7 Merge branch 'milestone-20250722-抽奖' into milestone-20250722-众筹抽奖合并专用分支 4 weeks ago
zhangjiahao 2f65a7baa2 更改状态 4 weeks ago
zhangjiahao cfc8afdef4 添加助力成功动画 4 weeks ago
Ethereal f6f878775f Merge branch 'wangyi/feature-20250710191445-抽奖' into milestone-20250722-抽奖 4 weeks ago
Ethereal fd1fe50618 优化卡牌字体大小,解决最后一个商品不能抽取的bug 4 weeks ago
宋杰 5292ead3bb Merge branch 'milestone-20250722-众筹抽奖合并专用分支' of http://39.101.133.168:8807/hongxilin/activityLink into milestone-20250722-众筹抽奖合并专用分支 4 weeks ago
宋杰 a37445dc47 剩余分钟数小于3时字体变成红色。 4 weeks ago
no99 e8891edb65 Merge branch 'milestone-20250722-抽奖' into milestone-20250722-众筹抽奖合并专用分支 4 weeks ago
no99 d6e099201d Merge branch 'hongxilin/feature-20250710175148-抽奖' into milestone-20250722-抽奖 4 weeks ago
no99 e2170b97e2 中奖进度条初始化不对的问题 4 weeks ago
no99 3b125e172e 修改获取中奖名单api 4 weeks ago
宋杰 0e2f6d6110 火箭图片在周年庆下面。 4 weeks ago
宋杰 a879bbb605 更换美股背景图片;公告提示语修改。 4 weeks ago
宋杰 05bf98e358 传参token修改为ApiToken。 4 weeks ago
宋杰 733c41db7c 取消导入tween;一修改为二。 4 weeks ago
宋杰 04269f7e09 统一tweenjs导入方式。 4 weeks ago
宋杰 2d2445b7f6 压缩图片;测试环境打包;抽奖登录路由调整;删除无用文件。 4 weeks ago
宋杰 4ffa3a5472 新增打包环境。 4 weeks ago
宋杰 6fe70f29c8 获取地址栏token。 4 weeks ago
宋杰 752b1ae951 从浏览器获取token。 4 weeks ago
宋杰 8f182e2624 合并代码 4 weeks ago
宋杰 1bffac237a Merge branch 'milestone-20250723-众筹' into milestone-20250722-众筹抽奖合并专用分支 4 weeks ago
zhangjiahao bf600b46c7 测试 4 weeks ago
songtongtong 3fe0974961 修改手机端活动时间框样式 4 weeks ago
songtongtong 95d05a0d8b Merge branch 'zhangjiahao/feature-20250717125955-众筹' into songtongtong/feature-20250717104937-众筹 4 weeks ago
songtongtong 9c569cfecc Merge branch 'zhangjiahao/feature-20250717125955-众筹' of http://39.101.133.168:8807/hongxilin/activityLink into zhangjiahao/feature-20250717125955-众筹 4 weeks ago
zhangjiahao c05e28574c 修改点击助力从后端接收数据的逻辑;修改助力数据从后端动态传入 4 weeks ago
songtongtong 8660d78a39 Merge branch 'zhangjiahao/feature-20250717125955-众筹' of http://39.101.133.168:8807/hongxilin/activityLink into zhangjiahao/feature-20250717125955-众筹 4 weeks ago
zhangjiahao 07c8c4c008 添加周年庆装饰;解决addrecordAPI接口问题 4 weeks ago
songtongtong 150508b73a Merge branch 'milestone-20250723-众筹' into songtongtong/feature-20250717104937-众筹 4 weeks ago
zhangjiahao e933f5378b 获取投票数据接口修改; 4 weeks ago
songtongtong c18d680d94 Merge branch 'zhangjiahao/feature-20250717125955-众筹' of http://39.101.133.168:8807/hongxilin/activityLink into zhangjiahao/feature-20250717125955-众筹 4 weeks ago
zhangjiahao 924609188d 适配手机端界面 4 weeks ago
zhangjiahao bbdda16b53 适配手机端界面 4 weeks ago
songtongtong f1b5101c48 Merge branch 'zhangjiahao/feature-20250717125955-众筹' of http://39.101.133.168:8807/hongxilin/activityLink into zhangjiahao/feature-20250717125955-众筹 4 weeks ago
zhangjiahao fd6c272f62 适配手机端部分样式 4 weeks ago
songtongtong bb84dc61f9 Merge branch 'zhangjiahao/feature-20250717125955-众筹' of http://39.101.133.168:8807/hongxilin/activityLink into zhangjiahao/feature-20250717125955-众筹 4 weeks ago
zhangjiahao 0715f26652 拉取手机端照片 4 weeks ago
songtongtong bffa7a73fb Merge branch 'milestone-20250723-众筹' into songtongtong/feature-20250717104937-众筹 4 weeks ago
zhangjiahao 80b4f4fb28 Merge branch 'milestone-20250723-众筹' into zhangjiahao/feature-20250717125955-众筹 4 weeks ago
宋杰 fb8276e604 上传手机版图片;删除注释的适配手机端代码;重新写了一个js文件单独存放众筹的接口。 4 weeks ago
songtongtong 1d08502ecf Merge branch 'zhangjiahao/feature-20250717125955-众筹' into songtongtong/feature-20250717104937-众筹 4 weeks ago
songtongtong 5dba014967 Merge branch 'zhangjiahao/feature-20250717125955-众筹' of http://39.101.133.168:8807/hongxilin/activityLink into zhangjiahao/feature-20250717125955-众筹 4 weeks ago
zhangjiahao 754dba78c7 480px下修改大标题,活动规则,股票板块显示大小等适配 4 weeks ago
songtongtong 5b083237b1 拉取合并宋杰代码 4 weeks ago
宋杰 dfc1677baa 根据接口返回的数据确定助力状态,计算进度; 4 weeks ago
songtongtong 1824e17ece 样式+接口 4 weeks ago
宋杰 61ae4ce8f8 时间从接口获取;新需求去掉港股; 4 weeks ago
宋杰 4999490ede Merge branch 'milestone-20250723-众筹' of http://39.101.133.168:8807/hongxilin/activityLink into songjie/feature-20250710175416-众筹项目7月23提测 4 weeks ago
songtongtong 669bd92934 Merge branch 'zhangjiahao/feature-20250717125955-众筹' of http://39.101.133.168:8807/hongxilin/activityLink into songtongtong/feature-20250717104937-众筹 4 weeks ago
songtongtong 75711ef179 Merge branch 'songtongtong/feature-20250717104937-众筹' into zhangjiahao/feature-20250717125955-众筹 4 weeks ago
songtongtong 6e34b56d70 修改样式 4 weeks ago
宋杰 d355fba903 合并张家豪代码 4 weeks ago
zhangjiahao 4192624cfa 使用token验证activity1接口 4 weeks ago
songtongtong cc9a8f6241 同步代码 4 weeks ago
songtongtong 0643c8cd84 样式优化 4 weeks ago
zhangjiahao f02c5aacd3 Merge branch 'milestone-20250723-众筹' of http://39.101.133.168:8807/hongxilin/activityLink into milestone-20250723-众筹 4 weeks ago
zhangjiahao db6d7f2277 修改样式 4 weeks ago
宋杰 ea0602bb90 众筹初版样式。 1 month ago
songtongtong d21d60e400 合并代码 1 month ago
zhangjiahao 84318e7939 合并代码 1 month ago
宋杰 97fd0f1d71 众筹初版样式完成。 1 month ago
宋杰 fcea9f519e 众筹使用的图片上传完成;众筹样式初版完成。 1 month ago
songtongtong 1b5fcbd4fc 众筹 1 month ago
songtongtong 313d66fe29 style(zhongchou): 调整按钮格式,增加可读性 1 month ago
zhangjiahao 2a00f67195 去除部分重复代码 1 month ago
zhangjiahao b9c06ffead feat(views): 实现进度条动态高度计算和响应式布局优化 1 month ago
zhangjiahao 5e8770562b 处理控制台bug 1 month ago
zhangjiahao 1e5361622b feat(众筹页面): 实现股票助力活动页面及交互功能 1 month ago
songtongtong dabdbc33d1 安装element-plus,调试按钮 1 month ago
songtongtong 520f3f53e9 新增空格 1 month ago
  1. 290
      .eslintrc-auto-import.json
  2. 2
      .vercel/project.json
  3. 44
      CORS_README.md
  4. 43
      build/utils.js
  5. 44
      build/vite/build.js
  6. 26
      build/vite/plugin/autoImport.js
  7. 21
      build/vite/plugin/autocomponents.js
  8. 37
      build/vite/plugin/compress.js
  9. 37
      build/vite/plugin/index.js
  10. 19
      build/vite/plugin/mock.js
  11. 43
      build/vite/proxy.js
  12. 2
      index.html
  13. 1259
      package-lock.json
  14. 8
      package.json
  15. 2
      src/api/API.js
  16. 25
      src/api/zhongchouApi.js
  17. BIN
      src/assets/bg@2x.png
  18. BIN
      src/assets/daijiemi.png
  19. BIN
      src/assets/img/bg.png
  20. BIN
      src/assets/img/zhongchou/bg.png
  21. BIN
      src/assets/img/zhongchou/blueBg.png
  22. BIN
      src/assets/img/zhongchou/redBg.png
  23. BIN
      src/assets/img/zhongchou/rocket.gif
  24. BIN
      src/assets/img/zhongchou/助力成功.png
  25. BIN
      src/assets/img/zhongchou/助力港股.png
  26. BIN
      src/assets/img/zhongchou/助力美股.png
  27. BIN
      src/assets/img/zhongchou/助力美股享实时数据.png
  28. BIN
      src/assets/img/zhongchou/周年庆装饰.png
  29. BIN
      src/assets/img/zhongchou/大标题.png
  30. BIN
      src/assets/img/zhongchou/底座.png
  31. BIN
      src/assets/img/zhongchou/手机bg.png
  32. BIN
      src/assets/img/zhongchou/手机助力美股享实时数据.png
  33. BIN
      src/assets/img/zhongchou/手机周年庆装饰.png
  34. BIN
      src/assets/img/zhongchou/手机矩形.png
  35. BIN
      src/assets/img/zhongchou/手机组2.png
  36. BIN
      src/assets/img/zhongchou/时间边框.png
  37. BIN
      src/assets/img/zhongchou/框.png
  38. BIN
      src/assets/img/zhongchou/活动需知.png
  39. BIN
      src/assets/img/zhongchou/浮窗.png
  40. BIN
      src/assets/img/zhongchou/港股.png
  41. BIN
      src/assets/img/zhongchou/港股已助力.png
  42. BIN
      src/assets/img/zhongchou/火箭.png
  43. BIN
      src/assets/img/zhongchou/知道了.png
  44. BIN
      src/assets/img/zhongchou/美股.png
  45. BIN
      src/assets/img/zhongchou/美股已助力.png
  46. BIN
      src/assets/img/待揭秘.png
  47. 1
      src/assets/vue.svg
  48. BIN
      src/assets/登录背景.png
  49. 285
      src/auto-import.d.ts
  50. 14
      src/components.d.ts
  51. 2
      src/style.css
  52. 2
      src/utils/prizeList.js
  53. 23
      src/utils/request.js
  54. 50
      src/views/choujiang/Login.vue
  55. 41
      src/views/choujiang/hxl-cj/cj.vue
  56. 23
      src/views/choujiang/index.vue
  57. 2
      src/views/choujiang/lottery/CardItem.vue
  58. 2
      src/views/choujiang/lottery/Lottery3D.vue
  59. 2
      src/views/choujiang/lottery/PrizePanel.vue
  60. 1365
      src/views/zhongchou/index.vue
  61. 94
      vite.config.js
  62. 98
      修改完成总结.md
  63. 92
      抽奖逻辑修改说明.md
  64. 113
      测试用例.md

290
.eslintrc-auto-import.json

@ -0,0 +1,290 @@
{
"globals": {
"Component": true,
"ComponentPublicInstance": true,
"ComputedRef": true,
"DirectiveBinding": true,
"EffectScope": true,
"ExtractDefaultPropTypes": true,
"ExtractPropTypes": true,
"ExtractPublicPropTypes": true,
"InjectionKey": true,
"MaybeRef": true,
"MaybeRefOrGetter": true,
"PropType": true,
"Ref": true,
"Slot": true,
"Slots": true,
"VNode": true,
"WritableComputedRef": true,
"asyncComputed": true,
"autoResetRef": true,
"computed": true,
"computedAsync": true,
"computedEager": true,
"computedInject": true,
"computedWithControl": true,
"controlledComputed": true,
"controlledRef": true,
"createApp": true,
"createEventHook": true,
"createGlobalState": true,
"createInjectionState": true,
"createReactiveFn": true,
"createSharedComposable": true,
"createUnrefFn": true,
"customRef": true,
"debouncedRef": true,
"debouncedWatch": true,
"defineAsyncComponent": true,
"defineComponent": true,
"eagerComputed": true,
"effectScope": true,
"extendRef": true,
"getCurrentInstance": true,
"getCurrentScope": true,
"h": true,
"ignorableWatch": true,
"inject": true,
"isDefined": true,
"isProxy": true,
"isReactive": true,
"isReadonly": true,
"isRef": true,
"makeDestructurable": true,
"markRaw": true,
"nextTick": true,
"onActivated": true,
"onBeforeMount": true,
"onBeforeRouteLeave": true,
"onBeforeRouteUpdate": true,
"onBeforeUnmount": true,
"onBeforeUpdate": true,
"onClickOutside": true,
"onDeactivated": true,
"onErrorCaptured": true,
"onKeyStroke": true,
"onLongPress": true,
"onMounted": true,
"onRenderTracked": true,
"onRenderTriggered": true,
"onScopeDispose": true,
"onServerPrefetch": true,
"onStartTyping": true,
"onUnmounted": true,
"onUpdated": true,
"onWatcherCleanup": true,
"pausableWatch": true,
"provide": true,
"reactify": true,
"reactifyObject": true,
"reactive": true,
"reactiveComputed": true,
"reactiveOmit": true,
"reactivePick": true,
"readonly": true,
"ref": true,
"refAutoReset": true,
"refDebounced": true,
"refDefault": true,
"refThrottled": true,
"refWithControl": true,
"resolveComponent": true,
"resolveRef": true,
"resolveUnref": true,
"shallowReactive": true,
"shallowReadonly": true,
"shallowRef": true,
"syncRef": true,
"syncRefs": true,
"templateRef": true,
"throttledRef": true,
"throttledWatch": true,
"toRaw": true,
"toReactive": true,
"toRef": true,
"toRefs": true,
"toValue": true,
"triggerRef": true,
"tryOnBeforeMount": true,
"tryOnBeforeUnmount": true,
"tryOnMounted": true,
"tryOnScopeDispose": true,
"tryOnUnmounted": true,
"unref": true,
"unrefElement": true,
"until": true,
"useActiveElement": true,
"useArrayEvery": true,
"useArrayFilter": true,
"useArrayFind": true,
"useArrayFindIndex": true,
"useArrayFindLast": true,
"useArrayJoin": true,
"useArrayMap": true,
"useArrayReduce": true,
"useArraySome": true,
"useArrayUnique": true,
"useAsyncQueue": true,
"useAsyncState": true,
"useAttrs": true,
"useBase64": true,
"useBattery": true,
"useBluetooth": true,
"useBreakpoints": true,
"useBroadcastChannel": true,
"useBrowserLocation": true,
"useCached": true,
"useClipboard": true,
"useCloned": true,
"useColorMode": true,
"useConfirmDialog": true,
"useCounter": true,
"useCssModule": true,
"useCssVar": true,
"useCssVars": true,
"useCurrentElement": true,
"useCycleList": true,
"useDark": true,
"useDateFormat": true,
"useDebounce": true,
"useDebounceFn": true,
"useDebouncedRefHistory": true,
"useDeviceMotion": true,
"useDeviceOrientation": true,
"useDevicePixelRatio": true,
"useDevicesList": true,
"useDisplayMedia": true,
"useDocumentVisibility": true,
"useDraggable": true,
"useDropZone": true,
"useElementBounding": true,
"useElementByPoint": true,
"useElementHover": true,
"useElementSize": true,
"useElementVisibility": true,
"useEventBus": true,
"useEventListener": true,
"useEventSource": true,
"useEyeDropper": true,
"useFavicon": true,
"useFetch": true,
"useFileDialog": true,
"useFileSystemAccess": true,
"useFocus": true,
"useFocusWithin": true,
"useFps": true,
"useFullscreen": true,
"useGamepad": true,
"useGeolocation": true,
"useId": true,
"useIdle": true,
"useImage": true,
"useInfiniteScroll": true,
"useIntersectionObserver": true,
"useInterval": true,
"useIntervalFn": true,
"useKeyModifier": true,
"useLastChanged": true,
"useLink": true,
"useLocalStorage": true,
"useMagicKeys": true,
"useManualRefHistory": true,
"useMediaControls": true,
"useMediaQuery": true,
"useMemoize": true,
"useMemory": true,
"useModel": true,
"useMounted": true,
"useMouse": true,
"useMouseInElement": true,
"useMousePressed": true,
"useMutationObserver": true,
"useNavigatorLanguage": true,
"useNetwork": true,
"useNow": true,
"useObjectUrl": true,
"useOffsetPagination": true,
"useOnline": true,
"usePageLeave": true,
"useParallax": true,
"usePermission": true,
"usePointer": true,
"usePointerLock": true,
"usePointerSwipe": true,
"usePreferredColorScheme": true,
"usePreferredContrast": true,
"usePreferredDark": true,
"usePreferredLanguages": true,
"usePreferredReducedMotion": true,
"usePrevious": true,
"useRafFn": true,
"useRefHistory": true,
"useResizeObserver": true,
"useRoute": true,
"useRouter": true,
"useScreenOrientation": true,
"useScreenSafeArea": true,
"useScriptTag": true,
"useScroll": true,
"useScrollLock": true,
"useSessionStorage": true,
"useShare": true,
"useSlots": true,
"useSorted": true,
"useSpeechRecognition": true,
"useSpeechSynthesis": true,
"useStepper": true,
"useStorage": true,
"useStorageAsync": true,
"useStyleTag": true,
"useSupported": true,
"useSwipe": true,
"useTemplateRef": true,
"useTemplateRefsList": true,
"useTextDirection": true,
"useTextSelection": true,
"useTextareaAutosize": true,
"useThrottle": true,
"useThrottleFn": true,
"useThrottledRefHistory": true,
"useTimeAgo": true,
"useTimeout": true,
"useTimeoutFn": true,
"useTimeoutPoll": true,
"useTimestamp": true,
"useTitle": true,
"useToNumber": true,
"useToString": true,
"useToggle": true,
"useTransition": true,
"useUrlSearchParams": true,
"useUserMedia": true,
"useVModel": true,
"useVModels": true,
"useVibrate": true,
"useVirtualList": true,
"useWakeLock": true,
"useWebNotification": true,
"useWebSocket": true,
"useWebWorker": true,
"useWebWorkerFn": true,
"useWindowFocus": true,
"useWindowScroll": true,
"useWindowSize": true,
"watch": true,
"watchArray": true,
"watchAtMost": true,
"watchDebounced": true,
"watchEffect": true,
"watchIgnorable": true,
"watchOnce": true,
"watchPausable": true,
"watchPostEffect": true,
"watchSyncEffect": true,
"watchThrottled": true,
"watchTriggerable": true,
"watchWithFilter": true,
"whenever": true
}
}

2
.vercel/project.json

@ -1 +1 @@
{"projectName":"trae_8qnxf0if"}
{"projectName":"trae_zf0uu3bt"}

44
CORS_README.md

@ -1,44 +0,0 @@
# 跨域问题解决方案
## 配置说明
本项目已配置Vite代理来解决跨域问题。
### 1. Vite配置 (vite.config.js)
```javascript
server: {
host: '0.0.0.0',
port: 3000,
proxy: {
'/api': {
target: 'https://dbqb.nfdxy.net',
changeOrigin: true,
secure: false,
rewrite: (path) => path.replace(/^\/api/, '/devLotApi/api')
}
}
}
```
### 2. 请求配置 (src/utils/request.js)
- `baseURL: '/api'` - 设置基础URL为代理路径
### 3. API调用 (src/api/API.js)
- 使用相对路径 `/prize/list` 而不是完整的URL
- 实际请求会被代理到 `https://dbqb.nfdxy.net/devLotApi/api/prize/list`
## 工作原理
1. 前端发起请求到 `/api/prize/list`
2. Vite开发服务器拦截请求
3. 代理将请求转发到 `https://dbqb.nfdxy.net/devLotApi/api/prize/list`
4. 服务器响应通过代理返回给前端
## 注意事项
- 此配置仅在开发环境有效
- 生产环境需要在服务器端配置CORS或使用nginx代理
- 确保目标服务器允许跨域请求

43
build/utils.js

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

44
build/vite/build.js

@ -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: true, // 生产环境移除console
drop_debugger: true // 生产环境移除debugger
}
}
};
}

26
build/vite/plugin/autoImport.js

@ -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')
}
})
}

21
build/vite/plugin/autocomponents.js

@ -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 { 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:[]
})
}

37
build/vite/plugin/compress.js

@ -0,0 +1,37 @@
/**
* 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
) {
if (!compress || compress === 'none') {
return []
}
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
}

37
build/vite/plugin/index.js

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

19
build/vite/plugin/mock.js

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

43
build/vite/proxy.js

@ -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' 的实例
// },
// },
}
}

2
index.html

@ -7,7 +7,7 @@
<title>Vite + Vue</title>
</head>
<body>
<script src="/src/utils/tween.min.js"></script>
<!-- <script src="/src/utils/tween.min.js"></script> -->
<div id="app"></div>
<script type="module" src="/src/main.js"></script>

1259
package-lock.json
File diff suppressed because it is too large
View File

8
package.json

@ -6,21 +6,27 @@
"scripts": {
"dev": "vite --host",
"build": "vite build",
"preview": "vite preview"
"preview": "vite preview",
"build:test": "vite build --mode development",
"build:prod": "vite build --mode production"
},
"dependencies": {
"@tweenjs/tween.js": "^18.6.4",
"@vitejs/plugin-vue": "^4.6.2",
"@vitejs/plugin-vue-jsx": "^3.1.0",
"axios": "^1.10.0",
"dayjs": "^1.11.13",
"element-plus": "^2.10.3",
"pinia": "^3.0.3",
"pinia-plugin-persistedstate": "^4.4.1",
"three": "^0.178.0",
"vite": "^4.5.3",
"vite-plugin-compression": "^0.5.1",
"vue": "^3.5.17",
"vue-router": "^4.5.1"
},
"devDependencies": {
"terser": "^5.43.1",
"unplugin-auto-import": "^19.3.0",
"unplugin-vue-components": "^28.8.0"
}

2
src/api/API.js

@ -24,7 +24,7 @@ export const getUserListApi = function (params) {
// 查询中奖名单
export const getGetPrizeUserListApi = function (params) {
return request({
url: `${APIurl}/admin/win/list`,
url: `${APIurl}/api/winUser/list`,
method: "POST",
data: params,
});

25
src/api/zhongchouApi.js

@ -0,0 +1,25 @@
import request from "../utils/request";
const APIurl = import.meta.env.VITE_APP_API_BASE_URL;
// 开发环境使用代理,生产环境使用环境变量
// const APIurl = import.meta.env.DEV ? '/Api' : import.meta.env.VITE_APP_API_BASE_URL;
export function addRecordAPI(data) {
return request({
url: `${APIurl}/api/funding/addRecord`,
method: 'post',
data: data,
headers: {
ApiToken: localStorage.getItem('localToken')
},
})
}
// 新增:获取活动信息接口
export function getActivity1API() {
return request({
url: `${APIurl}/api/funding/getActivity`,
method: 'post',
headers: {
ApiToken: localStorage.getItem('localToken')
},
})
}

BIN
src/assets/bg@2x.png

Before

Width: 3840  |  Height: 2160  |  Size: 5.6 MiB

After

Width: 1920  |  Height: 1080  |  Size: 492 KiB

BIN
src/assets/daijiemi.png

Before

Width: 766  |  Height: 220  |  Size: 144 KiB

After

Width: 766  |  Height: 220  |  Size: 43 KiB

BIN
src/assets/img/bg.png

Before

Width: 1920  |  Height: 1080  |  Size: 1.8 MiB

BIN
src/assets/img/zhongchou/bg.png

After

Width: 1920  |  Height: 1080  |  Size: 174 KiB

BIN
src/assets/img/zhongchou/blueBg.png

After

Width: 1292  |  Height: 741  |  Size: 21 KiB

BIN
src/assets/img/zhongchou/redBg.png

After

Width: 1320  |  Height: 769  |  Size: 23 KiB

BIN
src/assets/img/zhongchou/rocket.gif

After

Width: 500  |  Height: 500  |  Size: 932 KiB

BIN
src/assets/img/zhongchou/助力成功.png

After

Width: 624  |  Height: 754  |  Size: 92 KiB

BIN
src/assets/img/zhongchou/助力港股.png

After

Width: 402  |  Height: 88  |  Size: 8.8 KiB

BIN
src/assets/img/zhongchou/助力美股.png

After

Width: 402  |  Height: 88  |  Size: 11 KiB

BIN
src/assets/img/zhongchou/助力美股享实时数据.png

After

Width: 852  |  Height: 98  |  Size: 40 KiB

BIN
src/assets/img/zhongchou/周年庆装饰.png

After

Width: 708  |  Height: 267  |  Size: 155 KiB

BIN
src/assets/img/zhongchou/大标题.png

After

Width: 982  |  Height: 98  |  Size: 16 KiB

BIN
src/assets/img/zhongchou/底座.png

After

Width: 390  |  Height: 220  |  Size: 9.5 KiB

BIN
src/assets/img/zhongchou/手机bg.png

After

Width: 750  |  Height: 1624  |  Size: 177 KiB

BIN
src/assets/img/zhongchou/手机助力美股享实时数据.png

After

Width: 492  |  Height: 229  |  Size: 14 KiB

BIN
src/assets/img/zhongchou/手机周年庆装饰.png

After

Width: 571  |  Height: 225  |  Size: 109 KiB

BIN
src/assets/img/zhongchou/手机矩形.png

After

Width: 688  |  Height: 1051  |  Size: 20 KiB

BIN
src/assets/img/zhongchou/手机组2.png

After

Width: 622  |  Height: 938  |  Size: 134 KiB

BIN
src/assets/img/zhongchou/时间边框.png

After

Width: 578  |  Height: 58  |  Size: 831 B

BIN
src/assets/img/zhongchou/框.png

After

Width: 790  |  Height: 586  |  Size: 25 KiB

BIN
src/assets/img/zhongchou/活动需知.png

After

Width: 100  |  Height: 70  |  Size: 4.2 KiB

BIN
src/assets/img/zhongchou/浮窗.png

After

Width: 190  |  Height: 190  |  Size: 17 KiB

BIN
src/assets/img/zhongchou/港股.png

After

Width: 1369  |  Height: 812  |  Size: 185 KiB

BIN
src/assets/img/zhongchou/港股已助力.png

After

Width: 402  |  Height: 88  |  Size: 8.5 KiB

BIN
src/assets/img/zhongchou/火箭.png

After

Width: 219  |  Height: 586  |  Size: 29 KiB

BIN
src/assets/img/zhongchou/知道了.png

After

Width: 228  |  Height: 194  |  Size: 8.2 KiB

BIN
src/assets/img/zhongchou/美股.png

After

Width: 1319  |  Height: 773  |  Size: 243 KiB

BIN
src/assets/img/zhongchou/美股已助力.png

After

Width: 402  |  Height: 88  |  Size: 9.9 KiB

BIN
src/assets/img/待揭秘.png

Before

Width: 383  |  Height: 110  |  Size: 47 KiB

After

Width: 383  |  Height: 110  |  Size: 15 KiB

1
src/assets/vue.svg

@ -1 +0,0 @@
<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>

BIN
src/assets/登录背景.png

Before

Width: 5760  |  Height: 3240  |  Size: 867 KiB

After

Width: 5760  |  Height: 3240  |  Size: 251 KiB

285
src/auto-import.d.ts

@ -0,0 +1,285 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
const computed: typeof import('vue')['computed']
const computedAsync: typeof import('@vueuse/core')['computedAsync']
const computedEager: typeof import('@vueuse/core')['computedEager']
const computedInject: typeof import('@vueuse/core')['computedInject']
const computedWithControl: typeof import('@vueuse/core')['computedWithControl']
const controlledComputed: typeof import('@vueuse/core')['controlledComputed']
const controlledRef: typeof import('@vueuse/core')['controlledRef']
const createApp: typeof import('vue')['createApp']
const createEventHook: typeof import('@vueuse/core')['createEventHook']
const createGlobalState: typeof import('@vueuse/core')['createGlobalState']
const createInjectionState: typeof import('@vueuse/core')['createInjectionState']
const createReactiveFn: typeof import('@vueuse/core')['createReactiveFn']
const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable']
const createUnrefFn: typeof import('@vueuse/core')['createUnrefFn']
const customRef: typeof import('vue')['customRef']
const debouncedRef: typeof import('@vueuse/core')['debouncedRef']
const debouncedWatch: typeof import('@vueuse/core')['debouncedWatch']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
const effectScope: typeof import('vue')['effectScope']
const extendRef: typeof import('@vueuse/core')['extendRef']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
const inject: typeof import('vue')['inject']
const isDefined: typeof import('@vueuse/core')['isDefined']
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 makeDestructurable: typeof import('@vueuse/core')['makeDestructurable']
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 onClickOutside: typeof import('@vueuse/core')['onClickOutside']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onKeyStroke: typeof import('@vueuse/core')['onKeyStroke']
const onLongPress: typeof import('@vueuse/core')['onLongPress']
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 onStartTyping: typeof import('@vueuse/core')['onStartTyping']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
const provide: typeof import('vue')['provide']
const reactify: typeof import('@vueuse/core')['reactify']
const reactifyObject: typeof import('@vueuse/core')['reactifyObject']
const reactive: typeof import('vue')['reactive']
const reactiveComputed: typeof import('@vueuse/core')['reactiveComputed']
const reactiveOmit: typeof import('@vueuse/core')['reactiveOmit']
const reactivePick: typeof import('@vueuse/core')['reactivePick']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const refAutoReset: typeof import('@vueuse/core')['refAutoReset']
const refDebounced: typeof import('@vueuse/core')['refDebounced']
const refDefault: typeof import('@vueuse/core')['refDefault']
const refThrottled: typeof import('@vueuse/core')['refThrottled']
const refWithControl: typeof import('@vueuse/core')['refWithControl']
const resolveComponent: typeof import('vue')['resolveComponent']
const resolveRef: typeof import('@vueuse/core')['resolveRef']
const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const syncRef: typeof import('@vueuse/core')['syncRef']
const syncRefs: typeof import('@vueuse/core')['syncRefs']
const templateRef: typeof import('@vueuse/core')['templateRef']
const throttledRef: typeof import('@vueuse/core')['throttledRef']
const throttledWatch: typeof import('@vueuse/core')['throttledWatch']
const toRaw: typeof import('vue')['toRaw']
const toReactive: typeof import('@vueuse/core')['toReactive']
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 tryOnBeforeMount: typeof import('@vueuse/core')['tryOnBeforeMount']
const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount']
const tryOnMounted: typeof import('@vueuse/core')['tryOnMounted']
const tryOnScopeDispose: typeof import('@vueuse/core')['tryOnScopeDispose']
const tryOnUnmounted: typeof import('@vueuse/core')['tryOnUnmounted']
const unref: typeof import('vue')['unref']
const unrefElement: typeof import('@vueuse/core')['unrefElement']
const until: typeof import('@vueuse/core')['until']
const useActiveElement: typeof import('@vueuse/core')['useActiveElement']
const useArrayEvery: typeof import('@vueuse/core')['useArrayEvery']
const useArrayFilter: typeof import('@vueuse/core')['useArrayFilter']
const useArrayFind: typeof import('@vueuse/core')['useArrayFind']
const useArrayFindIndex: typeof import('@vueuse/core')['useArrayFindIndex']
const useArrayFindLast: typeof import('@vueuse/core')['useArrayFindLast']
const useArrayJoin: typeof import('@vueuse/core')['useArrayJoin']
const useArrayMap: typeof import('@vueuse/core')['useArrayMap']
const useArrayReduce: typeof import('@vueuse/core')['useArrayReduce']
const useArraySome: typeof import('@vueuse/core')['useArraySome']
const useArrayUnique: typeof import('@vueuse/core')['useArrayUnique']
const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue']
const useAsyncState: typeof import('@vueuse/core')['useAsyncState']
const useAttrs: typeof import('vue')['useAttrs']
const useBase64: typeof import('@vueuse/core')['useBase64']
const useBattery: typeof import('@vueuse/core')['useBattery']
const useBluetooth: typeof import('@vueuse/core')['useBluetooth']
const useBreakpoints: typeof import('@vueuse/core')['useBreakpoints']
const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel']
const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation']
const useCached: typeof import('@vueuse/core')['useCached']
const useClipboard: typeof import('@vueuse/core')['useClipboard']
const useCloned: typeof import('@vueuse/core')['useCloned']
const useColorMode: typeof import('@vueuse/core')['useColorMode']
const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog']
const useCounter: typeof import('@vueuse/core')['useCounter']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVar: typeof import('@vueuse/core')['useCssVar']
const useCssVars: typeof import('vue')['useCssVars']
const useCurrentElement: typeof import('@vueuse/core')['useCurrentElement']
const useCycleList: typeof import('@vueuse/core')['useCycleList']
const useDark: typeof import('@vueuse/core')['useDark']
const useDateFormat: typeof import('@vueuse/core')['useDateFormat']
const useDebounce: typeof import('@vueuse/core')['useDebounce']
const useDebounceFn: typeof import('@vueuse/core')['useDebounceFn']
const useDebouncedRefHistory: typeof import('@vueuse/core')['useDebouncedRefHistory']
const useDeviceMotion: typeof import('@vueuse/core')['useDeviceMotion']
const useDeviceOrientation: typeof import('@vueuse/core')['useDeviceOrientation']
const useDevicePixelRatio: typeof import('@vueuse/core')['useDevicePixelRatio']
const useDevicesList: typeof import('@vueuse/core')['useDevicesList']
const useDisplayMedia: typeof import('@vueuse/core')['useDisplayMedia']
const useDocumentVisibility: typeof import('@vueuse/core')['useDocumentVisibility']
const useDraggable: typeof import('@vueuse/core')['useDraggable']
const useDropZone: typeof import('@vueuse/core')['useDropZone']
const useElementBounding: typeof import('@vueuse/core')['useElementBounding']
const useElementByPoint: typeof import('@vueuse/core')['useElementByPoint']
const useElementHover: typeof import('@vueuse/core')['useElementHover']
const useElementSize: typeof import('@vueuse/core')['useElementSize']
const useElementVisibility: typeof import('@vueuse/core')['useElementVisibility']
const useEventBus: typeof import('@vueuse/core')['useEventBus']
const useEventListener: typeof import('@vueuse/core')['useEventListener']
const useEventSource: typeof import('@vueuse/core')['useEventSource']
const useEyeDropper: typeof import('@vueuse/core')['useEyeDropper']
const useFavicon: typeof import('@vueuse/core')['useFavicon']
const useFetch: typeof import('@vueuse/core')['useFetch']
const useFileDialog: typeof import('@vueuse/core')['useFileDialog']
const useFileSystemAccess: typeof import('@vueuse/core')['useFileSystemAccess']
const useFocus: typeof import('@vueuse/core')['useFocus']
const useFocusWithin: typeof import('@vueuse/core')['useFocusWithin']
const useFps: typeof import('@vueuse/core')['useFps']
const useFullscreen: typeof import('@vueuse/core')['useFullscreen']
const useGamepad: typeof import('@vueuse/core')['useGamepad']
const useGeolocation: typeof import('@vueuse/core')['useGeolocation']
const useId: typeof import('vue')['useId']
const useIdle: typeof import('@vueuse/core')['useIdle']
const useImage: typeof import('@vueuse/core')['useImage']
const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll']
const useIntersectionObserver: typeof import('@vueuse/core')['useIntersectionObserver']
const useInterval: typeof import('@vueuse/core')['useInterval']
const useIntervalFn: typeof import('@vueuse/core')['useIntervalFn']
const useKeyModifier: typeof import('@vueuse/core')['useKeyModifier']
const useLastChanged: typeof import('@vueuse/core')['useLastChanged']
const useLink: typeof import('vue-router')['useLink']
const useLocalStorage: typeof import('@vueuse/core')['useLocalStorage']
const useMagicKeys: typeof import('@vueuse/core')['useMagicKeys']
const useManualRefHistory: typeof import('@vueuse/core')['useManualRefHistory']
const useMediaControls: typeof import('@vueuse/core')['useMediaControls']
const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery']
const useMemoize: typeof import('@vueuse/core')['useMemoize']
const useMemory: typeof import('@vueuse/core')['useMemory']
const useModel: typeof import('vue')['useModel']
const useMounted: typeof import('@vueuse/core')['useMounted']
const useMouse: typeof import('@vueuse/core')['useMouse']
const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement']
const useMousePressed: typeof import('@vueuse/core')['useMousePressed']
const useMutationObserver: typeof import('@vueuse/core')['useMutationObserver']
const useNavigatorLanguage: typeof import('@vueuse/core')['useNavigatorLanguage']
const useNetwork: typeof import('@vueuse/core')['useNetwork']
const useNow: typeof import('@vueuse/core')['useNow']
const useObjectUrl: typeof import('@vueuse/core')['useObjectUrl']
const useOffsetPagination: typeof import('@vueuse/core')['useOffsetPagination']
const useOnline: typeof import('@vueuse/core')['useOnline']
const usePageLeave: typeof import('@vueuse/core')['usePageLeave']
const useParallax: typeof import('@vueuse/core')['useParallax']
const usePermission: typeof import('@vueuse/core')['usePermission']
const usePointer: typeof import('@vueuse/core')['usePointer']
const usePointerLock: typeof import('@vueuse/core')['usePointerLock']
const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe']
const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme']
const usePreferredContrast: typeof import('@vueuse/core')['usePreferredContrast']
const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark']
const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages']
const usePreferredReducedMotion: typeof import('@vueuse/core')['usePreferredReducedMotion']
const usePrevious: typeof import('@vueuse/core')['usePrevious']
const useRafFn: typeof import('@vueuse/core')['useRafFn']
const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter']
const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation']
const useScreenSafeArea: typeof import('@vueuse/core')['useScreenSafeArea']
const useScriptTag: typeof import('@vueuse/core')['useScriptTag']
const useScroll: typeof import('@vueuse/core')['useScroll']
const useScrollLock: typeof import('@vueuse/core')['useScrollLock']
const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage']
const useShare: typeof import('@vueuse/core')['useShare']
const useSlots: typeof import('vue')['useSlots']
const useSorted: typeof import('@vueuse/core')['useSorted']
const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition']
const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis']
const useStepper: typeof import('@vueuse/core')['useStepper']
const useStorage: typeof import('@vueuse/core')['useStorage']
const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync']
const useStyleTag: typeof import('@vueuse/core')['useStyleTag']
const useSupported: typeof import('@vueuse/core')['useSupported']
const useSwipe: typeof import('@vueuse/core')['useSwipe']
const useTemplateRef: typeof import('vue')['useTemplateRef']
const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList']
const useTextDirection: typeof import('@vueuse/core')['useTextDirection']
const useTextSelection: typeof import('@vueuse/core')['useTextSelection']
const useTextareaAutosize: typeof import('@vueuse/core')['useTextareaAutosize']
const useThrottle: typeof import('@vueuse/core')['useThrottle']
const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn']
const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory']
const useTimeAgo: typeof import('@vueuse/core')['useTimeAgo']
const useTimeout: typeof import('@vueuse/core')['useTimeout']
const useTimeoutFn: typeof import('@vueuse/core')['useTimeoutFn']
const useTimeoutPoll: typeof import('@vueuse/core')['useTimeoutPoll']
const useTimestamp: typeof import('@vueuse/core')['useTimestamp']
const useTitle: typeof import('@vueuse/core')['useTitle']
const useToNumber: typeof import('@vueuse/core')['useToNumber']
const useToString: typeof import('@vueuse/core')['useToString']
const useToggle: typeof import('@vueuse/core')['useToggle']
const useTransition: typeof import('@vueuse/core')['useTransition']
const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams']
const useUserMedia: typeof import('@vueuse/core')['useUserMedia']
const useVModel: typeof import('@vueuse/core')['useVModel']
const useVModels: typeof import('@vueuse/core')['useVModels']
const useVibrate: typeof import('@vueuse/core')['useVibrate']
const useVirtualList: typeof import('@vueuse/core')['useVirtualList']
const useWakeLock: typeof import('@vueuse/core')['useWakeLock']
const useWebNotification: typeof import('@vueuse/core')['useWebNotification']
const useWebSocket: typeof import('@vueuse/core')['useWebSocket']
const useWebWorker: typeof import('@vueuse/core')['useWebWorker']
const useWebWorkerFn: typeof import('@vueuse/core')['useWebWorkerFn']
const useWindowFocus: typeof import('@vueuse/core')['useWindowFocus']
const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll']
const useWindowSize: typeof import('@vueuse/core')['useWindowSize']
const watch: typeof import('vue')['watch']
const watchArray: typeof import('@vueuse/core')['watchArray']
const watchAtMost: typeof import('@vueuse/core')['watchAtMost']
const watchDebounced: typeof import('@vueuse/core')['watchDebounced']
const watchEffect: typeof import('vue')['watchEffect']
const watchIgnorable: typeof import('@vueuse/core')['watchIgnorable']
const watchOnce: typeof import('@vueuse/core')['watchOnce']
const watchPausable: typeof import('@vueuse/core')['watchPausable']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
const watchThrottled: typeof import('@vueuse/core')['watchThrottled']
const watchTriggerable: typeof import('@vueuse/core')['watchTriggerable']
const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter']
const whenever: typeof import('@vueuse/core')['whenever']
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue')
}

14
src/components.d.ts

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

2
src/style.css

@ -3,7 +3,7 @@
body {
margin: 0;
display: flex;
/* place-items: center; */
place-items: center;
min-width: 320px;
min-height: 100vh;
}

2
src/utils/prizeList.js

@ -1,4 +1,4 @@
import * as TWEEN from "./tween.min.js";
import TWEEN from "@tweenjs/tween.js";
const MAX_TOP = 300;
const MAX_WIDTH = document.body.clientWidth;

23
src/utils/request.js

@ -102,26 +102,11 @@ service.interceptors.request.use(
}
)
// Response interceptors
// 响应拦截器(简化版)
service.interceptors.response.use(
async (response) => {
// await new Promise(resovle => setTimeout(resovle, 3000));
// if (response.config.loadingInstance) {
// response.config.loadingInstance.close();
// }
const res = response.data
if (res.code !== 200) {
const errorMsg = res.msg || 'Unkonw error'
// ElMessage.error(errorMsg)
// return Promise.reject(new Error(res.msg || 'Error'))
return response.data
} else {
return response.data
}
},
(error) => {
const errorMessage = setErrorMsg(error)
ElMessage.error(errorMessage)
response => response.data,
error => {
ElMessage.error(error.message || '请求错误')
return Promise.reject(error)
}
)

50
src/views/choujiang/Login.vue

@ -3,13 +3,7 @@
<div class="login-card">
<form @submit.prevent="handleLogin">
<div class="form-group">
<input
type="password"
id="password"
v-model="password"
placeholder="请输入密码"
/>
<input type="password" id="password" v-model="password" placeholder="请输入密码" />
</div>
<button type="submit" class="login-button">进入抽奖</button>
</form>
@ -30,6 +24,11 @@ const handleLogin = () => {
alert('请输入密码');
return;
}
if (password.value == '000000') {
router.push('/hxlCj');
} else {
if (password.value === CORRECT_PASSWORD) {
//
authStore.login(); // 使Pinia
@ -37,6 +36,7 @@ const handleLogin = () => {
} else {
alert('密码错误,请重试');
}
}
};
//
console.log('登录信息:', {
@ -46,12 +46,16 @@ const handleLogin = () => {
</script>
<style scoped>
.login-container {
background-image: url('../../assets/登录背景.png'); /* 确保路径正确 */
background-image: url('../../assets/登录背景.png');
/* 确保路径正确 */
background-position: center;
background-size: cover;
height: 100vh; /* 确保背景图片覆盖整个视口高度 */
width: 100vw; /* 确保背景图片覆盖整个视口宽度 */
position: fixed; /* 使用fixed定位确保背景图片覆盖整个页面 */
height: 100vh;
/* 确保背景图片覆盖整个视口高度 */
width: 100vw;
/* 确保背景图片覆盖整个视口宽度 */
position: fixed;
/* 使用fixed定位确保背景图片覆盖整个页面 */
top: 0;
left: 0;
/* z-index: -1; 确保背景图片在其他内容下方 */
@ -62,14 +66,18 @@ const handleLogin = () => {
top: 55%;
left: 50%;
transform: translate(-50%, -50%);
width: 450px; /* 增加卡片宽度 */
width: 450px;
/* 增加卡片宽度 */
height: 285px;
padding: 2.5rem; /* 增加内边距 */
background: rgba(255, 255, 255, 0.3); /* 调整背景颜色为半透明白色 */
padding: 2.5rem;
/* 增加内边距 */
background: rgba(255, 255, 255, 0.3);
/* 调整背景颜色为半透明白色 */
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
box-sizing: border-box;
z-index: 1; /* 确保卡片在背景图片上方 */
z-index: 1;
/* 确保卡片在背景图片上方 */
}
input {
@ -77,19 +85,23 @@ input {
padding: 1.2rem;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 1.3rem; /* 增大字体大小 */
margin-bottom: 2.5rem; /* 增加底部间距 */
font-size: 1.3rem;
/* 增大字体大小 */
margin-bottom: 2.5rem;
/* 增加底部间距 */
box-sizing: border-box
}
.login-button {
width: 100%;
padding: 1.2rem; /* 增加按钮内边距 */
padding: 1.2rem;
/* 增加按钮内边距 */
background-color: #e92821a3;
color: white;
border: none;
border-radius: 4px;
font-size: 1.3rem; /* 增大字体大小 */
font-size: 1.3rem;
/* 增大字体大小 */
cursor: pointer;
transition: background-color 0.3s;
box-sizing: border-box

41
src/views/choujiang/hxl-cj/cj.vue

@ -24,7 +24,7 @@
>
<span></span><span></span><span></span><span></span>
<div class="prize-img">
<img :src="item.img" :alt="item.title" />
<img :src="item.imageUrl" :alt="item.title" />
</div>
<div class="prize-text">
<div class="prize-title">
@ -145,6 +145,7 @@ import { resetPrize } from "../../../utils/prizeList";
import { NUMBER_MATRIX } from "../../../utils/config";
import { CSS3DObject, CSS3DRenderer } from "../../../utils/CSS3DRenderer.js";
import { TrackballControls } from "../../../utils/TrackballControls.js";
import TWEEN from "@tweenjs/tween.js";
import {
getPrizeListApi,
@ -267,7 +268,7 @@ const closeGetPrize = () => {
};
//
const lookPrize = (item) => {
const lookPrize = async (item) => {
//
if (!joinLottery) {
addQipao("请先进入抽奖。");
@ -287,6 +288,7 @@ const lookPrize = (item) => {
item.isLook = true;
} else if (
!isLotting && //
currentPrize.value.isLook &&
currentPrize.value.leftCount == 0 && //
prizes.value[currentPrizeIndex - 1] == item //
) {
@ -315,6 +317,8 @@ const lookPrize = (item) => {
//
item.isLook = true;
}
await nextTick();
setPrizeData(currentPrizeIndex);
};
function setPrizeData(currentPrizeIndex, isInit) {
@ -345,7 +349,8 @@ function setPrizeData(currentPrizeIndex, isInit) {
}
}
// console.log("currentPrize", currentPrize);
console.log("count", count);
console.log("totalCount", totalCount);
let percent = (count / totalCount).toFixed(2);
if (elements.bar) {
@ -1370,7 +1375,7 @@ body,
width: 100%;
height: 100%;
display: flex;
background-image: url("../../../assets/img/bg.png");
background-image: url("../../../assets/bg@2x.png");
background-repeat: no-repeat;
background-size: 100% 100%;
justify-content: center;
@ -1586,12 +1591,15 @@ a {
overflow-y: auto;
/* 隐藏滚动条 */
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE */
scrollbar-width: none;
/* Firefox */
-ms-overflow-style: none;
/* IE */
}
#prizeBar::-webkit-scrollbar {
display: none; /* Chrome, Safari */
display: none;
/* Chrome, Safari */
}
.prize-list {
@ -1671,6 +1679,7 @@ a {
100% {
transform: rotate(180deg) translateY(0);
}
50% {
transform: rotate(180deg) translateY(-8px);
}
@ -1681,6 +1690,7 @@ a {
100% {
transform: translateY(0);
}
50% {
transform: translateY(-8px);
}
@ -1701,6 +1711,7 @@ a {
width: 50%;
text-align: center;
}
.tableHead2 {
width: 50%;
text-align: center;
@ -1727,15 +1738,20 @@ a {
width: 100%;
height: 54vh;
justify-content: center;
overflow-y: auto; /* 启用垂直滚动 */
overflow-x: hidden; /* 启用垂直滚动 */
overflow-y: auto;
/* 启用垂直滚动 */
overflow-x: hidden;
/* 启用垂直滚动 */
/* 隐藏滚动条 */
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE */
scrollbar-width: none;
/* Firefox */
-ms-overflow-style: none;
/* IE */
}
.tableBody::-webkit-scrollbar {
display: none; /* Chrome, Safari */
display: none;
/* Chrome, Safari */
}
.tableItem {
@ -1806,6 +1822,7 @@ a {
display: flex;
align-items: center;
}
.level {
width: 38%;
height: 100%;

23
src/views/choujiang/index.vue

@ -25,6 +25,12 @@
</div>
</div>
<div v-if="showPrizeExhaustedModal2" class="prize-exhausted-modal">
<div class="modal-content">
<p class="modal-text">该礼品已抽取完毕</p>
</div>
</div>
<!-- <UserList
:lucky-users="
dataManager.state.basicData.luckyUsers[
@ -56,6 +62,7 @@ const qipaoText = ref("");
const showQipao = ref(false);
const showPrizeExhaustedModal = ref(false);
const showPrizeExhaustedModal1 = ref(false);
const showPrizeExhaustedModal2 = ref(false);
// const lotteryState = ref('idle'); // idle, ready, rotating, result
@ -161,7 +168,7 @@ async function handleLotteryClick() {
break;
case "ready":
if (waitingForNextReveal.value || lastRevealed.value === 0) {
if (waitingForNextReveal.value) {
console.log("waitingForNextReveal.value", waitingForNextReveal.value);
//
showPrizeExhaustedModal.value = true;
@ -184,6 +191,20 @@ async function handleLotteryClick() {
break;
}
if (lastRevealed.value === 0 && dataManager.state.basicData.prizes[lastRevealed.value].remainNum === 0) {
// 0
// const currentPrize = dataManager.state.basicData.prizes[lastRevealed.value];
// if (currentPrize && currentPrize.remainNum === 0) {
showPrizeExhaustedModal2.value = true;
setTimeout(() => {
showPrizeExhaustedModal2.value = false;
}, 1000);
isDisabled.value = false;
break;
// }
}
console.log("lotteryState 变更前:", lotteryState.value, "-> rotating");
lotteryState.value = "rotating";
console.log("lotteryState 变更后:", lotteryState.value);

2
src/views/choujiang/lottery/CardItem.vue

@ -173,7 +173,7 @@ onBeforeUnmount(() => {
/* ... */
}
.details {
font-size: 26px;
font-size: 24px;
color: white;
text-align: center;
display: flex;

2
src/views/choujiang/lottery/Lottery3D.vue

@ -571,7 +571,7 @@ function changeCard(cardIndex, user) {
const username = user.username || user[1] || "";
const company = user.company || user[2] || "PSST";
card.innerHTML = `<div style="font-size: 30px; font-weight: bold; color: #ffffff; text-align: center; display: flex; justify-content: center; align-items: center; width: 100%; height: 100%;">${jwcode}</div>`;
card.innerHTML = `<div style="font-size: 20px; font-weight: bold; color: #ffffff; text-align: center; display: flex; justify-content: center; align-items: center; width: 100%; height: 100%;">${jwcode}</div>`;
//
card.classList.add("prize");

2
src/views/choujiang/lottery/PrizePanel.vue

@ -400,7 +400,7 @@ onMounted(() => {
gap: 18px;
max-height: 700px;
overflow-x: hidden !important;
overflow-y: auto;
/* overflow-y: auto; */
padding-right: 10px;
padding-left: 10px;
scrollbar-width: thin;

1365
src/views/zhongchou/index.vue
File diff suppressed because it is too large
View File

94
vite.config.js

@ -1,23 +1,83 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// import { defineConfig } from 'vite'
// import vue from '@vitejs/plugin-vue'
// import path from 'path'
// // https://vite.dev/config/
// // export default defineConfig({
// // plugins: [vue()],
// // })
// https://vite.dev/config/
// export default defineConfig({
// plugins: [vue()],
// plugins: [
// vue(),
// ],
// resolve: {
// alias: {
// '@': path.resolve(process.cwd(), 'src')
// }
// },
// server: {
// proxy: {
// '/Api': {
// target: 'https://dbqb.nfdxy.net/devLotApi',
// // target: 'http://localhost:8080',
// changeOrigin: true,
// rewrite: (path) => path.replace(/^\/Api/, '')
// }
// }
// }
// })
export default defineConfig({
plugins: [
vue(),
],
import { defineConfig, loadEnv } from "vite";
import pkg from "./package.json"; // 新增包信息导入
import dayjs from "dayjs"; // 新增时间库导入
import { fileURLToPath, URL } from "url"; // 新增路径处理模块
import { wrapperEnv } from "./build/utils";
import { createVitePlugins } from "./build/vite/plugin";
import { createProxy } from "./build/vite/proxy";
import { createBuild } from "./build/vite/build";
const { dependencies, devDependencies, name, version } = pkg;
// 应用信息
const __APP_INFO__ = {
pkg: { dependencies, devDependencies, name, version },
lastBuildTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
};
// https://vite.dev/config/
export default defineConfig(({ command, mode }) => {
// console.log('command', command)
const root = process.cwd(); // 当前工作目录
const isBuild = command === "build"; // 是否是构建 serve
const env = loadEnv(mode, root); // 加载env环境
// The boolean type read by loadEnv is a string. This function can be converted to boolean type
const viteEnv = wrapperEnv(env);
// console.log('viteEnv', viteEnv)
const { VITE_PUBLIC_PATH, VITE_OUTPUT_DIR } = viteEnv;
return {
base: VITE_PUBLIC_PATH,
root,
plugins: createVitePlugins(viteEnv, isBuild),
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
css: {
preprocessorOptions: {
scss: {
charset: false, // 避免出现: build时的 @charset 必须在第一行的警告
},
},
},
server: {
proxy: {
'/Api': {
target: 'https://dbqb.nfdxy.net/devLotApi',
// target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/Api/, '')
}
}
host: true,
proxy: createProxy(),
},
build: createBuild(viteEnv),
define: {
__APP_INFO__: JSON.stringify(__APP_INFO__),
}
})
};
});

98
修改完成总结.md

@ -1,98 +0,0 @@
# 抽奖逻辑修改完成总结
## 修改完成情况
✅ **已完成所有必要的修改**
## 修改文件清单
### 1. API接口层 (`src/api/API.js`)
- ✅ 新增 `drawLottery` 接口
- ✅ 支持传递奖项信息和轮次参数
### 2. 抽奖引擎 (`src/views/choujiang/lottery/lotteryEngine.js`)
- ✅ 修改 `executeLottery` 函数,每轮抽奖请求后端
- ✅ 添加错误处理机制,支持回退到前端随机抽奖
- ✅ 适配新的数据格式 `{ jwcode: "xxx", username: "xxx" }`
### 3. 数据管理器 (`src/views/choujiang/lottery/dataManager.js`)
- ✅ 使用真实用户数据替代假数据
- ✅ 确保数据格式与后端返回格式兼容
- ✅ 支持新旧两种数据格式
### 4. 3D显示组件 (`src/views/choujiang/lottery/Lottery3D.vue`)
- ✅ 修改 `changeCard` 函数,适配新的数据格式
- ✅ 支持显示 `jwcode``username` 字段
- ✅ 保持向后兼容性
### 5. 主抽奖页面 (`src/views/choujiang/index.vue`)
- ✅ 修改气泡提示逻辑,支持新的数据格式
- ✅ 确保中奖用户信息正确显示
## 核心功能
### 1. 后端抽奖接口
```javascript
// 请求参数
{
gradeName: "一等奖",
prizeName: "iPhone 15",
perWin: 5,
round: 1
}
// 返回数据
{
data: [
{ jwcode: "5412", username: "猪八戒22" },
{ jwcode: "45125", username: "宝玉" }
]
}
```
### 2. 错误处理机制
- 后端请求失败时自动回退到前端随机抽奖
- 确保抽奖功能不中断
- 提供详细的错误日志
### 3. 数据格式兼容性
- 支持新格式:`{ jwcode: "5412", username: "猪八戒22" }`
- 支持旧格式:`["5412", "猪八戒22", "PSST"]`
- 自动识别和适配不同格式
## 工作流程
1. **页面初始化** → 获取奖品列表和用户列表
2. **开始抽奖** → 用户点击抽奖按钮
3. **请求后端** → 发送抽奖请求,包含奖项信息和轮次
4. **获取结果** → 后端返回中奖用户列表
5. **显示动画** → 前端根据返回的中奖用户显示3D抽奖动画
6. **保存结果** → 将中奖用户保存到本地状态
## 测试建议
1. **正常流程测试**:验证完整的抽奖流程
2. **异常处理测试**:模拟后端接口异常
3. **数据格式测试**:验证新旧数据格式兼容性
4. **多轮抽奖测试**:验证轮次管理和奖品切换
5. **性能测试**:验证大量用户数据下的表现
## 部署注意事项
1. **后端接口**:确保实现 `/lottery/draw` 接口
2. **数据格式**:确保返回的数据格式符合要求
3. **错误处理**:建议后端提供详细的错误信息
4. **性能优化**:考虑大量并发抽奖请求的处理
## 后续优化建议
1. **缓存机制**:可以考虑缓存用户数据,减少重复请求
2. **实时更新**:可以考虑WebSocket实时更新中奖结果
3. **数据统计**:可以添加抽奖统计和分析功能
4. **界面优化**:可以根据实际需求优化3D动画效果
---
**修改完成时间**:2024年12月19日
**修改状态**:✅ 已完成
**测试状态**:🔄 待测试

92
抽奖逻辑修改说明.md

@ -1,92 +0,0 @@
# 抽奖逻辑修改说明
## 修改概述
本次修改将抽奖逻辑从前端随机抽奖改为每轮抽奖都请求后端获取中奖数据。
## 主要修改内容
### 1. API接口修改 (`src/api/API.js`)
新增了 `drawLottery` 接口,用于每轮抽奖时请求后端:
```javascript
export function drawLottery(data){
return request({
url: '/lottery/draw',
method: 'post',
data: {
gradeName: data.gradeName, // 奖项名称
prizeName: data.prizeName, // 奖品名称
perWin: data.perWin, // 每轮抽奖人数
round: data.round // 当前轮次
}
})
}
```
### 2. 抽奖引擎修改 (`src/views/choujiang/lottery/lotteryEngine.js`)
- 修改 `executeLottery` 函数,每轮抽奖都请求后端
- 后端返回数据格式:`{ data: [{ jwcode: "5412", username: "猪八戒22" }, ...] }`
- 添加了错误处理机制,如果后端请求失败会回退到前端随机抽奖
### 3. 数据管理器修改 (`src/views/choujiang/lottery/dataManager.js`)
- 使用真实的用户数据替代假数据
- 确保数据格式与后端返回格式兼容
- 用户数据格式:`{ jwcode: "5412", username: "猪八戒22", company: "公司名称" }`
### 4. 3D显示组件修改 (`src/views/choujiang/lottery/Lottery3D.vue`)
- 修改 `changeCard` 函数,适配新的数据格式
- 支持显示 `jwcode``username` 字段
## 后端接口要求
### 抽奖接口 `/lottery/draw`
**请求参数:**
```json
{
"gradeName": "一等奖",
"prizeName": "iPhone 15",
"perWin": 5,
"round": 1
}
```
**返回数据格式:**
```json
{
"data": [
{
"jwcode": "5412",
"username": "猪八戒22"
},
{
"jwcode": "45125",
"username": "宝玉"
}
]
}
```
## 工作流程
1. **初始化**:页面加载时获取奖品列表和用户列表
2. **开始抽奖**:用户点击抽奖按钮
3. **请求后端**:发送抽奖请求到后端,包含奖项信息和轮次
4. **获取结果**:后端返回中奖用户列表
5. **显示动画**:前端根据返回的中奖用户显示3D抽奖动画
6. **保存结果**:将中奖用户保存到本地状态
## 错误处理
如果后端抽奖接口请求失败,系统会自动回退到前端随机抽奖逻辑,确保抽奖功能不会中断。
## 兼容性
修改后的代码保持了与原有数据格式的兼容性,支持新旧两种数据格式:
- 新格式:`{ jwcode: "5412", username: "猪八戒22" }`
- 旧格式:`["5412", "猪八戒22", "PSST"]`

113
测试用例.md

@ -1,113 +0,0 @@
# 抽奖逻辑测试用例
## 测试环境准备
1. 确保后端服务正常运行
2. 确保以下接口可用:
- `/prize/list` - 获取奖品列表
- `/user/list` - 获取用户列表
- `/lottery/draw` - 抽奖接口(新增)
## 测试用例
### 测试用例1:正常抽奖流程
**测试步骤:**
1. 打开抽奖页面
2. 点击"进入抽奖"按钮
3. 点击"开始抽奖"按钮
4. 点击"结束抽奖"按钮
5. 观察抽奖结果
**预期结果:**
- 页面正常加载,显示奖品列表和用户卡片
- 抽奖动画正常播放
- 后端返回中奖用户数据
- 3D卡片正确显示中奖用户信息(jwcode和username)
### 测试用例2:后端接口异常处理
**测试步骤:**
1. 模拟后端抽奖接口返回错误
2. 执行抽奖流程
3. 观察系统行为
**预期结果:**
- 系统自动回退到前端随机抽奖逻辑
- 抽奖功能不中断
- 控制台显示错误日志
### 测试用例3:数据格式兼容性
**测试步骤:**
1. 使用新数据格式:`{ jwcode: "5412", username: "猪八戒22" }`
2. 使用旧数据格式:`["5412", "猪八戒22", "PSST"]`
3. 观察显示效果
**预期结果:**
- 两种数据格式都能正确显示
- 卡片内容包含jwcode和username信息
### 测试用例4:多轮抽奖
**测试步骤:**
1. 完成第一轮抽奖
2. 继续第二轮抽奖
3. 观察轮次信息是否正确传递
**预期结果:**
- 每轮抽奖都请求后端
- 轮次信息正确递增
- 中奖用户不重复
### 测试用例5:奖品切换
**测试步骤:**
1. 完成当前奖品的所有轮次抽奖
2. 观察是否自动切换到下一个奖品
3. 验证新奖品的抽奖逻辑
**预期结果:**
- 奖品自动切换
- 新奖品的抽奖参数正确传递
- 轮次重新开始计算
## 调试信息
在浏览器控制台中查看以下日志:
1. **用户数据加载:**
```
userList {data: Array(5)}
```
2. **抽奖请求:**
```
请求后端抽奖,参数: {gradeName: "一等奖", prizeName: "iPhone 15", perWin: 5, round: 1}
```
3. **后端返回结果:**
```
后端抽奖返回结果: {data: Array(5)}
后端返回的中奖用户: [{jwcode: "5412", username: "猪八戒22"}, ...]
```
4. **卡片选择:**
```
executeLottery - selectedCardIndex: [12, 34, 56, 78, 90]
executeLottery - currentLuckys: [{jwcode: "5412", username: "猪八戒22"}, ...]
```
## 常见问题排查
### 问题1:抽奖接口404错误
**解决方案:** 检查后端是否实现了 `/lottery/draw` 接口
### 问题2:数据格式不匹配
**解决方案:** 检查后端返回的数据格式是否符合 `{data: [{jwcode: "xxx", username: "xxx"}]}`
### 问题3:用户数据为空
**解决方案:** 检查 `/user/list` 接口是否正常返回数据
### 问题4:奖品数据为空
**解决方案:** 检查 `/prize/list` 接口是否正常返回数据
Loading…
Cancel
Save