diff --git a/dashboard-ui/app.js b/dashboard-ui/app.js
index 6ec92bd..3732c05 100644
--- a/dashboard-ui/app.js
+++ b/dashboard-ui/app.js
@@ -12,6 +12,7 @@ let tagChart;
document.addEventListener('DOMContentLoaded', () => {
initCharts();
setupNavigation();
+ setupRepurchasePeriod();
// Fetch cutoff dates + initial page data
fetchDataCutoff();
@@ -181,9 +182,14 @@ async function fetchTrend() {
}
// ============== PAGE 2: PRODUCT INSIGHTS ==============
-async function fetchRepurchase() {
+
+// 当前选中的复购率统计周期
+let repurchaseDays = 30;
+
+async function fetchRepurchase(days) {
+ if (days !== undefined) repurchaseDays = days;
try {
- const response = await fetch(`${BASE_URL}/product/repurchase`);
+ const response = await fetch(`${BASE_URL}/product/repurchase?days=${repurchaseDays}`);
if (!response.ok) return;
const data = await response.json();
@@ -215,6 +221,20 @@ async function fetchRepurchase() {
} catch (e) {}
}
+// 初始化复购率周期切换控件
+function setupRepurchasePeriod() {
+ const container = document.getElementById('repurchase-period');
+ if (!container) return;
+ container.addEventListener('click', (e) => {
+ const btn = e.target.closest('.segment-btn');
+ if (!btn) return;
+ container.querySelectorAll('.segment-btn').forEach(b => b.classList.remove('active'));
+ btn.classList.add('active');
+ const days = parseInt(btn.dataset.days);
+ fetchRepurchase(days);
+ });
+}
+
async function fetchBasket() {
try {
const response = await fetch(`${BASE_URL}/product/basket`);
diff --git a/dashboard-ui/index.html b/dashboard-ui/index.html
index 1348c8a..585d9c7 100644
--- a/dashboard-ui/index.html
+++ b/dashboard-ui/index.html
@@ -4,10 +4,7 @@
餐饮零售数据中台 | 核心引擎
-
-
-
-
+
@@ -92,17 +89,22 @@
| 商品名称 |
- 30天购买人数 ⓘ |
- 30天复购人数 ⓘ |
+ 购买人数 ⓘ |
+ 复购人数 ⓘ |
复购率 ⓘ |
- 波士顿矩阵打标 ⓘ |
+ 波士顿矩阵打标 ⓘ |
diff --git a/dashboard-ui/styles.css b/dashboard-ui/styles.css
index d365fb6..f36aea9 100644
--- a/dashboard-ui/styles.css
+++ b/dashboard-ui/styles.css
@@ -36,7 +36,7 @@
margin: 0;
padding: 0;
box-sizing: border-box;
- font-family: -apple-system, BlinkMacSystemFont, "Inter", "Helvetica Neue", sans-serif;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', sans-serif;
-webkit-font-smoothing: antialiased;
}
@@ -302,6 +302,52 @@ body {
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.08);
}
+/* Chart header with optional controls */
+.chart-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 12px;
+ margin-bottom: 1rem;
+}
+
+.chart-header h2 {
+ margin: 0;
+}
+
+/* Apple-style Segmented Control */
+.segment-control {
+ display: inline-flex;
+ background: rgba(134, 134, 139, 0.08);
+ border-radius: 10px;
+ padding: 3px;
+ gap: 2px;
+}
+
+.segment-btn {
+ padding: 5px 16px;
+ border: none;
+ border-radius: 8px;
+ background: transparent;
+ color: var(--text-secondary);
+ font-size: 0.8rem;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.25s ease;
+ font-family: inherit;
+}
+
+.segment-btn:hover {
+ color: var(--text-primary);
+}
+
+.segment-btn.active {
+ background: var(--text-primary);
+ color: var(--bg-base);
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
+}
+
/* Dashboard Grid */
.dashboard-grid {
display: flex;
diff --git a/server/src/main/java/com/chuyishidai/datahub/controller/ProductController.java b/server/src/main/java/com/chuyishidai/datahub/controller/ProductController.java
index 6503152..e6c2256 100644
--- a/server/src/main/java/com/chuyishidai/datahub/controller/ProductController.java
+++ b/server/src/main/java/com/chuyishidai/datahub/controller/ProductController.java
@@ -4,6 +4,7 @@ import lombok.RequiredArgsConstructor;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@@ -55,22 +56,74 @@ public class ProductController {
}
/**
- * 商品30天复购率与波士顿矩阵打标
+ * 商品复购率与波士顿矩阵打标
+ * @param days 统计周期: 7 / 15 / 30 (默认30)
+ * - 30天: 直接读取预计算表 adm_item_repurchase
+ * - 7/15天: 从订单明细实时计算
*/
@GetMapping("/repurchase")
- public List