From 69138ddcf4936098cb3b67688412badfc8f503a0 Mon Sep 17 00:00:00 2001
From: shinnosuke <tantao@1hoper.com>
Date: 星期二, 18 八月 2026 17:13:53 +0800
Subject: [PATCH] 又又又更新

---
 talent-card-server/src/main/java/com/talentcard/server/business/admin/AdminBusinessService.java |  100 ++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 81 insertions(+), 19 deletions(-)

diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/admin/AdminBusinessService.java b/talent-card-server/src/main/java/com/talentcard/server/business/admin/AdminBusinessService.java
index f18842c..46f596c 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/admin/AdminBusinessService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/admin/AdminBusinessService.java
@@ -2,9 +2,12 @@
 
 import java.math.BigDecimal;
 import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.ZoneId;
 import java.time.format.DateTimeParseException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -228,21 +231,7 @@
 		StringBuilder sql = new StringBuilder("""
 				select m.id, m.merchant_name, m.merchant_type, m.contact_name, m.contact_mobile,
 				       m.logo_url, m.cover_url, m.address, m.is_recommend, m.sort_no, m.status,
-				       case
-				         when m.status <> 1 then '休息中'
-				         when lower(coalesce(m.business_status, 'open')) in ('closed', '休息中') then '休息中'
-				         when exists (
-				           select 1
-				           from merchant_business_hours h
-				           join merchant_store s on s.id = h.store_id and s.status = 1 and s.deleted = 0
-				           where h.merchant_id = m.id
-				             and (
-				               (h.start_time <= h.end_time and current_time() >= h.start_time and current_time() < h.end_time)
-				               or (h.start_time > h.end_time and (current_time() >= h.start_time or current_time() < h.end_time))
-				             )
-				         ) then '营业中'
-				         else '休息中'
-				       end as business_status, m.created_at,
+				       m.created_at,
 				       (select count(*) from merchant_product p where p.merchant_id = m.id and p.deleted = 0) as product_count,
 				       (select count(*) from benefit_order o where o.merchant_id = m.id and o.deleted = 0) as order_count,
 				       0 as reservation_count
@@ -290,7 +279,45 @@
 			args.add(createdEnd);
 		}
 		sql.append(" order by m.is_recommend desc, m.sort_no desc, m.id desc");
-		return page(sql.toString(), countSql.toString(), page, size, args.toArray());
+		PageResult<Map<String, Object>> result = page(sql.toString(), countSql.toString(), page, size, args.toArray());
+		applyBusinessStatus(result.records());
+		return result;
+	}
+
+	@Transactional(readOnly = true)
+	public List<Map<String, Object>> pendingNotices() {
+		List<Map<String, Object>> notices = new ArrayList<>();
+		addPendingNotice(notices, "product-audit", "团单审核", "您有 %d 条团单待审核", "/products",
+				"select count(*) as pending_count, max(coalesce(submit_time, created_at)) as latest_time from merchant_product where deleted = 0 and audit_status = 1");
+		addPendingNotice(notices, "family-card", "家属卡申请", "您有 %d 条家属卡申请待审核", "/family-card-applications",
+				"select count(*) as pending_count, max(apply_time) as latest_time from family_card_application where deleted = 0 and status = '待审核'");
+		addPendingNotice(notices, "upgrade", "升级申请", "您有 %d 条升级申请待审核", "/upgrade-applications",
+				"select count(*) as pending_count, max(apply_time) as latest_time from upgrade_application where deleted = 0 and status = '待审核'");
+		addPendingNotice(notices, "merchant-onboarding", "商户进件", "您有 %d 条商户进件待审核", "/merchant-settlement?kind=onboardings",
+				"select count(*) as pending_count, max(created_at) as latest_time from merchant_onboarding_application where status = 'pending'");
+		addPendingNotice(notices, "merchant-bank-card", "银行卡申请", "您有 %d 条银行卡申请待审核", "/merchant-settlement?kind=bank-cards",
+				"select count(*) as pending_count, max(created_at) as latest_time from merchant_bank_card where status = 'pending'");
+		addPendingNotice(notices, "merchant-withdrawal", "提现审核", "您有 %d 条提现申请待审核", "/merchant-settlement?kind=withdrawals",
+				"select count(*) as pending_count, max(created_at) as latest_time from merchant_withdrawal where status = 'pending'");
+		addPendingNotice(notices, "medical-reservation", "体检预约", "您有 %d 条体检预约待处理", "/medical-reservations",
+				"select count(*) as pending_count, max(submitted_at) as latest_time from service_application where deleted = 0 and application_type = 'MEDICAL_RESERVATION' and status = '待处理'");
+		addPendingNotice(notices, "medical-application", "就医申请", "您有 %d 条就医申请待处理", "/medical-applications",
+				"select count(*) as pending_count, max(submitted_at) as latest_time from service_application where deleted = 0 and application_type = 'MEDICAL_APPLICATION' and status = '待处理'");
+		notices.sort((left, right) -> String.valueOf(right.get("time")).compareTo(String.valueOf(left.get("time"))));
+		return notices;
+	}
+
+	private void addPendingNotice(List<Map<String, Object>> notices, String id, String category, String template, String path, String sql) {
+		Map<String, Object> summary = DatabaseRows.normalize(jdbcTemplate.queryForMap(sql));
+		long count = summary.get("pendingCount") instanceof Number number ? number.longValue() : 0;
+		if (count == 0) return;
+		Map<String, Object> notice = new LinkedHashMap<>();
+		notice.put("id", id);
+		notice.put("category", category);
+		notice.put("content", template.formatted(count));
+		notice.put("time", summary.get("latestTime"));
+		notice.put("path", path);
+		notices.add(notice);
 	}
 
 	@Transactional(readOnly = true)
@@ -335,7 +362,7 @@
 	@Transactional
 	public Map<String, Object> createMerchant(MerchantCreateRequest request) {
 		validateMerchantAddress(request.merchantType(), request.address());
-		validateScenicMerchantCreate(request);
+		validateRequiredMerchantCreateFields(request);
 		jdbcTemplate.update("""
 				insert into merchant(merchant_name, merchant_type, contact_name, contact_mobile, address,
 					                     logo_url, cover_url, business_status, longitude, latitude, can_login_merchant_app, group_buying_enabled,
@@ -396,8 +423,8 @@
 		return MERCHANT_APP_LOGIN_TYPES.contains(merchantType);
 	}
 
-	private void validateScenicMerchantCreate(MerchantCreateRequest request) {
-		if (!"景区服务".equals(request.merchantType())) {
+	private void validateRequiredMerchantCreateFields(MerchantCreateRequest request) {
+		if (!Set.of("景区服务", "餐饮服务").contains(request.merchantType())) {
 			return;
 		}
 		if (request.businessHours() == null || request.businessHours().isEmpty()
@@ -907,6 +934,41 @@
 		return new PageResult<>(records, safePage, safeSize, total == null ? 0 : total);
 	}
 
+	private void applyBusinessStatus(List<Map<String, Object>> merchants) {
+		if (merchants.isEmpty()) return;
+		List<Long> merchantIds = merchants.stream().map(row -> Long.valueOf(String.valueOf(row.get("id")))).toList();
+		String placeholders = String.join(",", java.util.Collections.nCopies(merchantIds.size(), "?"));
+		List<Map<String, Object>> periods = DatabaseRows.normalize(jdbcTemplate.queryForList("""
+				select h.merchant_id, h.start_time, h.end_time
+				from merchant_business_hours h
+				join merchant_store s on s.id = h.store_id
+				where s.status = 1 and s.deleted = 0 and h.merchant_id in (""" + placeholders + ")", merchantIds.toArray()));
+		LocalTime now = LocalTime.now(ZoneId.of("Asia/Shanghai"));
+		Set<Long> openMerchantIds = new HashSet<>();
+		for (Map<String, Object> period : periods) {
+			if (isWithinBusinessPeriod(now, String.valueOf(period.get("startTime")), String.valueOf(period.get("endTime")))) {
+				openMerchantIds.add(Long.valueOf(String.valueOf(period.get("merchantId"))));
+			}
+		}
+		for (Map<String, Object> merchant : merchants) {
+			Long merchantId = Long.valueOf(String.valueOf(merchant.get("id")));
+			boolean enabled = "1".equals(String.valueOf(merchant.get("status")));
+			merchant.put("businessStatus", enabled && openMerchantIds.contains(merchantId) ? "营业中" : "休息中");
+		}
+	}
+
+	private boolean isWithinBusinessPeriod(LocalTime now, String startValue, String endValue) {
+		try {
+			LocalTime start = LocalTime.parse(startValue);
+			LocalTime end = LocalTime.parse(endValue);
+			return start.isBefore(end)
+					? !now.isBefore(start) && now.isBefore(end)
+					: !now.isBefore(start) || now.isBefore(end);
+		} catch (DateTimeParseException ignored) {
+			return false;
+		}
+	}
+
 	private void ensureUpdated(int updated) {
 		if (updated == 0) {
 			throw new BusinessException(ErrorCode.NOT_FOUND, "Data not found");

--
Gitblit v1.7.1