From b55cd9aad0835a96a790e61f9f89edc2fae1be9f Mon Sep 17 00:00:00 2001
From: 刘帅 <rr.iii@qq.com>
Date: 星期二, 29 九月 2026 01:26:37 +0800
Subject: [PATCH] 注释优化、格式优化
---
cloud-server-other/src/main/java/com/dsh/other/mapper/QrLinkMapper.java | 12 +
cloud-server-management/src/main/webapp/static/modular/system/appGuide/appGuide.js | 121 +++++++++++-
cloud-server-other/src/main/java/com/dsh/other/entity/AppGuideConfig.java | 75 ++++++-
cloud-server-other/src/main/java/com/dsh/other/service/SysAccountAuditLogService.java | 11 +
cloud-server-management/src/main/java/cn/mb/cloud/common/sentinel/fallback/DefaultFeignFallback.java | 14
cloud-server-other/src/main/java/com/dsh/other/controller/AppGuideController.java | 68 +++++-
cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/code/AppGuideManagementController.java | 64 ++++++
cloud-server-management/src/main/java/com/dsh/guns/modular/system/util/ExcelUtil.java | 8
cloud-server-management/src/main/java/com/dsh/privacy/SensitiveDataMaskingAdvice.java | 22 +-
cloud-server-other/src/main/java/com/dsh/other/mapper/SysAccountAuditLogMapper.java | 5
cloud-server-account/src/main/java/com/dsh/privacy/UnmaskedSensitiveData.java | 4
cloud-server-other/src/main/java/com/dsh/other/entity/AppGuideBanner.java | 28 ++
cloud-server-other/src/main/java/com/dsh/other/mapper/AppGuideBannerMapper.java | 12 +
cloud-server-account/src/main/java/com/dsh/account/controller/AppUserController.java | 16
cloud-server-account/src/main/java/com/dsh/privacy/SensitiveDataMaskingAdvice.java | 4
cloud-server-other/src/main/java/com/dsh/other/feignclient/account/AppUserClient.java | 2
cloud-server-other/src/main/java/com/dsh/other/mapper/AppGuideConfigMapper.java | 12 +
cloud-server-other/src/main/java/com/dsh/other/entity/QrLink.java | 60 +++++-
cloud-server-management/src/main/java/com/dsh/course/feignClient/account/AppUserClient.java | 4
19 files changed, 443 insertions(+), 99 deletions(-)
diff --git a/cloud-server-account/src/main/java/com/dsh/account/controller/AppUserController.java b/cloud-server-account/src/main/java/com/dsh/account/controller/AppUserController.java
index d8b3fbe..69e1c50 100644
--- a/cloud-server-account/src/main/java/com/dsh/account/controller/AppUserController.java
+++ b/cloud-server-account/src/main/java/com/dsh/account/controller/AppUserController.java
@@ -247,10 +247,9 @@
}
/**
- * Internal-only data source for the management sensitive-data query. The
- * caller is authenticated and authorised by the management service; its
- * Feign interceptor adds the header that permits the response to remain
- * unmasked for that single request.
+ * 仅供管理端敏感信息查询使用的内部数据接口。
+ * 调用方由管理服务完成认证和授权;其 Feign 拦截器会添加请求头,
+ * 以允许本次响应不进行脱敏。
*/
@PostMapping("/internal/sensitive/app-user/{id}")
public Map<String, Object> sensitiveAppUser(@PathVariable("id") Integer id,
@@ -269,9 +268,8 @@
}
/**
- * Internal data source used when an APP booking submits its displayed,
- * masked phone number. Limit the response to the single field needed for
- * that booking; callers must use the internal sensitive-data header.
+ * APP 订场提交页面展示的脱敏手机号时使用的内部数据接口。
+ * 仅返回该预约所需的手机号字段;调用方必须携带内部敏感数据访问请求头。
*/
@PostMapping("/internal/sensitive/site-booking/app-user/{id}/phone")
public Map<String, Object> siteBookingPhone(@PathVariable("id") Integer id,
@@ -883,8 +881,8 @@
public void updateAppUser(@RequestBody TAppUser appUser) {
try {
TAppUser appUser1 = appUserService.getById(appUser.getId());
- // A management edit form may contain the displayed masked value.
- // Never persist that display value over the original identifier.
+ // 管理端编辑表单可能携带页面展示的脱敏值。
+ // 不得使用该展示值覆盖原始证件或联系方式。
if (appUser.getPhone() != null && appUser.getPhone().contains("*")) appUser.setPhone(appUser1.getPhone());
if (appUser.getIdCard() != null && appUser.getIdCard().contains("*")) appUser.setIdCard(appUser1.getIdCard());
appUserService.updateById(appUser);
diff --git a/cloud-server-account/src/main/java/com/dsh/privacy/SensitiveDataMaskingAdvice.java b/cloud-server-account/src/main/java/com/dsh/privacy/SensitiveDataMaskingAdvice.java
index d19eeef..b9fde6f 100644
--- a/cloud-server-account/src/main/java/com/dsh/privacy/SensitiveDataMaskingAdvice.java
+++ b/cloud-server-account/src/main/java/com/dsh/privacy/SensitiveDataMaskingAdvice.java
@@ -57,8 +57,8 @@
private void mask(Object value, IdentityHashMap<Object, Boolean> visited) {
if (value == null || value instanceof String || value.getClass().isEnum() || visited.put(value, Boolean.TRUE) != null) return;
- // Path 的实现类(如 sun.nio.fs.UnixPath)本身是 Iterable;遍历其子路径会不断创建新对象,
- // IdentityHashMap 无法识别该循环,因而会导致 StackOverflowError。
+ // java.nio.file.Path 的实现类(如 sun.nio.fs.UnixPath)实现了 Iterable 接口;
+ // 遍历其子路径会不断创建新对象,IdentityHashMap 无法识别该循环,因而会导致 StackOverflowError。
if (value instanceof java.nio.file.Path || isJdkType(value.getClass())) return;
if (value instanceof Map) {
for (Object entryObject : ((Map<?, ?>) value).entrySet()) {
diff --git a/cloud-server-account/src/main/java/com/dsh/privacy/UnmaskedSensitiveData.java b/cloud-server-account/src/main/java/com/dsh/privacy/UnmaskedSensitiveData.java
index 95b6240..a09e59b 100644
--- a/cloud-server-account/src/main/java/com/dsh/privacy/UnmaskedSensitiveData.java
+++ b/cloud-server-account/src/main/java/com/dsh/privacy/UnmaskedSensitiveData.java
@@ -6,8 +6,8 @@
import java.lang.annotation.Target;
/**
- * Allows a single response field to bypass sensitive-data masking.
- * Use only for endpoints that are authorised to return the original value.
+ * 允许单个响应字段跳过敏感数据脱敏。
+ * 仅限已获授权返回原始数据的接口使用。
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
diff --git a/cloud-server-management/src/main/java/cn/mb/cloud/common/sentinel/fallback/DefaultFeignFallback.java b/cloud-server-management/src/main/java/cn/mb/cloud/common/sentinel/fallback/DefaultFeignFallback.java
index 4b6230f..d792aa8 100644
--- a/cloud-server-management/src/main/java/cn/mb/cloud/common/sentinel/fallback/DefaultFeignFallback.java
+++ b/cloud-server-management/src/main/java/cn/mb/cloud/common/sentinel/fallback/DefaultFeignFallback.java
@@ -18,12 +18,11 @@
import java.util.Set;
/**
- * Safe replacement for the common Sentinel Feign fallback.
+ * 公共 Sentinel Feign 降级处理的安全替代实现。
*
- * <p>The dependency version assumes every generic return type is a Class. That
- * is false for declarations such as {@code Map<String, Object>}, whose runtime
- * type is {@link ParameterizedType}; the failed cast used to hide the original
- * downstream exception behind an AssertionError.</p>
+ * <p>依赖版本假定所有泛型返回类型均为 {@link Class}。对于
+ * {@code Map<String, Object>} 等声明并不成立,其运行时类型为
+ * {@link ParameterizedType};此前转换失败会以 AssertionError 掩盖原始下游异常。</p>
*/
public class DefaultFeignFallback<T> implements MethodInterceptor {
private static final Logger log = LoggerFactory.getLogger(DefaultFeignFallback.class);
@@ -47,9 +46,8 @@
Class<?> returnType = rawType(declaredReturnType);
Object data = defaultValue(returnType);
- // Only methods that explicitly declare ResponseData may receive a
- // ResponseData fallback. Returning it from Map/List methods causes a
- // second ClassCastException in the Feign proxy.
+ // 仅显式声明返回 ResponseData 的方法可以返回 ResponseData 降级结果。
+ // 在 Map/List 方法中返回该对象会导致 Feign 代理再次抛出 ClassCastException。
if (ResponseData.class.equals(returnType)) {
Type dataType = firstTypeArgument(declaredReturnType);
return ResponseData.builder()
diff --git a/cloud-server-management/src/main/java/com/dsh/course/feignClient/account/AppUserClient.java b/cloud-server-management/src/main/java/com/dsh/course/feignClient/account/AppUserClient.java
index eeaac72..3a70a7b 100644
--- a/cloud-server-management/src/main/java/com/dsh/course/feignClient/account/AppUserClient.java
+++ b/cloud-server-management/src/main/java/com/dsh/course/feignClient/account/AppUserClient.java
@@ -28,11 +28,11 @@
@FeignClient("mb-cloud-account")
public interface AppUserClient {
- /** Only invoked by the super-administrator sensitive data query. */
+ /** 仅供超级管理员敏感信息查询接口调用。 */
@PostMapping("/internal/sensitive/app-user/{id}")
Map<String, Object> sensitiveAppUser(@PathVariable("id") Integer id);
- /** Only invoked by the super-administrator sensitive student-data query. */
+ /** 仅供超级管理员学员敏感信息查询接口调用。 */
@PostMapping("/internal/sensitive/student/{id}")
Map<String, Object> sensitiveStudent(@PathVariable("id") Integer id);
diff --git a/cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/code/AppGuideManagementController.java b/cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/code/AppGuideManagementController.java
index d874b00..2a1046e 100644
--- a/cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/code/AppGuideManagementController.java
+++ b/cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/code/AppGuideManagementController.java
@@ -39,17 +39,32 @@
@Autowired
private ITSiteService siteService;
+ /**
+ * 打开 APP 下载引导管理页面。
+ *
+ * @return APP 下载引导管理页面路径
+ */
@GetMapping("")
public String index() {
return "/system/appGuide/appGuide.html";
}
+ /**
+ * 查询可用于生成订场二维码的场地列表。
+ *
+ * @return 按 ID 倒序排列的场地列表
+ */
@ResponseBody
@GetMapping("/sites")
public List<TSite> queryAvailableSites() {
return siteService.list(new QueryWrapper<TSite>().orderByDesc("id"));
}
+ /**
+ * 查询 APP 下载引导页面所需的配置、宣传图和订场二维码数据。
+ *
+ * @return 下载引导页面的聚合数据
+ */
@ResponseBody
@GetMapping("/data")
public Map<String, Object> data() {
@@ -69,6 +84,12 @@
return r;
}
+ /**
+ * 保存 APP 下载引导配置。
+ *
+ * @param config 下载引导配置
+ * @return 保存结果
+ */
@ResponseBody
@PostMapping("/config")
public Map<String, Object> saveConfig(AppGuideConfig config) {
@@ -80,6 +101,12 @@
return ok();
}
+ /**
+ * 保存 APP 下载引导宣传图。
+ *
+ * @param banner 宣传图配置
+ * @return 保存结果
+ */
@ResponseBody
@PostMapping("/banner")
public Map<String, Object> saveBanner(AppGuideBanner banner) {
@@ -89,6 +116,12 @@
return ok();
}
+ /**
+ * 删除 APP 下载引导宣传图。
+ *
+ * @param id 宣传图 ID
+ * @return 删除结果
+ */
@ResponseBody
@PostMapping("/banner/delete")
public Map<String, Object> deleteBanner(Long id) {
@@ -96,6 +129,16 @@
return ok();
}
+ /**
+ * 为指定场地创建订场二维码。
+ *
+ * @param storeId 门店 ID
+ * @param siteId 场地 ID
+ * @param name 二维码名称
+ * @param channel 投放渠道
+ * @param pageName 引导页面名称
+ * @return 创建结果及二维码引导链接
+ */
@ResponseBody
@PostMapping("/siteQr")
public Map<String, Object> createSiteQr(Integer storeId, Integer siteId, String name, String channel, String pageName) {
@@ -118,6 +161,13 @@
return r;
}
+ /**
+ * 修改场地订场二维码的启用状态。
+ *
+ * @param id 二维码 ID
+ * @param enabled 启用状态(0:停用;1:启用)
+ * @return 修改结果
+ */
@ResponseBody
@PostMapping("/siteQr/status")
public Map<String, Object> changeStatus(Long id, Integer enabled) {
@@ -128,7 +178,12 @@
return ok();
}
- /** 逻辑删除场地订场二维码。 */
+ /**
+ * 逻辑删除场地订场二维码。
+ *
+ * @param id 二维码 ID
+ * @return 删除结果
+ */
@ResponseBody
@PostMapping("/siteQr/delete")
public Map<String, Object> deleteSiteQr(Long id) {
@@ -136,6 +191,13 @@
return ok();
}
+ /**
+ * 生成并输出场地订场二维码图片。
+ *
+ * @param id 二维码 ID
+ * @param response HTTP 响应
+ * @throws IOException 图片输出失败时抛出
+ */
@GetMapping("/siteQr/{id}.png")
public void qrImage(@PathVariable Long id, HttpServletResponse response) throws IOException {
QrLink link = qrLinkMapper.selectById(id);
diff --git a/cloud-server-management/src/main/java/com/dsh/guns/modular/system/util/ExcelUtil.java b/cloud-server-management/src/main/java/com/dsh/guns/modular/system/util/ExcelUtil.java
index 22e26b5..b757ddc 100644
--- a/cloud-server-management/src/main/java/com/dsh/guns/modular/system/util/ExcelUtil.java
+++ b/cloud-server-management/src/main/java/com/dsh/guns/modular/system/util/ExcelUtil.java
@@ -40,7 +40,13 @@
return wb;
}
- /** Export files are an external disclosure channel and always remain masked. */
+ /**
+ * 导出文件属于对外数据出口,敏感字段必须始终保持脱敏。
+ *
+ * @param columnName 列名,用于识别手机号和身份证号等敏感字段
+ * @param value 原始单元格值
+ * @return 脱敏后的单元格值
+ */
private static String maskSensitiveValue(String columnName, String value) {
if (value == null) return null;
String column = columnName == null ? "" : columnName.toLowerCase();
diff --git a/cloud-server-management/src/main/java/com/dsh/privacy/SensitiveDataMaskingAdvice.java b/cloud-server-management/src/main/java/com/dsh/privacy/SensitiveDataMaskingAdvice.java
index 5948ebb..3724891 100644
--- a/cloud-server-management/src/main/java/com/dsh/privacy/SensitiveDataMaskingAdvice.java
+++ b/cloud-server-management/src/main/java/com/dsh/privacy/SensitiveDataMaskingAdvice.java
@@ -15,14 +15,14 @@
import java.util.Iterator;
import java.util.Map;
-/** Ensures every normal management JSON response uses the same privacy rules. */
+/** 确保所有常规管理端 JSON 响应均遵循统一的隐私保护规则。 */
@ControllerAdvice
public class SensitiveDataMaskingAdvice implements ResponseBodyAdvice<Object> {
private final HttpServletRequest request;
public SensitiveDataMaskingAdvice(HttpServletRequest request) { this.request = request; }
@Override public boolean supports(MethodParameter type, Class<? extends HttpMessageConverter<?>> converter) {
- // Only the explicit, admin-only and audited endpoint returns the source value.
+ // 仅明确限定、仅管理员可访问且已审计的接口返回原始数据。
return !request.getRequestURI().startsWith("/system/sensitive/");
}
@Override public Object beforeBodyWrite(Object body, MethodParameter type, MediaType mediaType,
@@ -32,13 +32,12 @@
}
private void mask(Object value, IdentityHashMap<Object, Boolean> seen) {
if (value == null || value instanceof String || value.getClass().isEnum() || seen.put(value, Boolean.TRUE) != null) return;
- // Reactive streams and their internal queues are runtime infrastructure, not
- // response DTOs. In particular, Reactor's MpscLinkedQueue implements
- // Iterable but deliberately throws UnsupportedOperationException from
- // iterator(). Do not introspect it (or any other reactive infrastructure).
+ // 响应式流及其内部队列属于运行时基础设施,并非响应 DTO。特别是 Reactor 的
+ // MpscLinkedQueue 虽实现了 Iterable,却会在 iterator() 中主动抛出
+ // UnsupportedOperationException;不得反射遍历它或其他响应式基础设施。
if (isReactiveInfrastructure(value.getClass())) return;
- // UnixPath implements Iterable. Its iterator creates a new Path for every
- // segment, so identity-based cycle detection cannot stop the recursion.
+ // UnixPath 实现了 Iterable,其迭代器会为每个路径段创建新的 Path 对象,
+ // 因此基于对象标识的循环检测无法终止递归。
if (value instanceof Path) return;
if (value instanceof Map) {
for (Object item : ((Map<?, ?>) value).entrySet()) {
@@ -62,16 +61,15 @@
}
/**
- * Some third-party containers expose Iterable only for API compatibility and
- * intentionally do not support iteration. A response privacy filter must never
- * turn such an implementation detail into a 500 response.
+ * 部分第三方容器仅为 API 兼容而实现 Iterable,并不支持实际迭代。
+ * 响应隐私过滤器不得因这类实现细节导致接口返回 500 错误。
*/
private void maskIterable(Iterable<?> values, IdentityHashMap<Object, Boolean> seen) {
try {
Iterator<?> iterator = values.iterator();
while (iterator.hasNext()) mask(iterator.next(), seen);
} catch (UnsupportedOperationException ignored) {
- // There is no safely accessible element to mask.
+ // 没有可安全访问并进行脱敏的元素。
}
}
diff --git a/cloud-server-management/src/main/webapp/static/modular/system/appGuide/appGuide.js b/cloud-server-management/src/main/webapp/static/modular/system/appGuide/appGuide.js
index 270e688..56d88f1 100644
--- a/cloud-server-management/src/main/webapp/static/modular/system/appGuide/appGuide.js
+++ b/cloud-server-management/src/main/webapp/static/modular/system/appGuide/appGuide.js
@@ -1,11 +1,110 @@
-(function(){
- function esc(v){return $('<div>').text(v==null?'':v).html()} function val(n,v){$('#configForm [name='+n+']').val(v==null?'':v)}
- window.reloadAppGuide=function(){ $.get(Feng.ctxPath+'/appGuide/data',function(d){var c=d.config||{};['id','apkUrl','iosStoreUrl'].forEach(function(k){val(k,c[k])});$('#bannerRows').html((d.banners||[]).map(function(x){return '<tr><td><img class="qr" src="'+esc(x.imageUrl)+'"></td><td>'+esc(x.title)+'</td><td>'+esc(x.sort)+'</td><td>'+((x.enabled===1)?'启用':'停用')+'</td><td><button class="btn btn-danger btn-xs" onclick="deleteBanner(\''+x.id+'\')">删除</button></td></tr>'}).join(''));$('#linkRows').html((d.links||[]).map(function(x){var id=String(x.id),q=Feng.ctxPath+'/appGuide/siteQr/'+encodeURIComponent(id)+'.png';return '<tr><td>'+esc(x.name)+'</td><td>'+esc(x.pageName)+'</td><td>'+x.storeId+' / '+x.siteId+'</td><td><a href="'+q+'" target="_blank"><img class="qr" src="'+q+'"></a></td><td><code>'+esc(x.guideUrl)+'</code></td><td>'+((x.enabled===1)?'启用':'停用')+'</td><td><button class="btn btn-warning btn-xs" onclick="changeQr(\''+id+'\','+(x.enabled===1?0:1)+')">'+(x.enabled===1?'停用':'启用')+'</button> <button class="btn btn-danger btn-xs" onclick="deleteQr(\''+id+'\')">删除</button></td></tr>'}).join(''))})};
- window.saveConfig=function(){$.post(Feng.ctxPath+'/appGuide/config',$('#configForm').serialize(),function(){Feng.success('保存成功');reloadAppGuide()})};
- window.uploadBanner=function(){var f=$('#bannerFile')[0].files[0];if(!f){Feng.info('请选择图片');return}var d=new FormData();d.append('file',f);$.ajax({url:Feng.ctxPath+'/mgr/uploadFile',data:d,type:'POST',contentType:false,processData:false,success:function(url){$('#bannerUrl').val(url);$('#uploadTip').text('上传成功')}})};
- window.addBanner=function(){if(!$('#bannerUrl').val()){Feng.info('请先上传图片');return}$.post(Feng.ctxPath+'/appGuide/banner',{imageUrl:$('#bannerUrl').val(),title:$('#bannerTitle').val(),sort:$('#bannerSort').val()||0,enabled:1},function(){reloadAppGuide();$('#bannerUrl,#bannerTitle,#bannerSort,#bannerFile').val('')})};
- window.deleteBanner=function(id){$.post(Feng.ctxPath+'/appGuide/banner/delete',{id:id},reloadAppGuide)};
- window.createQr=function(){var o=$('#siteSelect option:selected'),pageName='com.sinata.wepark.ui.home.PlaceDetailActivity';if(!o.val()){Feng.info('请选择场地');return}$.post(Feng.ctxPath+'/appGuide/siteQr',{storeId:o.data('store'),siteId:o.val(),name:o.text(),pageName:pageName},function(r){if(!r.success){Feng.error(r.message);return}Feng.success('已生成');reloadAppGuide()})};
- window.changeQr=function(id,enabled){$.post(Feng.ctxPath+'/appGuide/siteQr/status',{id:id,enabled:enabled},reloadAppGuide)};$.get(Feng.ctxPath+'/appGuide/sites',function(s){$('#siteSelect').append((s||[]).map(function(x){return '<option value="'+x.id+'" data-store="'+x.storeId+'">['+x.storeId+'] '+esc(x.name)+'</option>'}).join(''))});$(reloadAppGuide);
- window.deleteQr=function(id){if(!confirm('确认删除该场地订场二维码?'))return;$.post(Feng.ctxPath+'/appGuide/siteQr/delete',{id:id},reloadAppGuide)};
-})();
+(function() {
+ function esc(v) {
+ return $('<div>').text(v == null ? '' : v).html()
+ }
+
+ function val(n, v) {
+ $('#configForm [name=' + n + ']').val(v == null ? '' : v)
+ }
+ window.reloadAppGuide = function() {
+ $.get(Feng.ctxPath + '/appGuide/data', function(d) {
+ var c = d.config || {};
+ ['id', 'apkUrl', 'iosStoreUrl'].forEach(function(k) {
+ val(k, c[k])
+ });
+ $('#bannerRows').html((d.banners || []).map(function(x) {
+ return '<tr><td><img class="qr" src="' + esc(x.imageUrl) + '"></td><td>' + esc(x.title) + '</td><td>' + esc(x.sort) + '</td><td>' + ((x.enabled === 1) ? '启用' : '停用') + '</td><td><button class="btn btn-danger btn-xs" onclick="deleteBanner(\'' + x.id + '\')">删除</button></td></tr>'
+ }).join(''));
+ $('#linkRows').html((d.links || []).map(function(x) {
+ var id = String(x.id),
+ q = Feng.ctxPath + '/appGuide/siteQr/' + encodeURIComponent(id) + '.png';
+ return '<tr><td>' + esc(x.name) + '</td><td>' + esc(x.pageName) + '</td><td>' + x.storeId + ' / ' + x.siteId + '</td><td><a href="' + q + '" target="_blank"><img class="qr" src="' + q + '"></a></td><td><code>' + esc(x.guideUrl) + '</code></td><td>' + ((x.enabled === 1) ? '启用' : '停用') + '</td><td><button class="btn btn-warning btn-xs" onclick="changeQr(\'' + id + '\',' + (x.enabled === 1 ? 0 : 1) + ')">' + (x.enabled === 1 ? '停用' : '启用') + '</button> <button class="btn btn-danger btn-xs" onclick="deleteQr(\'' + id + '\')">删除</button></td></tr>'
+ }).join(''))
+ })
+ };
+ window.saveConfig = function() {
+ $.post(Feng.ctxPath + '/appGuide/config', $('#configForm').serialize(), function() {
+ Feng.success('保存成功');
+ reloadAppGuide()
+ })
+ };
+ window.uploadBanner = function() {
+ var f = $('#bannerFile')[0].files[0];
+ if (!f) {
+ Feng.info('请选择图片');
+ return
+ }
+ var d = new FormData();
+ d.append('file', f);
+ $.ajax({
+ url: Feng.ctxPath + '/mgr/uploadFile',
+ data: d,
+ type: 'POST',
+ contentType: false,
+ processData: false,
+ success: function(url) {
+ $('#bannerUrl').val(url);
+ $('#uploadTip').text('上传成功')
+ }
+ })
+ };
+ window.addBanner = function() {
+ if (!$('#bannerUrl').val()) {
+ Feng.info('请先上传图片');
+ return
+ }
+ $.post(Feng.ctxPath + '/appGuide/banner', {
+ imageUrl: $('#bannerUrl').val(),
+ title: $('#bannerTitle').val(),
+ sort: $('#bannerSort').val() || 0,
+ enabled: 1
+ }, function() {
+ reloadAppGuide();
+ $('#bannerUrl,#bannerTitle,#bannerSort,#bannerFile').val('')
+ })
+ };
+ window.deleteBanner = function(id) {
+ $.post(Feng.ctxPath + '/appGuide/banner/delete', {
+ id: id
+ }, reloadAppGuide)
+ };
+ window.createQr = function() {
+ var o = $('#siteSelect option:selected'),
+ pageName = 'com.sinata.wepark.ui.home.PlaceDetailActivity';
+ if (!o.val()) {
+ Feng.info('请选择场地');
+ return
+ }
+ $.post(Feng.ctxPath + '/appGuide/siteQr', {
+ storeId: o.data('store'),
+ siteId: o.val(),
+ name: o.text(),
+ pageName: pageName
+ }, function(r) {
+ if (!r.success) {
+ Feng.error(r.message);
+ return
+ }
+ Feng.success('已生成');
+ reloadAppGuide()
+ })
+ };
+ window.changeQr = function(id, enabled) {
+ $.post(Feng.ctxPath + '/appGuide/siteQr/status', {
+ id: id,
+ enabled: enabled
+ }, reloadAppGuide)
+ };
+ $.get(Feng.ctxPath + '/appGuide/sites', function(s) {
+ $('#siteSelect').append((s || []).map(function(x) {
+ return '<option value="' + x.id + '" data-store="' + x.storeId + '">[' + x.storeId + '] ' + esc(x.name) + '</option>'
+ }).join(''))
+ });
+ $(reloadAppGuide);
+ window.deleteQr = function(id) {
+ if (!confirm('确认删除该场地订场二维码?')) return;
+ $.post(Feng.ctxPath + '/appGuide/siteQr/delete', {
+ id: id
+ }, reloadAppGuide)
+ };
+})();
\ No newline at end of file
diff --git a/cloud-server-other/src/main/java/com/dsh/other/controller/AppGuideController.java b/cloud-server-other/src/main/java/com/dsh/other/controller/AppGuideController.java
index 8ff8bcf..83af6e9 100644
--- a/cloud-server-other/src/main/java/com/dsh/other/controller/AppGuideController.java
+++ b/cloud-server-other/src/main/java/com/dsh/other/controller/AppGuideController.java
@@ -15,26 +15,36 @@
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
-import org.springframework.beans.factory.annotation.Autowired;
+
+import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
-
-import javax.annotation.Resource;
-import java.util.*;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
/** 对外下载引导页与 App 扫码解析接口。 */
@RestController
@Api(tags = "APP下载引导与场地二维码")
public class AppGuideController {
- @Autowired private AppGuideConfigMapper appGuideConfigMapper;
- @Autowired private AppGuideBannerMapper appGuideBannerMapper;
- @Autowired private QrLinkMapper qrLinkMapper;
- @Autowired private TokenUtil tokenUtil;
+ @Autowired
+ private AppGuideConfigMapper appGuideConfigMapper;
+
+ @Autowired
+ private AppGuideBannerMapper appGuideBannerMapper;
+
+ @Autowired
+ private QrLinkMapper qrLinkMapper;
+
+ @Autowired
+ private TokenUtil tokenUtil;
// @GetMapping("/q/{shortCode}")
// public void guidePage(@PathVariable String shortCode, HttpServletRequest request,
@@ -48,10 +58,16 @@
@ApiOperation("获取下载引导页配置(无需登录)")
public ResultUtil<Map<String, Object>> guideConfig(String code) {
AppGuideConfig config = appGuideConfigMapper.selectOne(new QueryWrapper<AppGuideConfig>()
- .eq("enabled", EnableStatusEnum.ENABLED.getCode()).orderByDesc("updateTime").last("limit 1"));
- if (config == null) return ResultUtil.error("下载引导页尚未配置");
+ .eq("enabled", EnableStatusEnum.ENABLED.getCode())
+ .orderByDesc("updateTime")
+ .last("limit 1"));
+ if (config == null) {
+ return ResultUtil.error("下载引导页尚未配置");
+ }
QrLink link = validLink(code);
- if (code != null && !code.isEmpty() && link == null) return ResultUtil.error("二维码无效或已失效");
+ if (code != null && !code.isEmpty() && link == null) {
+ return ResultUtil.error("二维码无效或已失效");
+ }
Map<String, Object> data = new HashMap<>();
data.put("appName", StringUtils.isNotBlank(config.getAppName()) ? config.getAppName() : "玩湃生活");
data.put("androidPackage", StringUtils.isNotBlank(config.getAndroidPackage()) ? config.getAndroidPackage() : "com.sinata.wepark");
@@ -61,7 +77,9 @@
data.put("androidDeepLink", config.getAndroidDeepLink() + (StringUtils.isNotBlank(code) ? "?route=" + code : ""));
data.put("iosDeepLink", "weparklife://app" + (StringUtils.isNotBlank(code) ? "?code=" + code : ""));
data.put("banners", appGuideBannerMapper.selectList(new QueryWrapper<AppGuideBanner>()
- .eq("enabled", EnableStatusEnum.ENABLED.getCode()).orderByAsc("sort").orderByDesc("id")));
+ .eq("enabled", EnableStatusEnum.ENABLED.getCode())
+ .orderByAsc("sort")
+ .orderByDesc("id")));
// if (link != null) data.put("target", target(link));
return ResultUtil.success(data);
}
@@ -70,15 +88,23 @@
@ApiOperation("App扫码解析二维码")
public ResultUtil<Map<String, Object>> resolve(String code) {
QrLink link = validLink(code);
- if (link == null) return ResultUtil.error("二维码无效或已失效");
+ if (link == null) {
+ return ResultUtil.error("二维码无效或已失效");
+ }
return ResultUtil.success(target(link));
}
private QrLink validLink(String code) {
- if (code == null || !code.matches("[A-Za-z0-9]{6,32}")) return null;
- QrLink link = qrLinkMapper.selectOne(new QueryWrapper<QrLink>().eq("shortCode", code).last("limit 1"));
+ if (code == null || !code.matches("[A-Za-z0-9]{6,32}")) {
+ return null;
+ }
+ QrLink link = qrLinkMapper.selectOne(new QueryWrapper<QrLink>()
+ .eq("shortCode", code)
+ .last("limit 1"));
if (link == null || !Integer.valueOf(1).equals(link.getEnabled())
- || (link.getExpiresAt() != null && link.getExpiresAt().before(new Date()))) return null;
+ || (link.getExpiresAt() != null && link.getExpiresAt().before(new Date()))) {
+ return null;
+ }
return link;
}
@@ -92,7 +118,13 @@
}
private Object parseJson(String text) {
- if (text == null || text.trim().isEmpty()) return Collections.emptyMap();
- try { return JSON.parseObject(text); } catch (Exception ignored) { return Collections.emptyMap(); }
+ if (text == null || text.trim().isEmpty()) {
+ return Collections.emptyMap();
+ }
+ try {
+ return JSON.parseObject(text);
+ } catch (Exception ignored) {
+ return Collections.emptyMap();
+ }
}
}
diff --git a/cloud-server-other/src/main/java/com/dsh/other/entity/AppGuideBanner.java b/cloud-server-other/src/main/java/com/dsh/other/entity/AppGuideBanner.java
index 788490e..c0d9f15 100644
--- a/cloud-server-other/src/main/java/com/dsh/other/entity/AppGuideBanner.java
+++ b/cloud-server-other/src/main/java/com/dsh/other/entity/AppGuideBanner.java
@@ -1,28 +1,48 @@
package com.dsh.other.entity;
import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
+
import java.util.Date;
/** APP 下载引导宣传图实体,对应表 t_app_guide_banner。 */
@Getter
@Setter
@TableName("t_app_guide_banner")
+@ApiModel(description = "APP 下载引导宣传图")
public class AppGuideBanner {
@TableId(type = IdType.ID_WORKER)
+ @ApiModelProperty("主键 ID")
private Long id;
- @TableField("imageUrl") private String imageUrl;
+
+ @TableField("imageUrl")
+ @ApiModelProperty("宣传图地址")
+ private String imageUrl;
+
+ @ApiModelProperty("宣传图标题")
private String title;
+
+ @ApiModelProperty("排序值")
private Integer sort;
+
+ @ApiModelProperty("启用状态:0-停用,1-启用")
private Integer enabled;
+
/** 逻辑删除标识:0-正常,1-删除。 */
@TableLogic
@TableField("isDeleted")
+ @ApiModelProperty("逻辑删除标识:0-正常,1-删除")
private Integer isDeleted;
- /** 创建时间。 */ @TableField("createTime") private Date createTime;
+
+ /** 创建时间。 */
+ @TableField("createTime")
+ @ApiModelProperty("创建时间")
+ private Date createTime;
}
diff --git a/cloud-server-other/src/main/java/com/dsh/other/entity/AppGuideConfig.java b/cloud-server-other/src/main/java/com/dsh/other/entity/AppGuideConfig.java
index 7a1c734..963a02b 100644
--- a/cloud-server-other/src/main/java/com/dsh/other/entity/AppGuideConfig.java
+++ b/cloud-server-other/src/main/java/com/dsh/other/entity/AppGuideConfig.java
@@ -1,10 +1,12 @@
package com.dsh.other.entity;
import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
@@ -14,24 +16,67 @@
@Getter
@Setter
@TableName("t_app_guide_config")
+@ApiModel(description = "APP 下载引导配置")
public class AppGuideConfig {
- /** 主键ID(雪花算法生成)。 */ @TableId(type = IdType.ID_WORKER)
+ /** 主键ID(雪花算法生成)。 */
+ @TableId(type = IdType.ID_WORKER)
+ @ApiModelProperty("主键 ID")
private Long id;
- @TableField("appName") private String appName;
- @TableField("appScheme") private String appScheme;
- @TableField("androidPackage") private String androidPackage;
- @TableField("iosPackage") private String iosPackage;
- @TableField("iosStoreUrl") private String iosStoreUrl;
- @TableField("androidDefaultUrl") private String androidDefaultUrl;
- @TableField("androidMarketUrls") private String androidMarketUrls;
- @TableField("apkUrl") private String apkUrl;
- @TableField("androidDeepLink") private String androidDeepLink;
- @TableField("iosDeepLink") private String iosDeepLink;
- @TableField("guideDomain") private String guideDomain;
+
+ @TableField("appName")
+ @ApiModelProperty("APP 名称")
+ private String appName;
+
+ @TableField("appScheme")
+ @ApiModelProperty("APP 自定义 Scheme")
+ private String appScheme;
+
+ @TableField("androidPackage")
+ @ApiModelProperty("Android 应用包名")
+ private String androidPackage;
+
+ @TableField("iosPackage")
+ @ApiModelProperty("iOS 应用包名")
+ private String iosPackage;
+
+ @TableField("iosStoreUrl")
+ @ApiModelProperty("iOS App Store 地址")
+ private String iosStoreUrl;
+
+ @TableField("androidDefaultUrl")
+ @ApiModelProperty("Android 默认应用市场地址")
+ private String androidDefaultUrl;
+
+ @TableField("androidMarketUrls")
+ @ApiModelProperty("Android 品牌应用市场地址 JSON")
+ private String androidMarketUrls;
+
+ @TableField("apkUrl")
+ @ApiModelProperty("APK 下载地址")
+ private String apkUrl;
+
+ @TableField("androidDeepLink")
+ @ApiModelProperty("Android 深度链接")
+ private String androidDeepLink;
+
+ @TableField("iosDeepLink")
+ @ApiModelProperty("iOS 深度链接")
+ private String iosDeepLink;
+
+ @TableField("guideDomain")
+ @ApiModelProperty("二维码引导域名")
+ private String guideDomain;
+
+ @ApiModelProperty("启用状态:0-停用,1-启用")
private Integer enabled;
+
/** 逻辑删除标识:0-正常,1-删除。 */
@TableLogic
@TableField("isDeleted")
+ @ApiModelProperty("逻辑删除标识:0-正常,1-删除")
private Integer isDeleted;
- @TableField("updateTime") private Date updateTime;
+
+ @TableField("updateTime")
+ @ApiModelProperty("更新时间")
+ private Date updateTime;
}
diff --git a/cloud-server-other/src/main/java/com/dsh/other/entity/QrLink.java b/cloud-server-other/src/main/java/com/dsh/other/entity/QrLink.java
index be3bba8..f0da645 100644
--- a/cloud-server-other/src/main/java/com/dsh/other/entity/QrLink.java
+++ b/cloud-server-other/src/main/java/com/dsh/other/entity/QrLink.java
@@ -1,35 +1,75 @@
package com.dsh.other.entity;
import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
+
import java.util.Date;
/** 二维码短链接实体,对应表 t_qr_link。 */
@Getter
@Setter
@TableName("t_qr_link")
+@ApiModel(description = "二维码短链接")
public class QrLink {
@TableId(type = IdType.ID_WORKER)
+ @ApiModelProperty("主键 ID")
private Long id;
- @TableField("shortCode") private String shortCode;
+
+ @TableField("shortCode")
+ @ApiModelProperty("二维码短码")
+ private String shortCode;
+
+ @ApiModelProperty("二维码类型")
private String type;
- @TableField("storeId") private Integer storeId;
- @TableField("siteId") private Integer siteId;
- @TableField("bookingId") private Integer bookingId;
+
+ @TableField("storeId")
+ @ApiModelProperty("关联门店 ID")
+ private Integer storeId;
+
+ @TableField("siteId")
+ @ApiModelProperty("关联场地 ID")
+ private Integer siteId;
+
+ @TableField("bookingId")
+ @ApiModelProperty("关联预约订单 ID")
+ private Integer bookingId;
+
+ @ApiModelProperty("二维码名称")
private String name;
+
+ @ApiModelProperty("投放渠道")
private String channel;
- @TableField("pageName") private String pageName;
- @TableField("expiresAt") private Date expiresAt;
+
+ @TableField("pageName")
+ @ApiModelProperty("跳转页面名称")
+ private String pageName;
+
+ @TableField("expiresAt")
+ @ApiModelProperty("失效时间")
+ private Date expiresAt;
+
+ @ApiModelProperty("启用状态:0-停用,1-启用")
private Integer enabled;
+
/** 逻辑删除标识:0-正常,1-删除。 */
@TableLogic
@TableField("isDeleted")
+ @ApiModelProperty("逻辑删除标识:0-正常,1-删除")
private Integer isDeleted;
- /** 创建时间。 */ @TableField("createTime") private Date createTime;
- @TableField("updateTime") private Date updateTime;
+
+ /** 创建时间。 */
+ @TableField("createTime")
+ @ApiModelProperty("创建时间")
+ private Date createTime;
+
+ @TableField("updateTime")
+ @ApiModelProperty("更新时间")
+ private Date updateTime;
}
diff --git a/cloud-server-other/src/main/java/com/dsh/other/feignclient/account/AppUserClient.java b/cloud-server-other/src/main/java/com/dsh/other/feignclient/account/AppUserClient.java
index 1e2b234..5c5b1cb 100644
--- a/cloud-server-other/src/main/java/com/dsh/other/feignclient/account/AppUserClient.java
+++ b/cloud-server-other/src/main/java/com/dsh/other/feignclient/account/AppUserClient.java
@@ -33,7 +33,7 @@
@PostMapping("/base/appUser/updateAppUser")
void updateAppUser(AppUser appUser);
- /** Gets only the original phone for the authenticated user's site booking. */
+ /** 获取已认证用户订场所需的原始手机号。 */
@PostMapping("/internal/sensitive/site-booking/app-user/{id}/phone")
Map<String, Object> siteBookingPhone(@PathVariable("id") Integer appUserId,
@RequestHeader("X-Internal-Sensitive-Access") String sensitiveAccess);
diff --git a/cloud-server-other/src/main/java/com/dsh/other/mapper/AppGuideBannerMapper.java b/cloud-server-other/src/main/java/com/dsh/other/mapper/AppGuideBannerMapper.java
index b351b27..fb896d4 100644
--- a/cloud-server-other/src/main/java/com/dsh/other/mapper/AppGuideBannerMapper.java
+++ b/cloud-server-other/src/main/java/com/dsh/other/mapper/AppGuideBannerMapper.java
@@ -1,4 +1,14 @@
package com.dsh.other.mapper;
+
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dsh.other.entity.AppGuideBanner;
-public interface AppGuideBannerMapper extends BaseMapper<AppGuideBanner> {}
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * APP 下载引导宣传图数据访问层。
+ *
+ * <p>继承 {@link BaseMapper},提供 {@link AppGuideBanner} 的基础增删改查能力。</p>
+ */
+@Mapper
+public interface AppGuideBannerMapper extends BaseMapper<AppGuideBanner> {
+}
diff --git a/cloud-server-other/src/main/java/com/dsh/other/mapper/AppGuideConfigMapper.java b/cloud-server-other/src/main/java/com/dsh/other/mapper/AppGuideConfigMapper.java
index 7410414..fde70b2 100644
--- a/cloud-server-other/src/main/java/com/dsh/other/mapper/AppGuideConfigMapper.java
+++ b/cloud-server-other/src/main/java/com/dsh/other/mapper/AppGuideConfigMapper.java
@@ -1,4 +1,14 @@
package com.dsh.other.mapper;
+
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dsh.other.entity.AppGuideConfig;
-public interface AppGuideConfigMapper extends BaseMapper<AppGuideConfig> {}
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * APP 下载引导配置数据访问层。
+ *
+ * <p>继承 {@link BaseMapper},提供 {@link AppGuideConfig} 的基础增删改查能力。</p>
+ */
+@Mapper
+public interface AppGuideConfigMapper extends BaseMapper<AppGuideConfig> {
+}
diff --git a/cloud-server-other/src/main/java/com/dsh/other/mapper/QrLinkMapper.java b/cloud-server-other/src/main/java/com/dsh/other/mapper/QrLinkMapper.java
index cf988f8..c8a0f6c 100644
--- a/cloud-server-other/src/main/java/com/dsh/other/mapper/QrLinkMapper.java
+++ b/cloud-server-other/src/main/java/com/dsh/other/mapper/QrLinkMapper.java
@@ -1,4 +1,14 @@
package com.dsh.other.mapper;
+
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dsh.other.entity.QrLink;
-public interface QrLinkMapper extends BaseMapper<QrLink> {}
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 二维码短链接数据访问层。
+ *
+ * <p>继承 {@link BaseMapper},提供 {@link QrLink} 的基础增删改查能力。</p>
+ */
+@Mapper
+public interface QrLinkMapper extends BaseMapper<QrLink> {
+}
diff --git a/cloud-server-other/src/main/java/com/dsh/other/mapper/SysAccountAuditLogMapper.java b/cloud-server-other/src/main/java/com/dsh/other/mapper/SysAccountAuditLogMapper.java
index d614800..cf6ed0d 100644
--- a/cloud-server-other/src/main/java/com/dsh/other/mapper/SysAccountAuditLogMapper.java
+++ b/cloud-server-other/src/main/java/com/dsh/other/mapper/SysAccountAuditLogMapper.java
@@ -4,6 +4,11 @@
import com.dsh.other.entity.SysAccountAuditLog;
import org.apache.ibatis.annotations.Mapper;
+/**
+ * 账户敏感信息访问审计日志数据访问层。
+ *
+ * <p>继承 {@link BaseMapper},提供 {@link SysAccountAuditLog} 的基础增删改查能力。</p>
+ */
@Mapper
public interface SysAccountAuditLogMapper extends BaseMapper<SysAccountAuditLog> {
}
diff --git a/cloud-server-other/src/main/java/com/dsh/other/service/SysAccountAuditLogService.java b/cloud-server-other/src/main/java/com/dsh/other/service/SysAccountAuditLogService.java
index 4619176..f0df6a2 100644
--- a/cloud-server-other/src/main/java/com/dsh/other/service/SysAccountAuditLogService.java
+++ b/cloud-server-other/src/main/java/com/dsh/other/service/SysAccountAuditLogService.java
@@ -3,6 +3,17 @@
import com.baomidou.mybatisplus.extension.service.IService;
import com.dsh.other.entity.SysAccountAuditLog;
+/**
+ * 账户敏感信息访问审计日志服务。
+ *
+ * <p>继承 {@link IService},提供审计日志的基础服务能力。</p>
+ */
public interface SysAccountAuditLogService extends IService<SysAccountAuditLog> {
+
+ /**
+ * 追加一条审计日志。
+ *
+ * @param auditLog 待写入的审计日志
+ */
void append(SysAccountAuditLog auditLog);
}
--
Gitblit v1.7.1