From 3c54ed79d4821a96d7670a3eec8aef234ec99459 Mon Sep 17 00:00:00 2001 From: zhangsan <646228430@qq.com> Date: Sat, 19 Jul 2025 14:15:59 +0800 Subject: [PATCH] =?UTF-8?q?7.19=20=E9=85=8D=E7=BD=AERabbitMq?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/dev-ops/mysql/sql/0716paymall.sql | 10 +++ docs/dev-ops/nginx/html/css/index.css | 13 +++- docs/dev-ops/nginx/html/js/index.js | 74 +++++++++++++------ pay-mall-app/pom.xml | 5 +- .../java/edu/whut/config/RabbitMQConfig.java | 31 ++++++++ .../src/main/resources/application-dev.yml | 22 ++++++ .../src/main/resources/application.yml | 2 +- pay-mall-trigger/pom.xml | 5 +- .../listener/TeamSuccessTopicListener.java | 32 ++++++++ pom.xml | 6 ++ 10 files changed, 173 insertions(+), 27 deletions(-) create mode 100644 pay-mall-app/src/main/java/edu/whut/config/RabbitMQConfig.java create mode 100644 pay-mall-trigger/src/main/java/edu/whut/trigger/listener/TeamSuccessTopicListener.java diff --git a/docs/dev-ops/mysql/sql/0716paymall.sql b/docs/dev-ops/mysql/sql/0716paymall.sql index 85d7701..52cfb98 100644 --- a/docs/dev-ops/mysql/sql/0716paymall.sql +++ b/docs/dev-ops/mysql/sql/0716paymall.sql @@ -13,6 +13,16 @@ Date: 16/07/2025 17:08:44 */ +-- 如果存在就删除 +DROP DATABASE IF EXISTS `pay-mall`; + +-- 创建(如需指定字符集与排序规则,可自行调整) +CREATE DATABASE IF NOT EXISTS `group_buying_sys` + DEFAULT CHARACTER SET utf8mb4 + COLLATE utf8mb4_unicode_ci; + +-- 切换到该库 +USE `pay-mall`; SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; diff --git a/docs/dev-ops/nginx/html/css/index.css b/docs/dev-ops/nginx/html/css/index.css index 7ec93be..f35e1f4 100644 --- a/docs/dev-ops/nginx/html/css/index.css +++ b/docs/dev-ops/nginx/html/css/index.css @@ -14,7 +14,7 @@ body{ /* ========== 轮播图 ========== */ .swiper-container{ - width:100%;height:375px;position:relative;overflow:hidden; + width:100%;height:375px;position:relative;overflow:hidden;margin-top: 10px; } .swiper-wrapper{display:flex;transition:transform .3s;} .swiper-slide{flex:0 0 100%;height:375px;} @@ -62,7 +62,14 @@ body{ } /* ========== 拼单列表 ========== */ -.group-buying{background:#fff;padding:15px;margin-bottom:10px;position:relative;overflow:hidden;} +.group-buying { + background: #fff; + padding: 15px; + margin-bottom: 10px; /* 如果还想保留一点外边距 */ + min-height: 230px; /* 根据需要调整数值 */ + position: relative; + overflow: hidden; +} .section-title{ font-size:16px;font-weight:bold;margin-bottom:12px;position:relative;padding-left:10px; } @@ -71,7 +78,7 @@ body{ width:3px;height:16px;background:#ff5000;border-radius:2px; } -.group-users{height:120px;position:relative;overflow:hidden;} +.group-users{height:180px;position:relative;overflow:hidden;} .user-list{position:absolute;top:0;left:0;width:100%;transition:transform .5s ease;} .user-item{ diff --git a/docs/dev-ops/nginx/html/js/index.js b/docs/dev-ops/nginx/html/js/index.js index 387a64e..e899bf2 100644 --- a/docs/dev-ops/nginx/html/js/index.js +++ b/docs/dev-ops/nginx/html/js/index.js @@ -25,7 +25,7 @@ document.addEventListener('DOMContentLoaded', () => { /* ===================================================== * 1. 取接口数据并渲染 * =================================================== */ - const CFG_API = 'http://127.0.0.1:8091/api/v1/gbm/index/query_group_buy_market_config'; + const CFG_API = '/api/v1/gbm/index/query_group_buy_market_config'; // 登录检查 const loginToken = getCookie('loginToken'); @@ -86,7 +86,7 @@ document.addEventListener('DOMContentLoaded', () => { } userList.innerHTML = ''; list.forEach(t => userList.appendChild(makeItem(t, groupPrice))); - initUserMarquee(); + initUserMarquee(3); // 显示 3 条 initCountdown(); } @@ -137,28 +137,61 @@ document.addEventListener('DOMContentLoaded', () => { /* ===================================================== * 2. 拼单列表纵向轮播 * =================================================== */ - function initUserMarquee() { - const items = userList.querySelectorAll('.user-item'); - if (items.length <= 1) return; + function initUserMarquee(visibleCount = 3, interval = 3000, duration = 500) { + const box = document.querySelector('.group-users'); + const listEl = userList; + let originals = Array.from(listEl.children); + const total = originals.length; - const itemH = items[0].offsetHeight; - userList.appendChild(items[0].cloneNode(true)); + if (total === 0) return; + // 如果原本就 <= 可见数,直接定高,不滚 + if (total <= visibleCount) { + const h0 = originals[0].offsetHeight; + box.style.height = (h0 * visibleCount) + 'px'; + return; + } - let idx = 0; - userList.addEventListener('transitionend', () => { - if (idx >= items.length) { - userList.style.transition = 'none'; - userList.style.transform = 'translateY(0)'; - idx = 0; - void userList.offsetWidth; + // 1. 复制整份加入末尾 + originals.forEach(item => listEl.appendChild(item.cloneNode(true))); + + // 2. 重新测量单条高度(此时 DOM 完整) + const itemH = listEl.children[0].offsetHeight; + + // 3. 设定窗口高度 + box.style.height = (itemH * visibleCount) + 'px'; + + // 4. 状态 + let index = 0; + let ticking = false; + + function step() { + index++; + listEl.style.transition = `transform ${duration}ms ease`; + listEl.style.transform = `translateY(-${index * itemH}px)`; + } + + listEl.addEventListener('transitionend', () => { + ticking = false; + // 5. 到达复制段的“第一帧”(index === total)就无缝重置 + if (index === total) { + listEl.style.transition = 'none'; + listEl.style.transform = 'translateY(0)'; + index = 0; + // 强制 reflow 再恢复 transition + void listEl.offsetHeight; + listEl.style.transition = `transform ${duration}ms ease`; } }); - setInterval(() => { - idx++; - userList.style.transition = 'transform .5s ease'; - userList.style.transform = `translateY(${-idx * itemH}px)`; - }, 3000); + const timer = setInterval(() => { + if (!ticking) { + ticking = true; + step(); + } + }, interval); + + // 可选:鼠标悬停暂停 + listEl.addEventListener('mouseenter', () => clearInterval(timer)); } /* ===================================================== @@ -202,8 +235,7 @@ document.addEventListener('DOMContentLoaded', () => { /* ===================================================== * 4. 支付相关 * =================================================== */ - const PAY_MALL_URL = 'http://127.0.0.1:8092'; - const CREATE_PAY_API = `${PAY_MALL_URL}/api/v1/alipay/create_pay_order`; + const CREATE_PAY_API = `/api/v1/alipay/create_pay_order`; // 4.1 支付确认弹窗 function showPaymentConfirm(price){ diff --git a/pay-mall-app/pom.xml b/pay-mall-app/pom.xml index e0fa5ad..99d1aa5 100644 --- a/pay-mall-app/pom.xml +++ b/pay-mall-app/pom.xml @@ -78,7 +78,10 @@ converter-gson 2.9.0 - + + org.springframework.boot + spring-boot-starter-amqp + edu.whut diff --git a/pay-mall-app/src/main/java/edu/whut/config/RabbitMQConfig.java b/pay-mall-app/src/main/java/edu/whut/config/RabbitMQConfig.java new file mode 100644 index 0000000..b0b144c --- /dev/null +++ b/pay-mall-app/src/main/java/edu/whut/config/RabbitMQConfig.java @@ -0,0 +1,31 @@ +package edu.whut.config; + +import org.springframework.amqp.core.Binding; +import org.springframework.amqp.core.BindingBuilder; +import org.springframework.amqp.core.Queue; +import org.springframework.amqp.core.TopicExchange; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class RabbitMQConfig { + + /** + * 消费拼团消息 + */ + @Bean + public Binding topicTeamSuccessBinding( + @Value("${spring.rabbitmq.config.consumer.topic_team_success.exchange}") String exchangeName, + @Value("${spring.rabbitmq.config.consumer.topic_team_success.routing_key}") String routingKey, + @Value("${spring.rabbitmq.config.consumer.topic_team_success.queue}") String queue) { + + // 消息生产方的交换机 + TopicExchange topicExchange = new TopicExchange(exchangeName, true, false); + + return BindingBuilder.bind(new Queue(queue, true)) + .to(topicExchange) + .with(routingKey); + } + +} diff --git a/pay-mall-app/src/main/resources/application-dev.yml b/pay-mall-app/src/main/resources/application-dev.yml index 593e3d6..ab6497b 100644 --- a/pay-mall-app/src/main/resources/application-dev.yml +++ b/pay-mall-app/src/main/resources/application-dev.yml @@ -43,6 +43,28 @@ spring: connection-timeout: 30000 #数据库连接超时时间,默认30秒,即30000 connection-test-query: SELECT 1 type: com.zaxxer.hikari.HikariDataSource + # RabbitMQ + rabbitmq: + addresses: 192.168.10.218 + port: 5672 + username: admin + password: admin + listener: + simple: + prefetch: 1 # 每次投递n个消息,消费完在投递n个 + template: + delivery-mode: persistent # 确保全局默认设置为持久化(可选) + # 消息配置 + config: + consumer: + # 消费 topic 主题,team_success + topic_team_success: + # 绑定交换机 - 消息提供者的交换机 + exchange: group_buy_market_exchange + # 消息主题 + routing_key: topic.team_success + # 消费队列 - 每个系统有自己的消费队列 + queue: pay_mall_queue_2_topic_team_success # MyBatis 配置【如需使用记得打开】 mybatis: diff --git a/pay-mall-app/src/main/resources/application.yml b/pay-mall-app/src/main/resources/application.yml index 999d6e4..7f350e7 100644 --- a/pay-mall-app/src/main/resources/application.yml +++ b/pay-mall-app/src/main/resources/application.yml @@ -1,3 +1,3 @@ spring: profiles: - active: prod,local + active: dev,local diff --git a/pay-mall-trigger/pom.xml b/pay-mall-trigger/pom.xml index 0862007..62c586b 100644 --- a/pay-mall-trigger/pom.xml +++ b/pay-mall-trigger/pom.xml @@ -26,7 +26,10 @@ org.apache.commons commons-lang3 - + + org.springframework.boot + spring-boot-starter-amqp + edu.whut diff --git a/pay-mall-trigger/src/main/java/edu/whut/trigger/listener/TeamSuccessTopicListener.java b/pay-mall-trigger/src/main/java/edu/whut/trigger/listener/TeamSuccessTopicListener.java new file mode 100644 index 0000000..fff155b --- /dev/null +++ b/pay-mall-trigger/src/main/java/edu/whut/trigger/listener/TeamSuccessTopicListener.java @@ -0,0 +1,32 @@ +package edu.whut.trigger.listener; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.ExchangeTypes; +import org.springframework.amqp.rabbit.annotation.Exchange; +import org.springframework.amqp.rabbit.annotation.Queue; +import org.springframework.amqp.rabbit.annotation.QueueBinding; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.stereotype.Component; + +/** + * 结算完成消息监听 + */ +@Slf4j +@Component +public class TeamSuccessTopicListener { + + /** + * 指定消费队列 + */ + @RabbitListener( + bindings = @QueueBinding( + value = @Queue(value = "${spring.rabbitmq.config.consumer.topic_team_success.queue}"), + exchange = @Exchange(value = "${spring.rabbitmq.config.consumer.topic_team_success.exchange}", type = ExchangeTypes.TOPIC), + key = "${spring.rabbitmq.config.consumer.topic_team_success.routing_key}" + ) + ) + public void listener(String message) { + log.info("接收消息:{}", message); + } + +} diff --git a/pom.xml b/pom.xml index 5250d11..d882b51 100644 --- a/pom.xml +++ b/pom.xml @@ -141,6 +141,12 @@ hutool-all 5.8.26 + + + org.springframework.boot + spring-boot-starter-amqp + 3.2.0 + edu.whut