7.8 调整前端数据请求,动态加载后端数据;构建镜像部署云服务器
This commit is contained in:
parent
6ebd80a6c8
commit
88f74950bc
@ -1,27 +1,132 @@
|
|||||||
# /usr/local/bin/docker-compose -f /docs/dev-ops/environment/environment-docker-compose-2.4.yml up -d
|
|
||||||
version: '3.8'
|
version: '3.8'
|
||||||
# docker-compose -f docker-compose-app.yml up -d
|
|
||||||
# 你需要修改system为你自身系统的仓库名
|
|
||||||
services:
|
|
||||||
group-buying-sys:
|
|
||||||
image: system/group-buying-sys:1.0-SNAPSHOT
|
|
||||||
container_name: group-buying-sys
|
|
||||||
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"
|
|
||||||
networks:
|
|
||||||
- my-network
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
my-network:
|
my-network:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
|
||||||
|
services:
|
||||||
|
# 1. 前端
|
||||||
|
group-buy-market-front:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: group-buy-market-front
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- '80:80'
|
||||||
|
- '443:443'
|
||||||
|
volumes:
|
||||||
|
- ./nginx/html:/usr/share/nginx/html
|
||||||
|
privileged: true
|
||||||
|
networks:
|
||||||
|
- my-network
|
||||||
|
|
||||||
|
# 2. MySQL
|
||||||
|
mysql:
|
||||||
|
image: mysql:8.0
|
||||||
|
container_name: mysql
|
||||||
|
command: --default-authentication-plugin=mysql_native_password
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
TZ: Asia/Shanghai
|
||||||
|
MYSQL_ROOT_PASSWORD: 123456
|
||||||
|
ports:
|
||||||
|
- '13306:3306' # 宿主机访问用 13306
|
||||||
|
volumes:
|
||||||
|
- ./mysql/my.cnf:/etc/mysql/conf.d/mysql.cnf:ro
|
||||||
|
- ./mysql/sql:/docker-entrypoint-initdb.d
|
||||||
|
healthcheck:
|
||||||
|
test: ['CMD', 'mysqladmin', 'ping', '-h', 'localhost']
|
||||||
|
interval: 5s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 10
|
||||||
|
start_period: 15s
|
||||||
|
networks:
|
||||||
|
- my-network
|
||||||
|
|
||||||
|
# 3. Redis
|
||||||
|
redis:
|
||||||
|
image: redis:6.2
|
||||||
|
container_name: redis
|
||||||
|
restart: always
|
||||||
|
hostname: redis
|
||||||
|
ports:
|
||||||
|
- '16379:6379' # 宿主机访问用 16379
|
||||||
|
volumes:
|
||||||
|
- ./redis/redis.conf:/usr/local/etc/redis/redis.conf
|
||||||
|
command: redis-server /usr/local/etc/redis/redis.conf
|
||||||
|
healthcheck:
|
||||||
|
test: ['CMD', 'redis-cli', 'ping']
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
networks:
|
||||||
|
- my-network
|
||||||
|
|
||||||
|
# 4. Java 后端
|
||||||
|
group-buying-sys:
|
||||||
|
image: smile/group-buying-sys
|
||||||
|
container_name: group-buying-sys
|
||||||
|
restart: on-failure
|
||||||
|
depends_on:
|
||||||
|
mysql:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
ports:
|
||||||
|
- '8091:8091'
|
||||||
|
environment:
|
||||||
|
# 时区 & 端口
|
||||||
|
- TZ=PRC
|
||||||
|
- SERVER_PORT=8091
|
||||||
|
# —— MySQL ——
|
||||||
|
- SPRING_DATASOURCE_USERNAME=root
|
||||||
|
- SPRING_DATASOURCE_PASSWORD=123456
|
||||||
|
- SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/big_market?useUnicode=true&characterEncoding=utf8&autoReconnect=true&serverTimezone=Asia/Shanghai&useSSL=false
|
||||||
|
- SPRING_DATASOURCE_DRIVER_CLASS_NAME=com.mysql.cj.jdbc.Driver
|
||||||
|
- SPRING_HIKARI_POOL_NAME=Retail_HikariCP
|
||||||
|
# —— Redis ——
|
||||||
|
- REDIS_SDK_CONFIG_HOST=redis
|
||||||
|
- REDIS_SDK_CONFIG_PORT=6379
|
||||||
|
volumes:
|
||||||
|
- ./log:/data/log
|
||||||
|
logging:
|
||||||
|
driver: json-file
|
||||||
|
options:
|
||||||
|
max-size: '10m'
|
||||||
|
max-file: '3'
|
||||||
|
networks:
|
||||||
|
- my-network
|
||||||
|
|
||||||
|
# 5. phpMyAdmin
|
||||||
|
phpmyadmin:
|
||||||
|
image: phpmyadmin:5.2.1
|
||||||
|
container_name: phpmyadmin
|
||||||
|
hostname: phpmyadmin
|
||||||
|
depends_on:
|
||||||
|
mysql:
|
||||||
|
condition: service_healthy
|
||||||
|
ports:
|
||||||
|
- '8899:80'
|
||||||
|
environment:
|
||||||
|
- PMA_HOST=mysql
|
||||||
|
- PMA_PORT=3306
|
||||||
|
- MYSQL_ROOT_PASSWORD=123456
|
||||||
|
networks:
|
||||||
|
- my-network
|
||||||
|
|
||||||
|
# 6. Redis Commander
|
||||||
|
redis-admin:
|
||||||
|
image: spryker/redis-commander:0.8.0
|
||||||
|
container_name: redis-admin
|
||||||
|
hostname: redis-commander
|
||||||
|
restart: always
|
||||||
|
depends_on:
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
ports:
|
||||||
|
- '8081:8081'
|
||||||
|
environment:
|
||||||
|
- REDIS_HOSTS=local:redis:6379
|
||||||
|
- HTTP_USER=admin
|
||||||
|
- HTTP_PASSWORD=admin
|
||||||
|
networks:
|
||||||
|
- my-network
|
||||||
|
@ -12,6 +12,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "13306:3306"
|
- "13306:3306"
|
||||||
volumes:
|
volumes:
|
||||||
|
- ./mysql/my.cnf:/etc/mysql/conf.d/mysql.cnf:ro
|
||||||
- ./mysql/sql:/docker-entrypoint-initdb.d
|
- ./mysql/sql:/docker-entrypoint-initdb.d
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
|
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
version: '3.9'
|
version: '3.8'
|
||||||
services:
|
services:
|
||||||
mysql:
|
mysql:
|
||||||
image: mysql:8.0
|
image: mysql:8.0
|
||||||
@ -11,6 +11,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "13306:3306"
|
- "13306:3306"
|
||||||
volumes:
|
volumes:
|
||||||
|
- ./mysql/my.cnf:/etc/mysql/conf.d/mysql.cnf:ro
|
||||||
- ./mysql/sql:/docker-entrypoint-initdb.d
|
- ./mysql/sql:/docker-entrypoint-initdb.d
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
|
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
|
||||||
|
24
docs/dev-ops/mysql/my.cnf
Normal file
24
docs/dev-ops/mysql/my.cnf
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
[client]
|
||||||
|
port = 3306
|
||||||
|
default-character-set = utf8mb4
|
||||||
|
|
||||||
|
[mysqld]
|
||||||
|
user = mysql
|
||||||
|
port = 3306
|
||||||
|
sql_mode = NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
|
||||||
|
|
||||||
|
default-storage-engine = InnoDB
|
||||||
|
default-authentication-plugin = mysql_native_password
|
||||||
|
character-set-server = utf8mb4
|
||||||
|
collation-server = utf8mb4_unicode_ci
|
||||||
|
init_connect = 'SET NAMES utf8mb4'
|
||||||
|
|
||||||
|
slow_query_log
|
||||||
|
#long_query_time = 3
|
||||||
|
slow-query-log-file = /var/log/mysql/mysql.slow.log
|
||||||
|
log-error = /var/log/mysql/mysql.error.log
|
||||||
|
|
||||||
|
default-time-zone = '+8:00'
|
||||||
|
|
||||||
|
[mysql]
|
||||||
|
default-character-set = utf8mb4
|
@ -1,140 +1,83 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="zh-CN">
|
<html lang="zh-CN">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
<title>手写MyBatis:渐进式源码实践 - 拼多多</title>
|
<title>手写 MyBatis:渐进式源码实践 - 拼多多</title>
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
||||||
<link rel="stylesheet" href="css/index.css">
|
<!-- 现成样式 -->
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" />
|
||||||
|
<link rel="stylesheet" href="css/index.css" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<!-- 顶部轮播图 -->
|
<!-- 顶部轮播图 -->
|
||||||
<div class="swiper-container">
|
<div class="swiper-container">
|
||||||
<div class="swiper-wrapper">
|
<div class="swiper-wrapper">
|
||||||
<div class="swiper-slide"><img src="images/goods_info2.png"></div>
|
<div class="swiper-slide"><img src="images/goods_info2.png" /></div>
|
||||||
<div class="swiper-slide"><img src="images/goods_info3.png"></div>
|
<div class="swiper-slide"><img src="images/goods_info3.png" /></div>
|
||||||
<div class="swiper-slide"><img src="images/goods_info1.png"></div>
|
<div class="swiper-slide"><img src="images/goods_info1.png" /></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="swiper-pagination"></div>
|
<div class="swiper-pagination"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 商品信息区域 -->
|
<!-- 商品信息 -->
|
||||||
<div class="product-info">
|
<div class="product-info">
|
||||||
<div class="price-row">
|
<div class="price-row">
|
||||||
<div class="current-price">80</div>
|
<div class="current-price" id="currentPrice"></div>
|
||||||
<div class="original-price">100</div>
|
<div class="original-price" id="originalPrice"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="title">手写MyBatis:渐进式源码实践(全彩)</div>
|
|
||||||
|
<!-- 标题写死即可,如需从接口取也可在 JS 中替换 -->
|
||||||
|
<div class="title" id="goodsTitle">手写 MyBatis:渐进式源码实践(全彩)</div>
|
||||||
|
|
||||||
<div class="promo-row">
|
<div class="promo-row">
|
||||||
<span class="promo-tag">大促优惠</span>
|
<span class="promo-tag">大促优惠</span>
|
||||||
<!-- 直降价 -->
|
<span class="promo-box drop" id="dropPrice"></span>
|
||||||
<span class="promo-box drop">直降 ¥60</span>
|
|
||||||
<!-- 已抢件数,由 JS 动态写入 -->
|
|
||||||
<span class="promo-box sold" id="soldBox"></span>
|
<span class="promo-box sold" id="soldBox"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 拼单区域 - 修改了高度 -->
|
<!-- 拼单区域 -->
|
||||||
<div class="group-buying">
|
<div class="group-buying">
|
||||||
<div class="section-title" id="groupTitle"></div>
|
<div class="section-title" id="groupTitle"></div>
|
||||||
|
|
||||||
<div class="group-users">
|
<div class="group-users">
|
||||||
<div class="user-list" id="userList">
|
<!-- 列表由 JS 动态注入 -->
|
||||||
<div class="user-item">
|
<div class="user-list" id="userList"></div>
|
||||||
<div class="user-avatar">
|
|
||||||
<i class="fas fa-user"></i>
|
|
||||||
</div>
|
|
||||||
<div class="user-info">
|
|
||||||
<div class="user-name">宇哥</div>
|
|
||||||
<div class="user-status">拼单即将结束 <span class="countdown">00:05:49</span></div>
|
|
||||||
</div>
|
|
||||||
<button class="buy-btn" data-price="80">参与拼团</button>
|
|
||||||
</div>
|
|
||||||
<div class="user-item">
|
|
||||||
<div class="user-avatar">
|
|
||||||
<i class="fas fa-user"></i>
|
|
||||||
</div>
|
|
||||||
<div class="user-info">
|
|
||||||
<div class="user-name">李二狗</div>
|
|
||||||
<div class="user-status">拼单即将结束 <span class="countdown">00:05:49</span></div>
|
|
||||||
</div>
|
|
||||||
<button class="buy-btn" data-price="80">参与拼团</button>
|
|
||||||
</div>
|
|
||||||
<div class="user-item">
|
|
||||||
<div class="user-avatar">
|
|
||||||
<i class="fas fa-user"></i>
|
|
||||||
</div>
|
|
||||||
<div class="user-info">
|
|
||||||
<div class="user-name">张全蛋</div>
|
|
||||||
<div class="user-status">拼单即将结束 <span class="countdown">00:02:30</span></div>
|
|
||||||
</div>
|
|
||||||
<button class="buy-btn" data-price="80">参与拼团</button>
|
|
||||||
</div>
|
|
||||||
<div class="user-item">
|
|
||||||
<div class="user-avatar">
|
|
||||||
<i class="fas fa-user"></i>
|
|
||||||
</div>
|
|
||||||
<div class="user-info">
|
|
||||||
<div class="user-name">王翠花</div>
|
|
||||||
<div class="user-status">拼单即将结束 <span class="countdown">00:01:15</span></div>
|
|
||||||
</div>
|
|
||||||
<button class="buy-btn" data-price="80">参与拼团</button>
|
|
||||||
</div>
|
|
||||||
<!-- 添加更多用户项确保轮播效果 -->
|
|
||||||
<div class="user-item">
|
|
||||||
<div class="user-avatar">
|
|
||||||
<i class="fas fa-user"></i>
|
|
||||||
</div>
|
|
||||||
<div class="user-info">
|
|
||||||
<div class="user-name">刘大壮</div>
|
|
||||||
<div class="user-status">拼单即将结束 <span class="countdown">00:03:45</span></div>
|
|
||||||
</div>
|
|
||||||
<button class="buy-btn" data-price="80">参与拼团</button>
|
|
||||||
</div>
|
|
||||||
<div class="user-item">
|
|
||||||
<div class="user-avatar">
|
|
||||||
<i class="fas fa-user"></i>
|
|
||||||
</div>
|
|
||||||
<div class="user-info">
|
|
||||||
<div class="user-name">赵小敏</div>
|
|
||||||
<div class="user-status" data-price="80">拼单即将结束 <span class="countdown">00:04:20</span></div>
|
|
||||||
</div>
|
|
||||||
<button class="buy-btn">参与拼团</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 底部操作栏 -->
|
<!-- 底部操作栏 -->
|
||||||
<div class="action-bar">
|
<div class="action-bar">
|
||||||
<div class="action-btn">
|
<div class="action-btn">
|
||||||
<i class="fas fa-home"></i>
|
<i class="fas fa-home"></i><span>首页</span>
|
||||||
<span>首页</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="action-btn">
|
<div class="action-btn">
|
||||||
<i class="fas fa-heart"></i>
|
<i class="fas fa-heart"></i><span>收藏</span>
|
||||||
<span>收藏</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="action-btn">
|
<div class="action-btn">
|
||||||
<i class="fas fa-shopping-cart"></i>
|
<i class="fas fa-shopping-cart"></i><span>购物车</span>
|
||||||
<span>购物车</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="purchase-btn">
|
<div class="purchase-btn">
|
||||||
<button class="btn-single" data-price="100">
|
<button class="btn-single" id="btnSingle" data-price="">
|
||||||
<span class="btn-price">¥100</span>
|
<span class="btn-price" id="singlePrice"></span>
|
||||||
<span class="btn-label">单独购买</span>
|
<span class="btn-label">单独购买</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn-group" data-price="80">
|
<button class="btn-group" id="btnGroup" data-price="">
|
||||||
<span class="btn-price">¥80</span>
|
<span class="btn-price" id="groupPrice"></span>
|
||||||
<span class="btn-label">开团购买</span>
|
<span class="btn-label">开团购买</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 支付弹窗(默认隐藏) -->
|
|
||||||
|
<!-- 支付弹窗 -->
|
||||||
<div id="paymentModal" class="pay-mask">
|
<div id="paymentModal" class="pay-mask">
|
||||||
<div class="pay-box">
|
<div class="pay-box">
|
||||||
<h2 class="pay-title">请扫码支付</h2>
|
<h2 class="pay-title">请扫码支付</h2>
|
||||||
<p class="pay-amount" id="paymentAmount"></p>
|
<p class="pay-amount" id="paymentAmount"></p>
|
||||||
<img src="images/qrcode.png" alt="支付二维码" class="qr-code">
|
<img src="images/qrcode.png" alt="支付二维码" class="qr-code" />
|
||||||
<div class="pay-btns">
|
<div class="pay-btns">
|
||||||
<button id="cancelPayment" class="btn-secondary">取消支付</button>
|
<button id="cancelPayment" class="btn-secondary">取消支付</button>
|
||||||
<button id="completePayment" class="btn-primary">支付完成</button>
|
<button id="completePayment" class="btn-primary">支付完成</button>
|
||||||
@ -142,6 +85,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 逻辑脚本 -->
|
||||||
<script src="js/index.js"></script>
|
<script src="js/index.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,205 +1,253 @@
|
|||||||
// index.js (改进版)
|
/* -------------------------------------------------------
|
||||||
// 功能:
|
* Author : 你
|
||||||
// 1. 解决用户列表竖向轮播在无缝跳转时出现的卡顿/闪动问题
|
* Desc : 改进版拼团页面脚本(userId 从 cookie 里读)
|
||||||
// 2. 为每条拼单信息增加实时倒计时,秒级更新
|
* ----------------------------------------------------- */
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
/* ========== 通用工具 ========== */
|
||||||
/* ---------- 顶部横向轮播 ---------- */
|
const getCookie = (k) =>
|
||||||
|
document.cookie
|
||||||
|
.split(';')
|
||||||
|
.map((c) => c.trim())
|
||||||
|
.find((c) => c.startsWith(k + '='))?.split('=')[1] || null;
|
||||||
|
|
||||||
|
/* ----------- 0. DOM 快捷引用 ----------- */
|
||||||
|
const $ = (id) => document.getElementById(id);
|
||||||
|
const currentPrice = $('currentPrice');
|
||||||
|
const originalPriceElem = $('originalPrice');
|
||||||
|
const dropPrice = $('dropPrice');
|
||||||
|
const soldBox = $('soldBox');
|
||||||
|
const groupTitle = $('groupTitle');
|
||||||
|
const userList = $('userList');
|
||||||
|
const singlePriceSpan = $('singlePrice');
|
||||||
|
const groupPriceSpan = $('groupPrice');
|
||||||
|
const btnSingle = $('btnSingle');
|
||||||
|
const btnGroup = $('btnGroup');
|
||||||
|
|
||||||
|
/* =====================================================
|
||||||
|
* 1. 取接口数据并渲染
|
||||||
|
* =================================================== */
|
||||||
|
const API_URL = 'http://127.0.0.1:8091/api/v1/gbm/index/query_group_buy_market_config';
|
||||||
|
|
||||||
|
// 读取 cookie 中的 username 当作 userId
|
||||||
|
const username = getCookie('username');
|
||||||
|
|
||||||
|
// 如果没登录,直接跳去登录页,免得后面接口 401/判空
|
||||||
|
if (!username) {
|
||||||
|
location.href = 'login.html';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const POST_BODY = {
|
||||||
|
userId : username, // 不再写死
|
||||||
|
source : 's01',
|
||||||
|
channel: 'c01',
|
||||||
|
goodsId: '9890001'
|
||||||
|
};
|
||||||
|
|
||||||
|
fetch(API_URL, {
|
||||||
|
method : 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body : JSON.stringify(POST_BODY),
|
||||||
|
})
|
||||||
|
.then((r) => r.json())
|
||||||
|
.then(({ code, info, data }) => {
|
||||||
|
if (code !== '0000' || !data) {
|
||||||
|
console.error('接口异常:', info);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
renderGoods(data.goods);
|
||||||
|
renderStatistic(data.teamStatistic);
|
||||||
|
renderTeams(data.teamList, data.goods?.payPrice);
|
||||||
|
})
|
||||||
|
.catch((e) => console.error('接口请求失败:', e));
|
||||||
|
|
||||||
|
/* ------------- 渲染商品信息 ------------- */
|
||||||
|
function renderGoods(g = {}) {
|
||||||
|
const { originalPrice = 0, payPrice = 0, deductionPrice = 0 } = g;
|
||||||
|
currentPrice.textContent = payPrice;
|
||||||
|
originalPriceElem.textContent = originalPrice;
|
||||||
|
dropPrice.textContent = `直降 ¥${deductionPrice}`;
|
||||||
|
|
||||||
|
singlePriceSpan.textContent = `¥${originalPrice}`;
|
||||||
|
groupPriceSpan.textContent = `¥${payPrice}`;
|
||||||
|
btnSingle.dataset.price = originalPrice;
|
||||||
|
btnGroup.dataset.price = payPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------- 渲染统计信息 ------------- */
|
||||||
|
function renderStatistic(stat = {}) {
|
||||||
|
const { allTeamUserCount = 0 } = stat;
|
||||||
|
groupTitle.textContent = `${allTeamUserCount}人在抢,参与可立即拼成`;
|
||||||
|
soldBox.textContent = `${allTeamUserCount}人再抢`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------- 渲染拼团列表 ------------- */
|
||||||
|
function renderTeams(list = [], groupPrice = 0) {
|
||||||
|
if (!list || list.length === 0) {
|
||||||
|
groupTitle.textContent = '小伙伴,赶紧去开团吧,做村里最靓的仔。';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
userList.innerHTML = '';
|
||||||
|
list.forEach((t) => userList.appendChild(makeItem(t, groupPrice)));
|
||||||
|
initUserMarquee();
|
||||||
|
initCountdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeItem(team, price) {
|
||||||
|
const { userId, targetCount, lockCount, validTimeCountdown } = team;
|
||||||
|
const leftNum = Math.max(targetCount - lockCount, 0);
|
||||||
|
const timeText = validTimeCountdown || '00:00:00';
|
||||||
|
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.className = 'user-item';
|
||||||
|
div.innerHTML = `
|
||||||
|
<div class="user-avatar"><i class="fas fa-user"></i></div>
|
||||||
|
<div class="user-info">
|
||||||
|
<div class="user-name">${userId}</div>
|
||||||
|
<div class="user-status">
|
||||||
|
仅剩${leftNum}人成团
|
||||||
|
<span class="countdown">${timeText}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="buy-btn" data-price="${price}">参与拼团</button>
|
||||||
|
`;
|
||||||
|
return div;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =====================================================
|
||||||
|
* 2. 拼单列表纵向轮播
|
||||||
|
* =================================================== */
|
||||||
|
function initUserMarquee() {
|
||||||
|
const items = userList.querySelectorAll('.user-item');
|
||||||
|
if (items.length <= 1) return;
|
||||||
|
|
||||||
|
const itemH = items[0].offsetHeight;
|
||||||
|
userList.appendChild(items[0].cloneNode(true)); // 无缝衔接
|
||||||
|
|
||||||
|
let idx = 0;
|
||||||
|
userList.addEventListener('transitionend', () => {
|
||||||
|
if (idx >= items.length) {
|
||||||
|
userList.style.transition = 'none';
|
||||||
|
userList.style.transform = 'translateY(0)';
|
||||||
|
idx = 0;
|
||||||
|
void userList.offsetWidth;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
idx++;
|
||||||
|
userList.style.transition = 'transform .5s ease';
|
||||||
|
userList.style.transform = `translateY(${-idx * itemH}px)`;
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =====================================================
|
||||||
|
* 3. 倒计时
|
||||||
|
* =================================================== */
|
||||||
|
let countdownData = [];
|
||||||
|
|
||||||
|
function initCountdown() {
|
||||||
|
const els = document.querySelectorAll('.countdown');
|
||||||
|
countdownData = Array.from(els).map((el) => ({
|
||||||
|
el,
|
||||||
|
remain: toSec(el.textContent.trim()),
|
||||||
|
}));
|
||||||
|
setInterval(tick, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
const toSec = (t) => {
|
||||||
|
if (!t.includes(':')) return 0;
|
||||||
|
const [h = '00', m = '00', s = '00'] = t.split(':');
|
||||||
|
return +h * 3600 + +m * 60 + +s;
|
||||||
|
};
|
||||||
|
const fmt = (n) => String(n).padStart(2, '0');
|
||||||
|
const format = (s) => `${fmt(s / 3600 | 0)}:${fmt((s % 3600) / 60 | 0)}:${fmt(s % 60)}`;
|
||||||
|
|
||||||
|
function tick() {
|
||||||
|
countdownData.forEach((c) => {
|
||||||
|
if (c.remain > 0) {
|
||||||
|
c.remain--;
|
||||||
|
c.el.textContent = format(c.remain);
|
||||||
|
if (c.remain === 0) expire(c.el);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function expire(el) {
|
||||||
|
el.textContent = '00:00:00';
|
||||||
|
const item = el.closest('.user-item');
|
||||||
|
item?.classList.add('expired');
|
||||||
|
item?.querySelector('.buy-btn')?.setAttribute('disabled', 'disabled');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =====================================================
|
||||||
|
* 4. 支付弹窗(事件委托)
|
||||||
|
* =================================================== */
|
||||||
|
const modal = $('paymentModal');
|
||||||
|
const amountText = $('paymentAmount');
|
||||||
|
const cancelPayment = $('cancelPayment');
|
||||||
|
const completePayment= $('completePayment');
|
||||||
|
|
||||||
|
document.body.addEventListener('click', (e) => {
|
||||||
|
const btn = e.target.closest('.buy-btn, .btn-single, .btn-group');
|
||||||
|
if (!btn) return;
|
||||||
|
|
||||||
|
// 再次确认 cookie,防止手动删 cookie
|
||||||
|
if (!getCookie('username')) {
|
||||||
|
location.href = 'login.html';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
amountText.textContent = `支付金额 ¥${btn.dataset.price || 0}`;
|
||||||
|
modal.style.display = 'flex';
|
||||||
|
});
|
||||||
|
|
||||||
|
cancelPayment.onclick = () => modal.style.display = 'none';
|
||||||
|
completePayment.onclick= () => { alert('支付成功!'); modal.style.display = 'none'; };
|
||||||
|
modal.addEventListener('click', (e) => { if (e.target === modal) modal.style.display = 'none'; });
|
||||||
|
|
||||||
|
/* =====================================================
|
||||||
|
* 5. 顶部横向轮播(原逻辑保留)
|
||||||
|
* =================================================== */
|
||||||
const wrapper = document.querySelector('.swiper-wrapper');
|
const wrapper = document.querySelector('.swiper-wrapper');
|
||||||
const slides = [...wrapper.children];
|
const slides = [...wrapper.children];
|
||||||
const pagination = document.querySelector('.swiper-pagination');
|
const pagination = document.querySelector('.swiper-pagination');
|
||||||
const count = slides.length;
|
const count = slides.length;
|
||||||
|
|
||||||
let current = 0; // 当前索引
|
let current = 0, startX = 0, dragging = false, timer;
|
||||||
let startX = 0; // 手势起点
|
for (let i = 0; i < count; i++) {
|
||||||
let dragging = false; // 拖动状态
|
|
||||||
let timer = null; // 自动轮播计时器
|
|
||||||
|
|
||||||
/* --- 1. 生成分页小圆点 --- */
|
|
||||||
for(let i=0;i<count;i++){
|
|
||||||
const dot = document.createElement('div');
|
const dot = document.createElement('div');
|
||||||
dot.className = 'swiper-dot' + (i===0?' active':'');
|
dot.className = 'swiper-dot' + (i === 0 ? ' active' : '');
|
||||||
dot.addEventListener('click',()=>goTo(i));
|
dot.onclick = () => goTo(i);
|
||||||
pagination.appendChild(dot);
|
pagination.appendChild(dot);
|
||||||
}
|
}
|
||||||
const dots = pagination.children;
|
const dots = pagination.children;
|
||||||
|
|
||||||
/* --- 2. 切换核心 --- */
|
const goTo = (i) => {
|
||||||
function goTo(index){
|
current = (i + count) % count;
|
||||||
current = (index + count) % count; // 防越界
|
|
||||||
wrapper.style.transition = 'transform .3s ease';
|
wrapper.style.transition = 'transform .3s ease';
|
||||||
wrapper.style.transform = `translateX(-${current*100}%)`;
|
wrapper.style.transform = `translateX(-${current * 100}%)`;
|
||||||
[...dots].forEach((d,i)=>d.classList.toggle('active',i===current));
|
[...dots].forEach((d, j) => d.classList.toggle('active', j === current));
|
||||||
}
|
|
||||||
|
|
||||||
/* --- 3. 自动轮播 --- */
|
|
||||||
function startAuto(){
|
|
||||||
timer = setInterval(()=>goTo(current+1),3000);
|
|
||||||
}
|
|
||||||
function stopAuto(){
|
|
||||||
clearInterval(timer);
|
|
||||||
}
|
|
||||||
startAuto();
|
|
||||||
|
|
||||||
/* --- 4. 手势/鼠标拖动 --- */
|
|
||||||
const getX = e => e.touches ? e.touches[0].clientX : e.clientX;
|
|
||||||
|
|
||||||
wrapper.addEventListener('pointerdown',e=>{
|
|
||||||
stopAuto();
|
|
||||||
dragging = true;
|
|
||||||
startX = getX(e);
|
|
||||||
wrapper.style.transition = 'none'; // 跟手拖动
|
|
||||||
});
|
|
||||||
|
|
||||||
wrapper.addEventListener('pointermove',e=>{
|
|
||||||
if(!dragging) return;
|
|
||||||
const diff = getX(e) - startX; // 像素位移
|
|
||||||
wrapper.style.transform =
|
|
||||||
`translateX(calc(${-current*100}% + ${diff}px))`;
|
|
||||||
});
|
|
||||||
|
|
||||||
const endSwipe = e=>{
|
|
||||||
if(!dragging) return;
|
|
||||||
dragging = false;
|
|
||||||
const diff = getX(e) - startX;
|
|
||||||
const limit = wrapper.offsetWidth * 0.15; // 15% 宽度阈值
|
|
||||||
if(diff > limit) goTo(current-1);
|
|
||||||
else if(diff < -limit) goTo(current+1);
|
|
||||||
else goTo(current); // 回弹
|
|
||||||
startAuto();
|
|
||||||
};
|
};
|
||||||
wrapper.addEventListener('pointerup', endSwipe);
|
const auto = () => { timer = setInterval(() => goTo(current + 1), 3000); };
|
||||||
wrapper.addEventListener('pointercancel', endSwipe);
|
const stop = () => clearInterval(timer);
|
||||||
wrapper.addEventListener('pointerleave', endSwipe);
|
auto();
|
||||||
|
|
||||||
|
const getX = (e) => (e.touches ? e.touches[0].clientX : e.clientX);
|
||||||
|
wrapper.addEventListener('pointerdown', (e) => { stop(); dragging = true; startX = getX(e); wrapper.style.transition = 'none'; });
|
||||||
|
wrapper.addEventListener('pointermove', (e) => { if (!dragging) return; const diff = getX(e) - startX; wrapper.style.transform = `translateX(calc(${-current * 100}% + ${diff}px))`; });
|
||||||
|
wrapper.addEventListener('pointerup', endSwipe);
|
||||||
|
wrapper.addEventListener('pointercancel',endSwipe);
|
||||||
|
wrapper.addEventListener('pointerleave', endSwipe);
|
||||||
|
|
||||||
/* --------- 动态生成“xx人在抢,参与可立即拼成” --------- */
|
function endSwipe(e) {
|
||||||
const leftNum = Math.floor(Math.random() * 101) + 100; // 100 ~ 200
|
if (!dragging) return;
|
||||||
const groupTitle = document.getElementById('groupTitle');
|
dragging = false;
|
||||||
if (groupTitle) groupTitle.textContent = `${leftNum}人在抢,参与可立即拼成`;
|
const diff = getX(e) - startX;
|
||||||
|
const limit = wrapper.offsetWidth * 0.15;
|
||||||
/* ---------- 拼单用户纵向轮播 ---------- */
|
if (diff > limit) goTo(current - 1);
|
||||||
const userList = document.getElementById('userList');
|
else if (diff < -limit) goTo(current + 1);
|
||||||
const userItems = userList.querySelectorAll('.user-item');
|
else goTo(current);
|
||||||
const itemHeight = userItems[0].offsetHeight;
|
auto();
|
||||||
let userIndex = 0;
|
|
||||||
const originalCount = userItems.length;
|
|
||||||
|
|
||||||
// 克隆第一条放到末尾,实现无缝衔接
|
|
||||||
userList.appendChild(userItems[0].cloneNode(true));
|
|
||||||
|
|
||||||
userList.addEventListener('transitionend', () => {
|
|
||||||
if (userIndex >= originalCount) {
|
|
||||||
// 闪电跳回首条,关闭过渡以避免闪屏
|
|
||||||
userList.style.transition = 'none';
|
|
||||||
userList.style.transform = 'translateY(0)';
|
|
||||||
userIndex = 0;
|
|
||||||
// 强制回流,保证下次 transition 生效
|
|
||||||
void userList.offsetWidth;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function rotateUsers() {
|
|
||||||
userIndex++;
|
|
||||||
userList.style.transition = 'transform 0.5s ease';
|
|
||||||
userList.style.transform = `translateY(${-userIndex * itemHeight}px)`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 每 3 秒滚动一次
|
|
||||||
setInterval(rotateUsers, 3000);
|
|
||||||
// 页面加载后立即滚动一次,保证视觉一致
|
|
||||||
rotateUsers();
|
|
||||||
|
|
||||||
/* ---------- 拼单倒计时 ---------- */
|
|
||||||
const countdownEls = document.querySelectorAll('.countdown');
|
|
||||||
// 预处理:把初始文本转为秒数
|
|
||||||
const countdownData = Array.from(countdownEls).map((el) => ({
|
|
||||||
el,
|
|
||||||
remain: parseTime(el.textContent.trim()),
|
|
||||||
}));
|
|
||||||
|
|
||||||
function parseTime(t) {
|
|
||||||
const [h = '00', m = '00', s = '00'] = t.split(':');
|
|
||||||
return Number(h) * 3600 + Number(m) * 60 + Number(s);
|
|
||||||
}
|
|
||||||
function formatTime(sec) {
|
|
||||||
const h = String(Math.floor(sec / 3600)).padStart(2, '0');
|
|
||||||
const m = String(Math.floor((sec % 3600) / 60)).padStart(2, '0');
|
|
||||||
const s = String(sec % 60).padStart(2, '0');
|
|
||||||
return `${h}:${m}:${s}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateCountdown() {
|
|
||||||
countdownData.forEach((c) => {
|
|
||||||
if (c.remain > 0) {
|
|
||||||
c.remain -= 1;
|
|
||||||
c.el.textContent = formatTime(c.remain);
|
|
||||||
} else {
|
|
||||||
c.el.textContent = '00:00:00';
|
|
||||||
// 可选:到点后给整条加灰色样式,并禁用按钮
|
|
||||||
const item = c.el.closest('.user-item');
|
|
||||||
item?.classList.add('expired');
|
|
||||||
item?.querySelector('.buy-btn')?.setAttribute('disabled', 'disabled');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --------- 动态填充“已抢 xxx 件” --------- */
|
|
||||||
const soldBox = document.getElementById('soldBox');
|
|
||||||
if (soldBox){
|
|
||||||
const soldNum = Math.floor(Math.random()*101)+200; // 200~300
|
|
||||||
soldBox.textContent = `已抢 ${soldNum} 件`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --------- 给每条拼单状态前加 “仅剩 x 人成团” --------- */
|
|
||||||
document.querySelectorAll('.user-status').forEach(statusEl=>{
|
|
||||||
const x = Math.floor(Math.random()*3)+1; // 1 ~ 3 随机整数
|
|
||||||
const span = document.createElement('span');
|
|
||||||
span.className = 'left-num';
|
|
||||||
span.textContent = `仅剩${x}人成团,`; // 注意带逗号或空格
|
|
||||||
statusEl.prepend(span);
|
|
||||||
});
|
|
||||||
|
|
||||||
/* ============= 支付 & 登录判断 ============= */
|
|
||||||
const modal = document.getElementById('paymentModal');
|
|
||||||
const paymentAmount = document.getElementById('paymentAmount');
|
|
||||||
const cancelPayment = document.getElementById('cancelPayment');
|
|
||||||
const completePayment= document.getElementById('completePayment');
|
|
||||||
|
|
||||||
/* 把 3 类按钮统一选出来 */
|
|
||||||
[...document.querySelectorAll('.buy-btn, .btn-single, .btn-group')].forEach(btn=>{
|
|
||||||
btn.addEventListener('click',()=>{
|
|
||||||
/* 简单读取 cookie 判断是否登录 */
|
|
||||||
if(!getCookie('username')){
|
|
||||||
window.location.href='login.html'; // 跳转到登录页
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* 已登录:弹出支付弹窗 */
|
|
||||||
const price = btn.dataset.price || '0';
|
|
||||||
paymentAmount.textContent = `支付金额 ¥${price}`;
|
|
||||||
modal.style.display='flex';
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/* 取消/完成支付 */
|
|
||||||
cancelPayment.addEventListener('click', ()=>modal.style.display='none');
|
|
||||||
completePayment.addEventListener('click', ()=>{
|
|
||||||
alert('支付成功!');
|
|
||||||
modal.style.display='none';
|
|
||||||
});
|
|
||||||
|
|
||||||
/* 读取 cookie 工具函数 */
|
|
||||||
function getCookie(name){
|
|
||||||
return document.cookie.split(';').map(c=>c.trim())
|
|
||||||
.find(c=>c.startsWith(name+'='))?.split('=')[1] || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 点击遮罩空白关闭弹窗 */
|
|
||||||
modal.addEventListener('click', e=>{
|
|
||||||
if(e.target===modal) modal.style.display='none';
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// 每秒刷新一次倒计时
|
|
||||||
setInterval(updateCountdown, 1000);
|
|
||||||
});
|
});
|
||||||
|
@ -3,13 +3,13 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8"/>
|
<meta charset="UTF-8"/>
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"/>
|
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"/>
|
||||||
<title>欢迎登录 - 小傅哥拼团</title>
|
<title>欢迎登录 - 宇哥拼团</title>
|
||||||
<link rel="stylesheet" href="css/login.css"/>
|
<link rel="stylesheet" href="css/login.css"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<form id="loginForm" class="login-form">
|
<form id="loginForm" class="login-form">
|
||||||
<h2>欢迎登录 - 小傅哥拼团</h2>
|
<h2>欢迎登录 - 宇哥拼团</h2>
|
||||||
|
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text" id="username" required/>
|
<input type="text" id="username" required/>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
FROM openjdk:8-jre-slim
|
FROM openjdk:8-jre-slim
|
||||||
|
|
||||||
# 作者
|
# 作者
|
||||||
MAINTAINER xiaofuge
|
MAINTAINER zy
|
||||||
|
|
||||||
# 配置
|
# 配置
|
||||||
ENV PARAMS=""
|
ENV PARAMS=""
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
# 普通镜像构建,随系统版本构建 amd/arm
|
# 普通镜像构建,随系统版本构建 amd/arm
|
||||||
docker build -t system/group-buying-sys-app:1.0-SNAPSHOT -f ./Dockerfile .
|
docker build -t smile/group-buying-sys-app -f ./Dockerfile .
|
||||||
|
|
||||||
# 兼容 amd、arm 构建镜像
|
# 兼容 amd、arm 构建镜像
|
||||||
# docker buildx build --load --platform liunx/amd64,linux/arm64 -t xiaofuge/xfg-frame-archetype-app:1.0 -f ./Dockerfile . --push
|
# docker buildx build --load --platform liunx/amd64,linux/arm64 -t xiaofuge/xfg-frame-archetype-app:1.0 -f ./Dockerfile . --push
|
@ -1,7 +1,7 @@
|
|||||||
server:
|
server:
|
||||||
port: 8091
|
port: 8091
|
||||||
|
|
||||||
# 线程池配置
|
# ---------- 线程池 ----------
|
||||||
thread:
|
thread:
|
||||||
pool:
|
pool:
|
||||||
executor:
|
executor:
|
||||||
@ -12,30 +12,45 @@ thread:
|
|||||||
block-queue-size: 5000
|
block-queue-size: 5000
|
||||||
policy: CallerRunsPolicy
|
policy: CallerRunsPolicy
|
||||||
|
|
||||||
# 数据库配置
|
# ---------- 数据源 ----------
|
||||||
#spring:
|
spring:
|
||||||
# datasource:
|
datasource:
|
||||||
# username: root
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
# password: 123456
|
url: jdbc:mysql://mysql:3306/big_market?useUnicode=true&characterEncoding=utf8&autoReconnect=true&serverTimezone=Asia/Shanghai&useSSL=false
|
||||||
# url: jdbc:mysql://127.0.0.1:3306/xfg_frame_archetype?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC&useSSL=true
|
username: root
|
||||||
# driver-class-name: com.mysql.cj.jdbc.Driver
|
password: 123456
|
||||||
# hikari:
|
hikari:
|
||||||
# pool-name: Retail_HikariCP
|
pool-name: Retail_HikariCP
|
||||||
# minimum-idle: 15 #最小空闲连接数量
|
minimum-idle: 15 # 最小空闲连接
|
||||||
# idle-timeout: 180000 #空闲连接存活最大时间,默认600000(10分钟)
|
idle-timeout: 180000 # 空闲连接存活(ms)
|
||||||
# maximum-pool-size: 25 #连接池最大连接数,默认是10
|
maximum-pool-size: 25 # 最大连接
|
||||||
# auto-commit: true #此属性控制从池返回的连接的默认自动提交行为,默认值:true
|
auto-commit: true
|
||||||
# max-lifetime: 1800000 #此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
|
max-lifetime: 1800000 # 连接最大生命周期(ms)
|
||||||
# connection-timeout: 30000 #数据库连接超时时间,默认30秒,即30000
|
connection-timeout: 30000
|
||||||
# connection-test-query: SELECT 1
|
connection-test-query: SELECT 1
|
||||||
# type: com.zaxxer.hikari.HikariDataSource
|
|
||||||
|
|
||||||
#mybatis:
|
# ---------- MyBatis ----------
|
||||||
# mapper-locations: classpath:/mybatis/mapper/*.xml
|
mybatis:
|
||||||
# config-location: classpath:/mybatis/config/mybatis-config.xml
|
mapper-locations: classpath:/mybatis/mapper/*.xml
|
||||||
|
config-location: classpath:/mybatis/config/mybatis-config.xml
|
||||||
|
|
||||||
# 日志
|
# ---------- Redis ----------
|
||||||
|
redis:
|
||||||
|
sdk:
|
||||||
|
config:
|
||||||
|
host: redis # 使用服务名
|
||||||
|
port: 6379
|
||||||
|
pool-size: 10
|
||||||
|
min-idle-size: 5
|
||||||
|
idle-timeout: 30000
|
||||||
|
connect-timeout: 5000
|
||||||
|
retry-attempts: 3
|
||||||
|
retry-interval: 1000
|
||||||
|
ping-interval: 60000
|
||||||
|
keep-alive: true
|
||||||
|
|
||||||
|
# ---------- 日志 ----------
|
||||||
logging:
|
logging:
|
||||||
level:
|
level:
|
||||||
root: info
|
root: info
|
||||||
config: classpath:logback-spring.xml
|
config: classpath:logback-spring.xml
|
||||||
|
@ -37,8 +37,8 @@ public class MarketIndexController implements IMarketIndexService {
|
|||||||
|
|
||||||
log.info("查询拼团营销配置开始: userId={} goodsId={}", req.getUserId(), req.getGoodsId());
|
log.info("查询拼团营销配置开始: userId={} goodsId={}", req.getUserId(), req.getGoodsId());
|
||||||
|
|
||||||
// —— 1. 参数校验 ——
|
// —— 1. 参数校验 —— req.getUserId()可为空
|
||||||
if (StringUtils.isAnyBlank(req.getUserId(), req.getSource(), req.getChannel(), req.getGoodsId())) {
|
if (StringUtils.isAnyBlank(req.getSource(), req.getChannel(), req.getGoodsId())) {
|
||||||
return Response.<GoodsMarketResponseDTO>builder()
|
return Response.<GoodsMarketResponseDTO>builder()
|
||||||
.code(ResponseCode.ILLEGAL_PARAMETER.getCode())
|
.code(ResponseCode.ILLEGAL_PARAMETER.getCode())
|
||||||
.info(ResponseCode.ILLEGAL_PARAMETER.getInfo())
|
.info(ResponseCode.ILLEGAL_PARAMETER.getInfo())
|
||||||
@ -60,7 +60,7 @@ public class MarketIndexController implements IMarketIndexService {
|
|||||||
//获取拼团展示列表
|
//获取拼团展示列表
|
||||||
List<UserGroupBuyOrderDetailEntity> details = indexGroupBuyMarketService.queryInProgressUserGroupBuyOrderDetailList(
|
List<UserGroupBuyOrderDetailEntity> details = indexGroupBuyMarketService.queryInProgressUserGroupBuyOrderDetailList(
|
||||||
trial.getGroupBuyActivityDiscountVO().getActivityId(),
|
trial.getGroupBuyActivityDiscountVO().getActivityId(),
|
||||||
req.getUserId(), 1, 2);
|
req.getUserId(), 1, 4);
|
||||||
|
|
||||||
List<GoodsMarketResponseDTO.Team> teams = details.stream()
|
List<GoodsMarketResponseDTO.Team> teams = details.stream()
|
||||||
.map(d -> {
|
.map(d -> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user