diff --git a/README.md b/README.md index 987f22f..c4f2da1 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ - ✅获奖API的完善,用户可查看获奖记录 - ✅完善保底策略【为每个用户维护保底计数器,保底后清空计数器】 - ✅Web添加奖品详细信息,概率等信息的展示 -- ✅实现活动最近获奖记录展示榜【分库分表的聚合操作,整合ES】(前端还没写,找个时间补上) +- ✅实现活动最近获奖记录展示榜【分库分表的聚合操作,整合ES】 看这里!!!!!定时任务选用的xxl-job,但原版滥用xxl-job,存在多端口问题,每个服务的定时任务执行器都需要占用一个端口,当我们部署到类似与docker的容器中时,如果两个服务 执行器占用的端口一样就会产生端口冲突问题,我们需要主动为他们分配不同的端口,这非常不利于我们服务的水平扩容,所以我这里找了一个老哥修改的版本https://github.com/kdyzm/xxl-job @@ -63,12 +63,14 @@ yarn run dev 活动主界面 电脑端网页效果 -![](https://img-blog.csdnimg.cn/direct/7de9e313b6714ff295a3b84f5f587e09.png) +![](https://github.com/1321928757/static-resources/blob/main/PC1.png?raw=true) +![](https://github.com/1321928757/static-resources/blob/main/PC2.png?raw=true) 移动端网页效果 -![](https://img-blog.csdnimg.cn/direct/385be76b39504e6a8411452edbd96baf.png) -![](https://img-blog.csdnimg.cn/direct/4cff95ebde68493699ad38a0a8aedf96.png) -![](https://img-blog.csdnimg.cn/direct/f0ae21b949b348b789c4ce72013bb89c.png) +![](https://github.com/1321928757/static-resources/blob/main/PE1.jpg?raw=true) +前端获奖记录展示没有找到合适的组件(有一个上下滚动展示的,但是太吃性能了,就换成这个横向滚动库了),效果貌似也还行? +![](https://github.com/1321928757/static-resources/blob/main/PE2.jpg?raw=true) +![](https://github.com/1321928757/static-resources/blob/main/PE3.jpg?raw=true) ## 🫧项目架构 diff --git a/big-market-app/src/main/resources/application.yml b/big-market-app/src/main/resources/application.yml index 2b835c3..9798735 100644 --- a/big-market-app/src/main/resources/application.yml +++ b/big-market-app/src/main/resources/application.yml @@ -2,4 +2,4 @@ spring: config: name: big-market-app profiles: - active: local + active: cloud diff --git a/big-market-domain/src/main/java/cn/bugstack/domain/award/service/AwardService.java b/big-market-domain/src/main/java/cn/bugstack/domain/award/service/AwardService.java index 28b1188..76c27b0 100644 --- a/big-market-domain/src/main/java/cn/bugstack/domain/award/service/AwardService.java +++ b/big-market-domain/src/main/java/cn/bugstack/domain/award/service/AwardService.java @@ -44,7 +44,7 @@ public void saveUserAwardRecord(UserAwardRecordEntity userAwardRecordEntity) { syncRecordMessage.setAwardTitle(userAwardRecordEntity.getAwardTitle()); syncRecordMessage.setAwardTime(userAwardRecordEntity.getAwardTime()); syncRecordMessage.setOrderId(userAwardRecordEntity.getOrderId()); - syncRecordMessage.setOrderId(userAwardRecordEntity.getOrderId()); + syncRecordMessage.setActivityId(userAwardRecordEntity.getActivityId()); BaseEvent.EventMessage syncRecordMessageEventMessage = syncAwardRecordEvent.buildEventMessage(syncRecordMessage); // 3.构建发货消息任务对象 diff --git a/big-market-infrastructure/pom.xml b/big-market-infrastructure/pom.xml index 9635a50..743f7a1 100644 --- a/big-market-infrastructure/pom.xml +++ b/big-market-infrastructure/pom.xml @@ -50,7 +50,6 @@ cn.hutool hutool-all - 5.8.25 diff --git a/big-market-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/repository/AwardRepository.java b/big-market-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/repository/AwardRepository.java index 64fd1fb..296840f 100644 --- a/big-market-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/repository/AwardRepository.java +++ b/big-market-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/repository/AwardRepository.java @@ -14,12 +14,12 @@ import cn.bugstack.infrastructure.persistent.doc.UserAwardRecordDoc; import cn.bugstack.infrastructure.persistent.po.Task; import cn.bugstack.infrastructure.persistent.po.UserAwardRecord; -import cn.bugstack.infrastructure.persistent.redis.IRedisService; import cn.bugstack.middleware.db.router.strategy.IDBRouterStrategy; import cn.bugstack.types.enums.ResponseCode; import cn.bugstack.types.exception.AppException; import cn.bugstack.types.model.PageData; import cn.hutool.core.util.DesensitizedUtil; +import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson2.JSON; import lombok.extern.slf4j.Slf4j; import org.springframework.dao.DuplicateKeyException; @@ -160,7 +160,15 @@ public List queryLastestAwardingRecord(Long activityId, i // 1.查询数据 List userAwardRecordDocs = userAwardRecordIndex.queryLastestDocByActivityId(activityId, count); - // 2.数据转换,使用hutool工具对用户id脱敏,页可以引入缓存+定时任务来优化性能,但是及时性没有直接查询好 + // 2.使用hutool工具对用户id脱敏,可以引入缓存+定时任务来优化性能,但是及时性没有直接查询好 + for (UserAwardRecordDoc userAwardRecordDoc : userAwardRecordDocs) { + // 从第七位开始截取 TODO 这里暂时硬编码了,微信的openid很长,前六位相等,所以截取七位以后的,可以根据系统用户id情况改写这个 + String userid = StrUtil.subSuf(userAwardRecordDoc.getUserId(), 7); + // 数据脱敏 + userAwardRecordDoc.setUserId(DesensitizedUtil.idCardNum(userid, 5, 5)); + } + + // 3.数据转换 return userAwardRecordDocs.stream().map(userAwardRecordDoc -> UserAwardRecordEntity.builder() .userId(userAwardRecordDoc.getUserId()) .awardTitle(userAwardRecordDoc.getAwardTitle()) diff --git a/docs/dev-ops/app/docker-compose-1.0.yml b/docs/dev-ops/app/docker-compose-1.0.yml deleted file mode 100644 index 71442c6..0000000 --- a/docs/dev-ops/app/docker-compose-1.0.yml +++ /dev/null @@ -1,21 +0,0 @@ -# /usr/local/bin/docker-compose -f /docs/dev-ops/environment/environment-docker-compose-2.4.yml up -d -version: '3.8' -# docker-compose -f docker-compose-1.0.yml up -d -# 你需要修改system为你自身系统的仓库名 -services: - x-api-app: - image: system/big-market:1.0-SNAPSHOT - container_name: big-market - restart: on-failure - ports: - - "8091:8091" - environment: - - TZ=PRC - - SERVER_PORT=8091 - volumes: - - ./log:/data/log - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" \ No newline at end of file diff --git a/docs/dev-ops/app/start.sh b/docs/dev-ops/app/start.sh deleted file mode 100644 index b0ccb0d..0000000 --- a/docs/dev-ops/app/start.sh +++ /dev/null @@ -1,20 +0,0 @@ -CONTAINER_NAME=big-market -IMAGE_NAME=system/big-market:1.0-SNAPSHOT -PORT=8091 - -echo "容器部署开始 ${CONTAINER_NAME}" - -# 停止容器 -docker stop ${CONTAINER_NAME} - -# 删除容器 -docker rm ${CONTAINER_NAME} - -# 启动容器 -docker run --name ${CONTAINER_NAME} \ --p ${PORT}:${PORT} \ --d ${IMAGE_NAME} - -echo "容器部署成功 ${CONTAINER_NAME}" - -docker logs -f ${CONTAINER_NAME} \ No newline at end of file diff --git a/docs/dev-ops/app/stop.sh b/docs/dev-ops/app/stop.sh deleted file mode 100644 index 9ec9a69..0000000 --- a/docs/dev-ops/app/stop.sh +++ /dev/null @@ -1 +0,0 @@ -docker stop big-market \ No newline at end of file diff --git a/docs/dev-ops/environment/docker-compose.yml b/docs/dev-ops/environment/docker-compose.yml deleted file mode 100644 index 478ced5..0000000 --- a/docs/dev-ops/environment/docker-compose.yml +++ /dev/null @@ -1,99 +0,0 @@ -# 命令执行 docker-compose up -d -version: '3.9' -services: - mysql: - image: mysql:8.0.32 - container_name: mysql - command: --default-authentication-plugin=mysql_native_password - restart: always - environment: - TZ: Asia/Shanghai - # MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' # 可配置无密码,注意配置 SPRING_DATASOURCE_PASSWORD= - MYSQL_ROOT_PASSWORD: 123456 - # MYSQL_USER: xfg - # MYSQL_PASSWORD: RTry78@#ww - networks: - - my-network - depends_on: - - mysql-job-dbdata - ports: - - "13306:3306" - volumes: - - ./mysql/sql:/docker-entrypoint-initdb.d - healthcheck: - test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ] - interval: 5s - timeout: 10s - retries: 10 - start_period: 15s - volumes_from: - - mysql-job-dbdata - - # 自动加载数据 - mysql-job-dbdata: - image: alpine:3.18.2 - container_name: mysql-job-dbdata - volumes: - - /var/lib/mysql - - # phpmyadmin https://hub.docker.com/_/phpmyadmin - phpmyadmin: - image: phpmyadmin:5.2.1 - container_name: phpmyadmin - hostname: phpmyadmin - ports: - - 8899:80 - environment: - - PMA_HOST=mysql - - PMA_PORT=3306 - - MYSQL_ROOT_PASSWORD=123456 - depends_on: - mysql: - condition: service_healthy - networks: - - my-network - - # Redis - redis: - image: redis:6.2 - container_name: redis - restart: always - hostname: redis - privileged: true - ports: - - 16379:6379 - volumes: - - ./redis/redis.conf:/usr/local/etc/redis/redis.conf - command: redis-server /usr/local/etc/redis/redis.conf - networks: - - my-network - healthcheck: - test: [ "CMD", "redis-cli", "ping" ] - interval: 10s - timeout: 5s - retries: 3 - - # RedisAdmin https://github.com/joeferner/redis-commander - redis-admin: - image: spryker/redis-commander:0.8.0 - container_name: redis-admin - hostname: redis-commander - restart: always - ports: - - 8081:8081 - environment: - - REDIS_HOSTS=local:redis:6379 - - HTTP_USER=admin - - HTTP_PASSWORD=admin - - LANG=C.UTF-8 - - LANGUAGE=C.UTF-8 - - LC_ALL=C.UTF-8 - networks: - - my-network - depends_on: - redis: - condition: service_healthy - -networks: - my-network: - driver: bridge \ No newline at end of file diff --git a/docs/dev-ops/environment/redis/redis.conf b/docs/dev-ops/environment/redis/redis.conf deleted file mode 100644 index f6f3781..0000000 --- a/docs/dev-ops/environment/redis/redis.conf +++ /dev/null @@ -1,2 +0,0 @@ -bind 0.0.0.0 -port 6379 \ No newline at end of file diff --git a/docs/web/big-market-vue3/.env.dev b/docs/web/big-market-vue3/.env.dev index 5aa046b..4975745 100644 --- a/docs/web/big-market-vue3/.env.dev +++ b/docs/web/big-market-vue3/.env.dev @@ -1,3 +1,2 @@ VITE_MODE_NAME=development -VITE_API_HOST= "http://localhost:80" -# VITE_API_HOST='http://154.201.80.213:11111' +VITE_API_HOST= "http://localhost:11111" diff --git a/docs/web/big-market-vue3/.env.product b/docs/web/big-market-vue3/.env.product index 1ea6d49..af1561d 100644 --- a/docs/web/big-market-vue3/.env.product +++ b/docs/web/big-market-vue3/.env.product @@ -1,2 +1,2 @@ VITE_MODE_NAME=production -VITE_API_HOST='http://154.201.80.213:11111' \ No newline at end of file +VITE_API_HOST='http://服务ip:服务端口' \ No newline at end of file diff --git a/docs/web/big-market-vue3/package.json b/docs/web/big-market-vue3/package.json index 3dd0072..36cbeca 100644 --- a/docs/web/big-market-vue3/package.json +++ b/docs/web/big-market-vue3/package.json @@ -22,7 +22,9 @@ "pinia-plugin-persistedstate": "^3.2.1", "sass": "^1.75.0", "vue": "^3.2.47", - "vue-router": "^4.2.2" + "vue-router": "^4.2.2", + "vue3-marquee": "^4.2.0", + "vue3-seamless-scroll": "^2.0.1" }, "devDependencies": { "@vitejs/plugin-vue": "^4.1.0", diff --git a/docs/web/big-market-vue3/src/api/raffle.js b/docs/web/big-market-vue3/src/api/raffle.js index b45d830..f7a0687 100644 --- a/docs/web/big-market-vue3/src/api/raffle.js +++ b/docs/web/big-market-vue3/src/api/raffle.js @@ -44,4 +44,9 @@ export const userSignUp = () => { // 分页查询用户的获奖记录 export const queryPageAwardRecord = (pageRequest) => { return axiosClient.post(`/api/v1/raffle/award/query_page_award_record`, pageRequest) +} + +// 查询活动下最新的获奖记录,展示用 +export const queryLatestAwardRecord = (request) => { + return axiosClient.post(`/api/v1/raffle/award/query_activity_award_record`, request) } \ No newline at end of file diff --git a/docs/web/big-market-vue3/src/components/raffle/earingAwardBoard/EaringAwardBoard.vue b/docs/web/big-market-vue3/src/components/raffle/earingAwardBoard/EaringAwardBoard.vue new file mode 100644 index 0000000..c2628a0 --- /dev/null +++ b/docs/web/big-market-vue3/src/components/raffle/earingAwardBoard/EaringAwardBoard.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/docs/web/big-market-vue3/src/components/raffle/index.vue b/docs/web/big-market-vue3/src/components/raffle/index.vue index 09505ec..8c09271 100644 --- a/docs/web/big-market-vue3/src/components/raffle/index.vue +++ b/docs/web/big-market-vue3/src/components/raffle/index.vue @@ -6,6 +6,7 @@ import { queryUserAccountById, queryRuleWeightById, queryActivityById, + queryLatestAwardRecord, } from "@/api/raffle.js"; import { succesMsg, errorMsg, warnMsg } from "@/utils/remind.js"; import { topathReplace } from "@/utils/router.js"; @@ -18,6 +19,7 @@ import UserAccountInfo from "./userAccountInfo/UserAccountInfo.vue"; import SignUpBoard from "./signUpBoard/SignUpBoard.vue"; import MyAwards from "./myEarningAward/MyAwards.vue"; import ActivityDetail from "./activityDetail/ActivityDetail.vue"; +import EaringAwardBoard from "./earingAwardBoard/EaringAwardBoard.vue"; import emitter from "@/utils/mitt"; const route = useRoute(); @@ -40,6 +42,9 @@ const originPrizes = ref([]); // 用户抽奖权重信息 const ruleWeightInfo = ref({}); +// 当前活动的最新获奖记录 +const latestAwardRecords = ref([]); + // 加载动画,防止高频点击 const load_btn_query = ref(false); const load_btn_prepare = ref(false); @@ -169,6 +174,20 @@ const queryActivityInfo = async () => { } }; +// 查询当前活动的获奖记录 +const queryLatestRecordInfo = async () => { + const requestDto = { + activityId: activityInfo.value.activityId, + size: 20, + }; + const res = await queryLatestAwardRecord(requestDto); + if (res.code == "0000") { + latestAwardRecords.value = res.data; + } else { + // errorMsg(res.info); + } +}; + // 初始化函数 const init = () => { // 1.首先检查是否存在用户信息 @@ -182,6 +201,7 @@ const init = () => { queryRuleWeightInfo(); queryUserAccountInfo(); queryActivityAwards(); + queryLatestRecordInfo(); // 注册数据更新监听 emitter.on("updateActivityData", (param) => { @@ -242,6 +262,12 @@ init(); >
+

活动抽奖

+
+ +
- - - - -
@@ -334,6 +355,10 @@ init(); border-radius: 20px; font-weight: 550; background-color: rgba(195, 195, 195, 0.095); + h3{ + color: gray; + margin: 12px 0px 3px 0px; + } .lucky-canvas { display: flex; /* 启用 Flex 布局 */ justify-content: center; /* 水平居中 */ diff --git a/docs/web/big-market-vue3/src/components/raffle/raffleCanvas/RaffleCanvas.vue b/docs/web/big-market-vue3/src/components/raffle/raffleCanvas/RaffleCanvas.vue index 004291e..f02cd9b 100644 --- a/docs/web/big-market-vue3/src/components/raffle/raffleCanvas/RaffleCanvas.vue +++ b/docs/web/big-market-vue3/src/components/raffle/raffleCanvas/RaffleCanvas.vue @@ -86,7 +86,6 @@ const endCallback = (prize) => {
-

活动抽奖

{ // 延时一段时间后重新加载次数信息 setTimeout(() => { emitter.emit("updateAccountData", true); - }, 300) + }, 600) }else{ warnMsg(res.info) } diff --git a/docs/web/big-market-vue3/src/main.js b/docs/web/big-market-vue3/src/main.js index 09bea0c..866b49b 100644 --- a/docs/web/big-market-vue3/src/main.js +++ b/docs/web/big-market-vue3/src/main.js @@ -1,6 +1,9 @@ import { createApp } from 'vue' import './style/global.css' +// 滚动数据组件 +import Vue3Marquee from 'vue3-marquee' + // element-plus import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' @@ -25,6 +28,7 @@ const app = createApp(App) for (const [key, component] of Object.entries(ElementPlusIconsVue)) { app.component(key, component) } +app.use(Vue3Marquee) app.use(pinia) app.use(ElementPlus) app.use(router) diff --git a/docs/web/big-market-vue3/src/utils/time.js b/docs/web/big-market-vue3/src/utils/time.js index 6bd3d6e..fe62786 100644 --- a/docs/web/big-market-vue3/src/utils/time.js +++ b/docs/web/big-market-vue3/src/utils/time.js @@ -2,4 +2,49 @@ import dayjs from "dayjs"; export const formattedDate = (value) => { return dayjs(value).format("YYYY-MM-DD HH:mm:ss"); - }; \ No newline at end of file + }; + + // 时间格式化,将时间简短化,如两周前 +export const formatDate = (timestamp) => { + // 转换为时间戳 + const arrTimestamp = new Date(timestamp).getTime(); + // 定义时间单位 + const minute = 1000 * 60; + const hour = minute * 60; + const day = hour * 24; + const month = parseFloat((day * 30).toString()); + const now = new Date().getTime(); + const diffValue = now - arrTimestamp; + + // 如果本地时间反而小于变量时间 + if (diffValue < 0) { + return '不久前'; + } + // 计算差异时间的量级 + const monthC = diffValue / month; + const weekC = diffValue / (7 * day); + const dayC = diffValue / day; + const hourC = diffValue / hour; + const minC = diffValue / minute; + + if (monthC > 12) { + // 超过1年,直接显示年月日 + return (() => { + const date = new Date(timestamp); + return ( + date.getFullYear() + '年' + (date.getMonth() + 1) + '月' + date.getDate() + '号' + ); + })(); + } else if (monthC >= 1) { + return parseInt(monthC.toString()) + '月前'; + } else if (weekC >= 1) { + return parseInt(weekC.toString()) + '周前'; + } else if (dayC >= 1) { + return parseInt(dayC.toString()) + '天前'; + } else if (hourC >= 1) { + return parseInt(hourC.toString()) + '小时前'; + } else if (minC >= 1) { + return parseInt(minC.toString()) + '分钟前'; + } + return '刚刚'; +}; \ No newline at end of file diff --git a/docs/web/big-market-vue3/yarn.lock b/docs/web/big-market-vue3/yarn.lock index 199e3e1..0b23d93 100644 --- a/docs/web/big-market-vue3/yarn.lock +++ b/docs/web/big-market-vue3/yarn.lock @@ -765,6 +765,11 @@ source-map@~0.6.0: resolved "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +throttle-debounce@5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/throttle-debounce/-/throttle-debounce-5.0.0.tgz#a17a4039e82a2ed38a5e7268e4132d6960d41933" + integrity sha512-2iQTSgkkc1Zyk0MeVrt/3BvuOXYPl/R8Z0U2xxo9rjwNciaHDG3R+Lm6dh4EeUci49DanvBnuqI6jshoQQRGEg== + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -810,6 +815,18 @@ vue-router@^4.2.2: dependencies: "@vue/devtools-api" "^6.5.0" +vue3-marquee@^4.2.0: + version "4.2.0" + resolved "https://registry.npmmirror.com/vue3-marquee/-/vue3-marquee-4.2.0.tgz#7d2d1d3c1b516f11fdc3e7fa59dda6bd85c5425b" + integrity sha512-Ij4iyvHZjTHMrsPqblpJjq6TYbEFq3utihUllAOfuy0E6W2QKX1vX4E7e7qV/ShmHbCbG0pljcEDq3y0FtzBGw== + +vue3-seamless-scroll@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/vue3-seamless-scroll/-/vue3-seamless-scroll-2.0.1.tgz#7b2d44afe94d545a2fe4affe8f81b884fc713268" + integrity sha512-mI3BaDU3pjcPUhVSw3/xNKdfPBDABTi/OdZaZqKysx4cSdNfGRbVvGNDzzptBbJ5S7imv5T55l6x/SqgnxKreg== + dependencies: + throttle-debounce "5.0.0" + vue@^3.2.47: version "3.3.4" resolved "https://registry.npmmirror.com/vue/-/vue-3.3.4.tgz" diff --git a/pom.xml b/pom.xml index 6b0ba5d..c914d78 100644 --- a/pom.xml +++ b/pom.xml @@ -146,7 +146,7 @@ cn.hutool hutool-all - 5.5.1 + 5.8.16