Compare commits

...

4 Commits

Author SHA1 Message Date
f27b57ec8b 【改进】完善教程详情页 2025-11-04 10:47:29 +08:00
5e0773a59f 【改进】更换接口 2025-11-04 10:47:15 +08:00
70ea5f4dd4 【改进】完善APP隐私协议政策 2025-11-04 10:46:57 +08:00
31ea86d90c 【新增】封装时间工具 2025-11-04 10:46:10 +08:00
9 changed files with 209 additions and 36 deletions

View File

@@ -33,7 +33,7 @@ public class SaTokenConfig implements WebMvcConfigurer {
// 排除教程接口(支持匿名查询)
.excludePathPatterns("/tutorial", "/tutorial/**")
// 排除隐私政策接口(支持匿名查询)
.excludePathPatterns("/agreement", "/agreement/**")
.excludePathPatterns("/privacy_policy", "/privacy_policy/**")
// 排除固件查询接口(不需要登录)
.excludePathPatterns("/firmware/**")
// 排除系统登录页(不需要登录)

View File

@@ -1,24 +0,0 @@
package com.corewing.app.modules.app;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 隐私政策与协议
*/
@Controller
@RequestMapping("/agreement")
public class AppAgreementController {
/**
* 隐私政策列表
* @return
*/
@GetMapping("/viewList/{lang}")
public String viewList(@PathVariable String lang) {
return "app/agreement/index";
}
}

View File

@@ -0,0 +1,37 @@
package com.corewing.app.modules.app;
import com.corewing.app.entity.PrivacyPolicy;
import com.corewing.app.service.PrivacyPolicyService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.Resource;
import java.util.List;
/**
* 隐私政策与协议
*/
@Controller
@RequestMapping("/privacy_policy")
public class AppPrivacyPolicyController {
@Resource
private PrivacyPolicyService privacyPolicyService;
/**
* 隐私政策列表
* @return
*/
@GetMapping("/view_list/{lang}")
public String viewList(@PathVariable String lang, ModelMap modelMap) {
List<PrivacyPolicy> list = privacyPolicyService.list();
modelMap.put("list", list);
// 获取最新更新时间
modelMap.put("lastUpdateTime", privacyPolicyService.getLastUpdateTime());
return "app/privacyPolicy/index";
}
}

View File

@@ -7,4 +7,6 @@ import com.corewing.app.entity.PrivacyPolicy;
public interface PrivacyPolicyService extends IService<PrivacyPolicy> {
Page<PrivacyPolicy> page(PrivacyPolicy privacyPolicy);
String getLastUpdateTime();
}

View File

@@ -7,6 +7,7 @@ import com.corewing.app.common.page.PageContext;
import com.corewing.app.entity.PrivacyPolicy;
import com.corewing.app.mapper.PrivacyPolicyMapper;
import com.corewing.app.service.PrivacyPolicyService;
import com.corewing.app.util.DateUtils;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
@@ -21,4 +22,12 @@ public class PrivacyPolicyServiceImpl extends ServiceImpl<PrivacyPolicyMapper, P
queryWrapper.eq(privacyPolicy.getVisible() != null, PrivacyPolicy::getVisible, privacyPolicy.getVisible());
return page(page, queryWrapper);
}
@Override
public String getLastUpdateTime() {
LambdaQueryWrapper<PrivacyPolicy> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.orderByDesc(PrivacyPolicy::getUpdateTime, PrivacyPolicy::getCreateTime);
PrivacyPolicy privacyPolicy = list(queryWrapper).get(0);
return DateUtils.format(privacyPolicy.getUpdateTime() == null ? privacyPolicy.getCreateTime() : privacyPolicy.getUpdateTime(), "yyyy年MM月dd日");
}
}

View File

@@ -0,0 +1,14 @@
package com.corewing.app.util;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class DateUtils {
// 格式化LocalDateTime为字符串
public static String format(LocalDateTime time, String pattern) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
return time.format(formatter);
}
}

View File

@@ -1,10 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>隐私政策</title>
</head>
<body>
</body>
</html>

View File

@@ -0,0 +1,145 @@
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>隐私政策</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
<!-- 配置Tailwind自定义样式 -->
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#165DFF',
secondary: '#6B7280',
light: '#F3F4F6',
dark: '#1F2937'
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
},
}
}
}
</script>
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.text-balance {
text-wrap: balance;
}
.transition-height {
transition: max-height 0.3s ease-out;
}
}
</style>
</head>
<body class="bg-gray-50 font-sans text-dark">
<!-- 顶部导航栏 -->
<header class="sticky top-0 z-50 bg-white shadow-sm">
<div class="container mx-auto px-4 py-4 flex justify-center items-center">
<h1 class="text-xl font-semibold text-dark">隐私政策</h1>
<!-- <button class="text-primary hover:text-primary/80 transition-colors">-->
<!-- <i class="fa fa-arrow-left text-lg"></i>-->
<!-- </button>-->
</div>
</header>
<!-- 主要内容区 -->
<main class="container mx-auto px-4 py-6">
<!-- 政策更新信息 -->
<div class="bg-primary/10 border-l-4 border-primary p-4 rounded-r mb-6">
<p class="text-sm text-primary">
<i class="fa fa-info-circle mr-2"></i>
最后更新日期:<span th:text="${lastUpdateTime}"></span>
</p>
</div>
<!-- 隐私政策列表 -->
<div class="space-y-1">
<!-- 使用Thymeleaf循环渲染列表项 -->
<div th:each="item: ${list}" class="bg-white rounded-lg shadow-sm overflow-hidden mb-3 transform hover:shadow-md transition-shadow">
<!-- 列表项标题 -->
<div class="flex justify-between items-center p-4 cursor-pointer policy-toggle">
<h2 class="text-base font-medium text-dark" th:text="${item.title}"></h2>
<i class="fa fa-chevron-down text-secondary transition-transform duration-300"></i>
</div>
<!-- 列表项内容 -->
<div class="policy-content max-h-0 overflow-hidden transition-height">
<div class="px-4 pb-4 text-sm text-secondary leading-relaxed text-balance">
<p th:utext="${item.content}">
这里将显示隐私政策的详细内容,包括我们如何收集、使用、存储和保护您的个人信息,以及您拥有的相关权利和选择。
</p>
</div>
</div>
</div>
<!-- 示例默认项实际使用时由Thymeleaf数据替换 -->
<div class="bg-white rounded-lg shadow-sm overflow-hidden mb-3 transform hover:shadow-md transition-shadow">
<div class="flex justify-between items-center p-4 cursor-pointer policy-toggle">
<h2 class="text-base font-medium text-dark">信息收集与使用</h2>
<i class="fa fa-chevron-down text-secondary transition-transform duration-300"></i>
</div>
<div class="policy-content max-h-0 overflow-hidden transition-height">
<div class="px-4 pb-4 text-sm text-secondary leading-relaxed text-balance">
<p>我们收集您在使用服务过程中提供的个人信息,包括但不限于姓名、联系方式、位置信息等。这些信息将用于提供、维护和改进我们的服务,开发新功能,并保护我们的用户和服务。</p>
</div>
</div>
</div>
<div class="bg-white rounded-lg shadow-sm overflow-hidden mb-3 transform hover:shadow-md transition-shadow">
<div class="flex justify-between items-center p-4 cursor-pointer policy-toggle">
<h2 class="text-base font-medium text-dark">信息共享与披露</h2>
<i class="fa fa-chevron-down text-secondary transition-transform duration-300"></i>
</div>
<div class="policy-content max-h-0 overflow-hidden transition-height">
<div class="px-4 pb-4 text-sm text-secondary leading-relaxed text-balance">
<p>我们不会向第三方出售您的个人信息。在以下情况下,我们可能会共享您的信息:获得您的明确同意;为提供您要求的产品或服务;遵守适用的法律法规、法律程序或政府要求;保护我们的权利、财产或安全,以及我们的用户和公众的权利。</p>
</div>
</div>
</div>
</div>
<!-- 底部提示 -->
<div class="mt-8 text-center text-xs text-secondary">
<p>如有任何疑问,请联系我们的客服团队</p>
<p class="mt-1">service@example.com</p>
</div>
</main>
<script>
// 处理折叠/展开功能
document.addEventListener('DOMContentLoaded', function() {
const toggles = document.querySelectorAll('.policy-toggle');
toggles.forEach(toggle => {
toggle.addEventListener('click', function() {
const content = this.nextElementSibling;
const icon = this.querySelector('i');
// 切换内容显示状态
if (content.style.maxHeight) {
content.style.maxHeight = null;
icon.style.transform = 'rotate(0deg)';
} else {
content.style.maxHeight = content.scrollHeight + 'px';
icon.style.transform = 'rotate(180deg)';
}
});
});
// 默认展开第一项
if (toggles.length > 0) {
toggles[0].click();
}
});
</script>
</body>
</html>

View File

@@ -5,6 +5,6 @@
<title th:text="${tutorial?.tutorialTitle}"></title>
</head>
<body>
<div th:utext="${tutorial.content}"></div>
</body>
</html>